// THIS FILE IS AUTOGENERATED. // Any changes to this file will be overwritten. // For more information about how codegen works, see font-codegen/README.md #[allow(unused_imports)] use crate::codegen_prelude::*; /// [Script List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-list-table-and-script-record) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct ScriptListMarker { script_records_byte_len: usize, } impl ScriptListMarker { pub fn script_count_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn script_records_byte_range(&self) -> Range { let start = self.script_count_byte_range().end; start..start + self.script_records_byte_len } } impl MinByteRange for ScriptListMarker { fn min_byte_range(&self) -> Range { 0..self.script_records_byte_range().end } } impl<'a> FontRead<'a> for ScriptList<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); let script_count: u16 = cursor.read()?; let script_records_byte_len = (script_count as usize) .checked_mul(ScriptRecord::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(script_records_byte_len); cursor.finish(ScriptListMarker { script_records_byte_len, }) } } /// [Script List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-list-table-and-script-record) pub type ScriptList<'a> = TableRef<'a, ScriptListMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> ScriptList<'a> { /// Number of ScriptRecords pub fn script_count(&self) -> u16 { let range = self.shape.script_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of ScriptRecords, listed alphabetically by script tag pub fn script_records(&self) -> &'a [ScriptRecord] { let range = self.shape.script_records_byte_range(); self.data.read_array(range).unwrap() } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for ScriptList<'a> { fn type_name(&self) -> &str { "ScriptList" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("script_count", self.script_count())), 1usize => Some(Field::new( "script_records", traversal::FieldType::array_of_records( stringify!(ScriptRecord), self.script_records(), self.offset_data(), ), )), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for ScriptList<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } /// [Script Record](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-list-table-and-script-record) #[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)] #[repr(C)] #[repr(packed)] pub struct ScriptRecord { /// 4-byte script tag identifier pub script_tag: BigEndian, /// Offset to Script table, from beginning of ScriptList pub script_offset: BigEndian, } impl ScriptRecord { /// 4-byte script tag identifier pub fn script_tag(&self) -> Tag { self.script_tag.get() } /// Offset to Script table, from beginning of ScriptList pub fn script_offset(&self) -> Offset16 { self.script_offset.get() } /// Offset to Script table, from beginning of ScriptList /// /// The `data` argument should be retrieved from the parent table /// By calling its `offset_data` method. pub fn script<'a>(&self, data: FontData<'a>) -> Result, ReadError> { self.script_offset().resolve(data) } } impl FixedSize for ScriptRecord { const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN; } #[cfg(feature = "experimental_traverse")] impl<'a> SomeRecord<'a> for ScriptRecord { fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> { RecordResolver { name: "ScriptRecord", get_field: Box::new(move |idx, _data| match idx { 0usize => Some(Field::new("script_tag", self.script_tag())), 1usize => Some(Field::new( "script_offset", FieldType::offset(self.script_offset(), self.script(_data)), )), _ => None, }), data, } } } /// [Script Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-table-and-language-system-record) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct ScriptMarker { lang_sys_records_byte_len: usize, } impl ScriptMarker { pub fn default_lang_sys_offset_byte_range(&self) -> Range { let start = 0; start..start + Offset16::RAW_BYTE_LEN } pub fn lang_sys_count_byte_range(&self) -> Range { let start = self.default_lang_sys_offset_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn lang_sys_records_byte_range(&self) -> Range { let start = self.lang_sys_count_byte_range().end; start..start + self.lang_sys_records_byte_len } } impl MinByteRange for ScriptMarker { fn min_byte_range(&self) -> Range { 0..self.lang_sys_records_byte_range().end } } impl<'a> FontRead<'a> for Script<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); let lang_sys_count: u16 = cursor.read()?; let lang_sys_records_byte_len = (lang_sys_count as usize) .checked_mul(LangSysRecord::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(lang_sys_records_byte_len); cursor.finish(ScriptMarker { lang_sys_records_byte_len, }) } } /// [Script Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-table-and-language-system-record) pub type Script<'a> = TableRef<'a, ScriptMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> Script<'a> { /// Offset to default LangSys table, from beginning of Script table /// — may be NULL pub fn default_lang_sys_offset(&self) -> Nullable { let range = self.shape.default_lang_sys_offset_byte_range(); self.data.read_at(range.start).unwrap() } /// Attempt to resolve [`default_lang_sys_offset`][Self::default_lang_sys_offset]. pub fn default_lang_sys(&self) -> Option, ReadError>> { let data = self.data; self.default_lang_sys_offset().resolve(data) } /// Number of LangSysRecords for this script — excluding the /// default LangSys pub fn lang_sys_count(&self) -> u16 { let range = self.shape.lang_sys_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of LangSysRecords, listed alphabetically by LangSys tag pub fn lang_sys_records(&self) -> &'a [LangSysRecord] { let range = self.shape.lang_sys_records_byte_range(); self.data.read_array(range).unwrap() } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for Script<'a> { fn type_name(&self) -> &str { "Script" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new( "default_lang_sys_offset", FieldType::offset(self.default_lang_sys_offset(), self.default_lang_sys()), )), 1usize => Some(Field::new("lang_sys_count", self.lang_sys_count())), 2usize => Some(Field::new( "lang_sys_records", traversal::FieldType::array_of_records( stringify!(LangSysRecord), self.lang_sys_records(), self.offset_data(), ), )), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for Script<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } #[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)] #[repr(C)] #[repr(packed)] pub struct LangSysRecord { /// 4-byte LangSysTag identifier pub lang_sys_tag: BigEndian, /// Offset to LangSys table, from beginning of Script table pub lang_sys_offset: BigEndian, } impl LangSysRecord { /// 4-byte LangSysTag identifier pub fn lang_sys_tag(&self) -> Tag { self.lang_sys_tag.get() } /// Offset to LangSys table, from beginning of Script table pub fn lang_sys_offset(&self) -> Offset16 { self.lang_sys_offset.get() } /// Offset to LangSys table, from beginning of Script table /// /// The `data` argument should be retrieved from the parent table /// By calling its `offset_data` method. pub fn lang_sys<'a>(&self, data: FontData<'a>) -> Result, ReadError> { self.lang_sys_offset().resolve(data) } } impl FixedSize for LangSysRecord { const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN; } #[cfg(feature = "experimental_traverse")] impl<'a> SomeRecord<'a> for LangSysRecord { fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> { RecordResolver { name: "LangSysRecord", get_field: Box::new(move |idx, _data| match idx { 0usize => Some(Field::new("lang_sys_tag", self.lang_sys_tag())), 1usize => Some(Field::new( "lang_sys_offset", FieldType::offset(self.lang_sys_offset(), self.lang_sys(_data)), )), _ => None, }), data, } } } /// [Language System Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#language-system-table) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct LangSysMarker { feature_indices_byte_len: usize, } impl LangSysMarker { pub fn lookup_order_offset_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn required_feature_index_byte_range(&self) -> Range { let start = self.lookup_order_offset_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn feature_index_count_byte_range(&self) -> Range { let start = self.required_feature_index_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn feature_indices_byte_range(&self) -> Range { let start = self.feature_index_count_byte_range().end; start..start + self.feature_indices_byte_len } } impl MinByteRange for LangSysMarker { fn min_byte_range(&self) -> Range { 0..self.feature_indices_byte_range().end } } impl<'a> FontRead<'a> for LangSys<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); let feature_index_count: u16 = cursor.read()?; let feature_indices_byte_len = (feature_index_count as usize) .checked_mul(u16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(feature_indices_byte_len); cursor.finish(LangSysMarker { feature_indices_byte_len, }) } } /// [Language System Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#language-system-table) pub type LangSys<'a> = TableRef<'a, LangSysMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> LangSys<'a> { /// Index of a feature required for this language system; if no /// required features = 0xFFFF pub fn required_feature_index(&self) -> u16 { let range = self.shape.required_feature_index_byte_range(); self.data.read_at(range.start).unwrap() } /// Number of feature index values for this language system — /// excludes the required feature pub fn feature_index_count(&self) -> u16 { let range = self.shape.feature_index_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of indices into the FeatureList, in arbitrary order pub fn feature_indices(&self) -> &'a [BigEndian] { let range = self.shape.feature_indices_byte_range(); self.data.read_array(range).unwrap() } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for LangSys<'a> { fn type_name(&self) -> &str { "LangSys" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new( "required_feature_index", self.required_feature_index(), )), 1usize => Some(Field::new( "feature_index_count", self.feature_index_count(), )), 2usize => Some(Field::new("feature_indices", self.feature_indices())), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for LangSys<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } /// [Feature List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-list-table) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct FeatureListMarker { feature_records_byte_len: usize, } impl FeatureListMarker { pub fn feature_count_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn feature_records_byte_range(&self) -> Range { let start = self.feature_count_byte_range().end; start..start + self.feature_records_byte_len } } impl MinByteRange for FeatureListMarker { fn min_byte_range(&self) -> Range { 0..self.feature_records_byte_range().end } } impl<'a> FontRead<'a> for FeatureList<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); let feature_count: u16 = cursor.read()?; let feature_records_byte_len = (feature_count as usize) .checked_mul(FeatureRecord::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(feature_records_byte_len); cursor.finish(FeatureListMarker { feature_records_byte_len, }) } } /// [Feature List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-list-table) pub type FeatureList<'a> = TableRef<'a, FeatureListMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> FeatureList<'a> { /// Number of FeatureRecords in this table pub fn feature_count(&self) -> u16 { let range = self.shape.feature_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of FeatureRecords — zero-based (first feature has /// FeatureIndex = 0), listed alphabetically by feature tag pub fn feature_records(&self) -> &'a [FeatureRecord] { let range = self.shape.feature_records_byte_range(); self.data.read_array(range).unwrap() } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for FeatureList<'a> { fn type_name(&self) -> &str { "FeatureList" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("feature_count", self.feature_count())), 1usize => Some(Field::new( "feature_records", traversal::FieldType::array_of_records( stringify!(FeatureRecord), self.feature_records(), self.offset_data(), ), )), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for FeatureList<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } /// Part of [FeatureList] #[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)] #[repr(C)] #[repr(packed)] pub struct FeatureRecord { /// 4-byte feature identification tag pub feature_tag: BigEndian, /// Offset to Feature table, from beginning of FeatureList pub feature_offset: BigEndian, } impl FeatureRecord { /// 4-byte feature identification tag pub fn feature_tag(&self) -> Tag { self.feature_tag.get() } /// Offset to Feature table, from beginning of FeatureList pub fn feature_offset(&self) -> Offset16 { self.feature_offset.get() } /// Offset to Feature table, from beginning of FeatureList /// /// The `data` argument should be retrieved from the parent table /// By calling its `offset_data` method. pub fn feature<'a>(&self, data: FontData<'a>) -> Result, ReadError> { let args = self.feature_tag(); self.feature_offset().resolve_with_args(data, &args) } } impl FixedSize for FeatureRecord { const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN; } #[cfg(feature = "experimental_traverse")] impl<'a> SomeRecord<'a> for FeatureRecord { fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> { RecordResolver { name: "FeatureRecord", get_field: Box::new(move |idx, _data| match idx { 0usize => Some(Field::new("feature_tag", self.feature_tag())), 1usize => Some(Field::new( "feature_offset", FieldType::offset(self.feature_offset(), self.feature(_data)), )), _ => None, }), data, } } } /// [Feature Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-table) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct FeatureMarker { feature_tag: Tag, lookup_list_indices_byte_len: usize, } impl FeatureMarker { pub fn feature_params_offset_byte_range(&self) -> Range { let start = 0; start..start + Offset16::RAW_BYTE_LEN } pub fn lookup_index_count_byte_range(&self) -> Range { let start = self.feature_params_offset_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn lookup_list_indices_byte_range(&self) -> Range { let start = self.lookup_index_count_byte_range().end; start..start + self.lookup_list_indices_byte_len } } impl MinByteRange for FeatureMarker { fn min_byte_range(&self) -> Range { 0..self.lookup_list_indices_byte_range().end } } impl ReadArgs for Feature<'_> { type Args = Tag; } impl<'a> FontReadWithArgs<'a> for Feature<'a> { fn read_with_args(data: FontData<'a>, args: &Tag) -> Result { let feature_tag = *args; let mut cursor = data.cursor(); cursor.advance::(); let lookup_index_count: u16 = cursor.read()?; let lookup_list_indices_byte_len = (lookup_index_count as usize) .checked_mul(u16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(lookup_list_indices_byte_len); cursor.finish(FeatureMarker { feature_tag, lookup_list_indices_byte_len, }) } } impl<'a> Feature<'a> { /// A constructor that requires additional arguments. /// /// This type requires some external state in order to be /// parsed. pub fn read(data: FontData<'a>, feature_tag: Tag) -> Result { let args = feature_tag; Self::read_with_args(data, &args) } } /// [Feature Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-table) pub type Feature<'a> = TableRef<'a, FeatureMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> Feature<'a> { /// Offset from start of Feature table to FeatureParams table, if defined for the feature and present, else NULL pub fn feature_params_offset(&self) -> Nullable { let range = self.shape.feature_params_offset_byte_range(); self.data.read_at(range.start).unwrap() } /// Attempt to resolve [`feature_params_offset`][Self::feature_params_offset]. pub fn feature_params(&self) -> Option, ReadError>> { let data = self.data; let args = self.feature_tag(); self.feature_params_offset().resolve_with_args(data, &args) } /// Number of LookupList indices for this feature pub fn lookup_index_count(&self) -> u16 { let range = self.shape.lookup_index_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of indices into the LookupList — zero-based (first /// lookup is LookupListIndex = 0) pub fn lookup_list_indices(&self) -> &'a [BigEndian] { let range = self.shape.lookup_list_indices_byte_range(); self.data.read_array(range).unwrap() } pub(crate) fn feature_tag(&self) -> Tag { self.shape.feature_tag } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for Feature<'a> { fn type_name(&self) -> &str { "Feature" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new( "feature_params_offset", FieldType::offset(self.feature_params_offset(), self.feature_params()), )), 1usize => Some(Field::new("lookup_index_count", self.lookup_index_count())), 2usize => Some(Field::new( "lookup_list_indices", self.lookup_list_indices(), )), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for Feature<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } /// [Lookup List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-list-table) #[derive(Debug)] #[doc(hidden)] pub struct LookupListMarker { lookup_offsets_byte_len: usize, offset_type: std::marker::PhantomData<*const T>, } impl LookupListMarker { pub fn lookup_count_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn lookup_offsets_byte_range(&self) -> Range { let start = self.lookup_count_byte_range().end; start..start + self.lookup_offsets_byte_len } } impl MinByteRange for LookupListMarker { fn min_byte_range(&self) -> Range { 0..self.lookup_offsets_byte_range().end } } impl Clone for LookupListMarker { fn clone(&self) -> Self { *self } } impl Copy for LookupListMarker {} impl<'a, T> FontRead<'a> for LookupList<'a, T> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); let lookup_count: u16 = cursor.read()?; let lookup_offsets_byte_len = (lookup_count as usize) .checked_mul(Offset16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(lookup_offsets_byte_len); cursor.finish(LookupListMarker { lookup_offsets_byte_len, offset_type: std::marker::PhantomData, }) } } impl<'a> LookupList<'a, ()> { #[allow(dead_code)] pub(crate) fn into_concrete(self) -> LookupList<'a, T> { let TableRef { data, shape } = self; TableRef { shape: LookupListMarker { lookup_offsets_byte_len: shape.lookup_offsets_byte_len, offset_type: std::marker::PhantomData, }, data, } } } impl<'a, T> LookupList<'a, T> { #[allow(dead_code)] /// Replace the specific generic type on this implementation with `()` pub(crate) fn of_unit_type(&self) -> LookupList<'a, ()> { let TableRef { data, shape } = self; TableRef { shape: LookupListMarker { lookup_offsets_byte_len: shape.lookup_offsets_byte_len, offset_type: std::marker::PhantomData, }, data: *data, } } } /// [Lookup List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-list-table) pub type LookupList<'a, T> = TableRef<'a, LookupListMarker>; #[allow(clippy::needless_lifetimes)] impl<'a, T> LookupList<'a, T> { /// Number of lookups in this table pub fn lookup_count(&self) -> u16 { let range = self.shape.lookup_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of offsets to Lookup tables, from beginning of LookupList /// — zero based (first lookup is Lookup index = 0) pub fn lookup_offsets(&self) -> &'a [BigEndian] { let range = self.shape.lookup_offsets_byte_range(); self.data.read_array(range).unwrap() } /// A dynamically resolving wrapper for [`lookup_offsets`][Self::lookup_offsets]. pub fn lookups(&self) -> ArrayOfOffsets<'a, T, Offset16> where T: FontRead<'a>, { let data = self.data; let offsets = self.lookup_offsets(); ArrayOfOffsets::new(offsets, data, ()) } } #[cfg(feature = "experimental_traverse")] impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> SomeTable<'a> for LookupList<'a, T> { fn type_name(&self) -> &str { "LookupList" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("lookup_count", self.lookup_count())), 1usize => Some({ let data = self.data; Field::new( "lookup_offsets", FieldType::array_of_offsets( better_type_name::(), self.lookup_offsets(), move |off| { let target = off.get().resolve::(data); FieldType::offset(off.get(), target) }, ), ) }), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> std::fmt::Debug for LookupList<'a, T> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } /// [Lookup Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-table) #[derive(Debug)] #[doc(hidden)] pub struct LookupMarker { subtable_offsets_byte_len: usize, mark_filtering_set_byte_start: Option, offset_type: std::marker::PhantomData<*const T>, } impl LookupMarker { pub fn lookup_type_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn lookup_flag_byte_range(&self) -> Range { let start = self.lookup_type_byte_range().end; start..start + LookupFlag::RAW_BYTE_LEN } pub fn sub_table_count_byte_range(&self) -> Range { let start = self.lookup_flag_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn subtable_offsets_byte_range(&self) -> Range { let start = self.sub_table_count_byte_range().end; start..start + self.subtable_offsets_byte_len } pub fn mark_filtering_set_byte_range(&self) -> Option> { let start = self.mark_filtering_set_byte_start?; Some(start..start + u16::RAW_BYTE_LEN) } } impl MinByteRange for LookupMarker { fn min_byte_range(&self) -> Range { 0..self.subtable_offsets_byte_range().end } } impl Clone for LookupMarker { fn clone(&self) -> Self { *self } } impl Copy for LookupMarker {} impl<'a, T> FontRead<'a> for Lookup<'a, T> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); let lookup_flag: LookupFlag = cursor.read()?; let sub_table_count: u16 = cursor.read()?; let subtable_offsets_byte_len = (sub_table_count as usize) .checked_mul(Offset16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(subtable_offsets_byte_len); let mark_filtering_set_byte_start = lookup_flag .contains(LookupFlag::USE_MARK_FILTERING_SET) .then(|| cursor.position()) .transpose()?; lookup_flag .contains(LookupFlag::USE_MARK_FILTERING_SET) .then(|| cursor.advance::()); cursor.finish(LookupMarker { subtable_offsets_byte_len, mark_filtering_set_byte_start, offset_type: std::marker::PhantomData, }) } } impl<'a> Lookup<'a, ()> { #[allow(dead_code)] pub(crate) fn into_concrete(self) -> Lookup<'a, T> { let TableRef { data, shape } = self; TableRef { shape: LookupMarker { subtable_offsets_byte_len: shape.subtable_offsets_byte_len, mark_filtering_set_byte_start: shape.mark_filtering_set_byte_start, offset_type: std::marker::PhantomData, }, data, } } } impl<'a, T> Lookup<'a, T> { #[allow(dead_code)] /// Replace the specific generic type on this implementation with `()` pub(crate) fn of_unit_type(&self) -> Lookup<'a, ()> { let TableRef { data, shape } = self; TableRef { shape: LookupMarker { subtable_offsets_byte_len: shape.subtable_offsets_byte_len, mark_filtering_set_byte_start: shape.mark_filtering_set_byte_start, offset_type: std::marker::PhantomData, }, data: *data, } } } /// [Lookup Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-table) pub type Lookup<'a, T> = TableRef<'a, LookupMarker>; #[allow(clippy::needless_lifetimes)] impl<'a, T> Lookup<'a, T> { /// Different enumerations for GSUB and GPOS pub fn lookup_type(&self) -> u16 { let range = self.shape.lookup_type_byte_range(); self.data.read_at(range.start).unwrap() } /// Lookup qualifiers pub fn lookup_flag(&self) -> LookupFlag { let range = self.shape.lookup_flag_byte_range(); self.data.read_at(range.start).unwrap() } /// Number of subtables for this lookup pub fn sub_table_count(&self) -> u16 { let range = self.shape.sub_table_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of offsets to lookup subtables, from beginning of Lookup /// table pub fn subtable_offsets(&self) -> &'a [BigEndian] { let range = self.shape.subtable_offsets_byte_range(); self.data.read_array(range).unwrap() } /// A dynamically resolving wrapper for [`subtable_offsets`][Self::subtable_offsets]. pub fn subtables(&self) -> ArrayOfOffsets<'a, T, Offset16> where T: FontRead<'a>, { let data = self.data; let offsets = self.subtable_offsets(); ArrayOfOffsets::new(offsets, data, ()) } /// Index (base 0) into GDEF mark glyph sets structure. This field /// is only present if the USE_MARK_FILTERING_SET lookup flag is /// set. pub fn mark_filtering_set(&self) -> Option { let range = self.shape.mark_filtering_set_byte_range()?; Some(self.data.read_at(range.start).unwrap()) } } #[cfg(feature = "experimental_traverse")] impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> SomeTable<'a> for Lookup<'a, T> { fn type_name(&self) -> &str { "Lookup" } fn get_field(&self, idx: usize) -> Option> { let lookup_flag = self.lookup_flag(); match idx { 0usize => Some(Field::new("lookup_type", self.lookup_type())), 1usize => Some(Field::new("lookup_flag", self.traverse_lookup_flag())), 2usize => Some(Field::new("sub_table_count", self.sub_table_count())), 3usize => Some({ let data = self.data; Field::new( "subtable_offsets", FieldType::array_of_offsets( better_type_name::(), self.subtable_offsets(), move |off| { let target = off.get().resolve::(data); FieldType::offset(off.get(), target) }, ), ) }), 4usize if lookup_flag.contains(LookupFlag::USE_MARK_FILTERING_SET) => Some(Field::new( "mark_filtering_set", self.mark_filtering_set().unwrap(), )), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> std::fmt::Debug for Lookup<'a, T> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } impl Format for CoverageFormat1Marker { const FORMAT: u16 = 1; } /// [Coverage Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-1) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct CoverageFormat1Marker { glyph_array_byte_len: usize, } impl CoverageFormat1Marker { pub fn coverage_format_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn glyph_count_byte_range(&self) -> Range { let start = self.coverage_format_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn glyph_array_byte_range(&self) -> Range { let start = self.glyph_count_byte_range().end; start..start + self.glyph_array_byte_len } } impl MinByteRange for CoverageFormat1Marker { fn min_byte_range(&self) -> Range { 0..self.glyph_array_byte_range().end } } impl<'a> FontRead<'a> for CoverageFormat1<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); let glyph_count: u16 = cursor.read()?; let glyph_array_byte_len = (glyph_count as usize) .checked_mul(GlyphId16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(glyph_array_byte_len); cursor.finish(CoverageFormat1Marker { glyph_array_byte_len, }) } } /// [Coverage Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-1) pub type CoverageFormat1<'a> = TableRef<'a, CoverageFormat1Marker>; #[allow(clippy::needless_lifetimes)] impl<'a> CoverageFormat1<'a> { /// Format identifier — format = 1 pub fn coverage_format(&self) -> u16 { let range = self.shape.coverage_format_byte_range(); self.data.read_at(range.start).unwrap() } /// Number of glyphs in the glyph array pub fn glyph_count(&self) -> u16 { let range = self.shape.glyph_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of glyph IDs — in numerical order pub fn glyph_array(&self) -> &'a [BigEndian] { let range = self.shape.glyph_array_byte_range(); self.data.read_array(range).unwrap() } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for CoverageFormat1<'a> { fn type_name(&self) -> &str { "CoverageFormat1" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("coverage_format", self.coverage_format())), 1usize => Some(Field::new("glyph_count", self.glyph_count())), 2usize => Some(Field::new("glyph_array", self.glyph_array())), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for CoverageFormat1<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } impl Format for CoverageFormat2Marker { const FORMAT: u16 = 2; } /// [Coverage Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-2) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct CoverageFormat2Marker { range_records_byte_len: usize, } impl CoverageFormat2Marker { pub fn coverage_format_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn range_count_byte_range(&self) -> Range { let start = self.coverage_format_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn range_records_byte_range(&self) -> Range { let start = self.range_count_byte_range().end; start..start + self.range_records_byte_len } } impl MinByteRange for CoverageFormat2Marker { fn min_byte_range(&self) -> Range { 0..self.range_records_byte_range().end } } impl<'a> FontRead<'a> for CoverageFormat2<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); let range_count: u16 = cursor.read()?; let range_records_byte_len = (range_count as usize) .checked_mul(RangeRecord::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(range_records_byte_len); cursor.finish(CoverageFormat2Marker { range_records_byte_len, }) } } /// [Coverage Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-2) pub type CoverageFormat2<'a> = TableRef<'a, CoverageFormat2Marker>; #[allow(clippy::needless_lifetimes)] impl<'a> CoverageFormat2<'a> { /// Format identifier — format = 2 pub fn coverage_format(&self) -> u16 { let range = self.shape.coverage_format_byte_range(); self.data.read_at(range.start).unwrap() } /// Number of RangeRecords pub fn range_count(&self) -> u16 { let range = self.shape.range_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of glyph ranges — ordered by startGlyphID. pub fn range_records(&self) -> &'a [RangeRecord] { let range = self.shape.range_records_byte_range(); self.data.read_array(range).unwrap() } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for CoverageFormat2<'a> { fn type_name(&self) -> &str { "CoverageFormat2" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("coverage_format", self.coverage_format())), 1usize => Some(Field::new("range_count", self.range_count())), 2usize => Some(Field::new( "range_records", traversal::FieldType::array_of_records( stringify!(RangeRecord), self.range_records(), self.offset_data(), ), )), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for CoverageFormat2<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } /// Used in [CoverageFormat2] #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)] #[repr(C)] #[repr(packed)] pub struct RangeRecord { /// First glyph ID in the range pub start_glyph_id: BigEndian, /// Last glyph ID in the range pub end_glyph_id: BigEndian, /// Coverage Index of first glyph ID in range pub start_coverage_index: BigEndian, } impl RangeRecord { /// First glyph ID in the range pub fn start_glyph_id(&self) -> GlyphId16 { self.start_glyph_id.get() } /// Last glyph ID in the range pub fn end_glyph_id(&self) -> GlyphId16 { self.end_glyph_id.get() } /// Coverage Index of first glyph ID in range pub fn start_coverage_index(&self) -> u16 { self.start_coverage_index.get() } } impl FixedSize for RangeRecord { const RAW_BYTE_LEN: usize = GlyphId16::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN; } #[cfg(feature = "experimental_traverse")] impl<'a> SomeRecord<'a> for RangeRecord { fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> { RecordResolver { name: "RangeRecord", get_field: Box::new(move |idx, _data| match idx { 0usize => Some(Field::new("start_glyph_id", self.start_glyph_id())), 1usize => Some(Field::new("end_glyph_id", self.end_glyph_id())), 2usize => Some(Field::new( "start_coverage_index", self.start_coverage_index(), )), _ => None, }), data, } } } /// [Coverage Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-table) #[derive(Clone)] pub enum CoverageTable<'a> { Format1(CoverageFormat1<'a>), Format2(CoverageFormat2<'a>), } impl<'a> CoverageTable<'a> { ///Return the `FontData` used to resolve offsets for this table. pub fn offset_data(&self) -> FontData<'a> { match self { Self::Format1(item) => item.offset_data(), Self::Format2(item) => item.offset_data(), } } /// Format identifier — format = 1 pub fn coverage_format(&self) -> u16 { match self { Self::Format1(item) => item.coverage_format(), Self::Format2(item) => item.coverage_format(), } } } impl<'a> FontRead<'a> for CoverageTable<'a> { fn read(data: FontData<'a>) -> Result { let format: u16 = data.read_at(0usize)?; match format { CoverageFormat1Marker::FORMAT => Ok(Self::Format1(FontRead::read(data)?)), CoverageFormat2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)), other => Err(ReadError::InvalidFormat(other.into())), } } } impl MinByteRange for CoverageTable<'_> { fn min_byte_range(&self) -> Range { match self { Self::Format1(item) => item.min_byte_range(), Self::Format2(item) => item.min_byte_range(), } } } #[cfg(feature = "experimental_traverse")] impl<'a> CoverageTable<'a> { fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> { match self { Self::Format1(table) => table, Self::Format2(table) => table, } } } #[cfg(feature = "experimental_traverse")] impl std::fmt::Debug for CoverageTable<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.dyn_inner().fmt(f) } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for CoverageTable<'a> { fn type_name(&self) -> &str { self.dyn_inner().type_name() } fn get_field(&self, idx: usize) -> Option> { self.dyn_inner().get_field(idx) } } impl Format for ClassDefFormat1Marker { const FORMAT: u16 = 1; } /// [Class Definition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-1) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct ClassDefFormat1Marker { class_value_array_byte_len: usize, } impl ClassDefFormat1Marker { pub fn class_format_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn start_glyph_id_byte_range(&self) -> Range { let start = self.class_format_byte_range().end; start..start + GlyphId16::RAW_BYTE_LEN } pub fn glyph_count_byte_range(&self) -> Range { let start = self.start_glyph_id_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn class_value_array_byte_range(&self) -> Range { let start = self.glyph_count_byte_range().end; start..start + self.class_value_array_byte_len } } impl MinByteRange for ClassDefFormat1Marker { fn min_byte_range(&self) -> Range { 0..self.class_value_array_byte_range().end } } impl<'a> FontRead<'a> for ClassDefFormat1<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); let glyph_count: u16 = cursor.read()?; let class_value_array_byte_len = (glyph_count as usize) .checked_mul(u16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(class_value_array_byte_len); cursor.finish(ClassDefFormat1Marker { class_value_array_byte_len, }) } } /// [Class Definition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-1) pub type ClassDefFormat1<'a> = TableRef<'a, ClassDefFormat1Marker>; #[allow(clippy::needless_lifetimes)] impl<'a> ClassDefFormat1<'a> { /// Format identifier — format = 1 pub fn class_format(&self) -> u16 { let range = self.shape.class_format_byte_range(); self.data.read_at(range.start).unwrap() } /// First glyph ID of the classValueArray pub fn start_glyph_id(&self) -> GlyphId16 { let range = self.shape.start_glyph_id_byte_range(); self.data.read_at(range.start).unwrap() } /// Size of the classValueArray pub fn glyph_count(&self) -> u16 { let range = self.shape.glyph_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of Class Values — one per glyph ID pub fn class_value_array(&self) -> &'a [BigEndian] { let range = self.shape.class_value_array_byte_range(); self.data.read_array(range).unwrap() } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for ClassDefFormat1<'a> { fn type_name(&self) -> &str { "ClassDefFormat1" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("class_format", self.class_format())), 1usize => Some(Field::new("start_glyph_id", self.start_glyph_id())), 2usize => Some(Field::new("glyph_count", self.glyph_count())), 3usize => Some(Field::new("class_value_array", self.class_value_array())), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for ClassDefFormat1<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } impl Format for ClassDefFormat2Marker { const FORMAT: u16 = 2; } /// [Class Definition Table Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-2) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct ClassDefFormat2Marker { class_range_records_byte_len: usize, } impl ClassDefFormat2Marker { pub fn class_format_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn class_range_count_byte_range(&self) -> Range { let start = self.class_format_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn class_range_records_byte_range(&self) -> Range { let start = self.class_range_count_byte_range().end; start..start + self.class_range_records_byte_len } } impl MinByteRange for ClassDefFormat2Marker { fn min_byte_range(&self) -> Range { 0..self.class_range_records_byte_range().end } } impl<'a> FontRead<'a> for ClassDefFormat2<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); let class_range_count: u16 = cursor.read()?; let class_range_records_byte_len = (class_range_count as usize) .checked_mul(ClassRangeRecord::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(class_range_records_byte_len); cursor.finish(ClassDefFormat2Marker { class_range_records_byte_len, }) } } /// [Class Definition Table Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-2) pub type ClassDefFormat2<'a> = TableRef<'a, ClassDefFormat2Marker>; #[allow(clippy::needless_lifetimes)] impl<'a> ClassDefFormat2<'a> { /// Format identifier — format = 2 pub fn class_format(&self) -> u16 { let range = self.shape.class_format_byte_range(); self.data.read_at(range.start).unwrap() } /// Number of ClassRangeRecords pub fn class_range_count(&self) -> u16 { let range = self.shape.class_range_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of ClassRangeRecords — ordered by startGlyphID pub fn class_range_records(&self) -> &'a [ClassRangeRecord] { let range = self.shape.class_range_records_byte_range(); self.data.read_array(range).unwrap() } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for ClassDefFormat2<'a> { fn type_name(&self) -> &str { "ClassDefFormat2" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("class_format", self.class_format())), 1usize => Some(Field::new("class_range_count", self.class_range_count())), 2usize => Some(Field::new( "class_range_records", traversal::FieldType::array_of_records( stringify!(ClassRangeRecord), self.class_range_records(), self.offset_data(), ), )), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for ClassDefFormat2<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } /// Used in [ClassDefFormat2] #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)] #[repr(C)] #[repr(packed)] pub struct ClassRangeRecord { /// First glyph ID in the range pub start_glyph_id: BigEndian, /// Last glyph ID in the range pub end_glyph_id: BigEndian, /// Applied to all glyphs in the range pub class: BigEndian, } impl ClassRangeRecord { /// First glyph ID in the range pub fn start_glyph_id(&self) -> GlyphId16 { self.start_glyph_id.get() } /// Last glyph ID in the range pub fn end_glyph_id(&self) -> GlyphId16 { self.end_glyph_id.get() } /// Applied to all glyphs in the range pub fn class(&self) -> u16 { self.class.get() } } impl FixedSize for ClassRangeRecord { const RAW_BYTE_LEN: usize = GlyphId16::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN; } #[cfg(feature = "experimental_traverse")] impl<'a> SomeRecord<'a> for ClassRangeRecord { fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> { RecordResolver { name: "ClassRangeRecord", get_field: Box::new(move |idx, _data| match idx { 0usize => Some(Field::new("start_glyph_id", self.start_glyph_id())), 1usize => Some(Field::new("end_glyph_id", self.end_glyph_id())), 2usize => Some(Field::new("class", self.class())), _ => None, }), data, } } } /// A [Class Definition Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table) #[derive(Clone)] pub enum ClassDef<'a> { Format1(ClassDefFormat1<'a>), Format2(ClassDefFormat2<'a>), } impl<'a> ClassDef<'a> { ///Return the `FontData` used to resolve offsets for this table. pub fn offset_data(&self) -> FontData<'a> { match self { Self::Format1(item) => item.offset_data(), Self::Format2(item) => item.offset_data(), } } /// Format identifier — format = 1 pub fn class_format(&self) -> u16 { match self { Self::Format1(item) => item.class_format(), Self::Format2(item) => item.class_format(), } } } impl<'a> FontRead<'a> for ClassDef<'a> { fn read(data: FontData<'a>) -> Result { let format: u16 = data.read_at(0usize)?; match format { ClassDefFormat1Marker::FORMAT => Ok(Self::Format1(FontRead::read(data)?)), ClassDefFormat2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)), other => Err(ReadError::InvalidFormat(other.into())), } } } impl MinByteRange for ClassDef<'_> { fn min_byte_range(&self) -> Range { match self { Self::Format1(item) => item.min_byte_range(), Self::Format2(item) => item.min_byte_range(), } } } #[cfg(feature = "experimental_traverse")] impl<'a> ClassDef<'a> { fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> { match self { Self::Format1(table) => table, Self::Format2(table) => table, } } } #[cfg(feature = "experimental_traverse")] impl std::fmt::Debug for ClassDef<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.dyn_inner().fmt(f) } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for ClassDef<'a> { fn type_name(&self) -> &str { self.dyn_inner().type_name() } fn get_field(&self, idx: usize) -> Option> { self.dyn_inner().get_field(idx) } } /// [Sequence Lookup Record](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-lookup-record) #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)] #[repr(C)] #[repr(packed)] pub struct SequenceLookupRecord { /// Index (zero-based) into the input glyph sequence pub sequence_index: BigEndian, /// Index (zero-based) into the LookupList pub lookup_list_index: BigEndian, } impl SequenceLookupRecord { /// Index (zero-based) into the input glyph sequence pub fn sequence_index(&self) -> u16 { self.sequence_index.get() } /// Index (zero-based) into the LookupList pub fn lookup_list_index(&self) -> u16 { self.lookup_list_index.get() } } impl FixedSize for SequenceLookupRecord { const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN; } #[cfg(feature = "experimental_traverse")] impl<'a> SomeRecord<'a> for SequenceLookupRecord { fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> { RecordResolver { name: "SequenceLookupRecord", get_field: Box::new(move |idx, _data| match idx { 0usize => Some(Field::new("sequence_index", self.sequence_index())), 1usize => Some(Field::new("lookup_list_index", self.lookup_list_index())), _ => None, }), data, } } } impl Format for SequenceContextFormat1Marker { const FORMAT: u16 = 1; } /// [Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-1-simple-glyph-contexts) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct SequenceContextFormat1Marker { seq_rule_set_offsets_byte_len: usize, } impl SequenceContextFormat1Marker { pub fn format_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn coverage_offset_byte_range(&self) -> Range { let start = self.format_byte_range().end; start..start + Offset16::RAW_BYTE_LEN } pub fn seq_rule_set_count_byte_range(&self) -> Range { let start = self.coverage_offset_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn seq_rule_set_offsets_byte_range(&self) -> Range { let start = self.seq_rule_set_count_byte_range().end; start..start + self.seq_rule_set_offsets_byte_len } } impl MinByteRange for SequenceContextFormat1Marker { fn min_byte_range(&self) -> Range { 0..self.seq_rule_set_offsets_byte_range().end } } impl<'a> FontRead<'a> for SequenceContextFormat1<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); let seq_rule_set_count: u16 = cursor.read()?; let seq_rule_set_offsets_byte_len = (seq_rule_set_count as usize) .checked_mul(Offset16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(seq_rule_set_offsets_byte_len); cursor.finish(SequenceContextFormat1Marker { seq_rule_set_offsets_byte_len, }) } } /// [Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-1-simple-glyph-contexts) pub type SequenceContextFormat1<'a> = TableRef<'a, SequenceContextFormat1Marker>; #[allow(clippy::needless_lifetimes)] impl<'a> SequenceContextFormat1<'a> { /// Format identifier: format = 1 pub fn format(&self) -> u16 { let range = self.shape.format_byte_range(); self.data.read_at(range.start).unwrap() } /// Offset to Coverage table, from beginning of /// SequenceContextFormat1 table pub fn coverage_offset(&self) -> Offset16 { let range = self.shape.coverage_offset_byte_range(); self.data.read_at(range.start).unwrap() } /// Attempt to resolve [`coverage_offset`][Self::coverage_offset]. pub fn coverage(&self) -> Result, ReadError> { let data = self.data; self.coverage_offset().resolve(data) } /// Number of SequenceRuleSet tables pub fn seq_rule_set_count(&self) -> u16 { let range = self.shape.seq_rule_set_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of offsets to SequenceRuleSet tables, from beginning of /// SequenceContextFormat1 table (offsets may be NULL) pub fn seq_rule_set_offsets(&self) -> &'a [BigEndian>] { let range = self.shape.seq_rule_set_offsets_byte_range(); self.data.read_array(range).unwrap() } /// A dynamically resolving wrapper for [`seq_rule_set_offsets`][Self::seq_rule_set_offsets]. pub fn seq_rule_sets(&self) -> ArrayOfNullableOffsets<'a, SequenceRuleSet<'a>, Offset16> { let data = self.data; let offsets = self.seq_rule_set_offsets(); ArrayOfNullableOffsets::new(offsets, data, ()) } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for SequenceContextFormat1<'a> { fn type_name(&self) -> &str { "SequenceContextFormat1" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("format", self.format())), 1usize => Some(Field::new( "coverage_offset", FieldType::offset(self.coverage_offset(), self.coverage()), )), 2usize => Some(Field::new("seq_rule_set_count", self.seq_rule_set_count())), 3usize => Some({ let data = self.data; Field::new( "seq_rule_set_offsets", FieldType::array_of_offsets( better_type_name::(), self.seq_rule_set_offsets(), move |off| { let target = off.get().resolve::(data); FieldType::offset(off.get(), target) }, ), ) }), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for SequenceContextFormat1<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } /// Part of [SequenceContextFormat1] #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct SequenceRuleSetMarker { seq_rule_offsets_byte_len: usize, } impl SequenceRuleSetMarker { pub fn seq_rule_count_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn seq_rule_offsets_byte_range(&self) -> Range { let start = self.seq_rule_count_byte_range().end; start..start + self.seq_rule_offsets_byte_len } } impl MinByteRange for SequenceRuleSetMarker { fn min_byte_range(&self) -> Range { 0..self.seq_rule_offsets_byte_range().end } } impl<'a> FontRead<'a> for SequenceRuleSet<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); let seq_rule_count: u16 = cursor.read()?; let seq_rule_offsets_byte_len = (seq_rule_count as usize) .checked_mul(Offset16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(seq_rule_offsets_byte_len); cursor.finish(SequenceRuleSetMarker { seq_rule_offsets_byte_len, }) } } /// Part of [SequenceContextFormat1] pub type SequenceRuleSet<'a> = TableRef<'a, SequenceRuleSetMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> SequenceRuleSet<'a> { /// Number of SequenceRule tables pub fn seq_rule_count(&self) -> u16 { let range = self.shape.seq_rule_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of offsets to SequenceRule tables, from beginning of the /// SequenceRuleSet table pub fn seq_rule_offsets(&self) -> &'a [BigEndian] { let range = self.shape.seq_rule_offsets_byte_range(); self.data.read_array(range).unwrap() } /// A dynamically resolving wrapper for [`seq_rule_offsets`][Self::seq_rule_offsets]. pub fn seq_rules(&self) -> ArrayOfOffsets<'a, SequenceRule<'a>, Offset16> { let data = self.data; let offsets = self.seq_rule_offsets(); ArrayOfOffsets::new(offsets, data, ()) } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for SequenceRuleSet<'a> { fn type_name(&self) -> &str { "SequenceRuleSet" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("seq_rule_count", self.seq_rule_count())), 1usize => Some({ let data = self.data; Field::new( "seq_rule_offsets", FieldType::array_of_offsets( better_type_name::(), self.seq_rule_offsets(), move |off| { let target = off.get().resolve::(data); FieldType::offset(off.get(), target) }, ), ) }), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for SequenceRuleSet<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } /// Part of [SequenceContextFormat1] #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct SequenceRuleMarker { input_sequence_byte_len: usize, seq_lookup_records_byte_len: usize, } impl SequenceRuleMarker { pub fn glyph_count_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn seq_lookup_count_byte_range(&self) -> Range { let start = self.glyph_count_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn input_sequence_byte_range(&self) -> Range { let start = self.seq_lookup_count_byte_range().end; start..start + self.input_sequence_byte_len } pub fn seq_lookup_records_byte_range(&self) -> Range { let start = self.input_sequence_byte_range().end; start..start + self.seq_lookup_records_byte_len } } impl MinByteRange for SequenceRuleMarker { fn min_byte_range(&self) -> Range { 0..self.seq_lookup_records_byte_range().end } } impl<'a> FontRead<'a> for SequenceRule<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); let glyph_count: u16 = cursor.read()?; let seq_lookup_count: u16 = cursor.read()?; let input_sequence_byte_len = (transforms::subtract(glyph_count, 1_usize)) .checked_mul(GlyphId16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(input_sequence_byte_len); let seq_lookup_records_byte_len = (seq_lookup_count as usize) .checked_mul(SequenceLookupRecord::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(seq_lookup_records_byte_len); cursor.finish(SequenceRuleMarker { input_sequence_byte_len, seq_lookup_records_byte_len, }) } } /// Part of [SequenceContextFormat1] pub type SequenceRule<'a> = TableRef<'a, SequenceRuleMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> SequenceRule<'a> { /// Number of glyphs in the input glyph sequence pub fn glyph_count(&self) -> u16 { let range = self.shape.glyph_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Number of SequenceLookupRecords pub fn seq_lookup_count(&self) -> u16 { let range = self.shape.seq_lookup_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of input glyph IDs—starting with the second glyph pub fn input_sequence(&self) -> &'a [BigEndian] { let range = self.shape.input_sequence_byte_range(); self.data.read_array(range).unwrap() } /// Array of Sequence lookup records pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] { let range = self.shape.seq_lookup_records_byte_range(); self.data.read_array(range).unwrap() } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for SequenceRule<'a> { fn type_name(&self) -> &str { "SequenceRule" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("glyph_count", self.glyph_count())), 1usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())), 2usize => Some(Field::new("input_sequence", self.input_sequence())), 3usize => Some(Field::new( "seq_lookup_records", traversal::FieldType::array_of_records( stringify!(SequenceLookupRecord), self.seq_lookup_records(), self.offset_data(), ), )), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for SequenceRule<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } impl Format for SequenceContextFormat2Marker { const FORMAT: u16 = 2; } /// [Sequence Context Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-2-class-based-glyph-contexts) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct SequenceContextFormat2Marker { class_seq_rule_set_offsets_byte_len: usize, } impl SequenceContextFormat2Marker { pub fn format_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn coverage_offset_byte_range(&self) -> Range { let start = self.format_byte_range().end; start..start + Offset16::RAW_BYTE_LEN } pub fn class_def_offset_byte_range(&self) -> Range { let start = self.coverage_offset_byte_range().end; start..start + Offset16::RAW_BYTE_LEN } pub fn class_seq_rule_set_count_byte_range(&self) -> Range { let start = self.class_def_offset_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn class_seq_rule_set_offsets_byte_range(&self) -> Range { let start = self.class_seq_rule_set_count_byte_range().end; start..start + self.class_seq_rule_set_offsets_byte_len } } impl MinByteRange for SequenceContextFormat2Marker { fn min_byte_range(&self) -> Range { 0..self.class_seq_rule_set_offsets_byte_range().end } } impl<'a> FontRead<'a> for SequenceContextFormat2<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); cursor.advance::(); let class_seq_rule_set_count: u16 = cursor.read()?; let class_seq_rule_set_offsets_byte_len = (class_seq_rule_set_count as usize) .checked_mul(Offset16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(class_seq_rule_set_offsets_byte_len); cursor.finish(SequenceContextFormat2Marker { class_seq_rule_set_offsets_byte_len, }) } } /// [Sequence Context Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-2-class-based-glyph-contexts) pub type SequenceContextFormat2<'a> = TableRef<'a, SequenceContextFormat2Marker>; #[allow(clippy::needless_lifetimes)] impl<'a> SequenceContextFormat2<'a> { /// Format identifier: format = 2 pub fn format(&self) -> u16 { let range = self.shape.format_byte_range(); self.data.read_at(range.start).unwrap() } /// Offset to Coverage table, from beginning of /// SequenceContextFormat2 table pub fn coverage_offset(&self) -> Offset16 { let range = self.shape.coverage_offset_byte_range(); self.data.read_at(range.start).unwrap() } /// Attempt to resolve [`coverage_offset`][Self::coverage_offset]. pub fn coverage(&self) -> Result, ReadError> { let data = self.data; self.coverage_offset().resolve(data) } /// Offset to ClassDef table, from beginning of /// SequenceContextFormat2 table pub fn class_def_offset(&self) -> Offset16 { let range = self.shape.class_def_offset_byte_range(); self.data.read_at(range.start).unwrap() } /// Attempt to resolve [`class_def_offset`][Self::class_def_offset]. pub fn class_def(&self) -> Result, ReadError> { let data = self.data; self.class_def_offset().resolve(data) } /// Number of ClassSequenceRuleSet tables pub fn class_seq_rule_set_count(&self) -> u16 { let range = self.shape.class_seq_rule_set_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of offsets to ClassSequenceRuleSet tables, from beginning /// of SequenceContextFormat2 table (may be NULL) pub fn class_seq_rule_set_offsets(&self) -> &'a [BigEndian>] { let range = self.shape.class_seq_rule_set_offsets_byte_range(); self.data.read_array(range).unwrap() } /// A dynamically resolving wrapper for [`class_seq_rule_set_offsets`][Self::class_seq_rule_set_offsets]. pub fn class_seq_rule_sets( &self, ) -> ArrayOfNullableOffsets<'a, ClassSequenceRuleSet<'a>, Offset16> { let data = self.data; let offsets = self.class_seq_rule_set_offsets(); ArrayOfNullableOffsets::new(offsets, data, ()) } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for SequenceContextFormat2<'a> { fn type_name(&self) -> &str { "SequenceContextFormat2" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("format", self.format())), 1usize => Some(Field::new( "coverage_offset", FieldType::offset(self.coverage_offset(), self.coverage()), )), 2usize => Some(Field::new( "class_def_offset", FieldType::offset(self.class_def_offset(), self.class_def()), )), 3usize => Some(Field::new( "class_seq_rule_set_count", self.class_seq_rule_set_count(), )), 4usize => Some({ let data = self.data; Field::new( "class_seq_rule_set_offsets", FieldType::array_of_offsets( better_type_name::(), self.class_seq_rule_set_offsets(), move |off| { let target = off.get().resolve::(data); FieldType::offset(off.get(), target) }, ), ) }), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for SequenceContextFormat2<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } /// Part of [SequenceContextFormat2] #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct ClassSequenceRuleSetMarker { class_seq_rule_offsets_byte_len: usize, } impl ClassSequenceRuleSetMarker { pub fn class_seq_rule_count_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn class_seq_rule_offsets_byte_range(&self) -> Range { let start = self.class_seq_rule_count_byte_range().end; start..start + self.class_seq_rule_offsets_byte_len } } impl MinByteRange for ClassSequenceRuleSetMarker { fn min_byte_range(&self) -> Range { 0..self.class_seq_rule_offsets_byte_range().end } } impl<'a> FontRead<'a> for ClassSequenceRuleSet<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); let class_seq_rule_count: u16 = cursor.read()?; let class_seq_rule_offsets_byte_len = (class_seq_rule_count as usize) .checked_mul(Offset16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(class_seq_rule_offsets_byte_len); cursor.finish(ClassSequenceRuleSetMarker { class_seq_rule_offsets_byte_len, }) } } /// Part of [SequenceContextFormat2] pub type ClassSequenceRuleSet<'a> = TableRef<'a, ClassSequenceRuleSetMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> ClassSequenceRuleSet<'a> { /// Number of ClassSequenceRule tables pub fn class_seq_rule_count(&self) -> u16 { let range = self.shape.class_seq_rule_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of offsets to ClassSequenceRule tables, from beginning of /// ClassSequenceRuleSet table pub fn class_seq_rule_offsets(&self) -> &'a [BigEndian] { let range = self.shape.class_seq_rule_offsets_byte_range(); self.data.read_array(range).unwrap() } /// A dynamically resolving wrapper for [`class_seq_rule_offsets`][Self::class_seq_rule_offsets]. pub fn class_seq_rules(&self) -> ArrayOfOffsets<'a, ClassSequenceRule<'a>, Offset16> { let data = self.data; let offsets = self.class_seq_rule_offsets(); ArrayOfOffsets::new(offsets, data, ()) } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for ClassSequenceRuleSet<'a> { fn type_name(&self) -> &str { "ClassSequenceRuleSet" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new( "class_seq_rule_count", self.class_seq_rule_count(), )), 1usize => Some({ let data = self.data; Field::new( "class_seq_rule_offsets", FieldType::array_of_offsets( better_type_name::(), self.class_seq_rule_offsets(), move |off| { let target = off.get().resolve::(data); FieldType::offset(off.get(), target) }, ), ) }), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for ClassSequenceRuleSet<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } /// Part of [SequenceContextFormat2] #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct ClassSequenceRuleMarker { input_sequence_byte_len: usize, seq_lookup_records_byte_len: usize, } impl ClassSequenceRuleMarker { pub fn glyph_count_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn seq_lookup_count_byte_range(&self) -> Range { let start = self.glyph_count_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn input_sequence_byte_range(&self) -> Range { let start = self.seq_lookup_count_byte_range().end; start..start + self.input_sequence_byte_len } pub fn seq_lookup_records_byte_range(&self) -> Range { let start = self.input_sequence_byte_range().end; start..start + self.seq_lookup_records_byte_len } } impl MinByteRange for ClassSequenceRuleMarker { fn min_byte_range(&self) -> Range { 0..self.seq_lookup_records_byte_range().end } } impl<'a> FontRead<'a> for ClassSequenceRule<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); let glyph_count: u16 = cursor.read()?; let seq_lookup_count: u16 = cursor.read()?; let input_sequence_byte_len = (transforms::subtract(glyph_count, 1_usize)) .checked_mul(u16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(input_sequence_byte_len); let seq_lookup_records_byte_len = (seq_lookup_count as usize) .checked_mul(SequenceLookupRecord::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(seq_lookup_records_byte_len); cursor.finish(ClassSequenceRuleMarker { input_sequence_byte_len, seq_lookup_records_byte_len, }) } } /// Part of [SequenceContextFormat2] pub type ClassSequenceRule<'a> = TableRef<'a, ClassSequenceRuleMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> ClassSequenceRule<'a> { /// Number of glyphs to be matched pub fn glyph_count(&self) -> u16 { let range = self.shape.glyph_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Number of SequenceLookupRecords pub fn seq_lookup_count(&self) -> u16 { let range = self.shape.seq_lookup_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Sequence of classes to be matched to the input glyph sequence, /// beginning with the second glyph position pub fn input_sequence(&self) -> &'a [BigEndian] { let range = self.shape.input_sequence_byte_range(); self.data.read_array(range).unwrap() } /// Array of SequenceLookupRecords pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] { let range = self.shape.seq_lookup_records_byte_range(); self.data.read_array(range).unwrap() } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for ClassSequenceRule<'a> { fn type_name(&self) -> &str { "ClassSequenceRule" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("glyph_count", self.glyph_count())), 1usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())), 2usize => Some(Field::new("input_sequence", self.input_sequence())), 3usize => Some(Field::new( "seq_lookup_records", traversal::FieldType::array_of_records( stringify!(SequenceLookupRecord), self.seq_lookup_records(), self.offset_data(), ), )), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for ClassSequenceRule<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } impl Format for SequenceContextFormat3Marker { const FORMAT: u16 = 3; } /// [Sequence Context Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-3-coverage-based-glyph-contexts) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct SequenceContextFormat3Marker { coverage_offsets_byte_len: usize, seq_lookup_records_byte_len: usize, } impl SequenceContextFormat3Marker { pub fn format_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn glyph_count_byte_range(&self) -> Range { let start = self.format_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn seq_lookup_count_byte_range(&self) -> Range { let start = self.glyph_count_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn coverage_offsets_byte_range(&self) -> Range { let start = self.seq_lookup_count_byte_range().end; start..start + self.coverage_offsets_byte_len } pub fn seq_lookup_records_byte_range(&self) -> Range { let start = self.coverage_offsets_byte_range().end; start..start + self.seq_lookup_records_byte_len } } impl MinByteRange for SequenceContextFormat3Marker { fn min_byte_range(&self) -> Range { 0..self.seq_lookup_records_byte_range().end } } impl<'a> FontRead<'a> for SequenceContextFormat3<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); let glyph_count: u16 = cursor.read()?; let seq_lookup_count: u16 = cursor.read()?; let coverage_offsets_byte_len = (glyph_count as usize) .checked_mul(Offset16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(coverage_offsets_byte_len); let seq_lookup_records_byte_len = (seq_lookup_count as usize) .checked_mul(SequenceLookupRecord::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(seq_lookup_records_byte_len); cursor.finish(SequenceContextFormat3Marker { coverage_offsets_byte_len, seq_lookup_records_byte_len, }) } } /// [Sequence Context Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-3-coverage-based-glyph-contexts) pub type SequenceContextFormat3<'a> = TableRef<'a, SequenceContextFormat3Marker>; #[allow(clippy::needless_lifetimes)] impl<'a> SequenceContextFormat3<'a> { /// Format identifier: format = 3 pub fn format(&self) -> u16 { let range = self.shape.format_byte_range(); self.data.read_at(range.start).unwrap() } /// Number of glyphs in the input sequence pub fn glyph_count(&self) -> u16 { let range = self.shape.glyph_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Number of SequenceLookupRecords pub fn seq_lookup_count(&self) -> u16 { let range = self.shape.seq_lookup_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of offsets to Coverage tables, from beginning of /// SequenceContextFormat3 subtable pub fn coverage_offsets(&self) -> &'a [BigEndian] { let range = self.shape.coverage_offsets_byte_range(); self.data.read_array(range).unwrap() } /// A dynamically resolving wrapper for [`coverage_offsets`][Self::coverage_offsets]. pub fn coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> { let data = self.data; let offsets = self.coverage_offsets(); ArrayOfOffsets::new(offsets, data, ()) } /// Array of SequenceLookupRecords pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] { let range = self.shape.seq_lookup_records_byte_range(); self.data.read_array(range).unwrap() } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for SequenceContextFormat3<'a> { fn type_name(&self) -> &str { "SequenceContextFormat3" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("format", self.format())), 1usize => Some(Field::new("glyph_count", self.glyph_count())), 2usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())), 3usize => Some({ let data = self.data; Field::new( "coverage_offsets", FieldType::array_of_offsets( better_type_name::(), self.coverage_offsets(), move |off| { let target = off.get().resolve::(data); FieldType::offset(off.get(), target) }, ), ) }), 4usize => Some(Field::new( "seq_lookup_records", traversal::FieldType::array_of_records( stringify!(SequenceLookupRecord), self.seq_lookup_records(), self.offset_data(), ), )), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for SequenceContextFormat3<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } #[derive(Clone)] pub enum SequenceContext<'a> { Format1(SequenceContextFormat1<'a>), Format2(SequenceContextFormat2<'a>), Format3(SequenceContextFormat3<'a>), } impl<'a> SequenceContext<'a> { ///Return the `FontData` used to resolve offsets for this table. pub fn offset_data(&self) -> FontData<'a> { match self { Self::Format1(item) => item.offset_data(), Self::Format2(item) => item.offset_data(), Self::Format3(item) => item.offset_data(), } } /// Format identifier: format = 1 pub fn format(&self) -> u16 { match self { Self::Format1(item) => item.format(), Self::Format2(item) => item.format(), Self::Format3(item) => item.format(), } } } impl<'a> FontRead<'a> for SequenceContext<'a> { fn read(data: FontData<'a>) -> Result { let format: u16 = data.read_at(0usize)?; match format { SequenceContextFormat1Marker::FORMAT => Ok(Self::Format1(FontRead::read(data)?)), SequenceContextFormat2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)), SequenceContextFormat3Marker::FORMAT => Ok(Self::Format3(FontRead::read(data)?)), other => Err(ReadError::InvalidFormat(other.into())), } } } impl MinByteRange for SequenceContext<'_> { fn min_byte_range(&self) -> Range { match self { Self::Format1(item) => item.min_byte_range(), Self::Format2(item) => item.min_byte_range(), Self::Format3(item) => item.min_byte_range(), } } } #[cfg(feature = "experimental_traverse")] impl<'a> SequenceContext<'a> { fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> { match self { Self::Format1(table) => table, Self::Format2(table) => table, Self::Format3(table) => table, } } } #[cfg(feature = "experimental_traverse")] impl std::fmt::Debug for SequenceContext<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.dyn_inner().fmt(f) } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for SequenceContext<'a> { fn type_name(&self) -> &str { self.dyn_inner().type_name() } fn get_field(&self, idx: usize) -> Option> { self.dyn_inner().get_field(idx) } } impl Format for ChainedSequenceContextFormat1Marker { const FORMAT: u16 = 1; } /// [Chained Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-1-simple-glyph-contexts) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct ChainedSequenceContextFormat1Marker { chained_seq_rule_set_offsets_byte_len: usize, } impl ChainedSequenceContextFormat1Marker { pub fn format_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn coverage_offset_byte_range(&self) -> Range { let start = self.format_byte_range().end; start..start + Offset16::RAW_BYTE_LEN } pub fn chained_seq_rule_set_count_byte_range(&self) -> Range { let start = self.coverage_offset_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn chained_seq_rule_set_offsets_byte_range(&self) -> Range { let start = self.chained_seq_rule_set_count_byte_range().end; start..start + self.chained_seq_rule_set_offsets_byte_len } } impl MinByteRange for ChainedSequenceContextFormat1Marker { fn min_byte_range(&self) -> Range { 0..self.chained_seq_rule_set_offsets_byte_range().end } } impl<'a> FontRead<'a> for ChainedSequenceContextFormat1<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); let chained_seq_rule_set_count: u16 = cursor.read()?; let chained_seq_rule_set_offsets_byte_len = (chained_seq_rule_set_count as usize) .checked_mul(Offset16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(chained_seq_rule_set_offsets_byte_len); cursor.finish(ChainedSequenceContextFormat1Marker { chained_seq_rule_set_offsets_byte_len, }) } } /// [Chained Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-1-simple-glyph-contexts) pub type ChainedSequenceContextFormat1<'a> = TableRef<'a, ChainedSequenceContextFormat1Marker>; #[allow(clippy::needless_lifetimes)] impl<'a> ChainedSequenceContextFormat1<'a> { /// Format identifier: format = 1 pub fn format(&self) -> u16 { let range = self.shape.format_byte_range(); self.data.read_at(range.start).unwrap() } /// Offset to Coverage table, from beginning of /// ChainSequenceContextFormat1 table pub fn coverage_offset(&self) -> Offset16 { let range = self.shape.coverage_offset_byte_range(); self.data.read_at(range.start).unwrap() } /// Attempt to resolve [`coverage_offset`][Self::coverage_offset]. pub fn coverage(&self) -> Result, ReadError> { let data = self.data; self.coverage_offset().resolve(data) } /// Number of ChainedSequenceRuleSet tables pub fn chained_seq_rule_set_count(&self) -> u16 { let range = self.shape.chained_seq_rule_set_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of offsets to ChainedSeqRuleSet tables, from beginning of /// ChainedSequenceContextFormat1 table (may be NULL) pub fn chained_seq_rule_set_offsets(&self) -> &'a [BigEndian>] { let range = self.shape.chained_seq_rule_set_offsets_byte_range(); self.data.read_array(range).unwrap() } /// A dynamically resolving wrapper for [`chained_seq_rule_set_offsets`][Self::chained_seq_rule_set_offsets]. pub fn chained_seq_rule_sets( &self, ) -> ArrayOfNullableOffsets<'a, ChainedSequenceRuleSet<'a>, Offset16> { let data = self.data; let offsets = self.chained_seq_rule_set_offsets(); ArrayOfNullableOffsets::new(offsets, data, ()) } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for ChainedSequenceContextFormat1<'a> { fn type_name(&self) -> &str { "ChainedSequenceContextFormat1" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("format", self.format())), 1usize => Some(Field::new( "coverage_offset", FieldType::offset(self.coverage_offset(), self.coverage()), )), 2usize => Some(Field::new( "chained_seq_rule_set_count", self.chained_seq_rule_set_count(), )), 3usize => Some({ let data = self.data; Field::new( "chained_seq_rule_set_offsets", FieldType::array_of_offsets( better_type_name::(), self.chained_seq_rule_set_offsets(), move |off| { let target = off.get().resolve::(data); FieldType::offset(off.get(), target) }, ), ) }), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for ChainedSequenceContextFormat1<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } /// Part of [ChainedSequenceContextFormat1] #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct ChainedSequenceRuleSetMarker { chained_seq_rule_offsets_byte_len: usize, } impl ChainedSequenceRuleSetMarker { pub fn chained_seq_rule_count_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn chained_seq_rule_offsets_byte_range(&self) -> Range { let start = self.chained_seq_rule_count_byte_range().end; start..start + self.chained_seq_rule_offsets_byte_len } } impl MinByteRange for ChainedSequenceRuleSetMarker { fn min_byte_range(&self) -> Range { 0..self.chained_seq_rule_offsets_byte_range().end } } impl<'a> FontRead<'a> for ChainedSequenceRuleSet<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); let chained_seq_rule_count: u16 = cursor.read()?; let chained_seq_rule_offsets_byte_len = (chained_seq_rule_count as usize) .checked_mul(Offset16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(chained_seq_rule_offsets_byte_len); cursor.finish(ChainedSequenceRuleSetMarker { chained_seq_rule_offsets_byte_len, }) } } /// Part of [ChainedSequenceContextFormat1] pub type ChainedSequenceRuleSet<'a> = TableRef<'a, ChainedSequenceRuleSetMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> ChainedSequenceRuleSet<'a> { /// Number of ChainedSequenceRule tables pub fn chained_seq_rule_count(&self) -> u16 { let range = self.shape.chained_seq_rule_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of offsets to ChainedSequenceRule tables, from beginning /// of ChainedSequenceRuleSet table pub fn chained_seq_rule_offsets(&self) -> &'a [BigEndian] { let range = self.shape.chained_seq_rule_offsets_byte_range(); self.data.read_array(range).unwrap() } /// A dynamically resolving wrapper for [`chained_seq_rule_offsets`][Self::chained_seq_rule_offsets]. pub fn chained_seq_rules(&self) -> ArrayOfOffsets<'a, ChainedSequenceRule<'a>, Offset16> { let data = self.data; let offsets = self.chained_seq_rule_offsets(); ArrayOfOffsets::new(offsets, data, ()) } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for ChainedSequenceRuleSet<'a> { fn type_name(&self) -> &str { "ChainedSequenceRuleSet" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new( "chained_seq_rule_count", self.chained_seq_rule_count(), )), 1usize => Some({ let data = self.data; Field::new( "chained_seq_rule_offsets", FieldType::array_of_offsets( better_type_name::(), self.chained_seq_rule_offsets(), move |off| { let target = off.get().resolve::(data); FieldType::offset(off.get(), target) }, ), ) }), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for ChainedSequenceRuleSet<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } /// Part of [ChainedSequenceContextFormat1] #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct ChainedSequenceRuleMarker { backtrack_sequence_byte_len: usize, input_sequence_byte_len: usize, lookahead_sequence_byte_len: usize, seq_lookup_records_byte_len: usize, } impl ChainedSequenceRuleMarker { pub fn backtrack_glyph_count_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn backtrack_sequence_byte_range(&self) -> Range { let start = self.backtrack_glyph_count_byte_range().end; start..start + self.backtrack_sequence_byte_len } pub fn input_glyph_count_byte_range(&self) -> Range { let start = self.backtrack_sequence_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn input_sequence_byte_range(&self) -> Range { let start = self.input_glyph_count_byte_range().end; start..start + self.input_sequence_byte_len } pub fn lookahead_glyph_count_byte_range(&self) -> Range { let start = self.input_sequence_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn lookahead_sequence_byte_range(&self) -> Range { let start = self.lookahead_glyph_count_byte_range().end; start..start + self.lookahead_sequence_byte_len } pub fn seq_lookup_count_byte_range(&self) -> Range { let start = self.lookahead_sequence_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn seq_lookup_records_byte_range(&self) -> Range { let start = self.seq_lookup_count_byte_range().end; start..start + self.seq_lookup_records_byte_len } } impl MinByteRange for ChainedSequenceRuleMarker { fn min_byte_range(&self) -> Range { 0..self.seq_lookup_records_byte_range().end } } impl<'a> FontRead<'a> for ChainedSequenceRule<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); let backtrack_glyph_count: u16 = cursor.read()?; let backtrack_sequence_byte_len = (backtrack_glyph_count as usize) .checked_mul(GlyphId16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(backtrack_sequence_byte_len); let input_glyph_count: u16 = cursor.read()?; let input_sequence_byte_len = (transforms::subtract(input_glyph_count, 1_usize)) .checked_mul(GlyphId16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(input_sequence_byte_len); let lookahead_glyph_count: u16 = cursor.read()?; let lookahead_sequence_byte_len = (lookahead_glyph_count as usize) .checked_mul(GlyphId16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(lookahead_sequence_byte_len); let seq_lookup_count: u16 = cursor.read()?; let seq_lookup_records_byte_len = (seq_lookup_count as usize) .checked_mul(SequenceLookupRecord::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(seq_lookup_records_byte_len); cursor.finish(ChainedSequenceRuleMarker { backtrack_sequence_byte_len, input_sequence_byte_len, lookahead_sequence_byte_len, seq_lookup_records_byte_len, }) } } /// Part of [ChainedSequenceContextFormat1] pub type ChainedSequenceRule<'a> = TableRef<'a, ChainedSequenceRuleMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> ChainedSequenceRule<'a> { /// Number of glyphs in the backtrack sequence pub fn backtrack_glyph_count(&self) -> u16 { let range = self.shape.backtrack_glyph_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of backtrack glyph IDs pub fn backtrack_sequence(&self) -> &'a [BigEndian] { let range = self.shape.backtrack_sequence_byte_range(); self.data.read_array(range).unwrap() } /// Number of glyphs in the input sequence pub fn input_glyph_count(&self) -> u16 { let range = self.shape.input_glyph_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of input glyph IDs—start with second glyph pub fn input_sequence(&self) -> &'a [BigEndian] { let range = self.shape.input_sequence_byte_range(); self.data.read_array(range).unwrap() } /// Number of glyphs in the lookahead sequence pub fn lookahead_glyph_count(&self) -> u16 { let range = self.shape.lookahead_glyph_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of lookahead glyph IDs pub fn lookahead_sequence(&self) -> &'a [BigEndian] { let range = self.shape.lookahead_sequence_byte_range(); self.data.read_array(range).unwrap() } /// Number of SequenceLookupRecords pub fn seq_lookup_count(&self) -> u16 { let range = self.shape.seq_lookup_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of SequenceLookupRecords pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] { let range = self.shape.seq_lookup_records_byte_range(); self.data.read_array(range).unwrap() } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for ChainedSequenceRule<'a> { fn type_name(&self) -> &str { "ChainedSequenceRule" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new( "backtrack_glyph_count", self.backtrack_glyph_count(), )), 1usize => Some(Field::new("backtrack_sequence", self.backtrack_sequence())), 2usize => Some(Field::new("input_glyph_count", self.input_glyph_count())), 3usize => Some(Field::new("input_sequence", self.input_sequence())), 4usize => Some(Field::new( "lookahead_glyph_count", self.lookahead_glyph_count(), )), 5usize => Some(Field::new("lookahead_sequence", self.lookahead_sequence())), 6usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())), 7usize => Some(Field::new( "seq_lookup_records", traversal::FieldType::array_of_records( stringify!(SequenceLookupRecord), self.seq_lookup_records(), self.offset_data(), ), )), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for ChainedSequenceRule<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } impl Format for ChainedSequenceContextFormat2Marker { const FORMAT: u16 = 2; } /// [Chained Sequence Context Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-2-class-based-glyph-contexts) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct ChainedSequenceContextFormat2Marker { chained_class_seq_rule_set_offsets_byte_len: usize, } impl ChainedSequenceContextFormat2Marker { pub fn format_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn coverage_offset_byte_range(&self) -> Range { let start = self.format_byte_range().end; start..start + Offset16::RAW_BYTE_LEN } pub fn backtrack_class_def_offset_byte_range(&self) -> Range { let start = self.coverage_offset_byte_range().end; start..start + Offset16::RAW_BYTE_LEN } pub fn input_class_def_offset_byte_range(&self) -> Range { let start = self.backtrack_class_def_offset_byte_range().end; start..start + Offset16::RAW_BYTE_LEN } pub fn lookahead_class_def_offset_byte_range(&self) -> Range { let start = self.input_class_def_offset_byte_range().end; start..start + Offset16::RAW_BYTE_LEN } pub fn chained_class_seq_rule_set_count_byte_range(&self) -> Range { let start = self.lookahead_class_def_offset_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn chained_class_seq_rule_set_offsets_byte_range(&self) -> Range { let start = self.chained_class_seq_rule_set_count_byte_range().end; start..start + self.chained_class_seq_rule_set_offsets_byte_len } } impl MinByteRange for ChainedSequenceContextFormat2Marker { fn min_byte_range(&self) -> Range { 0..self.chained_class_seq_rule_set_offsets_byte_range().end } } impl<'a> FontRead<'a> for ChainedSequenceContextFormat2<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); cursor.advance::(); cursor.advance::(); cursor.advance::(); let chained_class_seq_rule_set_count: u16 = cursor.read()?; let chained_class_seq_rule_set_offsets_byte_len = (chained_class_seq_rule_set_count as usize) .checked_mul(Offset16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(chained_class_seq_rule_set_offsets_byte_len); cursor.finish(ChainedSequenceContextFormat2Marker { chained_class_seq_rule_set_offsets_byte_len, }) } } /// [Chained Sequence Context Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-2-class-based-glyph-contexts) pub type ChainedSequenceContextFormat2<'a> = TableRef<'a, ChainedSequenceContextFormat2Marker>; #[allow(clippy::needless_lifetimes)] impl<'a> ChainedSequenceContextFormat2<'a> { /// Format identifier: format = 2 pub fn format(&self) -> u16 { let range = self.shape.format_byte_range(); self.data.read_at(range.start).unwrap() } /// Offset to Coverage table, from beginning of /// ChainedSequenceContextFormat2 table pub fn coverage_offset(&self) -> Offset16 { let range = self.shape.coverage_offset_byte_range(); self.data.read_at(range.start).unwrap() } /// Attempt to resolve [`coverage_offset`][Self::coverage_offset]. pub fn coverage(&self) -> Result, ReadError> { let data = self.data; self.coverage_offset().resolve(data) } /// Offset to ClassDef table containing backtrack sequence context, /// from beginning of ChainedSequenceContextFormat2 table pub fn backtrack_class_def_offset(&self) -> Offset16 { let range = self.shape.backtrack_class_def_offset_byte_range(); self.data.read_at(range.start).unwrap() } /// Attempt to resolve [`backtrack_class_def_offset`][Self::backtrack_class_def_offset]. pub fn backtrack_class_def(&self) -> Result, ReadError> { let data = self.data; self.backtrack_class_def_offset().resolve(data) } /// Offset to ClassDef table containing input sequence context, /// from beginning of ChainedSequenceContextFormat2 table pub fn input_class_def_offset(&self) -> Offset16 { let range = self.shape.input_class_def_offset_byte_range(); self.data.read_at(range.start).unwrap() } /// Attempt to resolve [`input_class_def_offset`][Self::input_class_def_offset]. pub fn input_class_def(&self) -> Result, ReadError> { let data = self.data; self.input_class_def_offset().resolve(data) } /// Offset to ClassDef table containing lookahead sequence context, /// from beginning of ChainedSequenceContextFormat2 table pub fn lookahead_class_def_offset(&self) -> Offset16 { let range = self.shape.lookahead_class_def_offset_byte_range(); self.data.read_at(range.start).unwrap() } /// Attempt to resolve [`lookahead_class_def_offset`][Self::lookahead_class_def_offset]. pub fn lookahead_class_def(&self) -> Result, ReadError> { let data = self.data; self.lookahead_class_def_offset().resolve(data) } /// Number of ChainedClassSequenceRuleSet tables pub fn chained_class_seq_rule_set_count(&self) -> u16 { let range = self.shape.chained_class_seq_rule_set_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of offsets to ChainedClassSequenceRuleSet tables, from /// beginning of ChainedSequenceContextFormat2 table (may be NULL) pub fn chained_class_seq_rule_set_offsets(&self) -> &'a [BigEndian>] { let range = self.shape.chained_class_seq_rule_set_offsets_byte_range(); self.data.read_array(range).unwrap() } /// A dynamically resolving wrapper for [`chained_class_seq_rule_set_offsets`][Self::chained_class_seq_rule_set_offsets]. pub fn chained_class_seq_rule_sets( &self, ) -> ArrayOfNullableOffsets<'a, ChainedClassSequenceRuleSet<'a>, Offset16> { let data = self.data; let offsets = self.chained_class_seq_rule_set_offsets(); ArrayOfNullableOffsets::new(offsets, data, ()) } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for ChainedSequenceContextFormat2<'a> { fn type_name(&self) -> &str { "ChainedSequenceContextFormat2" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("format", self.format())), 1usize => Some(Field::new( "coverage_offset", FieldType::offset(self.coverage_offset(), self.coverage()), )), 2usize => Some(Field::new( "backtrack_class_def_offset", FieldType::offset( self.backtrack_class_def_offset(), self.backtrack_class_def(), ), )), 3usize => Some(Field::new( "input_class_def_offset", FieldType::offset(self.input_class_def_offset(), self.input_class_def()), )), 4usize => Some(Field::new( "lookahead_class_def_offset", FieldType::offset( self.lookahead_class_def_offset(), self.lookahead_class_def(), ), )), 5usize => Some(Field::new( "chained_class_seq_rule_set_count", self.chained_class_seq_rule_set_count(), )), 6usize => Some({ let data = self.data; Field::new( "chained_class_seq_rule_set_offsets", FieldType::array_of_offsets( better_type_name::(), self.chained_class_seq_rule_set_offsets(), move |off| { let target = off.get().resolve::(data); FieldType::offset(off.get(), target) }, ), ) }), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for ChainedSequenceContextFormat2<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } /// Part of [ChainedSequenceContextFormat2] #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct ChainedClassSequenceRuleSetMarker { chained_class_seq_rule_offsets_byte_len: usize, } impl ChainedClassSequenceRuleSetMarker { pub fn chained_class_seq_rule_count_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn chained_class_seq_rule_offsets_byte_range(&self) -> Range { let start = self.chained_class_seq_rule_count_byte_range().end; start..start + self.chained_class_seq_rule_offsets_byte_len } } impl MinByteRange for ChainedClassSequenceRuleSetMarker { fn min_byte_range(&self) -> Range { 0..self.chained_class_seq_rule_offsets_byte_range().end } } impl<'a> FontRead<'a> for ChainedClassSequenceRuleSet<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); let chained_class_seq_rule_count: u16 = cursor.read()?; let chained_class_seq_rule_offsets_byte_len = (chained_class_seq_rule_count as usize) .checked_mul(Offset16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(chained_class_seq_rule_offsets_byte_len); cursor.finish(ChainedClassSequenceRuleSetMarker { chained_class_seq_rule_offsets_byte_len, }) } } /// Part of [ChainedSequenceContextFormat2] pub type ChainedClassSequenceRuleSet<'a> = TableRef<'a, ChainedClassSequenceRuleSetMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> ChainedClassSequenceRuleSet<'a> { /// Number of ChainedClassSequenceRule tables pub fn chained_class_seq_rule_count(&self) -> u16 { let range = self.shape.chained_class_seq_rule_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of offsets to ChainedClassSequenceRule tables, from /// beginning of ChainedClassSequenceRuleSet pub fn chained_class_seq_rule_offsets(&self) -> &'a [BigEndian] { let range = self.shape.chained_class_seq_rule_offsets_byte_range(); self.data.read_array(range).unwrap() } /// A dynamically resolving wrapper for [`chained_class_seq_rule_offsets`][Self::chained_class_seq_rule_offsets]. pub fn chained_class_seq_rules( &self, ) -> ArrayOfOffsets<'a, ChainedClassSequenceRule<'a>, Offset16> { let data = self.data; let offsets = self.chained_class_seq_rule_offsets(); ArrayOfOffsets::new(offsets, data, ()) } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for ChainedClassSequenceRuleSet<'a> { fn type_name(&self) -> &str { "ChainedClassSequenceRuleSet" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new( "chained_class_seq_rule_count", self.chained_class_seq_rule_count(), )), 1usize => Some({ let data = self.data; Field::new( "chained_class_seq_rule_offsets", FieldType::array_of_offsets( better_type_name::(), self.chained_class_seq_rule_offsets(), move |off| { let target = off.get().resolve::(data); FieldType::offset(off.get(), target) }, ), ) }), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for ChainedClassSequenceRuleSet<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } /// Part of [ChainedSequenceContextFormat2] #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct ChainedClassSequenceRuleMarker { backtrack_sequence_byte_len: usize, input_sequence_byte_len: usize, lookahead_sequence_byte_len: usize, seq_lookup_records_byte_len: usize, } impl ChainedClassSequenceRuleMarker { pub fn backtrack_glyph_count_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn backtrack_sequence_byte_range(&self) -> Range { let start = self.backtrack_glyph_count_byte_range().end; start..start + self.backtrack_sequence_byte_len } pub fn input_glyph_count_byte_range(&self) -> Range { let start = self.backtrack_sequence_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn input_sequence_byte_range(&self) -> Range { let start = self.input_glyph_count_byte_range().end; start..start + self.input_sequence_byte_len } pub fn lookahead_glyph_count_byte_range(&self) -> Range { let start = self.input_sequence_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn lookahead_sequence_byte_range(&self) -> Range { let start = self.lookahead_glyph_count_byte_range().end; start..start + self.lookahead_sequence_byte_len } pub fn seq_lookup_count_byte_range(&self) -> Range { let start = self.lookahead_sequence_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn seq_lookup_records_byte_range(&self) -> Range { let start = self.seq_lookup_count_byte_range().end; start..start + self.seq_lookup_records_byte_len } } impl MinByteRange for ChainedClassSequenceRuleMarker { fn min_byte_range(&self) -> Range { 0..self.seq_lookup_records_byte_range().end } } impl<'a> FontRead<'a> for ChainedClassSequenceRule<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); let backtrack_glyph_count: u16 = cursor.read()?; let backtrack_sequence_byte_len = (backtrack_glyph_count as usize) .checked_mul(u16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(backtrack_sequence_byte_len); let input_glyph_count: u16 = cursor.read()?; let input_sequence_byte_len = (transforms::subtract(input_glyph_count, 1_usize)) .checked_mul(u16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(input_sequence_byte_len); let lookahead_glyph_count: u16 = cursor.read()?; let lookahead_sequence_byte_len = (lookahead_glyph_count as usize) .checked_mul(u16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(lookahead_sequence_byte_len); let seq_lookup_count: u16 = cursor.read()?; let seq_lookup_records_byte_len = (seq_lookup_count as usize) .checked_mul(SequenceLookupRecord::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(seq_lookup_records_byte_len); cursor.finish(ChainedClassSequenceRuleMarker { backtrack_sequence_byte_len, input_sequence_byte_len, lookahead_sequence_byte_len, seq_lookup_records_byte_len, }) } } /// Part of [ChainedSequenceContextFormat2] pub type ChainedClassSequenceRule<'a> = TableRef<'a, ChainedClassSequenceRuleMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> ChainedClassSequenceRule<'a> { /// Number of glyphs in the backtrack sequence pub fn backtrack_glyph_count(&self) -> u16 { let range = self.shape.backtrack_glyph_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of backtrack-sequence classes pub fn backtrack_sequence(&self) -> &'a [BigEndian] { let range = self.shape.backtrack_sequence_byte_range(); self.data.read_array(range).unwrap() } /// Total number of glyphs in the input sequence pub fn input_glyph_count(&self) -> u16 { let range = self.shape.input_glyph_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of input sequence classes, beginning with the second /// glyph position pub fn input_sequence(&self) -> &'a [BigEndian] { let range = self.shape.input_sequence_byte_range(); self.data.read_array(range).unwrap() } /// Number of glyphs in the lookahead sequence pub fn lookahead_glyph_count(&self) -> u16 { let range = self.shape.lookahead_glyph_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of lookahead-sequence classes pub fn lookahead_sequence(&self) -> &'a [BigEndian] { let range = self.shape.lookahead_sequence_byte_range(); self.data.read_array(range).unwrap() } /// Number of SequenceLookupRecords pub fn seq_lookup_count(&self) -> u16 { let range = self.shape.seq_lookup_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of SequenceLookupRecords pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] { let range = self.shape.seq_lookup_records_byte_range(); self.data.read_array(range).unwrap() } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for ChainedClassSequenceRule<'a> { fn type_name(&self) -> &str { "ChainedClassSequenceRule" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new( "backtrack_glyph_count", self.backtrack_glyph_count(), )), 1usize => Some(Field::new("backtrack_sequence", self.backtrack_sequence())), 2usize => Some(Field::new("input_glyph_count", self.input_glyph_count())), 3usize => Some(Field::new("input_sequence", self.input_sequence())), 4usize => Some(Field::new( "lookahead_glyph_count", self.lookahead_glyph_count(), )), 5usize => Some(Field::new("lookahead_sequence", self.lookahead_sequence())), 6usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())), 7usize => Some(Field::new( "seq_lookup_records", traversal::FieldType::array_of_records( stringify!(SequenceLookupRecord), self.seq_lookup_records(), self.offset_data(), ), )), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for ChainedClassSequenceRule<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } impl Format for ChainedSequenceContextFormat3Marker { const FORMAT: u16 = 3; } /// [Chained Sequence Context Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-3-coverage-based-glyph-contexts) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct ChainedSequenceContextFormat3Marker { backtrack_coverage_offsets_byte_len: usize, input_coverage_offsets_byte_len: usize, lookahead_coverage_offsets_byte_len: usize, seq_lookup_records_byte_len: usize, } impl ChainedSequenceContextFormat3Marker { pub fn format_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn backtrack_glyph_count_byte_range(&self) -> Range { let start = self.format_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn backtrack_coverage_offsets_byte_range(&self) -> Range { let start = self.backtrack_glyph_count_byte_range().end; start..start + self.backtrack_coverage_offsets_byte_len } pub fn input_glyph_count_byte_range(&self) -> Range { let start = self.backtrack_coverage_offsets_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn input_coverage_offsets_byte_range(&self) -> Range { let start = self.input_glyph_count_byte_range().end; start..start + self.input_coverage_offsets_byte_len } pub fn lookahead_glyph_count_byte_range(&self) -> Range { let start = self.input_coverage_offsets_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn lookahead_coverage_offsets_byte_range(&self) -> Range { let start = self.lookahead_glyph_count_byte_range().end; start..start + self.lookahead_coverage_offsets_byte_len } pub fn seq_lookup_count_byte_range(&self) -> Range { let start = self.lookahead_coverage_offsets_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn seq_lookup_records_byte_range(&self) -> Range { let start = self.seq_lookup_count_byte_range().end; start..start + self.seq_lookup_records_byte_len } } impl MinByteRange for ChainedSequenceContextFormat3Marker { fn min_byte_range(&self) -> Range { 0..self.seq_lookup_records_byte_range().end } } impl<'a> FontRead<'a> for ChainedSequenceContextFormat3<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); let backtrack_glyph_count: u16 = cursor.read()?; let backtrack_coverage_offsets_byte_len = (backtrack_glyph_count as usize) .checked_mul(Offset16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(backtrack_coverage_offsets_byte_len); let input_glyph_count: u16 = cursor.read()?; let input_coverage_offsets_byte_len = (input_glyph_count as usize) .checked_mul(Offset16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(input_coverage_offsets_byte_len); let lookahead_glyph_count: u16 = cursor.read()?; let lookahead_coverage_offsets_byte_len = (lookahead_glyph_count as usize) .checked_mul(Offset16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(lookahead_coverage_offsets_byte_len); let seq_lookup_count: u16 = cursor.read()?; let seq_lookup_records_byte_len = (seq_lookup_count as usize) .checked_mul(SequenceLookupRecord::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(seq_lookup_records_byte_len); cursor.finish(ChainedSequenceContextFormat3Marker { backtrack_coverage_offsets_byte_len, input_coverage_offsets_byte_len, lookahead_coverage_offsets_byte_len, seq_lookup_records_byte_len, }) } } /// [Chained Sequence Context Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-3-coverage-based-glyph-contexts) pub type ChainedSequenceContextFormat3<'a> = TableRef<'a, ChainedSequenceContextFormat3Marker>; #[allow(clippy::needless_lifetimes)] impl<'a> ChainedSequenceContextFormat3<'a> { /// Format identifier: format = 3 pub fn format(&self) -> u16 { let range = self.shape.format_byte_range(); self.data.read_at(range.start).unwrap() } /// Number of glyphs in the backtrack sequence pub fn backtrack_glyph_count(&self) -> u16 { let range = self.shape.backtrack_glyph_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of offsets to coverage tables for the backtrack sequence pub fn backtrack_coverage_offsets(&self) -> &'a [BigEndian] { let range = self.shape.backtrack_coverage_offsets_byte_range(); self.data.read_array(range).unwrap() } /// A dynamically resolving wrapper for [`backtrack_coverage_offsets`][Self::backtrack_coverage_offsets]. pub fn backtrack_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> { let data = self.data; let offsets = self.backtrack_coverage_offsets(); ArrayOfOffsets::new(offsets, data, ()) } /// Number of glyphs in the input sequence pub fn input_glyph_count(&self) -> u16 { let range = self.shape.input_glyph_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of offsets to coverage tables for the input sequence pub fn input_coverage_offsets(&self) -> &'a [BigEndian] { let range = self.shape.input_coverage_offsets_byte_range(); self.data.read_array(range).unwrap() } /// A dynamically resolving wrapper for [`input_coverage_offsets`][Self::input_coverage_offsets]. pub fn input_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> { let data = self.data; let offsets = self.input_coverage_offsets(); ArrayOfOffsets::new(offsets, data, ()) } /// Number of glyphs in the lookahead sequence pub fn lookahead_glyph_count(&self) -> u16 { let range = self.shape.lookahead_glyph_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of offsets to coverage tables for the lookahead sequence pub fn lookahead_coverage_offsets(&self) -> &'a [BigEndian] { let range = self.shape.lookahead_coverage_offsets_byte_range(); self.data.read_array(range).unwrap() } /// A dynamically resolving wrapper for [`lookahead_coverage_offsets`][Self::lookahead_coverage_offsets]. pub fn lookahead_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> { let data = self.data; let offsets = self.lookahead_coverage_offsets(); ArrayOfOffsets::new(offsets, data, ()) } /// Number of SequenceLookupRecords pub fn seq_lookup_count(&self) -> u16 { let range = self.shape.seq_lookup_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of SequenceLookupRecords pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] { let range = self.shape.seq_lookup_records_byte_range(); self.data.read_array(range).unwrap() } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for ChainedSequenceContextFormat3<'a> { fn type_name(&self) -> &str { "ChainedSequenceContextFormat3" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("format", self.format())), 1usize => Some(Field::new( "backtrack_glyph_count", self.backtrack_glyph_count(), )), 2usize => Some({ let data = self.data; Field::new( "backtrack_coverage_offsets", FieldType::array_of_offsets( better_type_name::(), self.backtrack_coverage_offsets(), move |off| { let target = off.get().resolve::(data); FieldType::offset(off.get(), target) }, ), ) }), 3usize => Some(Field::new("input_glyph_count", self.input_glyph_count())), 4usize => Some({ let data = self.data; Field::new( "input_coverage_offsets", FieldType::array_of_offsets( better_type_name::(), self.input_coverage_offsets(), move |off| { let target = off.get().resolve::(data); FieldType::offset(off.get(), target) }, ), ) }), 5usize => Some(Field::new( "lookahead_glyph_count", self.lookahead_glyph_count(), )), 6usize => Some({ let data = self.data; Field::new( "lookahead_coverage_offsets", FieldType::array_of_offsets( better_type_name::(), self.lookahead_coverage_offsets(), move |off| { let target = off.get().resolve::(data); FieldType::offset(off.get(), target) }, ), ) }), 7usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())), 8usize => Some(Field::new( "seq_lookup_records", traversal::FieldType::array_of_records( stringify!(SequenceLookupRecord), self.seq_lookup_records(), self.offset_data(), ), )), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for ChainedSequenceContextFormat3<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } #[derive(Clone)] pub enum ChainedSequenceContext<'a> { Format1(ChainedSequenceContextFormat1<'a>), Format2(ChainedSequenceContextFormat2<'a>), Format3(ChainedSequenceContextFormat3<'a>), } impl<'a> ChainedSequenceContext<'a> { ///Return the `FontData` used to resolve offsets for this table. pub fn offset_data(&self) -> FontData<'a> { match self { Self::Format1(item) => item.offset_data(), Self::Format2(item) => item.offset_data(), Self::Format3(item) => item.offset_data(), } } /// Format identifier: format = 1 pub fn format(&self) -> u16 { match self { Self::Format1(item) => item.format(), Self::Format2(item) => item.format(), Self::Format3(item) => item.format(), } } } impl<'a> FontRead<'a> for ChainedSequenceContext<'a> { fn read(data: FontData<'a>) -> Result { let format: u16 = data.read_at(0usize)?; match format { ChainedSequenceContextFormat1Marker::FORMAT => Ok(Self::Format1(FontRead::read(data)?)), ChainedSequenceContextFormat2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)), ChainedSequenceContextFormat3Marker::FORMAT => Ok(Self::Format3(FontRead::read(data)?)), other => Err(ReadError::InvalidFormat(other.into())), } } } impl MinByteRange for ChainedSequenceContext<'_> { fn min_byte_range(&self) -> Range { match self { Self::Format1(item) => item.min_byte_range(), Self::Format2(item) => item.min_byte_range(), Self::Format3(item) => item.min_byte_range(), } } } #[cfg(feature = "experimental_traverse")] impl<'a> ChainedSequenceContext<'a> { fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> { match self { Self::Format1(table) => table, Self::Format2(table) => table, Self::Format3(table) => table, } } } #[cfg(feature = "experimental_traverse")] impl std::fmt::Debug for ChainedSequenceContext<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.dyn_inner().fmt(f) } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for ChainedSequenceContext<'a> { fn type_name(&self) -> &str { self.dyn_inner().type_name() } fn get_field(&self, idx: usize) -> Option> { self.dyn_inner().get_field(idx) } } /// [Device](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#device-and-variationindex-tables) /// delta formats #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[repr(u16)] #[allow(clippy::manual_non_exhaustive)] pub enum DeltaFormat { /// Signed 2-bit value, 8 values per uint16 #[default] Local2BitDeltas = 0x0001, /// Signed 4-bit value, 4 values per uint16 Local4BitDeltas = 0x0002, /// Signed 8-bit value, 2 values per uint16 Local8BitDeltas = 0x0003, /// VariationIndex table, contains a delta-set index pair. VariationIndex = 0x8000, #[doc(hidden)] /// If font data is malformed we will map unknown values to this variant Unknown, } impl DeltaFormat { /// Create from a raw scalar. /// /// This will never fail; unknown values will be mapped to the `Unknown` variant pub fn new(raw: u16) -> Self { match raw { 0x0001 => Self::Local2BitDeltas, 0x0002 => Self::Local4BitDeltas, 0x0003 => Self::Local8BitDeltas, 0x8000 => Self::VariationIndex, _ => Self::Unknown, } } } impl font_types::Scalar for DeltaFormat { type Raw = ::Raw; fn to_raw(self) -> Self::Raw { (self as u16).to_raw() } fn from_raw(raw: Self::Raw) -> Self { let t = ::from_raw(raw); Self::new(t) } } #[cfg(feature = "experimental_traverse")] impl<'a> From for FieldType<'a> { fn from(src: DeltaFormat) -> FieldType<'a> { (src as u16).into() } } /// [Device Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#device-and-variationindex-tables) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct DeviceMarker { delta_value_byte_len: usize, } impl DeviceMarker { pub fn start_size_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn end_size_byte_range(&self) -> Range { let start = self.start_size_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn delta_format_byte_range(&self) -> Range { let start = self.end_size_byte_range().end; start..start + DeltaFormat::RAW_BYTE_LEN } pub fn delta_value_byte_range(&self) -> Range { let start = self.delta_format_byte_range().end; start..start + self.delta_value_byte_len } } impl MinByteRange for DeviceMarker { fn min_byte_range(&self) -> Range { 0..self.delta_value_byte_range().end } } impl<'a> FontRead<'a> for Device<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); let start_size: u16 = cursor.read()?; let end_size: u16 = cursor.read()?; let delta_format: DeltaFormat = cursor.read()?; let delta_value_byte_len = (DeltaFormat::value_count(delta_format, start_size, end_size)) .checked_mul(u16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(delta_value_byte_len); cursor.finish(DeviceMarker { delta_value_byte_len, }) } } /// [Device Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#device-and-variationindex-tables) pub type Device<'a> = TableRef<'a, DeviceMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> Device<'a> { /// Smallest size to correct, in ppem pub fn start_size(&self) -> u16 { let range = self.shape.start_size_byte_range(); self.data.read_at(range.start).unwrap() } /// Largest size to correct, in ppem pub fn end_size(&self) -> u16 { let range = self.shape.end_size_byte_range(); self.data.read_at(range.start).unwrap() } /// Format of deltaValue array data: 0x0001, 0x0002, or 0x0003 pub fn delta_format(&self) -> DeltaFormat { let range = self.shape.delta_format_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of compressed data pub fn delta_value(&self) -> &'a [BigEndian] { let range = self.shape.delta_value_byte_range(); self.data.read_array(range).unwrap() } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for Device<'a> { fn type_name(&self) -> &str { "Device" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("start_size", self.start_size())), 1usize => Some(Field::new("end_size", self.end_size())), 2usize => Some(Field::new("delta_format", self.delta_format())), 3usize => Some(Field::new("delta_value", self.delta_value())), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for Device<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } /// Variation index table #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct VariationIndexMarker {} impl VariationIndexMarker { pub fn delta_set_outer_index_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn delta_set_inner_index_byte_range(&self) -> Range { let start = self.delta_set_outer_index_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn delta_format_byte_range(&self) -> Range { let start = self.delta_set_inner_index_byte_range().end; start..start + DeltaFormat::RAW_BYTE_LEN } } impl MinByteRange for VariationIndexMarker { fn min_byte_range(&self) -> Range { 0..self.delta_format_byte_range().end } } impl<'a> FontRead<'a> for VariationIndex<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); cursor.advance::(); cursor.finish(VariationIndexMarker {}) } } /// Variation index table pub type VariationIndex<'a> = TableRef<'a, VariationIndexMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> VariationIndex<'a> { /// A delta-set outer index — used to select an item variation /// data subtable within the item variation store. pub fn delta_set_outer_index(&self) -> u16 { let range = self.shape.delta_set_outer_index_byte_range(); self.data.read_at(range.start).unwrap() } /// A delta-set inner index — used to select a delta-set row /// within an item variation data subtable. pub fn delta_set_inner_index(&self) -> u16 { let range = self.shape.delta_set_inner_index_byte_range(); self.data.read_at(range.start).unwrap() } /// Format, = 0x8000 pub fn delta_format(&self) -> DeltaFormat { let range = self.shape.delta_format_byte_range(); self.data.read_at(range.start).unwrap() } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for VariationIndex<'a> { fn type_name(&self) -> &str { "VariationIndex" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new( "delta_set_outer_index", self.delta_set_outer_index(), )), 1usize => Some(Field::new( "delta_set_inner_index", self.delta_set_inner_index(), )), 2usize => Some(Field::new("delta_format", self.delta_format())), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for VariationIndex<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } /// Either a [Device] table (in a non-variable font) or a [VariationIndex] table (in a variable font) #[derive(Clone)] pub enum DeviceOrVariationIndex<'a> { Device(Device<'a>), VariationIndex(VariationIndex<'a>), } impl<'a> DeviceOrVariationIndex<'a> { ///Return the `FontData` used to resolve offsets for this table. pub fn offset_data(&self) -> FontData<'a> { match self { Self::Device(item) => item.offset_data(), Self::VariationIndex(item) => item.offset_data(), } } } impl<'a> FontRead<'a> for DeviceOrVariationIndex<'a> { fn read(data: FontData<'a>) -> Result { let format: DeltaFormat = data.read_at(4usize)?; #[allow(clippy::redundant_guards)] match format { format if format != DeltaFormat::VariationIndex => { Ok(Self::Device(FontRead::read(data)?)) } format if format == DeltaFormat::VariationIndex => { Ok(Self::VariationIndex(FontRead::read(data)?)) } other => Err(ReadError::InvalidFormat(other.into())), } } } impl MinByteRange for DeviceOrVariationIndex<'_> { fn min_byte_range(&self) -> Range { match self { Self::Device(item) => item.min_byte_range(), Self::VariationIndex(item) => item.min_byte_range(), } } } #[cfg(feature = "experimental_traverse")] impl<'a> DeviceOrVariationIndex<'a> { fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> { match self { Self::Device(table) => table, Self::VariationIndex(table) => table, } } } #[cfg(feature = "experimental_traverse")] impl std::fmt::Debug for DeviceOrVariationIndex<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.dyn_inner().fmt(f) } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for DeviceOrVariationIndex<'a> { fn type_name(&self) -> &str { self.dyn_inner().type_name() } fn get_field(&self, idx: usize) -> Option> { self.dyn_inner().get_field(idx) } } /// [FeatureVariations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featurevariations-table) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct FeatureVariationsMarker { feature_variation_records_byte_len: usize, } impl FeatureVariationsMarker { pub fn version_byte_range(&self) -> Range { let start = 0; start..start + MajorMinor::RAW_BYTE_LEN } pub fn feature_variation_record_count_byte_range(&self) -> Range { let start = self.version_byte_range().end; start..start + u32::RAW_BYTE_LEN } pub fn feature_variation_records_byte_range(&self) -> Range { let start = self.feature_variation_record_count_byte_range().end; start..start + self.feature_variation_records_byte_len } } impl MinByteRange for FeatureVariationsMarker { fn min_byte_range(&self) -> Range { 0..self.feature_variation_records_byte_range().end } } impl<'a> FontRead<'a> for FeatureVariations<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); let feature_variation_record_count: u32 = cursor.read()?; let feature_variation_records_byte_len = (feature_variation_record_count as usize) .checked_mul(FeatureVariationRecord::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(feature_variation_records_byte_len); cursor.finish(FeatureVariationsMarker { feature_variation_records_byte_len, }) } } /// [FeatureVariations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featurevariations-table) pub type FeatureVariations<'a> = TableRef<'a, FeatureVariationsMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> FeatureVariations<'a> { pub fn version(&self) -> MajorMinor { let range = self.shape.version_byte_range(); self.data.read_at(range.start).unwrap() } /// Number of feature variation records. pub fn feature_variation_record_count(&self) -> u32 { let range = self.shape.feature_variation_record_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of feature variation records. pub fn feature_variation_records(&self) -> &'a [FeatureVariationRecord] { let range = self.shape.feature_variation_records_byte_range(); self.data.read_array(range).unwrap() } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for FeatureVariations<'a> { fn type_name(&self) -> &str { "FeatureVariations" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("version", self.version())), 1usize => Some(Field::new( "feature_variation_record_count", self.feature_variation_record_count(), )), 2usize => Some(Field::new( "feature_variation_records", traversal::FieldType::array_of_records( stringify!(FeatureVariationRecord), self.feature_variation_records(), self.offset_data(), ), )), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for FeatureVariations<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } /// Part of [FeatureVariations] #[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)] #[repr(C)] #[repr(packed)] pub struct FeatureVariationRecord { /// Offset to a condition set table, from beginning of /// FeatureVariations table. pub condition_set_offset: BigEndian>, /// Offset to a feature table substitution table, from beginning of /// the FeatureVariations table. pub feature_table_substitution_offset: BigEndian>, } impl FeatureVariationRecord { /// Offset to a condition set table, from beginning of /// FeatureVariations table. pub fn condition_set_offset(&self) -> Nullable { self.condition_set_offset.get() } /// Offset to a condition set table, from beginning of /// FeatureVariations table. /// /// The `data` argument should be retrieved from the parent table /// By calling its `offset_data` method. pub fn condition_set<'a>( &self, data: FontData<'a>, ) -> Option, ReadError>> { self.condition_set_offset().resolve(data) } /// Offset to a feature table substitution table, from beginning of /// the FeatureVariations table. pub fn feature_table_substitution_offset(&self) -> Nullable { self.feature_table_substitution_offset.get() } /// Offset to a feature table substitution table, from beginning of /// the FeatureVariations table. /// /// The `data` argument should be retrieved from the parent table /// By calling its `offset_data` method. pub fn feature_table_substitution<'a>( &self, data: FontData<'a>, ) -> Option, ReadError>> { self.feature_table_substitution_offset().resolve(data) } } impl FixedSize for FeatureVariationRecord { const RAW_BYTE_LEN: usize = Offset32::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN; } #[cfg(feature = "experimental_traverse")] impl<'a> SomeRecord<'a> for FeatureVariationRecord { fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> { RecordResolver { name: "FeatureVariationRecord", get_field: Box::new(move |idx, _data| match idx { 0usize => Some(Field::new( "condition_set_offset", FieldType::offset(self.condition_set_offset(), self.condition_set(_data)), )), 1usize => Some(Field::new( "feature_table_substitution_offset", FieldType::offset( self.feature_table_substitution_offset(), self.feature_table_substitution(_data), ), )), _ => None, }), data, } } } /// [ConditionSet Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#conditionset-table) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct ConditionSetMarker { condition_offsets_byte_len: usize, } impl ConditionSetMarker { pub fn condition_count_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn condition_offsets_byte_range(&self) -> Range { let start = self.condition_count_byte_range().end; start..start + self.condition_offsets_byte_len } } impl MinByteRange for ConditionSetMarker { fn min_byte_range(&self) -> Range { 0..self.condition_offsets_byte_range().end } } impl<'a> FontRead<'a> for ConditionSet<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); let condition_count: u16 = cursor.read()?; let condition_offsets_byte_len = (condition_count as usize) .checked_mul(Offset32::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(condition_offsets_byte_len); cursor.finish(ConditionSetMarker { condition_offsets_byte_len, }) } } /// [ConditionSet Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#conditionset-table) pub type ConditionSet<'a> = TableRef<'a, ConditionSetMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> ConditionSet<'a> { /// Number of conditions for this condition set. pub fn condition_count(&self) -> u16 { let range = self.shape.condition_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of offsets to condition tables, from beginning of the /// ConditionSet table. pub fn condition_offsets(&self) -> &'a [BigEndian] { let range = self.shape.condition_offsets_byte_range(); self.data.read_array(range).unwrap() } /// A dynamically resolving wrapper for [`condition_offsets`][Self::condition_offsets]. pub fn conditions(&self) -> ArrayOfOffsets<'a, Condition<'a>, Offset32> { let data = self.data; let offsets = self.condition_offsets(); ArrayOfOffsets::new(offsets, data, ()) } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for ConditionSet<'a> { fn type_name(&self) -> &str { "ConditionSet" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("condition_count", self.condition_count())), 1usize => Some({ let data = self.data; Field::new( "condition_offsets", FieldType::array_of_offsets( better_type_name::(), self.condition_offsets(), move |off| { let target = off.get().resolve::(data); FieldType::offset(off.get(), target) }, ), ) }), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for ConditionSet<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } /// [Condition Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#condition-table) /// /// Formats 2..5 are implementations of specification changes currently under debate at ISO for an OFF /// update. For the time being the specification is . #[derive(Clone)] pub enum Condition<'a> { Format1AxisRange(ConditionFormat1<'a>), Format2VariableValue(ConditionFormat2<'a>), Format3And(ConditionFormat3<'a>), Format4Or(ConditionFormat4<'a>), Format5Negate(ConditionFormat5<'a>), } impl<'a> Condition<'a> { ///Return the `FontData` used to resolve offsets for this table. pub fn offset_data(&self) -> FontData<'a> { match self { Self::Format1AxisRange(item) => item.offset_data(), Self::Format2VariableValue(item) => item.offset_data(), Self::Format3And(item) => item.offset_data(), Self::Format4Or(item) => item.offset_data(), Self::Format5Negate(item) => item.offset_data(), } } /// Format, = 1 pub fn format(&self) -> u16 { match self { Self::Format1AxisRange(item) => item.format(), Self::Format2VariableValue(item) => item.format(), Self::Format3And(item) => item.format(), Self::Format4Or(item) => item.format(), Self::Format5Negate(item) => item.format(), } } } impl<'a> FontRead<'a> for Condition<'a> { fn read(data: FontData<'a>) -> Result { let format: u16 = data.read_at(0usize)?; match format { ConditionFormat1Marker::FORMAT => Ok(Self::Format1AxisRange(FontRead::read(data)?)), ConditionFormat2Marker::FORMAT => Ok(Self::Format2VariableValue(FontRead::read(data)?)), ConditionFormat3Marker::FORMAT => Ok(Self::Format3And(FontRead::read(data)?)), ConditionFormat4Marker::FORMAT => Ok(Self::Format4Or(FontRead::read(data)?)), ConditionFormat5Marker::FORMAT => Ok(Self::Format5Negate(FontRead::read(data)?)), other => Err(ReadError::InvalidFormat(other.into())), } } } impl MinByteRange for Condition<'_> { fn min_byte_range(&self) -> Range { match self { Self::Format1AxisRange(item) => item.min_byte_range(), Self::Format2VariableValue(item) => item.min_byte_range(), Self::Format3And(item) => item.min_byte_range(), Self::Format4Or(item) => item.min_byte_range(), Self::Format5Negate(item) => item.min_byte_range(), } } } #[cfg(feature = "experimental_traverse")] impl<'a> Condition<'a> { fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> { match self { Self::Format1AxisRange(table) => table, Self::Format2VariableValue(table) => table, Self::Format3And(table) => table, Self::Format4Or(table) => table, Self::Format5Negate(table) => table, } } } #[cfg(feature = "experimental_traverse")] impl std::fmt::Debug for Condition<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.dyn_inner().fmt(f) } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for Condition<'a> { fn type_name(&self) -> &str { self.dyn_inner().type_name() } fn get_field(&self, idx: usize) -> Option> { self.dyn_inner().get_field(idx) } } impl Format for ConditionFormat1Marker { const FORMAT: u16 = 1; } /// [Condition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#condition-table-format-1-font-variation-axis-range): Font Variation Axis Range #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct ConditionFormat1Marker {} impl ConditionFormat1Marker { pub fn format_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn axis_index_byte_range(&self) -> Range { let start = self.format_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn filter_range_min_value_byte_range(&self) -> Range { let start = self.axis_index_byte_range().end; start..start + F2Dot14::RAW_BYTE_LEN } pub fn filter_range_max_value_byte_range(&self) -> Range { let start = self.filter_range_min_value_byte_range().end; start..start + F2Dot14::RAW_BYTE_LEN } } impl MinByteRange for ConditionFormat1Marker { fn min_byte_range(&self) -> Range { 0..self.filter_range_max_value_byte_range().end } } impl<'a> FontRead<'a> for ConditionFormat1<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); cursor.advance::(); cursor.advance::(); cursor.finish(ConditionFormat1Marker {}) } } /// [Condition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#condition-table-format-1-font-variation-axis-range): Font Variation Axis Range pub type ConditionFormat1<'a> = TableRef<'a, ConditionFormat1Marker>; #[allow(clippy::needless_lifetimes)] impl<'a> ConditionFormat1<'a> { /// Format, = 1 pub fn format(&self) -> u16 { let range = self.shape.format_byte_range(); self.data.read_at(range.start).unwrap() } /// Index (zero-based) for the variation axis within the 'fvar' /// table. pub fn axis_index(&self) -> u16 { let range = self.shape.axis_index_byte_range(); self.data.read_at(range.start).unwrap() } /// Minimum value of the font variation instances that satisfy this /// condition. pub fn filter_range_min_value(&self) -> F2Dot14 { let range = self.shape.filter_range_min_value_byte_range(); self.data.read_at(range.start).unwrap() } /// Maximum value of the font variation instances that satisfy this /// condition. pub fn filter_range_max_value(&self) -> F2Dot14 { let range = self.shape.filter_range_max_value_byte_range(); self.data.read_at(range.start).unwrap() } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for ConditionFormat1<'a> { fn type_name(&self) -> &str { "ConditionFormat1" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("format", self.format())), 1usize => Some(Field::new("axis_index", self.axis_index())), 2usize => Some(Field::new( "filter_range_min_value", self.filter_range_min_value(), )), 3usize => Some(Field::new( "filter_range_max_value", self.filter_range_max_value(), )), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for ConditionFormat1<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } impl Format for ConditionFormat2Marker { const FORMAT: u16 = 2; } /// [Condition Table Format 2](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3237-L3255): Variation index #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct ConditionFormat2Marker {} impl ConditionFormat2Marker { pub fn format_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn default_value_byte_range(&self) -> Range { let start = self.format_byte_range().end; start..start + i16::RAW_BYTE_LEN } pub fn var_index_byte_range(&self) -> Range { let start = self.default_value_byte_range().end; start..start + u32::RAW_BYTE_LEN } } impl MinByteRange for ConditionFormat2Marker { fn min_byte_range(&self) -> Range { 0..self.var_index_byte_range().end } } impl<'a> FontRead<'a> for ConditionFormat2<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); cursor.advance::(); cursor.finish(ConditionFormat2Marker {}) } } /// [Condition Table Format 2](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3237-L3255): Variation index pub type ConditionFormat2<'a> = TableRef<'a, ConditionFormat2Marker>; #[allow(clippy::needless_lifetimes)] impl<'a> ConditionFormat2<'a> { /// Format, = 2 pub fn format(&self) -> u16 { let range = self.shape.format_byte_range(); self.data.read_at(range.start).unwrap() } /// Value at default instance. pub fn default_value(&self) -> i16 { let range = self.shape.default_value_byte_range(); self.data.read_at(range.start).unwrap() } /// Variation index to vary the value based on current designspace location. pub fn var_index(&self) -> u32 { let range = self.shape.var_index_byte_range(); self.data.read_at(range.start).unwrap() } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for ConditionFormat2<'a> { fn type_name(&self) -> &str { "ConditionFormat2" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("format", self.format())), 1usize => Some(Field::new("default_value", self.default_value())), 2usize => Some(Field::new("var_index", self.var_index())), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for ConditionFormat2<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } impl Format for ConditionFormat3Marker { const FORMAT: u16 = 3; } /// [Condition Table Format 3](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3257-L3275): AND #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct ConditionFormat3Marker { condition_offsets_byte_len: usize, } impl ConditionFormat3Marker { pub fn format_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn condition_count_byte_range(&self) -> Range { let start = self.format_byte_range().end; start..start + u8::RAW_BYTE_LEN } pub fn condition_offsets_byte_range(&self) -> Range { let start = self.condition_count_byte_range().end; start..start + self.condition_offsets_byte_len } } impl MinByteRange for ConditionFormat3Marker { fn min_byte_range(&self) -> Range { 0..self.condition_offsets_byte_range().end } } impl<'a> FontRead<'a> for ConditionFormat3<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); let condition_count: u8 = cursor.read()?; let condition_offsets_byte_len = (condition_count as usize) .checked_mul(Offset24::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(condition_offsets_byte_len); cursor.finish(ConditionFormat3Marker { condition_offsets_byte_len, }) } } /// [Condition Table Format 3](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3257-L3275): AND pub type ConditionFormat3<'a> = TableRef<'a, ConditionFormat3Marker>; #[allow(clippy::needless_lifetimes)] impl<'a> ConditionFormat3<'a> { /// Format, = 3 pub fn format(&self) -> u16 { let range = self.shape.format_byte_range(); self.data.read_at(range.start).unwrap() } /// Number of conditions. pub fn condition_count(&self) -> u8 { let range = self.shape.condition_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of condition tables for this conjunction (AND) expression. pub fn condition_offsets(&self) -> &'a [BigEndian] { let range = self.shape.condition_offsets_byte_range(); self.data.read_array(range).unwrap() } /// A dynamically resolving wrapper for [`condition_offsets`][Self::condition_offsets]. pub fn conditions(&self) -> ArrayOfOffsets<'a, Condition<'a>, Offset24> { let data = self.data; let offsets = self.condition_offsets(); ArrayOfOffsets::new(offsets, data, ()) } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for ConditionFormat3<'a> { fn type_name(&self) -> &str { "ConditionFormat3" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("format", self.format())), 1usize => Some(Field::new("condition_count", self.condition_count())), 2usize => Some({ let data = self.data; Field::new( "condition_offsets", FieldType::array_of_offsets( better_type_name::(), self.condition_offsets(), move |off| { let target = off.get().resolve::(data); FieldType::offset(off.get(), target) }, ), ) }), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for ConditionFormat3<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } impl Format for ConditionFormat4Marker { const FORMAT: u16 = 4; } /// [Condition Table Format 4](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3276-L3295): OR #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct ConditionFormat4Marker { condition_offsets_byte_len: usize, } impl ConditionFormat4Marker { pub fn format_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn condition_count_byte_range(&self) -> Range { let start = self.format_byte_range().end; start..start + u8::RAW_BYTE_LEN } pub fn condition_offsets_byte_range(&self) -> Range { let start = self.condition_count_byte_range().end; start..start + self.condition_offsets_byte_len } } impl MinByteRange for ConditionFormat4Marker { fn min_byte_range(&self) -> Range { 0..self.condition_offsets_byte_range().end } } impl<'a> FontRead<'a> for ConditionFormat4<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); let condition_count: u8 = cursor.read()?; let condition_offsets_byte_len = (condition_count as usize) .checked_mul(Offset24::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(condition_offsets_byte_len); cursor.finish(ConditionFormat4Marker { condition_offsets_byte_len, }) } } /// [Condition Table Format 4](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3276-L3295): OR pub type ConditionFormat4<'a> = TableRef<'a, ConditionFormat4Marker>; #[allow(clippy::needless_lifetimes)] impl<'a> ConditionFormat4<'a> { /// Format, = 4 pub fn format(&self) -> u16 { let range = self.shape.format_byte_range(); self.data.read_at(range.start).unwrap() } /// Number of conditions. pub fn condition_count(&self) -> u8 { let range = self.shape.condition_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of condition tables for this disjunction (OR) expression. pub fn condition_offsets(&self) -> &'a [BigEndian] { let range = self.shape.condition_offsets_byte_range(); self.data.read_array(range).unwrap() } /// A dynamically resolving wrapper for [`condition_offsets`][Self::condition_offsets]. pub fn conditions(&self) -> ArrayOfOffsets<'a, Condition<'a>, Offset24> { let data = self.data; let offsets = self.condition_offsets(); ArrayOfOffsets::new(offsets, data, ()) } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for ConditionFormat4<'a> { fn type_name(&self) -> &str { "ConditionFormat4" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("format", self.format())), 1usize => Some(Field::new("condition_count", self.condition_count())), 2usize => Some({ let data = self.data; Field::new( "condition_offsets", FieldType::array_of_offsets( better_type_name::(), self.condition_offsets(), move |off| { let target = off.get().resolve::(data); FieldType::offset(off.get(), target) }, ), ) }), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for ConditionFormat4<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } impl Format for ConditionFormat5Marker { const FORMAT: u16 = 5; } /// [Condition Table Format 5](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3296-L3308): NOT #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct ConditionFormat5Marker {} impl ConditionFormat5Marker { pub fn format_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn condition_offset_byte_range(&self) -> Range { let start = self.format_byte_range().end; start..start + Offset24::RAW_BYTE_LEN } } impl MinByteRange for ConditionFormat5Marker { fn min_byte_range(&self) -> Range { 0..self.condition_offset_byte_range().end } } impl<'a> FontRead<'a> for ConditionFormat5<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); cursor.finish(ConditionFormat5Marker {}) } } /// [Condition Table Format 5](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3296-L3308): NOT pub type ConditionFormat5<'a> = TableRef<'a, ConditionFormat5Marker>; #[allow(clippy::needless_lifetimes)] impl<'a> ConditionFormat5<'a> { /// Format, = 5 pub fn format(&self) -> u16 { let range = self.shape.format_byte_range(); self.data.read_at(range.start).unwrap() } /// Condition to negate. pub fn condition_offset(&self) -> Offset24 { let range = self.shape.condition_offset_byte_range(); self.data.read_at(range.start).unwrap() } /// Attempt to resolve [`condition_offset`][Self::condition_offset]. pub fn condition(&self) -> Result, ReadError> { let data = self.data; self.condition_offset().resolve(data) } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for ConditionFormat5<'a> { fn type_name(&self) -> &str { "ConditionFormat5" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("format", self.format())), 1usize => Some(Field::new( "condition_offset", FieldType::offset(self.condition_offset(), self.condition()), )), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for ConditionFormat5<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } /// [FeatureTableSubstitution Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featuretablesubstitution-table) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct FeatureTableSubstitutionMarker { substitutions_byte_len: usize, } impl FeatureTableSubstitutionMarker { pub fn version_byte_range(&self) -> Range { let start = 0; start..start + MajorMinor::RAW_BYTE_LEN } pub fn substitution_count_byte_range(&self) -> Range { let start = self.version_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn substitutions_byte_range(&self) -> Range { let start = self.substitution_count_byte_range().end; start..start + self.substitutions_byte_len } } impl MinByteRange for FeatureTableSubstitutionMarker { fn min_byte_range(&self) -> Range { 0..self.substitutions_byte_range().end } } impl<'a> FontRead<'a> for FeatureTableSubstitution<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); let substitution_count: u16 = cursor.read()?; let substitutions_byte_len = (substitution_count as usize) .checked_mul(FeatureTableSubstitutionRecord::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(substitutions_byte_len); cursor.finish(FeatureTableSubstitutionMarker { substitutions_byte_len, }) } } /// [FeatureTableSubstitution Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featuretablesubstitution-table) pub type FeatureTableSubstitution<'a> = TableRef<'a, FeatureTableSubstitutionMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> FeatureTableSubstitution<'a> { /// Major & minor version of the table: (1, 0) pub fn version(&self) -> MajorMinor { let range = self.shape.version_byte_range(); self.data.read_at(range.start).unwrap() } /// Number of feature table substitution records. pub fn substitution_count(&self) -> u16 { let range = self.shape.substitution_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of feature table substitution records. pub fn substitutions(&self) -> &'a [FeatureTableSubstitutionRecord] { let range = self.shape.substitutions_byte_range(); self.data.read_array(range).unwrap() } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for FeatureTableSubstitution<'a> { fn type_name(&self) -> &str { "FeatureTableSubstitution" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("version", self.version())), 1usize => Some(Field::new("substitution_count", self.substitution_count())), 2usize => Some(Field::new( "substitutions", traversal::FieldType::array_of_records( stringify!(FeatureTableSubstitutionRecord), self.substitutions(), self.offset_data(), ), )), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for FeatureTableSubstitution<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } /// Used in [FeatureTableSubstitution] #[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)] #[repr(C)] #[repr(packed)] pub struct FeatureTableSubstitutionRecord { /// The feature table index to match. pub feature_index: BigEndian, /// Offset to an alternate feature table, from start of the /// FeatureTableSubstitution table. pub alternate_feature_offset: BigEndian, } impl FeatureTableSubstitutionRecord { /// The feature table index to match. pub fn feature_index(&self) -> u16 { self.feature_index.get() } /// Offset to an alternate feature table, from start of the /// FeatureTableSubstitution table. pub fn alternate_feature_offset(&self) -> Offset32 { self.alternate_feature_offset.get() } } impl FixedSize for FeatureTableSubstitutionRecord { const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN; } #[cfg(feature = "experimental_traverse")] impl<'a> SomeRecord<'a> for FeatureTableSubstitutionRecord { fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> { RecordResolver { name: "FeatureTableSubstitutionRecord", get_field: Box::new(move |idx, _data| match idx { 0usize => Some(Field::new("feature_index", self.feature_index())), 1usize => Some(Field::new( "alternate_feature_offset", FieldType::offset( self.alternate_feature_offset(), self.alternate_feature(_data), ), )), _ => None, }), data, } } } #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct SizeParamsMarker {} impl SizeParamsMarker { pub fn design_size_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn identifier_byte_range(&self) -> Range { let start = self.design_size_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn name_entry_byte_range(&self) -> Range { let start = self.identifier_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn range_start_byte_range(&self) -> Range { let start = self.name_entry_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn range_end_byte_range(&self) -> Range { let start = self.range_start_byte_range().end; start..start + u16::RAW_BYTE_LEN } } impl MinByteRange for SizeParamsMarker { fn min_byte_range(&self) -> Range { 0..self.range_end_byte_range().end } } impl<'a> FontRead<'a> for SizeParams<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); cursor.advance::(); cursor.advance::(); cursor.advance::(); cursor.finish(SizeParamsMarker {}) } } pub type SizeParams<'a> = TableRef<'a, SizeParamsMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> SizeParams<'a> { /// The first value represents the design size in 720/inch units (decipoints). /// /// The design size entry must be non-zero. When there is a design size but /// no recommended size range, the rest of the array will consist of zeros. pub fn design_size(&self) -> u16 { let range = self.shape.design_size_byte_range(); self.data.read_at(range.start).unwrap() } /// The second value has no independent meaning, but serves as an identifier that associates fonts in a subfamily. /// /// All fonts which share a Typographic or Font Family name and which differ /// only by size range shall have the same subfamily value, and no fonts /// which differ in weight or style shall have the same subfamily value. /// If this value is zero, the remaining fields in the array will be ignored. pub fn identifier(&self) -> u16 { let range = self.shape.identifier_byte_range(); self.data.read_at(range.start).unwrap() } /// The third value enables applications to use a single name for the subfamily identified by the second value. /// /// If the preceding value is non-zero, this value must be set in the range /// 256 – 32767 (inclusive). It records the value of a field in the 'name' /// table, which must contain English-language strings encoded in Windows /// Unicode and Macintosh Roman, and may contain additional strings localized /// to other scripts and languages. Each of these strings is the name /// an application should use, in combination with the family name, to /// represent the subfamily in a menu. Applications will choose the /// appropriate version based on their selection criteria. pub fn name_entry(&self) -> u16 { let range = self.shape.name_entry_byte_range(); self.data.read_at(range.start).unwrap() } /// The fourth and fifth values represent the small end of the recommended /// usage range (exclusive) and the large end of the recommended usage range /// (inclusive), stored in 720/inch units (decipoints). /// /// Ranges must not overlap, and should generally be contiguous. pub fn range_start(&self) -> u16 { let range = self.shape.range_start_byte_range(); self.data.read_at(range.start).unwrap() } pub fn range_end(&self) -> u16 { let range = self.shape.range_end_byte_range(); self.data.read_at(range.start).unwrap() } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for SizeParams<'a> { fn type_name(&self) -> &str { "SizeParams" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("design_size", self.design_size())), 1usize => Some(Field::new("identifier", self.identifier())), 2usize => Some(Field::new("name_entry", self.name_entry())), 3usize => Some(Field::new("range_start", self.range_start())), 4usize => Some(Field::new("range_end", self.range_end())), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for SizeParams<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct StylisticSetParamsMarker {} impl StylisticSetParamsMarker { pub fn version_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn ui_name_id_byte_range(&self) -> Range { let start = self.version_byte_range().end; start..start + NameId::RAW_BYTE_LEN } } impl MinByteRange for StylisticSetParamsMarker { fn min_byte_range(&self) -> Range { 0..self.ui_name_id_byte_range().end } } impl<'a> FontRead<'a> for StylisticSetParams<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); cursor.finish(StylisticSetParamsMarker {}) } } pub type StylisticSetParams<'a> = TableRef<'a, StylisticSetParamsMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> StylisticSetParams<'a> { pub fn version(&self) -> u16 { let range = self.shape.version_byte_range(); self.data.read_at(range.start).unwrap() } /// The 'name' table name ID that specifies a string (or strings, for /// multiple languages) for a user-interface label for this feature. /// /// The value of uiLabelNameId is expected to be in the font-specific name /// ID range (256-32767), though that is not a requirement in this Feature /// Parameters specification. The user-interface label for the feature can /// be provided in multiple languages. An English string should be included /// as a fallback. The string should be kept to a minimal length to fit /// comfortably with different application interfaces. pub fn ui_name_id(&self) -> NameId { let range = self.shape.ui_name_id_byte_range(); self.data.read_at(range.start).unwrap() } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for StylisticSetParams<'a> { fn type_name(&self) -> &str { "StylisticSetParams" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("version", self.version())), 1usize => Some(Field::new("ui_name_id", self.ui_name_id())), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for StylisticSetParams<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } impl Format for CharacterVariantParamsMarker { const FORMAT: u16 = 0; } /// featureParams for ['cv01'-'cv99'](https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#cv01-cv99) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct CharacterVariantParamsMarker { character_byte_len: usize, } impl CharacterVariantParamsMarker { pub fn format_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn feat_ui_label_name_id_byte_range(&self) -> Range { let start = self.format_byte_range().end; start..start + NameId::RAW_BYTE_LEN } pub fn feat_ui_tooltip_text_name_id_byte_range(&self) -> Range { let start = self.feat_ui_label_name_id_byte_range().end; start..start + NameId::RAW_BYTE_LEN } pub fn sample_text_name_id_byte_range(&self) -> Range { let start = self.feat_ui_tooltip_text_name_id_byte_range().end; start..start + NameId::RAW_BYTE_LEN } pub fn num_named_parameters_byte_range(&self) -> Range { let start = self.sample_text_name_id_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn first_param_ui_label_name_id_byte_range(&self) -> Range { let start = self.num_named_parameters_byte_range().end; start..start + NameId::RAW_BYTE_LEN } pub fn char_count_byte_range(&self) -> Range { let start = self.first_param_ui_label_name_id_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn character_byte_range(&self) -> Range { let start = self.char_count_byte_range().end; start..start + self.character_byte_len } } impl MinByteRange for CharacterVariantParamsMarker { fn min_byte_range(&self) -> Range { 0..self.character_byte_range().end } } impl<'a> FontRead<'a> for CharacterVariantParams<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); cursor.advance::(); cursor.advance::(); cursor.advance::(); cursor.advance::(); let char_count: u16 = cursor.read()?; let character_byte_len = (char_count as usize) .checked_mul(Uint24::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(character_byte_len); cursor.finish(CharacterVariantParamsMarker { character_byte_len }) } } /// featureParams for ['cv01'-'cv99'](https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#cv01-cv99) pub type CharacterVariantParams<'a> = TableRef<'a, CharacterVariantParamsMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> CharacterVariantParams<'a> { /// Format number is set to 0. pub fn format(&self) -> u16 { let range = self.shape.format_byte_range(); self.data.read_at(range.start).unwrap() } /// The 'name' table name ID that specifies a string (or strings, /// for multiple languages) for a user-interface label for this /// feature. (May be NULL.) pub fn feat_ui_label_name_id(&self) -> NameId { let range = self.shape.feat_ui_label_name_id_byte_range(); self.data.read_at(range.start).unwrap() } /// The 'name' table name ID that specifies a string (or strings, /// for multiple languages) that an application can use for tooltip /// text for this feature. (May be NULL.) pub fn feat_ui_tooltip_text_name_id(&self) -> NameId { let range = self.shape.feat_ui_tooltip_text_name_id_byte_range(); self.data.read_at(range.start).unwrap() } /// The 'name' table name ID that specifies sample text that /// illustrates the effect of this feature. (May be NULL.) pub fn sample_text_name_id(&self) -> NameId { let range = self.shape.sample_text_name_id_byte_range(); self.data.read_at(range.start).unwrap() } /// Number of named parameters. (May be zero.) pub fn num_named_parameters(&self) -> u16 { let range = self.shape.num_named_parameters_byte_range(); self.data.read_at(range.start).unwrap() } /// The first 'name' table name ID used to specify strings for /// user-interface labels for the feature parameters. (Must be zero /// if numParameters is zero.) pub fn first_param_ui_label_name_id(&self) -> NameId { let range = self.shape.first_param_ui_label_name_id_byte_range(); self.data.read_at(range.start).unwrap() } /// The count of characters for which this feature provides glyph /// variants. (May be zero.) pub fn char_count(&self) -> u16 { let range = self.shape.char_count_byte_range(); self.data.read_at(range.start).unwrap() } /// The Unicode Scalar Value of the characters for which this /// feature provides glyph variants. pub fn character(&self) -> &'a [BigEndian] { let range = self.shape.character_byte_range(); self.data.read_array(range).unwrap() } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for CharacterVariantParams<'a> { fn type_name(&self) -> &str { "CharacterVariantParams" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("format", self.format())), 1usize => Some(Field::new( "feat_ui_label_name_id", self.feat_ui_label_name_id(), )), 2usize => Some(Field::new( "feat_ui_tooltip_text_name_id", self.feat_ui_tooltip_text_name_id(), )), 3usize => Some(Field::new( "sample_text_name_id", self.sample_text_name_id(), )), 4usize => Some(Field::new( "num_named_parameters", self.num_named_parameters(), )), 5usize => Some(Field::new( "first_param_ui_label_name_id", self.first_param_ui_label_name_id(), )), 6usize => Some(Field::new("char_count", self.char_count())), 7usize => Some(Field::new("character", self.character())), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for CharacterVariantParams<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } }