// 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 Base<'a> { fn min_byte_range(&self) -> Range { 0..self.vert_axis_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 TopLevelTable for Base<'_> { /// `BASE` const TAG: Tag = Tag::new(b"BASE"); } impl<'a> FontRead<'a> for Base<'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 }) } } /// The [BASE](https://learn.microsoft.com/en-us/typography/opentype/spec/base) (Baseline) table #[derive(Clone)] pub struct Base<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> Base<'a> { pub const MIN_SIZE: usize = (MajorMinor::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// (major, minor) Version for the BASE table (1,0) or (1,1) pub fn version(&self) -> MajorMinor { let range = self.version_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Offset to horizontal Axis table, from beginning of BASE table (may be NULL) pub fn horiz_axis_offset(&self) -> Nullable { let range = self.horiz_axis_offset_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Attempt to resolve [`horiz_axis_offset`][Self::horiz_axis_offset]. pub fn horiz_axis(&self) -> Option, ReadError>> { let data = self.data; self.horiz_axis_offset().resolve(data) } /// Offset to vertical Axis table, from beginning of BASE table (may be NULL) pub fn vert_axis_offset(&self) -> Nullable { let range = self.vert_axis_offset_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Attempt to resolve [`vert_axis_offset`][Self::vert_axis_offset]. pub fn vert_axis(&self) -> Option, ReadError>> { let data = self.data; self.vert_axis_offset().resolve(data) } /// Offset to Item Variation Store table, from beginning of BASE table (may be null) pub fn item_var_store_offset(&self) -> Option> { let range = self.item_var_store_offset_byte_range(); (!range.is_empty()) .then(|| self.data.read_at(range.start).ok()) .flatten() } /// Attempt to resolve [`item_var_store_offset`][Self::item_var_store_offset]. pub fn item_var_store(&self) -> Option, ReadError>> { let data = self.data; self.item_var_store_offset().map(|x| x.resolve(data))? } pub fn version_byte_range(&self) -> Range { let start = 0; let end = start + MajorMinor::RAW_BYTE_LEN; start..end } pub fn horiz_axis_offset_byte_range(&self) -> Range { let start = self.version_byte_range().end; let end = start + Offset16::RAW_BYTE_LEN; start..end } pub fn vert_axis_offset_byte_range(&self) -> Range { let start = self.horiz_axis_offset_byte_range().end; let end = start + Offset16::RAW_BYTE_LEN; start..end } pub fn item_var_store_offset_byte_range(&self) -> Range { let start = self.vert_axis_offset_byte_range().end; let end = if self.version().compatible((1u16, 1u16)) { start + Offset32::RAW_BYTE_LEN } else { start }; start..end } } const _: () = assert!(FontData::default_data_long_enough(Base::MIN_SIZE)); impl Default for Base<'_> { fn default() -> Self { Self { data: FontData::default_table_data(), } } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for Base<'a> { fn type_name(&self) -> &str { "Base" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("version", self.version())), 1usize => Some(Field::new( "horiz_axis_offset", FieldType::offset(self.horiz_axis_offset(), self.horiz_axis()), )), 2usize => Some(Field::new( "vert_axis_offset", FieldType::offset(self.vert_axis_offset(), self.vert_axis()), )), 3usize if self.version().compatible((1u16, 1u16)) => Some(Field::new( "item_var_store_offset", FieldType::offset(self.item_var_store_offset().unwrap(), self.item_var_store()), )), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for Base<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } impl<'a> MinByteRange<'a> for Axis<'a> { fn min_byte_range(&self) -> Range { 0..self.base_script_list_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 Axis<'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 }) } } /// [Axis Table](https://learn.microsoft.com/en-us/typography/opentype/spec/base#axis-tables-horizaxis-and-vertaxis) #[derive(Clone)] pub struct Axis<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> Axis<'a> { pub const MIN_SIZE: usize = (Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Offset to BaseTagList table, from beginning of Axis table (may /// be NULL) pub fn base_tag_list_offset(&self) -> Nullable { let range = self.base_tag_list_offset_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Attempt to resolve [`base_tag_list_offset`][Self::base_tag_list_offset]. pub fn base_tag_list(&self) -> Option, ReadError>> { let data = self.data; self.base_tag_list_offset().resolve(data) } /// Offset to BaseScriptList table, from beginning of Axis table pub fn base_script_list_offset(&self) -> Offset16 { let range = self.base_script_list_offset_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Attempt to resolve [`base_script_list_offset`][Self::base_script_list_offset]. pub fn base_script_list(&self) -> Result, ReadError> { let data = self.data; self.base_script_list_offset().resolve(data) } pub fn base_tag_list_offset_byte_range(&self) -> Range { let start = 0; let end = start + Offset16::RAW_BYTE_LEN; start..end } pub fn base_script_list_offset_byte_range(&self) -> Range { let start = self.base_tag_list_offset_byte_range().end; let end = start + Offset16::RAW_BYTE_LEN; start..end } } const _: () = assert!(FontData::default_data_long_enough(Axis::MIN_SIZE)); impl Default for Axis<'_> { fn default() -> Self { Self { data: FontData::default_table_data(), } } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for Axis<'a> { fn type_name(&self) -> &str { "Axis" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new( "base_tag_list_offset", FieldType::offset(self.base_tag_list_offset(), self.base_tag_list()), )), 1usize => Some(Field::new( "base_script_list_offset", FieldType::offset(self.base_script_list_offset(), self.base_script_list()), )), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for Axis<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } impl<'a> MinByteRange<'a> for BaseTagList<'a> { fn min_byte_range(&self) -> Range { 0..self.baseline_tags_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 BaseTagList<'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 }) } } /// [BaseTagList Table](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basetaglist-table) #[derive(Clone)] pub struct BaseTagList<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> BaseTagList<'a> { pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN; basic_table_impls!(impl_the_methods); /// Number of baseline identification tags in this text direction /// — may be zero (0) pub fn base_tag_count(&self) -> u16 { let range = self.base_tag_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of 4-byte baseline identification tags — must be in /// alphabetical order pub fn baseline_tags(&self) -> &'a [BigEndian] { let range = self.baseline_tags_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } pub fn base_tag_count_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn baseline_tags_byte_range(&self) -> Range { let base_tag_count = self.base_tag_count(); let start = self.base_tag_count_byte_range().end; let end = start + (transforms::to_usize(base_tag_count)).saturating_mul(Tag::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough(BaseTagList::MIN_SIZE)); impl Default for BaseTagList<'_> { fn default() -> Self { Self { data: FontData::default_table_data(), } } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for BaseTagList<'a> { fn type_name(&self) -> &str { "BaseTagList" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("base_tag_count", self.base_tag_count())), 1usize => Some(Field::new("baseline_tags", self.baseline_tags())), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for BaseTagList<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } impl<'a> MinByteRange<'a> for BaseScriptList<'a> { fn min_byte_range(&self) -> Range { 0..self.base_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 BaseScriptList<'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 }) } } /// [BaseScriptList Table](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basescriptlist-table) #[derive(Clone)] pub struct BaseScriptList<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> BaseScriptList<'a> { pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN; basic_table_impls!(impl_the_methods); /// Number of BaseScriptRecords defined pub fn base_script_count(&self) -> u16 { let range = self.base_script_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of BaseScriptRecords, in alphabetical order by /// baseScriptTag pub fn base_script_records(&self) -> &'a [BaseScriptRecord] { let range = self.base_script_records_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } pub fn base_script_count_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn base_script_records_byte_range(&self) -> Range { let base_script_count = self.base_script_count(); let start = self.base_script_count_byte_range().end; let end = start + (transforms::to_usize(base_script_count)) .saturating_mul(BaseScriptRecord::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough(BaseScriptList::MIN_SIZE)); impl Default for BaseScriptList<'_> { fn default() -> Self { Self { data: FontData::default_table_data(), } } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for BaseScriptList<'a> { fn type_name(&self) -> &str { "BaseScriptList" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("base_script_count", self.base_script_count())), 1usize => Some(Field::new( "base_script_records", traversal::FieldType::array_of_records( stringify!(BaseScriptRecord), self.base_script_records(), self.offset_data(), ), )), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for BaseScriptList<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } /// [BaseScriptRecord](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basescriptrecord) #[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)] #[repr(C)] #[repr(packed)] pub struct BaseScriptRecord { /// 4-byte script identification tag pub base_script_tag: BigEndian, /// Offset to BaseScript table, from beginning of BaseScriptList pub base_script_offset: BigEndian, } impl BaseScriptRecord { /// 4-byte script identification tag pub fn base_script_tag(&self) -> Tag { self.base_script_tag.get() } /// Offset to BaseScript table, from beginning of BaseScriptList pub fn base_script_offset(&self) -> Offset16 { self.base_script_offset.get() } /// Offset to BaseScript table, from beginning of BaseScriptList /// /// The `data` argument should be retrieved from the parent table /// By calling its `offset_data` method. pub fn base_script<'a>(&self, data: FontData<'a>) -> Result, ReadError> { self.base_script_offset().resolve(data) } } impl FixedSize for BaseScriptRecord { const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN; } #[cfg(feature = "experimental_traverse")] impl<'a> SomeRecord<'a> for BaseScriptRecord { fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> { RecordResolver { name: "BaseScriptRecord", get_field: Box::new(move |idx, _data| match idx { 0usize => Some(Field::new("base_script_tag", self.base_script_tag())), 1usize => Some(Field::new( "base_script_offset", FieldType::offset(self.base_script_offset(), self.base_script(_data)), )), _ => None, }), data, } } } impl<'a> MinByteRange<'a> for BaseScript<'a> { fn min_byte_range(&self) -> Range { 0..self.base_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 BaseScript<'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 }) } } /// [BaseScript Table](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basescript-table) #[derive(Clone)] pub struct BaseScript<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> BaseScript<'a> { pub const MIN_SIZE: usize = (Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Offset to BaseValues table, from beginning of BaseScript table (may be NULL) pub fn base_values_offset(&self) -> Nullable { let range = self.base_values_offset_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Attempt to resolve [`base_values_offset`][Self::base_values_offset]. pub fn base_values(&self) -> Option, ReadError>> { let data = self.data; self.base_values_offset().resolve(data) } /// Offset to MinMax table, from beginning of BaseScript table (may be NULL) pub fn default_min_max_offset(&self) -> Nullable { let range = self.default_min_max_offset_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Attempt to resolve [`default_min_max_offset`][Self::default_min_max_offset]. pub fn default_min_max(&self) -> Option, ReadError>> { let data = self.data; self.default_min_max_offset().resolve(data) } /// Number of BaseLangSysRecords defined — may be zero (0) pub fn base_lang_sys_count(&self) -> u16 { let range = self.base_lang_sys_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of BaseLangSysRecords, in alphabetical order by /// BaseLangSysTag pub fn base_lang_sys_records(&self) -> &'a [BaseLangSysRecord] { let range = self.base_lang_sys_records_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } pub fn base_values_offset_byte_range(&self) -> Range { let start = 0; let end = start + Offset16::RAW_BYTE_LEN; start..end } pub fn default_min_max_offset_byte_range(&self) -> Range { let start = self.base_values_offset_byte_range().end; let end = start + Offset16::RAW_BYTE_LEN; start..end } pub fn base_lang_sys_count_byte_range(&self) -> Range { let start = self.default_min_max_offset_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn base_lang_sys_records_byte_range(&self) -> Range { let base_lang_sys_count = self.base_lang_sys_count(); let start = self.base_lang_sys_count_byte_range().end; let end = start + (transforms::to_usize(base_lang_sys_count)) .saturating_mul(BaseLangSysRecord::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough(BaseScript::MIN_SIZE)); impl Default for BaseScript<'_> { fn default() -> Self { Self { data: FontData::default_table_data(), } } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for BaseScript<'a> { fn type_name(&self) -> &str { "BaseScript" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new( "base_values_offset", FieldType::offset(self.base_values_offset(), self.base_values()), )), 1usize => Some(Field::new( "default_min_max_offset", FieldType::offset(self.default_min_max_offset(), self.default_min_max()), )), 2usize => Some(Field::new( "base_lang_sys_count", self.base_lang_sys_count(), )), 3usize => Some(Field::new( "base_lang_sys_records", traversal::FieldType::array_of_records( stringify!(BaseLangSysRecord), self.base_lang_sys_records(), self.offset_data(), ), )), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for BaseScript<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } /// [BaseLangSysRecord](https://learn.microsoft.com/en-us/typography/opentype/spec/base#baselangsysrecord) #[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)] #[repr(C)] #[repr(packed)] pub struct BaseLangSysRecord { /// 4-byte language system identification tag pub base_lang_sys_tag: BigEndian, /// Offset to MinMax table, from beginning of BaseScript table pub min_max_offset: BigEndian, } impl BaseLangSysRecord { /// 4-byte language system identification tag pub fn base_lang_sys_tag(&self) -> Tag { self.base_lang_sys_tag.get() } /// Offset to MinMax table, from beginning of BaseScript table pub fn min_max_offset(&self) -> Offset16 { self.min_max_offset.get() } /// Offset to MinMax table, from beginning of BaseScript table /// /// The `data` argument should be retrieved from the parent table /// By calling its `offset_data` method. pub fn min_max<'a>(&self, data: FontData<'a>) -> Result, ReadError> { self.min_max_offset().resolve(data) } } impl FixedSize for BaseLangSysRecord { const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN; } #[cfg(feature = "experimental_traverse")] impl<'a> SomeRecord<'a> for BaseLangSysRecord { fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> { RecordResolver { name: "BaseLangSysRecord", get_field: Box::new(move |idx, _data| match idx { 0usize => Some(Field::new("base_lang_sys_tag", self.base_lang_sys_tag())), 1usize => Some(Field::new( "min_max_offset", FieldType::offset(self.min_max_offset(), self.min_max(_data)), )), _ => None, }), data, } } } impl<'a> MinByteRange<'a> for BaseValues<'a> { fn min_byte_range(&self) -> Range { 0..self.base_coord_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 BaseValues<'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 }) } } /// [BaseValues](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basevalues-table) table #[derive(Clone)] pub struct BaseValues<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> BaseValues<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Index number of default baseline for this script — equals /// index position of baseline tag in baselineTags array of the /// BaseTagList pub fn default_baseline_index(&self) -> u16 { let range = self.default_baseline_index_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Number of BaseCoord tables defined — should equal /// baseTagCount in the BaseTagList pub fn base_coord_count(&self) -> u16 { let range = self.base_coord_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of offsets to BaseCoord tables, from beginning of /// BaseValues table — order matches baselineTags array in the /// BaseTagList pub fn base_coord_offsets(&self) -> &'a [BigEndian] { let range = self.base_coord_offsets_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } /// A dynamically resolving wrapper for [`base_coord_offsets`][Self::base_coord_offsets]. pub fn base_coords(&self) -> ArrayOfOffsets<'a, BaseCoord<'a>, Offset16> { let data = self.data; let offsets = self.base_coord_offsets(); ArrayOfOffsets::new(offsets, data, ()) } pub fn default_baseline_index_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn base_coord_count_byte_range(&self) -> Range { let start = self.default_baseline_index_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn base_coord_offsets_byte_range(&self) -> Range { let base_coord_count = self.base_coord_count(); let start = self.base_coord_count_byte_range().end; let end = start + (transforms::to_usize(base_coord_count)).saturating_mul(Offset16::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough(BaseValues::MIN_SIZE)); impl Default for BaseValues<'_> { fn default() -> Self { Self { data: FontData::default_table_data(), } } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for BaseValues<'a> { fn type_name(&self) -> &str { "BaseValues" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new( "default_baseline_index", self.default_baseline_index(), )), 1usize => Some(Field::new("base_coord_count", self.base_coord_count())), 2usize => Some(Field::new( "base_coord_offsets", FieldType::from(self.base_coords()), )), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for BaseValues<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } impl<'a> MinByteRange<'a> for MinMax<'a> { fn min_byte_range(&self) -> Range { 0..self.feat_min_max_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 MinMax<'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 }) } } /// [MinMax](https://learn.microsoft.com/en-us/typography/opentype/spec/base#minmax-table) table #[derive(Clone)] pub struct MinMax<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> MinMax<'a> { pub const MIN_SIZE: usize = (Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Offset to BaseCoord table that defines the minimum extent /// value, from the beginning of MinMax table (may be NULL) pub fn min_coord_offset(&self) -> Nullable { let range = self.min_coord_offset_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Attempt to resolve [`min_coord_offset`][Self::min_coord_offset]. pub fn min_coord(&self) -> Option, ReadError>> { let data = self.data; self.min_coord_offset().resolve(data) } /// Offset to BaseCoord table that defines maximum extent value, /// from the beginning of MinMax table (may be NULL) pub fn max_coord_offset(&self) -> Nullable { let range = self.max_coord_offset_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Attempt to resolve [`max_coord_offset`][Self::max_coord_offset]. pub fn max_coord(&self) -> Option, ReadError>> { let data = self.data; self.max_coord_offset().resolve(data) } /// Number of FeatMinMaxRecords — may be zero (0) pub fn feat_min_max_count(&self) -> u16 { let range = self.feat_min_max_count_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Array of FeatMinMaxRecords, in alphabetical order by /// featureTableTag pub fn feat_min_max_records(&self) -> &'a [FeatMinMaxRecord] { let range = self.feat_min_max_records_byte_range(); self.data.read_array(range).ok().unwrap_or_default() } pub fn min_coord_offset_byte_range(&self) -> Range { let start = 0; let end = start + Offset16::RAW_BYTE_LEN; start..end } pub fn max_coord_offset_byte_range(&self) -> Range { let start = self.min_coord_offset_byte_range().end; let end = start + Offset16::RAW_BYTE_LEN; start..end } pub fn feat_min_max_count_byte_range(&self) -> Range { let start = self.max_coord_offset_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn feat_min_max_records_byte_range(&self) -> Range { let feat_min_max_count = self.feat_min_max_count(); let start = self.feat_min_max_count_byte_range().end; let end = start + (transforms::to_usize(feat_min_max_count)) .saturating_mul(FeatMinMaxRecord::RAW_BYTE_LEN); start..end } } const _: () = assert!(FontData::default_data_long_enough(MinMax::MIN_SIZE)); impl Default for MinMax<'_> { fn default() -> Self { Self { data: FontData::default_table_data(), } } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for MinMax<'a> { fn type_name(&self) -> &str { "MinMax" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new( "min_coord_offset", FieldType::offset(self.min_coord_offset(), self.min_coord()), )), 1usize => Some(Field::new( "max_coord_offset", FieldType::offset(self.max_coord_offset(), self.max_coord()), )), 2usize => Some(Field::new("feat_min_max_count", self.feat_min_max_count())), 3usize => Some(Field::new( "feat_min_max_records", traversal::FieldType::array_of_records( stringify!(FeatMinMaxRecord), self.feat_min_max_records(), self.offset_data(), ), )), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for MinMax<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } /// [FeatMinMaxRecord](https://learn.microsoft.com/en-us/typography/opentype/spec/base#baselangsysrecord) #[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)] #[repr(C)] #[repr(packed)] pub struct FeatMinMaxRecord { /// 4-byte feature identification tag — must match feature tag in /// FeatureList pub feature_table_tag: BigEndian, /// Offset to BaseCoord table that defines the minimum extent /// value, from beginning of MinMax table (may be NULL) pub min_coord_offset: BigEndian>, /// Offset to BaseCoord table that defines the maximum extent /// value, from beginning of MinMax table (may be NULL) pub max_coord_offset: BigEndian>, } impl FeatMinMaxRecord { /// 4-byte feature identification tag — must match feature tag in /// FeatureList pub fn feature_table_tag(&self) -> Tag { self.feature_table_tag.get() } /// Offset to BaseCoord table that defines the minimum extent /// value, from beginning of MinMax table (may be NULL) pub fn min_coord_offset(&self) -> Nullable { self.min_coord_offset.get() } /// Offset to BaseCoord table that defines the minimum extent /// value, from beginning of MinMax table (may be NULL) /// /// The `data` argument should be retrieved from the parent table /// By calling its `offset_data` method. pub fn min_coord<'a>(&self, data: FontData<'a>) -> Option, ReadError>> { self.min_coord_offset().resolve(data) } /// Offset to BaseCoord table that defines the maximum extent /// value, from beginning of MinMax table (may be NULL) pub fn max_coord_offset(&self) -> Nullable { self.max_coord_offset.get() } /// Offset to BaseCoord table that defines the maximum extent /// value, from beginning of MinMax table (may be NULL) /// /// The `data` argument should be retrieved from the parent table /// By calling its `offset_data` method. pub fn max_coord<'a>(&self, data: FontData<'a>) -> Option, ReadError>> { self.max_coord_offset().resolve(data) } } impl FixedSize for FeatMinMaxRecord { const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN; } #[cfg(feature = "experimental_traverse")] impl<'a> SomeRecord<'a> for FeatMinMaxRecord { fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> { RecordResolver { name: "FeatMinMaxRecord", get_field: Box::new(move |idx, _data| match idx { 0usize => Some(Field::new("feature_table_tag", self.feature_table_tag())), 1usize => Some(Field::new( "min_coord_offset", FieldType::offset(self.min_coord_offset(), self.min_coord(_data)), )), 2usize => Some(Field::new( "max_coord_offset", FieldType::offset(self.max_coord_offset(), self.max_coord(_data)), )), _ => None, }), data, } } } #[derive(Clone)] pub enum BaseCoord<'a> { Format1(BaseCoordFormat1<'a>), Format2(BaseCoordFormat2<'a>), Format3(BaseCoordFormat3<'a>), } impl Default for BaseCoord<'_> { fn default() -> Self { Self::Format1(Default::default()) } } impl<'a> BaseCoord<'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 base_coord_format(&self) -> u16 { match self { Self::Format1(item) => item.base_coord_format(), Self::Format2(item) => item.base_coord_format(), Self::Format3(item) => item.base_coord_format(), } } /// X or Y value, in design units pub fn coordinate(&self) -> i16 { match self { Self::Format1(item) => item.coordinate(), Self::Format2(item) => item.coordinate(), Self::Format3(item) => item.coordinate(), } } } impl<'a> FontRead<'a> for BaseCoord<'a> { fn read(data: FontData<'a>) -> Result { let format: u16 = data.read_at(0usize)?; match format { BaseCoordFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)), BaseCoordFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)), BaseCoordFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)), other => Err(ReadError::InvalidFormat(other.into())), } } } impl<'a> MinByteRange<'a> for BaseCoord<'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> BaseCoord<'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 BaseCoord<'_> { 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 BaseCoord<'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 BaseCoordFormat1<'_> { const FORMAT: u16 = 1; } impl<'a> MinByteRange<'a> for BaseCoordFormat1<'a> { fn min_byte_range(&self) -> Range { 0..self.coordinate_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 BaseCoordFormat1<'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 }) } } /// [BaseCoordFormat1](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basecoord-format-1) #[derive(Clone)] pub struct BaseCoordFormat1<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> BaseCoordFormat1<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Format identifier — format = 1 pub fn base_coord_format(&self) -> u16 { let range = self.base_coord_format_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// X or Y value, in design units pub fn coordinate(&self) -> i16 { let range = self.coordinate_byte_range(); self.data.read_at(range.start).ok().unwrap() } pub fn base_coord_format_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn coordinate_byte_range(&self) -> Range { let start = self.base_coord_format_byte_range().end; let end = start + i16::RAW_BYTE_LEN; start..end } } const _: () = assert!(FontData::default_data_long_enough( BaseCoordFormat1::MIN_SIZE )); impl Default for BaseCoordFormat1<'_> { fn default() -> Self { Self { data: FontData::default_format_1_u16_table_data(), } } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for BaseCoordFormat1<'a> { fn type_name(&self) -> &str { "BaseCoordFormat1" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("base_coord_format", self.base_coord_format())), 1usize => Some(Field::new("coordinate", self.coordinate())), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for BaseCoordFormat1<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } impl Format for BaseCoordFormat2<'_> { const FORMAT: u16 = 2; } impl<'a> MinByteRange<'a> for BaseCoordFormat2<'a> { fn min_byte_range(&self) -> Range { 0..self.base_coord_point_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 BaseCoordFormat2<'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 }) } } /// [BaseCoordFormat2](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basecoord-format-2) #[derive(Clone)] pub struct BaseCoordFormat2<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> BaseCoordFormat2<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Format identifier — format = 2 pub fn base_coord_format(&self) -> u16 { let range = self.base_coord_format_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// X or Y value, in design units pub fn coordinate(&self) -> i16 { let range = self.coordinate_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Glyph ID of control glyph pub fn reference_glyph(&self) -> u16 { let range = self.reference_glyph_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Index of contour point on the reference glyph pub fn base_coord_point(&self) -> u16 { let range = self.base_coord_point_byte_range(); self.data.read_at(range.start).ok().unwrap() } pub fn base_coord_format_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn coordinate_byte_range(&self) -> Range { let start = self.base_coord_format_byte_range().end; let end = start + i16::RAW_BYTE_LEN; start..end } pub fn reference_glyph_byte_range(&self) -> Range { let start = self.coordinate_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn base_coord_point_byte_range(&self) -> Range { let start = self.reference_glyph_byte_range().end; let end = start + u16::RAW_BYTE_LEN; start..end } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for BaseCoordFormat2<'a> { fn type_name(&self) -> &str { "BaseCoordFormat2" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("base_coord_format", self.base_coord_format())), 1usize => Some(Field::new("coordinate", self.coordinate())), 2usize => Some(Field::new("reference_glyph", self.reference_glyph())), 3usize => Some(Field::new("base_coord_point", self.base_coord_point())), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for BaseCoordFormat2<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } impl Format for BaseCoordFormat3<'_> { const FORMAT: u16 = 3; } impl<'a> MinByteRange<'a> for BaseCoordFormat3<'a> { fn min_byte_range(&self) -> Range { 0..self.device_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 BaseCoordFormat3<'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 }) } } /// [BaseCoordFormat3](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basecoord-format-3) #[derive(Clone)] pub struct BaseCoordFormat3<'a> { data: FontData<'a>, } #[allow(clippy::needless_lifetimes)] impl<'a> BaseCoordFormat3<'a> { pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN); basic_table_impls!(impl_the_methods); /// Format identifier — format = 3 pub fn base_coord_format(&self) -> u16 { let range = self.base_coord_format_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// X or Y value, in design units pub fn coordinate(&self) -> i16 { let range = self.coordinate_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Offset to Device table (non-variable font) / Variation Index /// table (variable font) for X or Y value, from beginning of /// BaseCoord table (may be NULL). pub fn device_offset(&self) -> Nullable { let range = self.device_offset_byte_range(); self.data.read_at(range.start).ok().unwrap() } /// Attempt to resolve [`device_offset`][Self::device_offset]. pub fn device(&self) -> Option, ReadError>> { let data = self.data; self.device_offset().resolve(data) } pub fn base_coord_format_byte_range(&self) -> Range { let start = 0; let end = start + u16::RAW_BYTE_LEN; start..end } pub fn coordinate_byte_range(&self) -> Range { let start = self.base_coord_format_byte_range().end; let end = start + i16::RAW_BYTE_LEN; start..end } pub fn device_offset_byte_range(&self) -> Range { let start = self.coordinate_byte_range().end; let end = start + Offset16::RAW_BYTE_LEN; start..end } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for BaseCoordFormat3<'a> { fn type_name(&self) -> &str { "BaseCoordFormat3" } fn get_field(&self, idx: usize) -> Option> { match idx { 0usize => Some(Field::new("base_coord_format", self.base_coord_format())), 1usize => Some(Field::new("coordinate", self.coordinate())), 2usize => Some(Field::new( "device_offset", FieldType::offset(self.device_offset(), self.device()), )), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for BaseCoordFormat3<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } }