// 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::*; impl<'a> MinByteRange<'a> for ScriptList<'a> { fn min_byte_range(&self) -> Range { 0..self.script_records_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for ScriptList<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// [Script List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-list-table-and-script-record) #[derive(Clone)] pub struct ScriptList<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> ScriptList<'a> { pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN; basic_table_impls!(impl_the_methods); /// Number of ScriptRecords pub fn script_count(&self) -> u16 { let range = self.script_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of ScriptRecords, listed alphabetically by script tag pub fn script_records(&self) -> &'a [ScriptRecord] { let range = self.script_records_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } pub fn script_count_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn script_records_byte_range(&self) -> Range { let script_count = self.script_count(); let start = self.script_count_byte_range().end; let end = start + (transforms::to_usize(script_count)).saturating_mul(ScriptRecord::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough(ScriptList::MIN_SIZE)); impl Default for ScriptList<'_> { fn default() -> Self { Self { data: FontData::default_table_data(), } } } #[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, } } } impl<'a> MinByteRange<'a> for Script<'a> { fn min_byte_range(&self) -> Range { 0..self.lang_sys_records_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for Script<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// [Script Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-table-and-language-system-record) #[derive(Clone)] pub struct Script<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> Script<'a> { pub const MIN_SIZE: usize = (Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Offset to default LangSys table, from beginning of Script table /// — may be NULL pub fn default_lang_sys_offset(&self) -> Nullable { let range = self.default_lang_sys_offset_byte_range(); self.data.read_at(range.start).ok().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.lang_sys_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of LangSysRecords, listed alphabetically by LangSys tag pub fn lang_sys_records(&self) -> &'a [LangSysRecord] { let range = self.lang_sys_records_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } pub fn default_lang_sys_offset_byte_range(&self) -> Range { let start = 0; let end = start + Offset16::RAW_BYTE_LEN; start..end } pub fn lang_sys_count_byte_range(&self) -> Range { let start = self.default_lang_sys_offset_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn lang_sys_records_byte_range(&self) -> Range { let lang_sys_count = self.lang_sys_count(); let start = self.lang_sys_count_byte_range().end; let end = start + (transforms::to_usize(lang_sys_count)).saturating_mul(LangSysRecord::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough(Script::MIN_SIZE)); impl Default for Script<'_> { fn default() -> Self { Self { data: FontData::default_table_data(), } } } #[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, } } } impl<'a> MinByteRange<'a> for LangSys<'a> { fn min_byte_range(&self) -> Range { 0..self.feature_indices_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for LangSys<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// [Language System Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#language-system-table) #[derive(Clone)] pub struct LangSys<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> LangSys<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Index of a feature required for this language system; if no /// required features = 0xFFFF pub fn required_feature_index(&self) -> u16 { let range = self.required_feature_index_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Number of feature index values for this language system — /// excludes the required feature pub fn feature_index_count(&self) -> u16 { let range = self.feature_index_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of indices into the FeatureList, in arbitrary order pub fn feature_indices(&self) -> &'a [BigEndian] { let range = self.feature_indices_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } pub fn lookup_order_offset_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn required_feature_index_byte_range(&self) -> Range { let start = self.lookup_order_offset_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn feature_index_count_byte_range(&self) -> Range { let start = self.required_feature_index_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn feature_indices_byte_range(&self) -> Range { let feature_index_count = self.feature_index_count(); let start = self.feature_index_count_byte_range().end; let end = start + (transforms::to_usize(feature_index_count)).saturating_mul(u16::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough(LangSys::MIN_SIZE)); impl Default for LangSys<'_> { fn default() -> Self { Self { data: FontData::default_table_data(), } } } #[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) } } impl<'a> MinByteRange<'a> for FeatureList<'a> { fn min_byte_range(&self) -> Range { 0..self.feature_records_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for FeatureList<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// [Feature List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-list-table) #[derive(Clone)] pub struct FeatureList<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> FeatureList<'a> { pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN; basic_table_impls!(impl_the_methods); /// Number of FeatureRecords in this table pub fn feature_count(&self) -> u16 { let range = self.feature_count_byte_range(); self.data.read_at(range.start).ok().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.feature_records_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } pub fn feature_count_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn feature_records_byte_range(&self) -> Range { let feature_count = self.feature_count(); let start = self.feature_count_byte_range().end; let end = start + (transforms::to_usize(feature_count)).saturating_mul(FeatureRecord::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough(FeatureList::MIN_SIZE)); impl Default for FeatureList<'_> { fn default() -> Self { Self { data: FontData::default_table_data(), } } } #[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, } } } impl<'a> MinByteRange<'a> for Feature<'a> { fn min_byte_range(&self) -> Range { 0..self.lookup_list_indices_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } 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; #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data, feature_tag }) } } 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) #[derive(Clone)] pub struct Feature<'a> { data: FontData<'a>, feature_tag: Tag, } #[allow(clippy::needless_lifetimes)] impl<'a> Feature<'a> { pub const MIN_SIZE: usize = (Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// 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.feature_params_offset_byte_range(); self.data.read_at(range.start).ok().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.lookup_index_count_byte_range(); self.data.read_at(range.start).ok().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.lookup_list_indices_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } pub(crate) fn feature_tag(&self) -> Tag { self.feature_tag } pub fn feature_params_offset_byte_range(&self) -> Range { let start = 0; let end = start + Offset16::RAW_BYTE_LEN; start..end } pub fn lookup_index_count_byte_range(&self) -> Range { let start = self.feature_params_offset_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn lookup_list_indices_byte_range(&self) -> Range { let lookup_index_count = self.lookup_index_count(); let start = self.lookup_index_count_byte_range().end; let end = start + (transforms::to_usize(lookup_index_count)).saturating_mul(u16::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough(Feature::MIN_SIZE)); impl Default for Feature<'_> { fn default() -> Self { Self { data: FontData::default_table_data(), feature_tag: Default::default(), } } } #[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) } } impl<'a, T> MinByteRange<'a> for LookupList<'a, T> { fn min_byte_range(&self) -> Range { 0..self.lookup_offsets_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a, T> FontRead<'a> for LookupList<'a, T> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data, offset_type: std::marker::PhantomData, }) } } 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, ()> { LookupList { data: self.data, offset_type: std::marker::PhantomData, } } } /// [Lookup List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-list-table) #[derive(Clone)] pub struct LookupList<'a, T = ()> { data: FontData<'a>, offset_type: std::marker::PhantomData<*const T>, } #[allow(clippy::needless_lifetimes)] impl<'a, T> LookupList<'a, T> { pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN; basic_table_impls!(impl_the_methods); /// Number of lookups in this table pub fn lookup_count(&self) -> u16 { let range = self.lookup_count_byte_range(); self.data.read_at(range.start).ok().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.lookup_offsets_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// 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, ()) } pub fn lookup_count_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn lookup_offsets_byte_range(&self) -> Range { let lookup_count = self.lookup_count(); let start = self.lookup_count_byte_range().end; let end = start + (transforms::to_usize(lookup_count)).saturating_mul(Offset16::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough( LookupList::<()>::MIN_SIZE )); impl Default for LookupList<'_, T> { fn default() -> Self { Self { data: FontData::default_table_data(), offset_type: std::marker::PhantomData, } } } #[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(Field::new( "lookup_offsets", FieldType::from(self.lookups()), )), _ => 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) } } impl Discriminant for Lookup<'_, ()> { fn read_discriminant(data: FontData<'_>) -> Result { data.read_at(0) } } impl<'a, T> MinByteRange<'a> for Lookup<'a, T> { fn min_byte_range(&self) -> Range { 0..self.subtable_offsets_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a, T> FontRead<'a> for Lookup<'a, T> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data, offset_type: std::marker::PhantomData, }) } } 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, ()> { Lookup { data: self.data, offset_type: std::marker::PhantomData, } } } /// [Lookup Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-table) #[derive(Clone)] pub struct Lookup<'a, T = ()> { data: FontData<'a>, offset_type: std::marker::PhantomData<*const T>, } #[allow(clippy::needless_lifetimes)] impl<'a, T> Lookup<'a, T> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + LookupFlag::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Different enumerations for GSUB and GPOS pub fn lookup_type(&self) -> u16 { let range = self.lookup_type_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Lookup qualifiers pub fn lookup_flag(&self) -> LookupFlag { let range = self.lookup_flag_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Number of subtables for this lookup pub fn sub_table_count(&self) -> u16 { let range = self.sub_table_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of offsets to lookup subtables, from beginning of Lookup /// table pub fn subtable_offsets(&self) -> &'a [BigEndian] { let range = self.subtable_offsets_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// 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.mark_filtering_set_byte_range(); (!range.is_empty()) .then(|| self.data.read_at(range.start).ok()) .flatten() } pub fn lookup_type_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn lookup_flag_byte_range(&self) -> Range { let start = self.lookup_type_byte_range().end; let end = start + LookupFlag::RAW_BYTE_LEN; start..end } pub fn sub_table_count_byte_range(&self) -> Range { let start = self.lookup_flag_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn subtable_offsets_byte_range(&self) -> Range { let sub_table_count = self.sub_table_count(); let start = self.sub_table_count_byte_range().end; let end = start + (transforms::to_usize(sub_table_count)).saturating_mul(Offset16::RAW_BYTE_LEN); start..end } pub fn mark_filtering_set_byte_range(&self) -> Range { let start = self.subtable_offsets_byte_range().end; let end = if self .lookup_flag() .contains(LookupFlag::USE_MARK_FILTERING_SET) { start + u16::RAW_BYTE_LEN } else { start }; start..end } } const _: () = assert!(FontData::default_data_long_enough(Lookup::<()>::MIN_SIZE)); impl Default for Lookup<'_, T> { fn default() -> Self { Self { data: FontData::default_table_data(), offset_type: std::marker::PhantomData, } } } #[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> { 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(Field::new( "subtable_offsets", FieldType::from(self.subtables()), )), 4usize if self .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 CoverageFormat1<'_> { const FORMAT: u16 = 1; } impl<'a> MinByteRange<'a> for CoverageFormat1<'a> { fn min_byte_range(&self) -> Range { 0..self.glyph_array_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for CoverageFormat1<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// [Coverage Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-1) #[derive(Clone)] pub struct CoverageFormat1<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> CoverageFormat1<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Format identifier — format = 1 pub fn coverage_format(&self) -> u16 { let range = self.coverage_format_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Number of glyphs in the glyph array pub fn glyph_count(&self) -> u16 { let range = self.glyph_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of glyph IDs — in numerical order pub fn glyph_array(&self) -> &'a [BigEndian] { let range = self.glyph_array_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } pub fn coverage_format_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn glyph_count_byte_range(&self) -> Range { let start = self.coverage_format_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn glyph_array_byte_range(&self) -> Range { let glyph_count = self.glyph_count(); let start = self.glyph_count_byte_range().end; let end = start + (transforms::to_usize(glyph_count)).saturating_mul(GlyphId16::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough( CoverageFormat1::MIN_SIZE )); impl Default for CoverageFormat1<'_> { fn default() -> Self { Self { data: FontData::default_format_1_u16_table_data(), } } } #[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 CoverageFormat2<'_> { const FORMAT: u16 = 2; } impl<'a> MinByteRange<'a> for CoverageFormat2<'a> { fn min_byte_range(&self) -> Range { 0..self.range_records_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for CoverageFormat2<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// [Coverage Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-2) #[derive(Clone)] pub struct CoverageFormat2<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> CoverageFormat2<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Format identifier — format = 2 pub fn coverage_format(&self) -> u16 { let range = self.coverage_format_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Number of RangeRecords pub fn range_count(&self) -> u16 { let range = self.range_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of glyph ranges — ordered by startGlyphID. pub fn range_records(&self) -> &'a [RangeRecord] { let range = self.range_records_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } pub fn coverage_format_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn range_count_byte_range(&self) -> Range { let start = self.coverage_format_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn range_records_byte_range(&self) -> Range { let range_count = self.range_count(); let start = self.range_count_byte_range().end; let end = start + (transforms::to_usize(range_count)).saturating_mul(RangeRecord::RAW_BYTE_LEN); start..end } } #[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 Default for CoverageTable<'_> { fn default() -> Self { Self::Format1(Default::default()) } } 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 { CoverageFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)), CoverageFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)), other => Err(ReadError::InvalidFormat(other.into())), } } } impl<'a> MinByteRange<'a> for CoverageTable<'a> { fn min_byte_range(&self) -> Range { match self { Self::Format1(item) => item.min_byte_range(), Self::Format2(item) => item.min_byte_range(), } } fn min_table_bytes(&self) -> &'a [u8] { match self { Self::Format1(item) => item.min_table_bytes(), Self::Format2(item) => item.min_table_bytes(), } } } #[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 ClassDefFormat1<'_> { const FORMAT: u16 = 1; } impl<'a> MinByteRange<'a> for ClassDefFormat1<'a> { fn min_byte_range(&self) -> Range { 0..self.class_value_array_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for ClassDefFormat1<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// [Class Definition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-1) #[derive(Clone)] pub struct ClassDefFormat1<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> ClassDefFormat1<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Format identifier — format = 1 pub fn class_format(&self) -> u16 { let range = self.class_format_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// First glyph ID of the classValueArray pub fn start_glyph_id(&self) -> GlyphId16 { let range = self.start_glyph_id_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Size of the classValueArray pub fn glyph_count(&self) -> u16 { let range = self.glyph_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of Class Values — one per glyph ID pub fn class_value_array(&self) -> &'a [BigEndian] { let range = self.class_value_array_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } pub fn class_format_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn start_glyph_id_byte_range(&self) -> Range { let start = self.class_format_byte_range().end; let end = start + GlyphId16::RAW_BYTE_LEN; start..end } pub fn glyph_count_byte_range(&self) -> Range { let start = self.start_glyph_id_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn class_value_array_byte_range(&self) -> Range { let glyph_count = self.glyph_count(); let start = self.glyph_count_byte_range().end; let end = start + (transforms::to_usize(glyph_count)).saturating_mul(u16::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough( ClassDefFormat1::MIN_SIZE )); impl Default for ClassDefFormat1<'_> { fn default() -> Self { Self { data: FontData::default_format_1_u16_table_data(), } } } #[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 ClassDefFormat2<'_> { const FORMAT: u16 = 2; } impl<'a> MinByteRange<'a> for ClassDefFormat2<'a> { fn min_byte_range(&self) -> Range { 0..self.class_range_records_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for ClassDefFormat2<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// [Class Definition Table Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-2) #[derive(Clone)] pub struct ClassDefFormat2<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> ClassDefFormat2<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Format identifier — format = 2 pub fn class_format(&self) -> u16 { let range = self.class_format_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Number of ClassRangeRecords pub fn class_range_count(&self) -> u16 { let range = self.class_range_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of ClassRangeRecords — ordered by startGlyphID pub fn class_range_records(&self) -> &'a [ClassRangeRecord] { let range = self.class_range_records_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } pub fn class_format_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn class_range_count_byte_range(&self) -> Range { let start = self.class_format_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn class_range_records_byte_range(&self) -> Range { let class_range_count = self.class_range_count(); let start = self.class_range_count_byte_range().end; let end = start + (transforms::to_usize(class_range_count)) .saturating_mul(ClassRangeRecord::RAW_BYTE_LEN); start..end } } #[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 Default for ClassDef<'_> { fn default() -> Self { Self::Format1(Default::default()) } } 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 { ClassDefFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)), ClassDefFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)), other => Err(ReadError::InvalidFormat(other.into())), } } } impl<'a> MinByteRange<'a> for ClassDef<'a> { fn min_byte_range(&self) -> Range { match self { Self::Format1(item) => item.min_byte_range(), Self::Format2(item) => item.min_byte_range(), } } fn min_table_bytes(&self) -> &'a [u8] { match self { Self::Format1(item) => item.min_table_bytes(), Self::Format2(item) => item.min_table_bytes(), } } } #[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 SequenceContextFormat1<'_> { const FORMAT: u16 = 1; } impl<'a> MinByteRange<'a> for SequenceContextFormat1<'a> { fn min_byte_range(&self) -> Range { 0..self.seq_rule_set_offsets_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for SequenceContextFormat1<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// [Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-1-simple-glyph-contexts) #[derive(Clone)] pub struct SequenceContextFormat1<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> SequenceContextFormat1<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Format identifier: format = 1 pub fn format(&self) -> u16 { let range = self.format_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Offset to Coverage table, from beginning of /// SequenceContextFormat1 table pub fn coverage_offset(&self) -> Offset16 { let range = self.coverage_offset_byte_range(); self.data.read_at(range.start).ok().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.seq_rule_set_count_byte_range(); self.data.read_at(range.start).ok().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.seq_rule_set_offsets_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// 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, ()) } pub fn format_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn coverage_offset_byte_range(&self) -> Range { let start = self.format_byte_range().end; let end = start + Offset16::RAW_BYTE_LEN; start..end } pub fn seq_rule_set_count_byte_range(&self) -> Range { let start = self.coverage_offset_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn seq_rule_set_offsets_byte_range(&self) -> Range { let seq_rule_set_count = self.seq_rule_set_count(); let start = self.seq_rule_set_count_byte_range().end; let end = start + (transforms::to_usize(seq_rule_set_count)).saturating_mul(Offset16::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough( SequenceContextFormat1::MIN_SIZE )); impl Default for SequenceContextFormat1<'_> { fn default() -> Self { Self { data: FontData::default_format_1_u16_table_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(Field::new( "seq_rule_set_offsets", FieldType::from(self.seq_rule_sets()), )), _ => 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) } } impl<'a> MinByteRange<'a> for SequenceRuleSet<'a> { fn min_byte_range(&self) -> Range { 0..self.seq_rule_offsets_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for SequenceRuleSet<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// Part of [SequenceContextFormat1] #[derive(Clone)] pub struct SequenceRuleSet<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> SequenceRuleSet<'a> { pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN; basic_table_impls!(impl_the_methods); /// Number of SequenceRule tables pub fn seq_rule_count(&self) -> u16 { let range = self.seq_rule_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of offsets to SequenceRule tables, from beginning of the /// SequenceRuleSet table pub fn seq_rule_offsets(&self) -> &'a [BigEndian] { let range = self.seq_rule_offsets_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// 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, ()) } pub fn seq_rule_count_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn seq_rule_offsets_byte_range(&self) -> Range { let seq_rule_count = self.seq_rule_count(); let start = self.seq_rule_count_byte_range().end; let end = start + (transforms::to_usize(seq_rule_count)).saturating_mul(Offset16::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough( SequenceRuleSet::MIN_SIZE )); impl Default for SequenceRuleSet<'_> { fn default() -> Self { Self { data: FontData::default_table_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(Field::new( "seq_rule_offsets", FieldType::from(self.seq_rules()), )), _ => 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) } } impl<'a> MinByteRange<'a> for SequenceRule<'a> { fn min_byte_range(&self) -> Range { 0..self.seq_lookup_records_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for SequenceRule<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// Part of [SequenceContextFormat1] #[derive(Clone)] pub struct SequenceRule<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> SequenceRule<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Number of glyphs in the input glyph sequence pub fn glyph_count(&self) -> u16 { let range = self.glyph_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Number of SequenceLookupRecords pub fn seq_lookup_count(&self) -> u16 { let range = self.seq_lookup_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of input glyph IDs—starting with the second glyph pub fn input_sequence(&self) -> &'a [BigEndian] { let range = self.input_sequence_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// Array of Sequence lookup records pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] { let range = self.seq_lookup_records_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } pub fn glyph_count_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn seq_lookup_count_byte_range(&self) -> Range { let start = self.glyph_count_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn input_sequence_byte_range(&self) -> Range { let glyph_count = self.glyph_count(); let start = self.seq_lookup_count_byte_range().end; let end = start + (transforms::subtract(glyph_count, 1_usize)).saturating_mul(GlyphId16::RAW_BYTE_LEN); start..end } pub fn seq_lookup_records_byte_range(&self) -> Range { let seq_lookup_count = self.seq_lookup_count(); let start = self.input_sequence_byte_range().end; let end = start + (transforms::to_usize(seq_lookup_count)) .saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough(SequenceRule::MIN_SIZE)); impl Default for SequenceRule<'_> { fn default() -> Self { Self { data: FontData::default_table_data(), } } } #[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 SequenceContextFormat2<'_> { const FORMAT: u16 = 2; } impl<'a> MinByteRange<'a> for SequenceContextFormat2<'a> { fn min_byte_range(&self) -> Range { 0..self.class_seq_rule_set_offsets_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for SequenceContextFormat2<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// [Sequence Context Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-2-class-based-glyph-contexts) #[derive(Clone)] pub struct SequenceContextFormat2<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> SequenceContextFormat2<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Format identifier: format = 2 pub fn format(&self) -> u16 { let range = self.format_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Offset to Coverage table, from beginning of /// SequenceContextFormat2 table pub fn coverage_offset(&self) -> Offset16 { let range = self.coverage_offset_byte_range(); self.data.read_at(range.start).ok().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.class_def_offset_byte_range(); self.data.read_at(range.start).ok().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.class_seq_rule_set_count_byte_range(); self.data.read_at(range.start).ok().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.class_seq_rule_set_offsets_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// 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, ()) } pub fn format_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn coverage_offset_byte_range(&self) -> Range { let start = self.format_byte_range().end; let end = start + Offset16::RAW_BYTE_LEN; start..end } pub fn class_def_offset_byte_range(&self) -> Range { let start = self.coverage_offset_byte_range().end; let end = start + Offset16::RAW_BYTE_LEN; start..end } pub fn class_seq_rule_set_count_byte_range(&self) -> Range { let start = self.class_def_offset_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn class_seq_rule_set_offsets_byte_range(&self) -> Range { let class_seq_rule_set_count = self.class_seq_rule_set_count(); let start = self.class_seq_rule_set_count_byte_range().end; let end = start + (transforms::to_usize(class_seq_rule_set_count)) .saturating_mul(Offset16::RAW_BYTE_LEN); start..end } } #[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(Field::new( "class_seq_rule_set_offsets", FieldType::from(self.class_seq_rule_sets()), )), _ => 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) } } impl<'a> MinByteRange<'a> for ClassSequenceRuleSet<'a> { fn min_byte_range(&self) -> Range { 0..self.class_seq_rule_offsets_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for ClassSequenceRuleSet<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// Part of [SequenceContextFormat2] #[derive(Clone)] pub struct ClassSequenceRuleSet<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> ClassSequenceRuleSet<'a> { pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN; basic_table_impls!(impl_the_methods); /// Number of ClassSequenceRule tables pub fn class_seq_rule_count(&self) -> u16 { let range = self.class_seq_rule_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of offsets to ClassSequenceRule tables, from beginning of /// ClassSequenceRuleSet table pub fn class_seq_rule_offsets(&self) -> &'a [BigEndian] { let range = self.class_seq_rule_offsets_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// 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, ()) } pub fn class_seq_rule_count_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn class_seq_rule_offsets_byte_range(&self) -> Range { let class_seq_rule_count = self.class_seq_rule_count(); let start = self.class_seq_rule_count_byte_range().end; let end = start + (transforms::to_usize(class_seq_rule_count)).saturating_mul(Offset16::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough( ClassSequenceRuleSet::MIN_SIZE )); impl Default for ClassSequenceRuleSet<'_> { fn default() -> Self { Self { data: FontData::default_table_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(Field::new( "class_seq_rule_offsets", FieldType::from(self.class_seq_rules()), )), _ => 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) } } impl<'a> MinByteRange<'a> for ClassSequenceRule<'a> { fn min_byte_range(&self) -> Range { 0..self.seq_lookup_records_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for ClassSequenceRule<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// Part of [SequenceContextFormat2] #[derive(Clone)] pub struct ClassSequenceRule<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> ClassSequenceRule<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Number of glyphs to be matched pub fn glyph_count(&self) -> u16 { let range = self.glyph_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Number of SequenceLookupRecords pub fn seq_lookup_count(&self) -> u16 { let range = self.seq_lookup_count_byte_range(); self.data.read_at(range.start).ok().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.input_sequence_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// Array of SequenceLookupRecords pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] { let range = self.seq_lookup_records_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } pub fn glyph_count_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn seq_lookup_count_byte_range(&self) -> Range { let start = self.glyph_count_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn input_sequence_byte_range(&self) -> Range { let glyph_count = self.glyph_count(); let start = self.seq_lookup_count_byte_range().end; let end = start + (transforms::subtract(glyph_count, 1_usize)).saturating_mul(u16::RAW_BYTE_LEN); start..end } pub fn seq_lookup_records_byte_range(&self) -> Range { let seq_lookup_count = self.seq_lookup_count(); let start = self.input_sequence_byte_range().end; let end = start + (transforms::to_usize(seq_lookup_count)) .saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough( ClassSequenceRule::MIN_SIZE )); impl Default for ClassSequenceRule<'_> { fn default() -> Self { Self { data: FontData::default_table_data(), } } } #[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 SequenceContextFormat3<'_> { const FORMAT: u16 = 3; } impl<'a> MinByteRange<'a> for SequenceContextFormat3<'a> { fn min_byte_range(&self) -> Range { 0..self.seq_lookup_records_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for SequenceContextFormat3<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// [Sequence Context Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-3-coverage-based-glyph-contexts) #[derive(Clone)] pub struct SequenceContextFormat3<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> SequenceContextFormat3<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Format identifier: format = 3 pub fn format(&self) -> u16 { let range = self.format_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Number of glyphs in the input sequence pub fn glyph_count(&self) -> u16 { let range = self.glyph_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Number of SequenceLookupRecords pub fn seq_lookup_count(&self) -> u16 { let range = self.seq_lookup_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of offsets to Coverage tables, from beginning of /// SequenceContextFormat3 subtable pub fn coverage_offsets(&self) -> &'a [BigEndian] { let range = self.coverage_offsets_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// 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.seq_lookup_records_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } pub fn format_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn glyph_count_byte_range(&self) -> Range { let start = self.format_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn seq_lookup_count_byte_range(&self) -> Range { let start = self.glyph_count_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn coverage_offsets_byte_range(&self) -> Range { let glyph_count = self.glyph_count(); let start = self.seq_lookup_count_byte_range().end; let end = start + (transforms::to_usize(glyph_count)).saturating_mul(Offset16::RAW_BYTE_LEN); start..end } pub fn seq_lookup_records_byte_range(&self) -> Range { let seq_lookup_count = self.seq_lookup_count(); let start = self.coverage_offsets_byte_range().end; let end = start + (transforms::to_usize(seq_lookup_count)) .saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN); start..end } } #[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(Field::new( "coverage_offsets", FieldType::from(self.coverages()), )), 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 Default for SequenceContext<'_> { fn default() -> Self { Self::Format1(Default::default()) } } 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 { SequenceContextFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)), SequenceContextFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)), SequenceContextFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)), other => Err(ReadError::InvalidFormat(other.into())), } } } impl<'a> MinByteRange<'a> for SequenceContext<'a> { 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(), } } fn min_table_bytes(&self) -> &'a [u8] { match self { Self::Format1(item) => item.min_table_bytes(), Self::Format2(item) => item.min_table_bytes(), Self::Format3(item) => item.min_table_bytes(), } } } #[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 ChainedSequenceContextFormat1<'_> { const FORMAT: u16 = 1; } impl<'a> MinByteRange<'a> for ChainedSequenceContextFormat1<'a> { fn min_byte_range(&self) -> Range { 0..self.chained_seq_rule_set_offsets_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for ChainedSequenceContextFormat1<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// [Chained Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-1-simple-glyph-contexts) #[derive(Clone)] pub struct ChainedSequenceContextFormat1<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> ChainedSequenceContextFormat1<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Format identifier: format = 1 pub fn format(&self) -> u16 { let range = self.format_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Offset to Coverage table, from beginning of /// ChainSequenceContextFormat1 table pub fn coverage_offset(&self) -> Offset16 { let range = self.coverage_offset_byte_range(); self.data.read_at(range.start).ok().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.chained_seq_rule_set_count_byte_range(); self.data.read_at(range.start).ok().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.chained_seq_rule_set_offsets_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// 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, ()) } pub fn format_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn coverage_offset_byte_range(&self) -> Range { let start = self.format_byte_range().end; let end = start + Offset16::RAW_BYTE_LEN; start..end } pub fn chained_seq_rule_set_count_byte_range(&self) -> Range { let start = self.coverage_offset_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn chained_seq_rule_set_offsets_byte_range(&self) -> Range { let chained_seq_rule_set_count = self.chained_seq_rule_set_count(); let start = self.chained_seq_rule_set_count_byte_range().end; let end = start + (transforms::to_usize(chained_seq_rule_set_count)) .saturating_mul(Offset16::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough( ChainedSequenceContextFormat1::MIN_SIZE )); impl Default for ChainedSequenceContextFormat1<'_> { fn default() -> Self { Self { data: FontData::default_format_1_u16_table_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(Field::new( "chained_seq_rule_set_offsets", FieldType::from(self.chained_seq_rule_sets()), )), _ => 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) } } impl<'a> MinByteRange<'a> for ChainedSequenceRuleSet<'a> { fn min_byte_range(&self) -> Range { 0..self.chained_seq_rule_offsets_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for ChainedSequenceRuleSet<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// Part of [ChainedSequenceContextFormat1] #[derive(Clone)] pub struct ChainedSequenceRuleSet<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> ChainedSequenceRuleSet<'a> { pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN; basic_table_impls!(impl_the_methods); /// Number of ChainedSequenceRule tables pub fn chained_seq_rule_count(&self) -> u16 { let range = self.chained_seq_rule_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of offsets to ChainedSequenceRule tables, from beginning /// of ChainedSequenceRuleSet table pub fn chained_seq_rule_offsets(&self) -> &'a [BigEndian] { let range = self.chained_seq_rule_offsets_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// 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, ()) } pub fn chained_seq_rule_count_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn chained_seq_rule_offsets_byte_range(&self) -> Range { let chained_seq_rule_count = self.chained_seq_rule_count(); let start = self.chained_seq_rule_count_byte_range().end; let end = start + (transforms::to_usize(chained_seq_rule_count)).saturating_mul(Offset16::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough( ChainedSequenceRuleSet::MIN_SIZE )); impl Default for ChainedSequenceRuleSet<'_> { fn default() -> Self { Self { data: FontData::default_table_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(Field::new( "chained_seq_rule_offsets", FieldType::from(self.chained_seq_rules()), )), _ => 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) } } impl<'a> MinByteRange<'a> for ChainedSequenceRule<'a> { fn min_byte_range(&self) -> Range { 0..self.seq_lookup_records_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for ChainedSequenceRule<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// Part of [ChainedSequenceContextFormat1] #[derive(Clone)] pub struct ChainedSequenceRule<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> ChainedSequenceRule<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Number of glyphs in the backtrack sequence pub fn backtrack_glyph_count(&self) -> u16 { let range = self.backtrack_glyph_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of backtrack glyph IDs pub fn backtrack_sequence(&self) -> &'a [BigEndian] { let range = self.backtrack_sequence_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// Number of glyphs in the input sequence pub fn input_glyph_count(&self) -> u16 { let range = self.input_glyph_count_byte_range(); self.data.read_at(range.start).ok().unwrap_or_default() } /// Array of input glyph IDs—start with second glyph pub fn input_sequence(&self) -> &'a [BigEndian] { let range = self.input_sequence_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// Number of glyphs in the lookahead sequence pub fn lookahead_glyph_count(&self) -> u16 { let range = self.lookahead_glyph_count_byte_range(); self.data.read_at(range.start).ok().unwrap_or_default() } /// Array of lookahead glyph IDs pub fn lookahead_sequence(&self) -> &'a [BigEndian] { let range = self.lookahead_sequence_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// Number of SequenceLookupRecords pub fn seq_lookup_count(&self) -> u16 { let range = self.seq_lookup_count_byte_range(); self.data.read_at(range.start).ok().unwrap_or_default() } /// Array of SequenceLookupRecords pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] { let range = self.seq_lookup_records_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } pub fn backtrack_glyph_count_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn backtrack_sequence_byte_range(&self) -> Range { let backtrack_glyph_count = self.backtrack_glyph_count(); let start = self.backtrack_glyph_count_byte_range().end; let end = start + (transforms::to_usize(backtrack_glyph_count)).saturating_mul(GlyphId16::RAW_BYTE_LEN); start..end } pub fn input_glyph_count_byte_range(&self) -> Range { let start = self.backtrack_sequence_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn input_sequence_byte_range(&self) -> Range { let input_glyph_count = self.input_glyph_count(); let start = self.input_glyph_count_byte_range().end; let end = start + (transforms::subtract(input_glyph_count, 1_usize)) .saturating_mul(GlyphId16::RAW_BYTE_LEN); start..end } pub fn lookahead_glyph_count_byte_range(&self) -> Range { let start = self.input_sequence_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn lookahead_sequence_byte_range(&self) -> Range { let lookahead_glyph_count = self.lookahead_glyph_count(); let start = self.lookahead_glyph_count_byte_range().end; let end = start + (transforms::to_usize(lookahead_glyph_count)).saturating_mul(GlyphId16::RAW_BYTE_LEN); start..end } pub fn seq_lookup_count_byte_range(&self) -> Range { let start = self.lookahead_sequence_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn seq_lookup_records_byte_range(&self) -> Range { let seq_lookup_count = self.seq_lookup_count(); let start = self.seq_lookup_count_byte_range().end; let end = start + (transforms::to_usize(seq_lookup_count)) .saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough( ChainedSequenceRule::MIN_SIZE )); impl Default for ChainedSequenceRule<'_> { fn default() -> Self { Self { data: FontData::default_table_data(), } } } #[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 ChainedSequenceContextFormat2<'_> { const FORMAT: u16 = 2; } impl<'a> MinByteRange<'a> for ChainedSequenceContextFormat2<'a> { fn min_byte_range(&self) -> Range { 0..self.chained_class_seq_rule_set_offsets_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for ChainedSequenceContextFormat2<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// [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(Clone)] pub struct ChainedSequenceContextFormat2<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> ChainedSequenceContextFormat2<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Format identifier: format = 2 pub fn format(&self) -> u16 { let range = self.format_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Offset to Coverage table, from beginning of /// ChainedSequenceContextFormat2 table pub fn coverage_offset(&self) -> Offset16 { let range = self.coverage_offset_byte_range(); self.data.read_at(range.start).ok().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.backtrack_class_def_offset_byte_range(); self.data.read_at(range.start).ok().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.input_class_def_offset_byte_range(); self.data.read_at(range.start).ok().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.lookahead_class_def_offset_byte_range(); self.data.read_at(range.start).ok().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.chained_class_seq_rule_set_count_byte_range(); self.data.read_at(range.start).ok().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.chained_class_seq_rule_set_offsets_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// 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, ()) } pub fn format_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn coverage_offset_byte_range(&self) -> Range { let start = self.format_byte_range().end; let end = start + Offset16::RAW_BYTE_LEN; start..end } pub fn backtrack_class_def_offset_byte_range(&self) -> Range { let start = self.coverage_offset_byte_range().end; let end = start + Offset16::RAW_BYTE_LEN; start..end } pub fn input_class_def_offset_byte_range(&self) -> Range { let start = self.backtrack_class_def_offset_byte_range().end; let end = start + Offset16::RAW_BYTE_LEN; start..end } pub fn lookahead_class_def_offset_byte_range(&self) -> Range { let start = self.input_class_def_offset_byte_range().end; let end = start + Offset16::RAW_BYTE_LEN; start..end } pub fn chained_class_seq_rule_set_count_byte_range(&self) -> Range { let start = self.lookahead_class_def_offset_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn chained_class_seq_rule_set_offsets_byte_range(&self) -> Range { let chained_class_seq_rule_set_count = self.chained_class_seq_rule_set_count(); let start = self.chained_class_seq_rule_set_count_byte_range().end; let end = start + (transforms::to_usize(chained_class_seq_rule_set_count)) .saturating_mul(Offset16::RAW_BYTE_LEN); start..end } } #[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(Field::new( "chained_class_seq_rule_set_offsets", FieldType::from(self.chained_class_seq_rule_sets()), )), _ => 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) } } impl<'a> MinByteRange<'a> for ChainedClassSequenceRuleSet<'a> { fn min_byte_range(&self) -> Range { 0..self.chained_class_seq_rule_offsets_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for ChainedClassSequenceRuleSet<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// Part of [ChainedSequenceContextFormat2] #[derive(Clone)] pub struct ChainedClassSequenceRuleSet<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> ChainedClassSequenceRuleSet<'a> { pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN; basic_table_impls!(impl_the_methods); /// Number of ChainedClassSequenceRule tables pub fn chained_class_seq_rule_count(&self) -> u16 { let range = self.chained_class_seq_rule_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of offsets to ChainedClassSequenceRule tables, from /// beginning of ChainedClassSequenceRuleSet pub fn chained_class_seq_rule_offsets(&self) -> &'a [BigEndian] { let range = self.chained_class_seq_rule_offsets_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// 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, ()) } pub fn chained_class_seq_rule_count_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn chained_class_seq_rule_offsets_byte_range(&self) -> Range { let chained_class_seq_rule_count = self.chained_class_seq_rule_count(); let start = self.chained_class_seq_rule_count_byte_range().end; let end = start + (transforms::to_usize(chained_class_seq_rule_count)) .saturating_mul(Offset16::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough( ChainedClassSequenceRuleSet::MIN_SIZE )); impl Default for ChainedClassSequenceRuleSet<'_> { fn default() -> Self { Self { data: FontData::default_table_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(Field::new( "chained_class_seq_rule_offsets", FieldType::from(self.chained_class_seq_rules()), )), _ => 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) } } impl<'a> MinByteRange<'a> for ChainedClassSequenceRule<'a> { fn min_byte_range(&self) -> Range { 0..self.seq_lookup_records_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for ChainedClassSequenceRule<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// Part of [ChainedSequenceContextFormat2] #[derive(Clone)] pub struct ChainedClassSequenceRule<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> ChainedClassSequenceRule<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Number of glyphs in the backtrack sequence pub fn backtrack_glyph_count(&self) -> u16 { let range = self.backtrack_glyph_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of backtrack-sequence classes pub fn backtrack_sequence(&self) -> &'a [BigEndian] { let range = self.backtrack_sequence_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// Total number of glyphs in the input sequence pub fn input_glyph_count(&self) -> u16 { let range = self.input_glyph_count_byte_range(); self.data.read_at(range.start).ok().unwrap_or_default() } /// Array of input sequence classes, beginning with the second /// glyph position pub fn input_sequence(&self) -> &'a [BigEndian] { let range = self.input_sequence_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// Number of glyphs in the lookahead sequence pub fn lookahead_glyph_count(&self) -> u16 { let range = self.lookahead_glyph_count_byte_range(); self.data.read_at(range.start).ok().unwrap_or_default() } /// Array of lookahead-sequence classes pub fn lookahead_sequence(&self) -> &'a [BigEndian] { let range = self.lookahead_sequence_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// Number of SequenceLookupRecords pub fn seq_lookup_count(&self) -> u16 { let range = self.seq_lookup_count_byte_range(); self.data.read_at(range.start).ok().unwrap_or_default() } /// Array of SequenceLookupRecords pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] { let range = self.seq_lookup_records_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } pub fn backtrack_glyph_count_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn backtrack_sequence_byte_range(&self) -> Range { let backtrack_glyph_count = self.backtrack_glyph_count(); let start = self.backtrack_glyph_count_byte_range().end; let end = start + (transforms::to_usize(backtrack_glyph_count)).saturating_mul(u16::RAW_BYTE_LEN); start..end } pub fn input_glyph_count_byte_range(&self) -> Range { let start = self.backtrack_sequence_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn input_sequence_byte_range(&self) -> Range { let input_glyph_count = self.input_glyph_count(); let start = self.input_glyph_count_byte_range().end; let end = start + (transforms::subtract(input_glyph_count, 1_usize)).saturating_mul(u16::RAW_BYTE_LEN); start..end } pub fn lookahead_glyph_count_byte_range(&self) -> Range { let start = self.input_sequence_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn lookahead_sequence_byte_range(&self) -> Range { let lookahead_glyph_count = self.lookahead_glyph_count(); let start = self.lookahead_glyph_count_byte_range().end; let end = start + (transforms::to_usize(lookahead_glyph_count)).saturating_mul(u16::RAW_BYTE_LEN); start..end } pub fn seq_lookup_count_byte_range(&self) -> Range { let start = self.lookahead_sequence_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn seq_lookup_records_byte_range(&self) -> Range { let seq_lookup_count = self.seq_lookup_count(); let start = self.seq_lookup_count_byte_range().end; let end = start + (transforms::to_usize(seq_lookup_count)) .saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough( ChainedClassSequenceRule::MIN_SIZE )); impl Default for ChainedClassSequenceRule<'_> { fn default() -> Self { Self { data: FontData::default_table_data(), } } } #[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 ChainedSequenceContextFormat3<'_> { const FORMAT: u16 = 3; } impl<'a> MinByteRange<'a> for ChainedSequenceContextFormat3<'a> { fn min_byte_range(&self) -> Range { 0..self.seq_lookup_records_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for ChainedSequenceContextFormat3<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// [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(Clone)] pub struct ChainedSequenceContextFormat3<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> ChainedSequenceContextFormat3<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Format identifier: format = 3 pub fn format(&self) -> u16 { let range = self.format_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Number of glyphs in the backtrack sequence pub fn backtrack_glyph_count(&self) -> u16 { let range = self.backtrack_glyph_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of offsets to coverage tables for the backtrack sequence pub fn backtrack_coverage_offsets(&self) -> &'a [BigEndian] { let range = self.backtrack_coverage_offsets_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// 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.input_glyph_count_byte_range(); self.data.read_at(range.start).ok().unwrap_or_default() } /// Array of offsets to coverage tables for the input sequence pub fn input_coverage_offsets(&self) -> &'a [BigEndian] { let range = self.input_coverage_offsets_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// 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.lookahead_glyph_count_byte_range(); self.data.read_at(range.start).ok().unwrap_or_default() } /// Array of offsets to coverage tables for the lookahead sequence pub fn lookahead_coverage_offsets(&self) -> &'a [BigEndian] { let range = self.lookahead_coverage_offsets_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// 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.seq_lookup_count_byte_range(); self.data.read_at(range.start).ok().unwrap_or_default() } /// Array of SequenceLookupRecords pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] { let range = self.seq_lookup_records_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } pub fn format_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn backtrack_glyph_count_byte_range(&self) -> Range { let start = self.format_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn backtrack_coverage_offsets_byte_range(&self) -> Range { let backtrack_glyph_count = self.backtrack_glyph_count(); let start = self.backtrack_glyph_count_byte_range().end; let end = start + (transforms::to_usize(backtrack_glyph_count)).saturating_mul(Offset16::RAW_BYTE_LEN); start..end } pub fn input_glyph_count_byte_range(&self) -> Range { let start = self.backtrack_coverage_offsets_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn input_coverage_offsets_byte_range(&self) -> Range { let input_glyph_count = self.input_glyph_count(); let start = self.input_glyph_count_byte_range().end; let end = start + (transforms::to_usize(input_glyph_count)).saturating_mul(Offset16::RAW_BYTE_LEN); start..end } pub fn lookahead_glyph_count_byte_range(&self) -> Range { let start = self.input_coverage_offsets_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn lookahead_coverage_offsets_byte_range(&self) -> Range { let lookahead_glyph_count = self.lookahead_glyph_count(); let start = self.lookahead_glyph_count_byte_range().end; let end = start + (transforms::to_usize(lookahead_glyph_count)).saturating_mul(Offset16::RAW_BYTE_LEN); start..end } pub fn seq_lookup_count_byte_range(&self) -> Range { let start = self.lookahead_coverage_offsets_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn seq_lookup_records_byte_range(&self) -> Range { let seq_lookup_count = self.seq_lookup_count(); let start = self.seq_lookup_count_byte_range().end; let end = start + (transforms::to_usize(seq_lookup_count)) .saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN); start..end } } #[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(Field::new( "backtrack_coverage_offsets", FieldType::from(self.backtrack_coverages()), )), 3usize => Some(Field::new("input_glyph_count", self.input_glyph_count())), 4usize => Some(Field::new( "input_coverage_offsets", FieldType::from(self.input_coverages()), )), 5usize => Some(Field::new( "lookahead_glyph_count", self.lookahead_glyph_count(), )), 6usize => Some(Field::new( "lookahead_coverage_offsets", FieldType::from(self.lookahead_coverages()), )), 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 Default for ChainedSequenceContext<'_> { fn default() -> Self { Self::Format1(Default::default()) } } 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 { ChainedSequenceContextFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)), ChainedSequenceContextFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)), ChainedSequenceContextFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)), other => Err(ReadError::InvalidFormat(other.into())), } } } impl<'a> MinByteRange<'a> for ChainedSequenceContext<'a> { 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(), } } fn min_table_bytes(&self) -> &'a [u8] { match self { Self::Format1(item) => item.min_table_bytes(), Self::Format2(item) => item.min_table_bytes(), Self::Format3(item) => item.min_table_bytes(), } } } #[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() } } impl<'a> MinByteRange<'a> for Device<'a> { fn min_byte_range(&self) -> Range { 0..self.delta_value_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for Device<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// [Device Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#device-and-variationindex-tables) #[derive(Clone)] pub struct Device<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> Device<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + DeltaFormat::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Smallest size to correct, in ppem pub fn start_size(&self) -> u16 { let range = self.start_size_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Largest size to correct, in ppem pub fn end_size(&self) -> u16 { let range = self.end_size_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Format of deltaValue array data: 0x0001, 0x0002, or 0x0003 pub fn delta_format(&self) -> DeltaFormat { let range = self.delta_format_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of compressed data pub fn delta_value(&self) -> &'a [BigEndian] { let range = self.delta_value_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } pub fn start_size_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn end_size_byte_range(&self) -> Range { let start = self.start_size_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn delta_format_byte_range(&self) -> Range { let start = self.end_size_byte_range().end; let end = start + DeltaFormat::RAW_BYTE_LEN; start..end } pub fn delta_value_byte_range(&self) -> Range { let delta_format = self.delta_format(); let start_size = self.start_size(); let end_size = self.end_size(); let start = self.delta_format_byte_range().end; let end = start + (DeltaFormat::value_count(delta_format, start_size, end_size)) .saturating_mul(u16::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough(Device::MIN_SIZE)); impl Default for Device<'_> { fn default() -> Self { Self { data: FontData::default_table_data(), } } } #[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) } } impl<'a> MinByteRange<'a> for VariationIndex<'a> { fn min_byte_range(&self) -> Range { 0..self.delta_format_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for VariationIndex<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// Variation index table #[derive(Clone)] pub struct VariationIndex<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> VariationIndex<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + DeltaFormat::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// 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.delta_set_outer_index_byte_range(); self.data.read_at(range.start).ok().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.delta_set_inner_index_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Format, = 0x8000 pub fn delta_format(&self) -> DeltaFormat { let range = self.delta_format_byte_range(); self.data.read_at(range.start).ok().unwrap() } pub fn delta_set_outer_index_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn delta_set_inner_index_byte_range(&self) -> Range { let start = self.delta_set_outer_index_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn delta_format_byte_range(&self) -> Range { let start = self.delta_set_inner_index_byte_range().end; let end = start + DeltaFormat::RAW_BYTE_LEN; start..end } } const _: () = assert!(FontData::default_data_long_enough(VariationIndex::MIN_SIZE)); impl Default for VariationIndex<'_> { fn default() -> Self { Self { data: FontData::default_table_data(), } } } #[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 Default for DeviceOrVariationIndex<'_> { fn default() -> Self { Self::Device(Default::default()) } } 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<'a> MinByteRange<'a> for DeviceOrVariationIndex<'a> { fn min_byte_range(&self) -> Range { match self { Self::Device(item) => item.min_byte_range(), Self::VariationIndex(item) => item.min_byte_range(), } } fn min_table_bytes(&self) -> &'a [u8] { match self { Self::Device(item) => item.min_table_bytes(), Self::VariationIndex(item) => item.min_table_bytes(), } } } #[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) } } impl<'a> MinByteRange<'a> for FeatureVariations<'a> { fn min_byte_range(&self) -> Range { 0..self.feature_variation_records_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for FeatureVariations<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// [FeatureVariations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featurevariations-table) #[derive(Clone)] pub struct FeatureVariations<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> FeatureVariations<'a> { pub const MIN_SIZE: usize = (MajorMinor::RAW_BYTE_LEN + u32::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); pub fn version(&self) -> MajorMinor { let range = self.version_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Number of feature variation records. pub fn feature_variation_record_count(&self) -> u32 { let range = self.feature_variation_record_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of feature variation records. pub fn feature_variation_records(&self) -> &'a [FeatureVariationRecord] { let range = self.feature_variation_records_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } pub fn version_byte_range(&self) -> Range { let start = 0; let end = start + MajorMinor::RAW_BYTE_LEN; start..end } pub fn feature_variation_record_count_byte_range(&self) -> Range { let start = self.version_byte_range().end; let end = start + u32::RAW_BYTE_LEN; start..end } pub fn feature_variation_records_byte_range(&self) -> Range { let feature_variation_record_count = self.feature_variation_record_count(); let start = self.feature_variation_record_count_byte_range().end; let end = start + (transforms::to_usize(feature_variation_record_count)) .saturating_mul(FeatureVariationRecord::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough( FeatureVariations::MIN_SIZE )); impl Default for FeatureVariations<'_> { fn default() -> Self { Self { data: FontData::default_table_data(), } } } #[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, } } } impl<'a> MinByteRange<'a> for ConditionSet<'a> { fn min_byte_range(&self) -> Range { 0..self.condition_offsets_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for ConditionSet<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// [ConditionSet Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#conditionset-table) #[derive(Clone)] pub struct ConditionSet<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> ConditionSet<'a> { pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN; basic_table_impls!(impl_the_methods); /// Number of conditions for this condition set. pub fn condition_count(&self) -> u16 { let range = self.condition_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of offsets to condition tables, from beginning of the /// ConditionSet table. pub fn condition_offsets(&self) -> &'a [BigEndian] { let range = self.condition_offsets_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// 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, ()) } pub fn condition_count_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn condition_offsets_byte_range(&self) -> Range { let condition_count = self.condition_count(); let start = self.condition_count_byte_range().end; let end = start + (transforms::to_usize(condition_count)).saturating_mul(Offset32::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough(ConditionSet::MIN_SIZE)); impl Default for ConditionSet<'_> { fn default() -> Self { Self { data: FontData::default_table_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(Field::new( "condition_offsets", FieldType::from(self.conditions()), )), _ => 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 Default for Condition<'_> { fn default() -> Self { Self::Format1AxisRange(Default::default()) } } 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 { ConditionFormat1::FORMAT => Ok(Self::Format1AxisRange(FontRead::read(data)?)), ConditionFormat2::FORMAT => Ok(Self::Format2VariableValue(FontRead::read(data)?)), ConditionFormat3::FORMAT => Ok(Self::Format3And(FontRead::read(data)?)), ConditionFormat4::FORMAT => Ok(Self::Format4Or(FontRead::read(data)?)), ConditionFormat5::FORMAT => Ok(Self::Format5Negate(FontRead::read(data)?)), other => Err(ReadError::InvalidFormat(other.into())), } } } impl<'a> MinByteRange<'a> for Condition<'a> { 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(), } } fn min_table_bytes(&self) -> &'a [u8] { match self { Self::Format1AxisRange(item) => item.min_table_bytes(), Self::Format2VariableValue(item) => item.min_table_bytes(), Self::Format3And(item) => item.min_table_bytes(), Self::Format4Or(item) => item.min_table_bytes(), Self::Format5Negate(item) => item.min_table_bytes(), } } } #[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 ConditionFormat1<'_> { const FORMAT: u16 = 1; } impl<'a> MinByteRange<'a> for ConditionFormat1<'a> { fn min_byte_range(&self) -> Range { 0..self.filter_range_max_value_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for ConditionFormat1<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// [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(Clone)] pub struct ConditionFormat1<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> ConditionFormat1<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Format, = 1 pub fn format(&self) -> u16 { let range = self.format_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Index (zero-based) for the variation axis within the 'fvar' /// table. pub fn axis_index(&self) -> u16 { let range = self.axis_index_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Minimum value of the font variation instances that satisfy this /// condition. pub fn filter_range_min_value(&self) -> F2Dot14 { let range = self.filter_range_min_value_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Maximum value of the font variation instances that satisfy this /// condition. pub fn filter_range_max_value(&self) -> F2Dot14 { let range = self.filter_range_max_value_byte_range(); self.data.read_at(range.start).ok().unwrap() } pub fn format_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn axis_index_byte_range(&self) -> Range { let start = self.format_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn filter_range_min_value_byte_range(&self) -> Range { let start = self.axis_index_byte_range().end; let end = start + F2Dot14::RAW_BYTE_LEN; start..end } pub fn filter_range_max_value_byte_range(&self) -> Range { let start = self.filter_range_min_value_byte_range().end; let end = start + F2Dot14::RAW_BYTE_LEN; start..end } } const _: () = assert!(FontData::default_data_long_enough( ConditionFormat1::MIN_SIZE )); impl Default for ConditionFormat1<'_> { fn default() -> Self { Self { data: FontData::default_format_1_u16_table_data(), } } } #[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 ConditionFormat2<'_> { const FORMAT: u16 = 2; } impl<'a> MinByteRange<'a> for ConditionFormat2<'a> { fn min_byte_range(&self) -> Range { 0..self.var_index_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for ConditionFormat2<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// [Condition Table Format 2](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3237-L3255): Variation index #[derive(Clone)] pub struct ConditionFormat2<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> ConditionFormat2<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Format, = 2 pub fn format(&self) -> u16 { let range = self.format_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Value at default instance. pub fn default_value(&self) -> i16 { let range = self.default_value_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Variation index to vary the value based on current designspace location. pub fn var_index(&self) -> u32 { let range = self.var_index_byte_range(); self.data.read_at(range.start).ok().unwrap() } pub fn format_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn default_value_byte_range(&self) -> Range { let start = self.format_byte_range().end; let end = start + i16::RAW_BYTE_LEN; start..end } pub fn var_index_byte_range(&self) -> Range { let start = self.default_value_byte_range().end; let end = start + u32::RAW_BYTE_LEN; start..end } } #[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 ConditionFormat3<'_> { const FORMAT: u16 = 3; } impl<'a> MinByteRange<'a> for ConditionFormat3<'a> { fn min_byte_range(&self) -> Range { 0..self.condition_offsets_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for ConditionFormat3<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// [Condition Table Format 3](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3257-L3275): AND #[derive(Clone)] pub struct ConditionFormat3<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> ConditionFormat3<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u8::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Format, = 3 pub fn format(&self) -> u16 { let range = self.format_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Number of conditions. pub fn condition_count(&self) -> u8 { let range = self.condition_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of condition tables for this conjunction (AND) expression. pub fn condition_offsets(&self) -> &'a [BigEndian] { let range = self.condition_offsets_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// 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, ()) } pub fn format_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn condition_count_byte_range(&self) -> Range { let start = self.format_byte_range().end; let end = start + u8::RAW_BYTE_LEN; start..end } pub fn condition_offsets_byte_range(&self) -> Range { let condition_count = self.condition_count(); let start = self.condition_count_byte_range().end; let end = start + (transforms::to_usize(condition_count)).saturating_mul(Offset24::RAW_BYTE_LEN); start..end } } #[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(Field::new( "condition_offsets", FieldType::from(self.conditions()), )), _ => 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 ConditionFormat4<'_> { const FORMAT: u16 = 4; } impl<'a> MinByteRange<'a> for ConditionFormat4<'a> { fn min_byte_range(&self) -> Range { 0..self.condition_offsets_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for ConditionFormat4<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// [Condition Table Format 4](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3276-L3295): OR #[derive(Clone)] pub struct ConditionFormat4<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> ConditionFormat4<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u8::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Format, = 4 pub fn format(&self) -> u16 { let range = self.format_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Number of conditions. pub fn condition_count(&self) -> u8 { let range = self.condition_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of condition tables for this disjunction (OR) expression. pub fn condition_offsets(&self) -> &'a [BigEndian] { let range = self.condition_offsets_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// 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, ()) } pub fn format_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn condition_count_byte_range(&self) -> Range { let start = self.format_byte_range().end; let end = start + u8::RAW_BYTE_LEN; start..end } pub fn condition_offsets_byte_range(&self) -> Range { let condition_count = self.condition_count(); let start = self.condition_count_byte_range().end; let end = start + (transforms::to_usize(condition_count)).saturating_mul(Offset24::RAW_BYTE_LEN); start..end } } #[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(Field::new( "condition_offsets", FieldType::from(self.conditions()), )), _ => 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 ConditionFormat5<'_> { const FORMAT: u16 = 5; } impl<'a> MinByteRange<'a> for ConditionFormat5<'a> { fn min_byte_range(&self) -> Range { 0..self.condition_offset_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for ConditionFormat5<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// [Condition Table Format 5](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3296-L3308): NOT #[derive(Clone)] pub struct ConditionFormat5<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> ConditionFormat5<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset24::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Format, = 5 pub fn format(&self) -> u16 { let range = self.format_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Condition to negate. pub fn condition_offset(&self) -> Offset24 { let range = self.condition_offset_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Attempt to resolve [`condition_offset`][Self::condition_offset]. pub fn condition(&self) -> Result, ReadError> { let data = self.data; self.condition_offset().resolve(data) } pub fn format_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn condition_offset_byte_range(&self) -> Range { let start = self.format_byte_range().end; let end = start + Offset24::RAW_BYTE_LEN; start..end } } #[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) } } impl<'a> MinByteRange<'a> for FeatureTableSubstitution<'a> { fn min_byte_range(&self) -> Range { 0..self.substitutions_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for FeatureTableSubstitution<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// [FeatureTableSubstitution Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featuretablesubstitution-table) #[derive(Clone)] pub struct FeatureTableSubstitution<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> FeatureTableSubstitution<'a> { pub const MIN_SIZE: usize = (MajorMinor::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Major & minor version of the table: (1, 0) pub fn version(&self) -> MajorMinor { let range = self.version_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Number of feature table substitution records. pub fn substitution_count(&self) -> u16 { let range = self.substitution_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of feature table substitution records. pub fn substitutions(&self) -> &'a [FeatureTableSubstitutionRecord] { let range = self.substitutions_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } pub fn version_byte_range(&self) -> Range { let start = 0; let end = start + MajorMinor::RAW_BYTE_LEN; start..end } pub fn substitution_count_byte_range(&self) -> Range { let start = self.version_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn substitutions_byte_range(&self) -> Range { let substitution_count = self.substitution_count(); let start = self.substitution_count_byte_range().end; let end = start + (transforms::to_usize(substitution_count)) .saturating_mul(FeatureTableSubstitutionRecord::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough( FeatureTableSubstitution::MIN_SIZE )); impl Default for FeatureTableSubstitution<'_> { fn default() -> Self { Self { data: FontData::default_table_data(), } } } #[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, } } } impl<'a> MinByteRange<'a> for SizeParams<'a> { fn min_byte_range(&self) -> Range { 0..self.range_end_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for SizeParams<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } #[derive(Clone)] pub struct SizeParams<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> SizeParams<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// 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.design_size_byte_range(); self.data.read_at(range.start).ok().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.identifier_byte_range(); self.data.read_at(range.start).ok().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.name_entry_byte_range(); self.data.read_at(range.start).ok().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.range_start_byte_range(); self.data.read_at(range.start).ok().unwrap() } pub fn range_end(&self) -> u16 { let range = self.range_end_byte_range(); self.data.read_at(range.start).ok().unwrap() } pub fn design_size_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn identifier_byte_range(&self) -> Range { let start = self.design_size_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn name_entry_byte_range(&self) -> Range { let start = self.identifier_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn range_start_byte_range(&self) -> Range { let start = self.name_entry_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn range_end_byte_range(&self) -> Range { let start = self.range_start_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } } const _: () = assert!(FontData::default_data_long_enough(SizeParams::MIN_SIZE)); impl Default for SizeParams<'_> { fn default() -> Self { Self { data: FontData::default_table_data(), } } } #[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) } } impl<'a> MinByteRange<'a> for StylisticSetParams<'a> { fn min_byte_range(&self) -> Range { 0..self.ui_name_id_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for StylisticSetParams<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } #[derive(Clone)] pub struct StylisticSetParams<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> StylisticSetParams<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + NameId::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); pub fn version(&self) -> u16 { let range = self.version_byte_range(); self.data.read_at(range.start).ok().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.ui_name_id_byte_range(); self.data.read_at(range.start).ok().unwrap() } pub fn version_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn ui_name_id_byte_range(&self) -> Range { let start = self.version_byte_range().end; let end = start + NameId::RAW_BYTE_LEN; start..end } } const _: () = assert!(FontData::default_data_long_enough( StylisticSetParams::MIN_SIZE )); impl Default for StylisticSetParams<'_> { fn default() -> Self { Self { data: FontData::default_table_data(), } } } #[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 CharacterVariantParams<'_> { const FORMAT: u16 = 0; } impl<'a> MinByteRange<'a> for CharacterVariantParams<'a> { fn min_byte_range(&self) -> Range { 0..self.character_byte_range().end } fn min_table_bytes(&self) -> &'a [u8] { let range = self.min_byte_range(); self.data.as_bytes().get(range).unwrap_or_default() } } impl<'a> FontRead<'a> for CharacterVariantParams<'a> { fn read(data: FontData<'a>) -> Result { #[allow(clippy::absurd_extreme_comparisons)] if data.len() < Self::MIN_SIZE { return Err(ReadError::OutOfBounds); } Ok(Self { data }) } } /// featureParams for ['cv01'-'cv99'](https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#cv01-cv99) #[derive(Clone)] pub struct CharacterVariantParams<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> CharacterVariantParams<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + NameId::RAW_BYTE_LEN + NameId::RAW_BYTE_LEN + NameId::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + NameId::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Format number is set to 0. pub fn format(&self) -> u16 { let range = self.format_byte_range(); self.data.read_at(range.start).ok().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.feat_ui_label_name_id_byte_range(); self.data.read_at(range.start).ok().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.feat_ui_tooltip_text_name_id_byte_range(); self.data.read_at(range.start).ok().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.sample_text_name_id_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Number of named parameters. (May be zero.) pub fn num_named_parameters(&self) -> u16 { let range = self.num_named_parameters_byte_range(); self.data.read_at(range.start).ok().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.first_param_ui_label_name_id_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// The count of characters for which this feature provides glyph /// variants. (May be zero.) pub fn char_count(&self) -> u16 { let range = self.char_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// The Unicode Scalar Value of the characters for which this /// feature provides glyph variants. pub fn character(&self) -> &'a [BigEndian] { let range = self.character_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } pub fn format_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn feat_ui_label_name_id_byte_range(&self) -> Range { let start = self.format_byte_range().end; let end = start + NameId::RAW_BYTE_LEN; start..end } pub fn feat_ui_tooltip_text_name_id_byte_range(&self) -> Range { let start = self.feat_ui_label_name_id_byte_range().end; let end = start + NameId::RAW_BYTE_LEN; start..end } pub fn sample_text_name_id_byte_range(&self) -> Range { let start = self.feat_ui_tooltip_text_name_id_byte_range().end; let end = start + NameId::RAW_BYTE_LEN; start..end } pub fn num_named_parameters_byte_range(&self) -> Range { let start = self.sample_text_name_id_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn first_param_ui_label_name_id_byte_range(&self) -> Range { let start = self.num_named_parameters_byte_range().end; let end = start + NameId::RAW_BYTE_LEN; start..end } pub fn char_count_byte_range(&self) -> Range { let start = self.first_param_ui_label_name_id_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn character_byte_range(&self) -> Range { let char_count = self.char_count(); let start = self.char_count_byte_range().end; let end = start + (transforms::to_usize(char_count)).saturating_mul(Uint24::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough( CharacterVariantParams::MIN_SIZE )); impl Default for CharacterVariantParams<'_> { fn default() -> Self { Self { data: FontData::default_table_data(), } } } #[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) } }