// 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::*; /// The [BASE](https://learn.microsoft.com/en-us/typography/opentype/spec/base) (Baseline) table #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct BaseMarker { item_var_store_offset_byte_start: Option, } impl BaseMarker { pub fn version_byte_range(&self) -> Range { let start = 0; start..start + MajorMinor::RAW_BYTE_LEN } pub fn horiz_axis_offset_byte_range(&self) -> Range { let start = self.version_byte_range().end; start..start + Offset16::RAW_BYTE_LEN } pub fn vert_axis_offset_byte_range(&self) -> Range { let start = self.horiz_axis_offset_byte_range().end; start..start + Offset16::RAW_BYTE_LEN } pub fn item_var_store_offset_byte_range(&self) -> Option> { let start = self.item_var_store_offset_byte_start?; Some(start..start + Offset32::RAW_BYTE_LEN) } } impl MinByteRange for BaseMarker { fn min_byte_range(&self) -> Range { 0..self.vert_axis_offset_byte_range().end } } 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 { let mut cursor = data.cursor(); let version: MajorMinor = cursor.read()?; cursor.advance::(); cursor.advance::(); let item_var_store_offset_byte_start = version .compatible((1u16, 1u16)) .then(|| cursor.position()) .transpose()?; version .compatible((1u16, 1u16)) .then(|| cursor.advance::()); cursor.finish(BaseMarker { item_var_store_offset_byte_start, }) } } /// The [BASE](https://learn.microsoft.com/en-us/typography/opentype/spec/base) (Baseline) table pub type Base<'a> = TableRef<'a, BaseMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> Base<'a> { /// (major, minor) Version for the BASE table (1,0) or (1,1) pub fn version(&self) -> MajorMinor { let range = self.shape.version_byte_range(); self.data.read_at(range.start).unwrap() } /// Offset to horizontal Axis table, from beginning of BASE table (may be NULL) pub fn horiz_axis_offset(&self) -> Nullable { let range = self.shape.horiz_axis_offset_byte_range(); self.data.read_at(range.start).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.shape.vert_axis_offset_byte_range(); self.data.read_at(range.start).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.shape.item_var_store_offset_byte_range()?; Some(self.data.read_at(range.start).unwrap()) } /// 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))? } } #[cfg(feature = "experimental_traverse")] impl<'a> SomeTable<'a> for Base<'a> { fn type_name(&self) -> &str { "Base" } fn get_field(&self, idx: usize) -> Option> { let version = self.version(); 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 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) } } /// [Axis Table](https://learn.microsoft.com/en-us/typography/opentype/spec/base#axis-tables-horizaxis-and-vertaxis) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct AxisMarker {} impl AxisMarker { pub fn base_tag_list_offset_byte_range(&self) -> Range { let start = 0; start..start + Offset16::RAW_BYTE_LEN } pub fn base_script_list_offset_byte_range(&self) -> Range { let start = self.base_tag_list_offset_byte_range().end; start..start + Offset16::RAW_BYTE_LEN } } impl MinByteRange for AxisMarker { fn min_byte_range(&self) -> Range { 0..self.base_script_list_offset_byte_range().end } } impl<'a> FontRead<'a> for Axis<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); cursor.finish(AxisMarker {}) } } /// [Axis Table](https://learn.microsoft.com/en-us/typography/opentype/spec/base#axis-tables-horizaxis-and-vertaxis) pub type Axis<'a> = TableRef<'a, AxisMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> Axis<'a> { /// Offset to BaseTagList table, from beginning of Axis table (may /// be NULL) pub fn base_tag_list_offset(&self) -> Nullable { let range = self.shape.base_tag_list_offset_byte_range(); self.data.read_at(range.start).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.shape.base_script_list_offset_byte_range(); self.data.read_at(range.start).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) } } #[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) } } /// [BaseTagList Table](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basetaglist-table) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct BaseTagListMarker { baseline_tags_byte_len: usize, } impl BaseTagListMarker { pub fn base_tag_count_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn baseline_tags_byte_range(&self) -> Range { let start = self.base_tag_count_byte_range().end; start..start + self.baseline_tags_byte_len } } impl MinByteRange for BaseTagListMarker { fn min_byte_range(&self) -> Range { 0..self.baseline_tags_byte_range().end } } impl<'a> FontRead<'a> for BaseTagList<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); let base_tag_count: u16 = cursor.read()?; let baseline_tags_byte_len = (base_tag_count as usize) .checked_mul(Tag::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(baseline_tags_byte_len); cursor.finish(BaseTagListMarker { baseline_tags_byte_len, }) } } /// [BaseTagList Table](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basetaglist-table) pub type BaseTagList<'a> = TableRef<'a, BaseTagListMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> BaseTagList<'a> { /// Number of baseline identification tags in this text direction /// — may be zero (0) pub fn base_tag_count(&self) -> u16 { let range = self.shape.base_tag_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of 4-byte baseline identification tags — must be in /// alphabetical order pub fn baseline_tags(&self) -> &'a [BigEndian] { let range = self.shape.baseline_tags_byte_range(); self.data.read_array(range).unwrap() } } #[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) } } /// [BaseScriptList Table](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basescriptlist-table) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct BaseScriptListMarker { base_script_records_byte_len: usize, } impl BaseScriptListMarker { pub fn base_script_count_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn base_script_records_byte_range(&self) -> Range { let start = self.base_script_count_byte_range().end; start..start + self.base_script_records_byte_len } } impl MinByteRange for BaseScriptListMarker { fn min_byte_range(&self) -> Range { 0..self.base_script_records_byte_range().end } } impl<'a> FontRead<'a> for BaseScriptList<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); let base_script_count: u16 = cursor.read()?; let base_script_records_byte_len = (base_script_count as usize) .checked_mul(BaseScriptRecord::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(base_script_records_byte_len); cursor.finish(BaseScriptListMarker { base_script_records_byte_len, }) } } /// [BaseScriptList Table](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basescriptlist-table) pub type BaseScriptList<'a> = TableRef<'a, BaseScriptListMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> BaseScriptList<'a> { /// Number of BaseScriptRecords defined pub fn base_script_count(&self) -> u16 { let range = self.shape.base_script_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of BaseScriptRecords, in alphabetical order by /// baseScriptTag pub fn base_script_records(&self) -> &'a [BaseScriptRecord] { let range = self.shape.base_script_records_byte_range(); self.data.read_array(range).unwrap() } } #[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, } } } /// [BaseScript Table](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basescript-table) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct BaseScriptMarker { base_lang_sys_records_byte_len: usize, } impl BaseScriptMarker { pub fn base_values_offset_byte_range(&self) -> Range { let start = 0; start..start + Offset16::RAW_BYTE_LEN } pub fn default_min_max_offset_byte_range(&self) -> Range { let start = self.base_values_offset_byte_range().end; start..start + Offset16::RAW_BYTE_LEN } pub fn base_lang_sys_count_byte_range(&self) -> Range { let start = self.default_min_max_offset_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn base_lang_sys_records_byte_range(&self) -> Range { let start = self.base_lang_sys_count_byte_range().end; start..start + self.base_lang_sys_records_byte_len } } impl MinByteRange for BaseScriptMarker { fn min_byte_range(&self) -> Range { 0..self.base_lang_sys_records_byte_range().end } } impl<'a> FontRead<'a> for BaseScript<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); let base_lang_sys_count: u16 = cursor.read()?; let base_lang_sys_records_byte_len = (base_lang_sys_count as usize) .checked_mul(BaseLangSysRecord::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(base_lang_sys_records_byte_len); cursor.finish(BaseScriptMarker { base_lang_sys_records_byte_len, }) } } /// [BaseScript Table](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basescript-table) pub type BaseScript<'a> = TableRef<'a, BaseScriptMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> BaseScript<'a> { /// Offset to BaseValues table, from beginning of BaseScript table (may be NULL) pub fn base_values_offset(&self) -> Nullable { let range = self.shape.base_values_offset_byte_range(); self.data.read_at(range.start).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.shape.default_min_max_offset_byte_range(); self.data.read_at(range.start).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.shape.base_lang_sys_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of BaseLangSysRecords, in alphabetical order by /// BaseLangSysTag pub fn base_lang_sys_records(&self) -> &'a [BaseLangSysRecord] { let range = self.shape.base_lang_sys_records_byte_range(); self.data.read_array(range).unwrap() } } #[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, } } } /// [BaseValues](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basevalues-table) table #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct BaseValuesMarker { base_coord_offsets_byte_len: usize, } impl BaseValuesMarker { pub fn default_baseline_index_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn base_coord_count_byte_range(&self) -> Range { let start = self.default_baseline_index_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn base_coord_offsets_byte_range(&self) -> Range { let start = self.base_coord_count_byte_range().end; start..start + self.base_coord_offsets_byte_len } } impl MinByteRange for BaseValuesMarker { fn min_byte_range(&self) -> Range { 0..self.base_coord_offsets_byte_range().end } } impl<'a> FontRead<'a> for BaseValues<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); let base_coord_count: u16 = cursor.read()?; let base_coord_offsets_byte_len = (base_coord_count as usize) .checked_mul(Offset16::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(base_coord_offsets_byte_len); cursor.finish(BaseValuesMarker { base_coord_offsets_byte_len, }) } } /// [BaseValues](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basevalues-table) table pub type BaseValues<'a> = TableRef<'a, BaseValuesMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> BaseValues<'a> { /// 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.shape.default_baseline_index_byte_range(); self.data.read_at(range.start).unwrap() } /// Number of BaseCoord tables defined — should equal /// baseTagCount in the BaseTagList pub fn base_coord_count(&self) -> u16 { let range = self.shape.base_coord_count_byte_range(); self.data.read_at(range.start).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.shape.base_coord_offsets_byte_range(); self.data.read_array(range).unwrap() } /// 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, ()) } } #[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({ let data = self.data; Field::new( "base_coord_offsets", FieldType::array_of_offsets( better_type_name::(), self.base_coord_offsets(), move |off| { let target = off.get().resolve::(data); FieldType::offset(off.get(), target) }, ), ) }), _ => None, } } } #[cfg(feature = "experimental_traverse")] #[allow(clippy::needless_lifetimes)] impl<'a> std::fmt::Debug for BaseValues<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { (self as &dyn SomeTable<'a>).fmt(f) } } /// [MinMax](https://learn.microsoft.com/en-us/typography/opentype/spec/base#minmax-table) table #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct MinMaxMarker { feat_min_max_records_byte_len: usize, } impl MinMaxMarker { pub fn min_coord_offset_byte_range(&self) -> Range { let start = 0; start..start + Offset16::RAW_BYTE_LEN } pub fn max_coord_offset_byte_range(&self) -> Range { let start = self.min_coord_offset_byte_range().end; start..start + Offset16::RAW_BYTE_LEN } pub fn feat_min_max_count_byte_range(&self) -> Range { let start = self.max_coord_offset_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn feat_min_max_records_byte_range(&self) -> Range { let start = self.feat_min_max_count_byte_range().end; start..start + self.feat_min_max_records_byte_len } } impl MinByteRange for MinMaxMarker { fn min_byte_range(&self) -> Range { 0..self.feat_min_max_records_byte_range().end } } impl<'a> FontRead<'a> for MinMax<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); let feat_min_max_count: u16 = cursor.read()?; let feat_min_max_records_byte_len = (feat_min_max_count as usize) .checked_mul(FeatMinMaxRecord::RAW_BYTE_LEN) .ok_or(ReadError::OutOfBounds)?; cursor.advance_by(feat_min_max_records_byte_len); cursor.finish(MinMaxMarker { feat_min_max_records_byte_len, }) } } /// [MinMax](https://learn.microsoft.com/en-us/typography/opentype/spec/base#minmax-table) table pub type MinMax<'a> = TableRef<'a, MinMaxMarker>; #[allow(clippy::needless_lifetimes)] impl<'a> MinMax<'a> { /// 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.shape.min_coord_offset_byte_range(); self.data.read_at(range.start).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.shape.max_coord_offset_byte_range(); self.data.read_at(range.start).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.shape.feat_min_max_count_byte_range(); self.data.read_at(range.start).unwrap() } /// Array of FeatMinMaxRecords, in alphabetical order by /// featureTableTag pub fn feat_min_max_records(&self) -> &'a [FeatMinMaxRecord] { let range = self.shape.feat_min_max_records_byte_range(); self.data.read_array(range).unwrap() } } #[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<'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 { BaseCoordFormat1Marker::FORMAT => Ok(Self::Format1(FontRead::read(data)?)), BaseCoordFormat2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)), BaseCoordFormat3Marker::FORMAT => Ok(Self::Format3(FontRead::read(data)?)), other => Err(ReadError::InvalidFormat(other.into())), } } } impl MinByteRange for BaseCoord<'_> { fn min_byte_range(&self) -> Range { match self { Self::Format1(item) => item.min_byte_range(), Self::Format2(item) => item.min_byte_range(), Self::Format3(item) => item.min_byte_range(), } } } #[cfg(feature = "experimental_traverse")] impl<'a> 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 BaseCoordFormat1Marker { const FORMAT: u16 = 1; } /// [BaseCoordFormat1](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basecoord-format-1) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct BaseCoordFormat1Marker {} impl BaseCoordFormat1Marker { pub fn base_coord_format_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn coordinate_byte_range(&self) -> Range { let start = self.base_coord_format_byte_range().end; start..start + i16::RAW_BYTE_LEN } } impl MinByteRange for BaseCoordFormat1Marker { fn min_byte_range(&self) -> Range { 0..self.coordinate_byte_range().end } } impl<'a> FontRead<'a> for BaseCoordFormat1<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); cursor.finish(BaseCoordFormat1Marker {}) } } /// [BaseCoordFormat1](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basecoord-format-1) pub type BaseCoordFormat1<'a> = TableRef<'a, BaseCoordFormat1Marker>; #[allow(clippy::needless_lifetimes)] impl<'a> BaseCoordFormat1<'a> { /// Format identifier — format = 1 pub fn base_coord_format(&self) -> u16 { let range = self.shape.base_coord_format_byte_range(); self.data.read_at(range.start).unwrap() } /// X or Y value, in design units pub fn coordinate(&self) -> i16 { let range = self.shape.coordinate_byte_range(); self.data.read_at(range.start).unwrap() } } #[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 BaseCoordFormat2Marker { const FORMAT: u16 = 2; } /// [BaseCoordFormat2](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basecoord-format-2) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct BaseCoordFormat2Marker {} impl BaseCoordFormat2Marker { pub fn base_coord_format_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn coordinate_byte_range(&self) -> Range { let start = self.base_coord_format_byte_range().end; start..start + i16::RAW_BYTE_LEN } pub fn reference_glyph_byte_range(&self) -> Range { let start = self.coordinate_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn base_coord_point_byte_range(&self) -> Range { let start = self.reference_glyph_byte_range().end; start..start + u16::RAW_BYTE_LEN } } impl MinByteRange for BaseCoordFormat2Marker { fn min_byte_range(&self) -> Range { 0..self.base_coord_point_byte_range().end } } impl<'a> FontRead<'a> for BaseCoordFormat2<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); cursor.advance::(); cursor.advance::(); cursor.finish(BaseCoordFormat2Marker {}) } } /// [BaseCoordFormat2](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basecoord-format-2) pub type BaseCoordFormat2<'a> = TableRef<'a, BaseCoordFormat2Marker>; #[allow(clippy::needless_lifetimes)] impl<'a> BaseCoordFormat2<'a> { /// Format identifier — format = 2 pub fn base_coord_format(&self) -> u16 { let range = self.shape.base_coord_format_byte_range(); self.data.read_at(range.start).unwrap() } /// X or Y value, in design units pub fn coordinate(&self) -> i16 { let range = self.shape.coordinate_byte_range(); self.data.read_at(range.start).unwrap() } /// Glyph ID of control glyph pub fn reference_glyph(&self) -> u16 { let range = self.shape.reference_glyph_byte_range(); self.data.read_at(range.start).unwrap() } /// Index of contour point on the reference glyph pub fn base_coord_point(&self) -> u16 { let range = self.shape.base_coord_point_byte_range(); self.data.read_at(range.start).unwrap() } } #[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 BaseCoordFormat3Marker { const FORMAT: u16 = 3; } /// [BaseCoordFormat3](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basecoord-format-3) #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub struct BaseCoordFormat3Marker {} impl BaseCoordFormat3Marker { pub fn base_coord_format_byte_range(&self) -> Range { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn coordinate_byte_range(&self) -> Range { let start = self.base_coord_format_byte_range().end; start..start + i16::RAW_BYTE_LEN } pub fn device_offset_byte_range(&self) -> Range { let start = self.coordinate_byte_range().end; start..start + Offset16::RAW_BYTE_LEN } } impl MinByteRange for BaseCoordFormat3Marker { fn min_byte_range(&self) -> Range { 0..self.device_offset_byte_range().end } } impl<'a> FontRead<'a> for BaseCoordFormat3<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); cursor.advance::(); cursor.finish(BaseCoordFormat3Marker {}) } } /// [BaseCoordFormat3](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basecoord-format-3) pub type BaseCoordFormat3<'a> = TableRef<'a, BaseCoordFormat3Marker>; #[allow(clippy::needless_lifetimes)] impl<'a> BaseCoordFormat3<'a> { /// Format identifier — format = 3 pub fn base_coord_format(&self) -> u16 { let range = self.shape.base_coord_format_byte_range(); self.data.read_at(range.start).unwrap() } /// X or Y value, in design units pub fn coordinate(&self) -> i16 { let range = self.shape.coordinate_byte_range(); self.data.read_at(range.start).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.shape.device_offset_byte_range(); self.data.read_at(range.start).unwrap() } /// Attempt to resolve [`device_offset`][Self::device_offset]. pub fn device(&self) -> Option, ReadError>> { let data = self.data; self.device_offset().resolve(data) } } #[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) } }