| // 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::*; |
| |
| #[derive(Clone)] |
| pub enum Ift<'a> { |
| Format1(PatchMapFormat1<'a>), |
| Format2(PatchMapFormat2<'a>), |
| } |
| |
| impl<'a> Ift<'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 format(&self) -> u8 { |
| match self { |
| Self::Format1(item) => item.format(), |
| Self::Format2(item) => item.format(), |
| } |
| } |
| |
| /// Unique ID that identifies compatible patches. |
| pub fn compatibility_id(&self) -> CompatibilityId { |
| match self { |
| Self::Format1(item) => item.compatibility_id(), |
| Self::Format2(item) => item.compatibility_id(), |
| } |
| } |
| |
| pub fn uri_template_length(&self) -> u16 { |
| match self { |
| Self::Format1(item) => item.uri_template_length(), |
| Self::Format2(item) => item.uri_template_length(), |
| } |
| } |
| |
| pub fn uri_template(&self) -> &'a [u8] { |
| match self { |
| Self::Format1(item) => item.uri_template(), |
| Self::Format2(item) => item.uri_template(), |
| } |
| } |
| } |
| |
| impl<'a> FontRead<'a> for Ift<'a> { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| let format: u8 = data.read_at(0usize)?; |
| match format { |
| PatchMapFormat1Marker::FORMAT => Ok(Self::Format1(FontRead::read(data)?)), |
| PatchMapFormat2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)), |
| other => Err(ReadError::InvalidFormat(other.into())), |
| } |
| } |
| } |
| |
| impl MinByteRange for Ift<'_> { |
| fn min_byte_range(&self) -> Range<usize> { |
| match self { |
| Self::Format1(item) => item.min_byte_range(), |
| Self::Format2(item) => item.min_byte_range(), |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> Ift<'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 Ift<'_> { |
| 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 Ift<'a> { |
| fn type_name(&self) -> &str { |
| self.dyn_inner().type_name() |
| } |
| fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
| self.dyn_inner().get_field(idx) |
| } |
| } |
| |
| impl Format<u8> for PatchMapFormat1Marker { |
| const FORMAT: u8 = 1; |
| } |
| |
| /// [Patch Map Format Format 1](https://w3c.github.io/IFT/Overview.html#patch-map-format-1) |
| #[derive(Debug, Clone, Copy)] |
| #[doc(hidden)] |
| pub struct PatchMapFormat1Marker { |
| applied_entries_bitmap_byte_len: usize, |
| uri_template_byte_len: usize, |
| } |
| |
| impl PatchMapFormat1Marker { |
| pub fn format_byte_range(&self) -> Range<usize> { |
| let start = 0; |
| start..start + u8::RAW_BYTE_LEN |
| } |
| |
| pub fn _reserved_byte_range(&self) -> Range<usize> { |
| let start = self.format_byte_range().end; |
| start..start + u32::RAW_BYTE_LEN |
| } |
| |
| pub fn compatibility_id_byte_range(&self) -> Range<usize> { |
| let start = self._reserved_byte_range().end; |
| start..start + CompatibilityId::RAW_BYTE_LEN |
| } |
| |
| pub fn max_entry_index_byte_range(&self) -> Range<usize> { |
| let start = self.compatibility_id_byte_range().end; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn max_glyph_map_entry_index_byte_range(&self) -> Range<usize> { |
| let start = self.max_entry_index_byte_range().end; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn glyph_count_byte_range(&self) -> Range<usize> { |
| let start = self.max_glyph_map_entry_index_byte_range().end; |
| start..start + Uint24::RAW_BYTE_LEN |
| } |
| |
| pub fn glyph_map_offset_byte_range(&self) -> Range<usize> { |
| let start = self.glyph_count_byte_range().end; |
| start..start + Offset32::RAW_BYTE_LEN |
| } |
| |
| pub fn feature_map_offset_byte_range(&self) -> Range<usize> { |
| let start = self.glyph_map_offset_byte_range().end; |
| start..start + Offset32::RAW_BYTE_LEN |
| } |
| |
| pub fn applied_entries_bitmap_byte_range(&self) -> Range<usize> { |
| let start = self.feature_map_offset_byte_range().end; |
| start..start + self.applied_entries_bitmap_byte_len |
| } |
| |
| pub fn uri_template_length_byte_range(&self) -> Range<usize> { |
| let start = self.applied_entries_bitmap_byte_range().end; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn uri_template_byte_range(&self) -> Range<usize> { |
| let start = self.uri_template_length_byte_range().end; |
| start..start + self.uri_template_byte_len |
| } |
| |
| pub fn patch_format_byte_range(&self) -> Range<usize> { |
| let start = self.uri_template_byte_range().end; |
| start..start + u8::RAW_BYTE_LEN |
| } |
| } |
| |
| impl MinByteRange for PatchMapFormat1Marker { |
| fn min_byte_range(&self) -> Range<usize> { |
| 0..self.patch_format_byte_range().end |
| } |
| } |
| |
| impl<'a> FontRead<'a> for PatchMapFormat1<'a> { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| let mut cursor = data.cursor(); |
| cursor.advance::<u8>(); |
| cursor.advance::<u32>(); |
| cursor.advance::<CompatibilityId>(); |
| let max_entry_index: u16 = cursor.read()?; |
| cursor.advance::<u16>(); |
| cursor.advance::<Uint24>(); |
| cursor.advance::<Offset32>(); |
| cursor.advance::<Offset32>(); |
| let applied_entries_bitmap_byte_len = (transforms::max_value_bitmap_len(max_entry_index)) |
| .checked_mul(u8::RAW_BYTE_LEN) |
| .ok_or(ReadError::OutOfBounds)?; |
| cursor.advance_by(applied_entries_bitmap_byte_len); |
| let uri_template_length: u16 = cursor.read()?; |
| let uri_template_byte_len = (uri_template_length as usize) |
| .checked_mul(u8::RAW_BYTE_LEN) |
| .ok_or(ReadError::OutOfBounds)?; |
| cursor.advance_by(uri_template_byte_len); |
| cursor.advance::<u8>(); |
| cursor.finish(PatchMapFormat1Marker { |
| applied_entries_bitmap_byte_len, |
| uri_template_byte_len, |
| }) |
| } |
| } |
| |
| /// [Patch Map Format Format 1](https://w3c.github.io/IFT/Overview.html#patch-map-format-1) |
| pub type PatchMapFormat1<'a> = TableRef<'a, PatchMapFormat1Marker>; |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> PatchMapFormat1<'a> { |
| /// Format identifier: format = 1 |
| pub fn format(&self) -> u8 { |
| let range = self.shape.format_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Unique ID that identifies compatible patches. |
| pub fn compatibility_id(&self) -> CompatibilityId { |
| let range = self.shape.compatibility_id_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Largest entry index which appears in either the glyph map or feature map. |
| pub fn max_entry_index(&self) -> u16 { |
| let range = self.shape.max_entry_index_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Largest entry index which appears in the glyph map. |
| pub fn max_glyph_map_entry_index(&self) -> u16 { |
| let range = self.shape.max_glyph_map_entry_index_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| pub fn glyph_count(&self) -> Uint24 { |
| let range = self.shape.glyph_count_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Sub table that maps glyph ids to entry indices. |
| pub fn glyph_map_offset(&self) -> Offset32 { |
| let range = self.shape.glyph_map_offset_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Attempt to resolve [`glyph_map_offset`][Self::glyph_map_offset]. |
| pub fn glyph_map(&self) -> Result<GlyphMap<'a>, ReadError> { |
| let data = self.data; |
| let args = (self.glyph_count(), self.max_entry_index()); |
| self.glyph_map_offset().resolve_with_args(data, &args) |
| } |
| |
| /// Sub table that maps feature and glyph ids to entry indices. |
| pub fn feature_map_offset(&self) -> Nullable<Offset32> { |
| let range = self.shape.feature_map_offset_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Attempt to resolve [`feature_map_offset`][Self::feature_map_offset]. |
| pub fn feature_map(&self) -> Option<Result<FeatureMap<'a>, ReadError>> { |
| let data = self.data; |
| let args = self.max_entry_index(); |
| self.feature_map_offset().resolve_with_args(data, &args) |
| } |
| |
| pub fn applied_entries_bitmap(&self) -> &'a [u8] { |
| let range = self.shape.applied_entries_bitmap_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| |
| pub fn uri_template_length(&self) -> u16 { |
| let range = self.shape.uri_template_length_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| pub fn uri_template(&self) -> &'a [u8] { |
| let range = self.shape.uri_template_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| |
| /// Patch format number for patches referenced by this mapping. |
| pub fn patch_format(&self) -> u8 { |
| let range = self.shape.patch_format_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeTable<'a> for PatchMapFormat1<'a> { |
| fn type_name(&self) -> &str { |
| "PatchMapFormat1" |
| } |
| fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
| match idx { |
| 0usize => Some(Field::new("format", self.format())), |
| 1usize => Some(Field::new( |
| "compatibility_id", |
| traversal::FieldType::Unknown, |
| )), |
| 2usize => Some(Field::new("max_entry_index", self.max_entry_index())), |
| 3usize => Some(Field::new( |
| "max_glyph_map_entry_index", |
| self.max_glyph_map_entry_index(), |
| )), |
| 4usize => Some(Field::new("glyph_count", self.glyph_count())), |
| 5usize => Some(Field::new( |
| "glyph_map_offset", |
| FieldType::offset(self.glyph_map_offset(), self.glyph_map()), |
| )), |
| 6usize => Some(Field::new( |
| "feature_map_offset", |
| FieldType::offset(self.feature_map_offset(), self.feature_map()), |
| )), |
| 7usize => Some(Field::new( |
| "applied_entries_bitmap", |
| self.applied_entries_bitmap(), |
| )), |
| 8usize => Some(Field::new( |
| "uri_template_length", |
| self.uri_template_length(), |
| )), |
| 9usize => Some(Field::new("uri_template", self.uri_template())), |
| 10usize => Some(Field::new("patch_format", self.patch_format())), |
| _ => None, |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> std::fmt::Debug for PatchMapFormat1<'a> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| (self as &dyn SomeTable<'a>).fmt(f) |
| } |
| } |
| |
| #[derive(Debug, Clone, Copy)] |
| #[doc(hidden)] |
| pub struct GlyphMapMarker { |
| max_entry_index: u16, |
| entry_index_byte_len: usize, |
| } |
| |
| impl GlyphMapMarker { |
| pub fn first_mapped_glyph_byte_range(&self) -> Range<usize> { |
| let start = 0; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn entry_index_byte_range(&self) -> Range<usize> { |
| let start = self.first_mapped_glyph_byte_range().end; |
| start..start + self.entry_index_byte_len |
| } |
| } |
| |
| impl MinByteRange for GlyphMapMarker { |
| fn min_byte_range(&self) -> Range<usize> { |
| 0..self.entry_index_byte_range().end |
| } |
| } |
| |
| impl ReadArgs for GlyphMap<'_> { |
| type Args = (Uint24, u16); |
| } |
| |
| impl<'a> FontReadWithArgs<'a> for GlyphMap<'a> { |
| fn read_with_args(data: FontData<'a>, args: &(Uint24, u16)) -> Result<Self, ReadError> { |
| let (glyph_count, max_entry_index) = *args; |
| let mut cursor = data.cursor(); |
| let first_mapped_glyph: u16 = cursor.read()?; |
| let entry_index_byte_len = (transforms::subtract(glyph_count, first_mapped_glyph)) |
| .checked_mul(<U8Or16 as ComputeSize>::compute_size(&max_entry_index)?) |
| .ok_or(ReadError::OutOfBounds)?; |
| cursor.advance_by(entry_index_byte_len); |
| cursor.finish(GlyphMapMarker { |
| max_entry_index, |
| entry_index_byte_len, |
| }) |
| } |
| } |
| |
| impl<'a> GlyphMap<'a> { |
| /// A constructor that requires additional arguments. |
| /// |
| /// This type requires some external state in order to be |
| /// parsed. |
| pub fn read( |
| data: FontData<'a>, |
| glyph_count: Uint24, |
| max_entry_index: u16, |
| ) -> Result<Self, ReadError> { |
| let args = (glyph_count, max_entry_index); |
| Self::read_with_args(data, &args) |
| } |
| } |
| |
| pub type GlyphMap<'a> = TableRef<'a, GlyphMapMarker>; |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> GlyphMap<'a> { |
| pub fn first_mapped_glyph(&self) -> u16 { |
| let range = self.shape.first_mapped_glyph_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| pub fn entry_index(&self) -> ComputedArray<'a, U8Or16> { |
| let range = self.shape.entry_index_byte_range(); |
| self.data |
| .read_with_args(range, &self.max_entry_index()) |
| .unwrap() |
| } |
| |
| pub(crate) fn max_entry_index(&self) -> u16 { |
| self.shape.max_entry_index |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeTable<'a> for GlyphMap<'a> { |
| fn type_name(&self) -> &str { |
| "GlyphMap" |
| } |
| fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
| match idx { |
| 0usize => Some(Field::new("first_mapped_glyph", self.first_mapped_glyph())), |
| 1usize => Some(Field::new("entry_index", traversal::FieldType::Unknown)), |
| _ => None, |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> std::fmt::Debug for GlyphMap<'a> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| (self as &dyn SomeTable<'a>).fmt(f) |
| } |
| } |
| |
| #[derive(Debug, Clone, Copy)] |
| #[doc(hidden)] |
| pub struct FeatureMapMarker { |
| max_entry_index: u16, |
| feature_records_byte_len: usize, |
| entry_map_data_byte_len: usize, |
| } |
| |
| impl FeatureMapMarker { |
| pub fn feature_count_byte_range(&self) -> Range<usize> { |
| let start = 0; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn feature_records_byte_range(&self) -> Range<usize> { |
| let start = self.feature_count_byte_range().end; |
| start..start + self.feature_records_byte_len |
| } |
| |
| pub fn entry_map_data_byte_range(&self) -> Range<usize> { |
| let start = self.feature_records_byte_range().end; |
| start..start + self.entry_map_data_byte_len |
| } |
| } |
| |
| impl MinByteRange for FeatureMapMarker { |
| fn min_byte_range(&self) -> Range<usize> { |
| 0..self.entry_map_data_byte_range().end |
| } |
| } |
| |
| impl ReadArgs for FeatureMap<'_> { |
| type Args = u16; |
| } |
| |
| impl<'a> FontReadWithArgs<'a> for FeatureMap<'a> { |
| fn read_with_args(data: FontData<'a>, args: &u16) -> Result<Self, ReadError> { |
| let max_entry_index = *args; |
| let mut cursor = data.cursor(); |
| let feature_count: u16 = cursor.read()?; |
| let feature_records_byte_len = (feature_count as usize) |
| .checked_mul(<FeatureRecord as ComputeSize>::compute_size( |
| &max_entry_index, |
| )?) |
| .ok_or(ReadError::OutOfBounds)?; |
| cursor.advance_by(feature_records_byte_len); |
| let entry_map_data_byte_len = |
| cursor.remaining_bytes() / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN; |
| cursor.advance_by(entry_map_data_byte_len); |
| cursor.finish(FeatureMapMarker { |
| max_entry_index, |
| feature_records_byte_len, |
| entry_map_data_byte_len, |
| }) |
| } |
| } |
| |
| impl<'a> FeatureMap<'a> { |
| /// A constructor that requires additional arguments. |
| /// |
| /// This type requires some external state in order to be |
| /// parsed. |
| pub fn read(data: FontData<'a>, max_entry_index: u16) -> Result<Self, ReadError> { |
| let args = max_entry_index; |
| Self::read_with_args(data, &args) |
| } |
| } |
| |
| pub type FeatureMap<'a> = TableRef<'a, FeatureMapMarker>; |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> FeatureMap<'a> { |
| pub fn feature_count(&self) -> u16 { |
| let range = self.shape.feature_count_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| pub fn feature_records(&self) -> ComputedArray<'a, FeatureRecord> { |
| let range = self.shape.feature_records_byte_range(); |
| self.data |
| .read_with_args(range, &self.max_entry_index()) |
| .unwrap() |
| } |
| |
| pub fn entry_map_data(&self) -> &'a [u8] { |
| let range = self.shape.entry_map_data_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| |
| pub(crate) fn max_entry_index(&self) -> u16 { |
| self.shape.max_entry_index |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeTable<'a> for FeatureMap<'a> { |
| fn type_name(&self) -> &str { |
| "FeatureMap" |
| } |
| fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
| match idx { |
| 0usize => Some(Field::new("feature_count", self.feature_count())), |
| 1usize => Some(Field::new("feature_records", traversal::FieldType::Unknown)), |
| 2usize => Some(Field::new("entry_map_data", self.entry_map_data())), |
| _ => None, |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> std::fmt::Debug for FeatureMap<'a> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| (self as &dyn SomeTable<'a>).fmt(f) |
| } |
| } |
| |
| #[derive(Clone, Debug)] |
| pub struct FeatureRecord { |
| pub feature_tag: BigEndian<Tag>, |
| pub first_new_entry_index: U8Or16, |
| pub entry_map_count: U8Or16, |
| } |
| |
| impl FeatureRecord { |
| pub fn feature_tag(&self) -> Tag { |
| self.feature_tag.get() |
| } |
| |
| pub fn first_new_entry_index(&self) -> &U8Or16 { |
| &self.first_new_entry_index |
| } |
| |
| pub fn entry_map_count(&self) -> &U8Or16 { |
| &self.entry_map_count |
| } |
| } |
| |
| impl ReadArgs for FeatureRecord { |
| type Args = u16; |
| } |
| |
| impl ComputeSize for FeatureRecord { |
| #[allow(clippy::needless_question_mark)] |
| fn compute_size(args: &u16) -> Result<usize, ReadError> { |
| let max_entry_index = *args; |
| let mut result = 0usize; |
| result = result |
| .checked_add(Tag::RAW_BYTE_LEN) |
| .ok_or(ReadError::OutOfBounds)?; |
| result = result |
| .checked_add(<U8Or16 as ComputeSize>::compute_size(&max_entry_index)?) |
| .ok_or(ReadError::OutOfBounds)?; |
| result = result |
| .checked_add(<U8Or16 as ComputeSize>::compute_size(&max_entry_index)?) |
| .ok_or(ReadError::OutOfBounds)?; |
| Ok(result) |
| } |
| } |
| |
| impl<'a> FontReadWithArgs<'a> for FeatureRecord { |
| fn read_with_args(data: FontData<'a>, args: &u16) -> Result<Self, ReadError> { |
| let mut cursor = data.cursor(); |
| let max_entry_index = *args; |
| Ok(Self { |
| feature_tag: cursor.read_be()?, |
| first_new_entry_index: cursor.read_with_args(&max_entry_index)?, |
| entry_map_count: cursor.read_with_args(&max_entry_index)?, |
| }) |
| } |
| } |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> FeatureRecord { |
| /// A constructor that requires additional arguments. |
| /// |
| /// This type requires some external state in order to be |
| /// parsed. |
| pub fn read(data: FontData<'a>, max_entry_index: u16) -> Result<Self, ReadError> { |
| let args = max_entry_index; |
| Self::read_with_args(data, &args) |
| } |
| } |
| |
| #[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( |
| "first_new_entry_index", |
| traversal::FieldType::Unknown, |
| )), |
| 2usize => Some(Field::new("entry_map_count", traversal::FieldType::Unknown)), |
| _ => None, |
| }), |
| data, |
| } |
| } |
| } |
| |
| #[derive(Clone, Debug)] |
| pub struct EntryMapRecord { |
| pub first_entry_index: U8Or16, |
| pub last_entry_index: U8Or16, |
| } |
| |
| impl EntryMapRecord { |
| pub fn first_entry_index(&self) -> &U8Or16 { |
| &self.first_entry_index |
| } |
| |
| pub fn last_entry_index(&self) -> &U8Or16 { |
| &self.last_entry_index |
| } |
| } |
| |
| impl ReadArgs for EntryMapRecord { |
| type Args = u16; |
| } |
| |
| impl ComputeSize for EntryMapRecord { |
| #[allow(clippy::needless_question_mark)] |
| fn compute_size(args: &u16) -> Result<usize, ReadError> { |
| let max_entry_index = *args; |
| let mut result = 0usize; |
| result = result |
| .checked_add(<U8Or16 as ComputeSize>::compute_size(&max_entry_index)?) |
| .ok_or(ReadError::OutOfBounds)?; |
| result = result |
| .checked_add(<U8Or16 as ComputeSize>::compute_size(&max_entry_index)?) |
| .ok_or(ReadError::OutOfBounds)?; |
| Ok(result) |
| } |
| } |
| |
| impl<'a> FontReadWithArgs<'a> for EntryMapRecord { |
| fn read_with_args(data: FontData<'a>, args: &u16) -> Result<Self, ReadError> { |
| let mut cursor = data.cursor(); |
| let max_entry_index = *args; |
| Ok(Self { |
| first_entry_index: cursor.read_with_args(&max_entry_index)?, |
| last_entry_index: cursor.read_with_args(&max_entry_index)?, |
| }) |
| } |
| } |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> EntryMapRecord { |
| /// A constructor that requires additional arguments. |
| /// |
| /// This type requires some external state in order to be |
| /// parsed. |
| pub fn read(data: FontData<'a>, max_entry_index: u16) -> Result<Self, ReadError> { |
| let args = max_entry_index; |
| Self::read_with_args(data, &args) |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeRecord<'a> for EntryMapRecord { |
| fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> { |
| RecordResolver { |
| name: "EntryMapRecord", |
| get_field: Box::new(move |idx, _data| match idx { |
| 0usize => Some(Field::new( |
| "first_entry_index", |
| traversal::FieldType::Unknown, |
| )), |
| 1usize => Some(Field::new( |
| "last_entry_index", |
| traversal::FieldType::Unknown, |
| )), |
| _ => None, |
| }), |
| data, |
| } |
| } |
| } |
| |
| impl Format<u8> for PatchMapFormat2Marker { |
| const FORMAT: u8 = 2; |
| } |
| |
| /// [Patch Map Format Format 2](https://w3c.github.io/IFT/Overview.html#patch-map-format-2) |
| #[derive(Debug, Clone, Copy)] |
| #[doc(hidden)] |
| pub struct PatchMapFormat2Marker { |
| uri_template_byte_len: usize, |
| } |
| |
| impl PatchMapFormat2Marker { |
| pub fn format_byte_range(&self) -> Range<usize> { |
| let start = 0; |
| start..start + u8::RAW_BYTE_LEN |
| } |
| |
| pub fn _reserved_byte_range(&self) -> Range<usize> { |
| let start = self.format_byte_range().end; |
| start..start + u32::RAW_BYTE_LEN |
| } |
| |
| pub fn compatibility_id_byte_range(&self) -> Range<usize> { |
| let start = self._reserved_byte_range().end; |
| start..start + CompatibilityId::RAW_BYTE_LEN |
| } |
| |
| pub fn default_patch_format_byte_range(&self) -> Range<usize> { |
| let start = self.compatibility_id_byte_range().end; |
| start..start + u8::RAW_BYTE_LEN |
| } |
| |
| pub fn entry_count_byte_range(&self) -> Range<usize> { |
| let start = self.default_patch_format_byte_range().end; |
| start..start + Uint24::RAW_BYTE_LEN |
| } |
| |
| pub fn entries_offset_byte_range(&self) -> Range<usize> { |
| let start = self.entry_count_byte_range().end; |
| start..start + Offset32::RAW_BYTE_LEN |
| } |
| |
| pub fn entry_id_string_data_offset_byte_range(&self) -> Range<usize> { |
| let start = self.entries_offset_byte_range().end; |
| start..start + Offset32::RAW_BYTE_LEN |
| } |
| |
| pub fn uri_template_length_byte_range(&self) -> Range<usize> { |
| let start = self.entry_id_string_data_offset_byte_range().end; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn uri_template_byte_range(&self) -> Range<usize> { |
| let start = self.uri_template_length_byte_range().end; |
| start..start + self.uri_template_byte_len |
| } |
| } |
| |
| impl MinByteRange for PatchMapFormat2Marker { |
| fn min_byte_range(&self) -> Range<usize> { |
| 0..self.uri_template_byte_range().end |
| } |
| } |
| |
| impl<'a> FontRead<'a> for PatchMapFormat2<'a> { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| let mut cursor = data.cursor(); |
| cursor.advance::<u8>(); |
| cursor.advance::<u32>(); |
| cursor.advance::<CompatibilityId>(); |
| cursor.advance::<u8>(); |
| cursor.advance::<Uint24>(); |
| cursor.advance::<Offset32>(); |
| cursor.advance::<Offset32>(); |
| let uri_template_length: u16 = cursor.read()?; |
| let uri_template_byte_len = (uri_template_length as usize) |
| .checked_mul(u8::RAW_BYTE_LEN) |
| .ok_or(ReadError::OutOfBounds)?; |
| cursor.advance_by(uri_template_byte_len); |
| cursor.finish(PatchMapFormat2Marker { |
| uri_template_byte_len, |
| }) |
| } |
| } |
| |
| /// [Patch Map Format Format 2](https://w3c.github.io/IFT/Overview.html#patch-map-format-2) |
| pub type PatchMapFormat2<'a> = TableRef<'a, PatchMapFormat2Marker>; |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> PatchMapFormat2<'a> { |
| /// Format identifier: format = 2 |
| pub fn format(&self) -> u8 { |
| let range = self.shape.format_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Unique ID that identifies compatible patches. |
| pub fn compatibility_id(&self) -> CompatibilityId { |
| let range = self.shape.compatibility_id_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Patch format number for patches referenced by this mapping. |
| pub fn default_patch_format(&self) -> u8 { |
| let range = self.shape.default_patch_format_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| pub fn entry_count(&self) -> Uint24 { |
| let range = self.shape.entry_count_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| pub fn entries_offset(&self) -> Offset32 { |
| let range = self.shape.entries_offset_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Attempt to resolve [`entries_offset`][Self::entries_offset]. |
| pub fn entries(&self) -> Result<MappingEntries<'a>, ReadError> { |
| let data = self.data; |
| self.entries_offset().resolve(data) |
| } |
| |
| pub fn entry_id_string_data_offset(&self) -> Nullable<Offset32> { |
| let range = self.shape.entry_id_string_data_offset_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Attempt to resolve [`entry_id_string_data_offset`][Self::entry_id_string_data_offset]. |
| pub fn entry_id_string_data(&self) -> Option<Result<IdStringData<'a>, ReadError>> { |
| let data = self.data; |
| self.entry_id_string_data_offset().resolve(data) |
| } |
| |
| pub fn uri_template_length(&self) -> u16 { |
| let range = self.shape.uri_template_length_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| pub fn uri_template(&self) -> &'a [u8] { |
| let range = self.shape.uri_template_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeTable<'a> for PatchMapFormat2<'a> { |
| fn type_name(&self) -> &str { |
| "PatchMapFormat2" |
| } |
| fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
| match idx { |
| 0usize => Some(Field::new("format", self.format())), |
| 1usize => Some(Field::new( |
| "compatibility_id", |
| traversal::FieldType::Unknown, |
| )), |
| 2usize => Some(Field::new( |
| "default_patch_format", |
| self.default_patch_format(), |
| )), |
| 3usize => Some(Field::new("entry_count", self.entry_count())), |
| 4usize => Some(Field::new( |
| "entries_offset", |
| FieldType::offset(self.entries_offset(), self.entries()), |
| )), |
| 5usize => Some(Field::new( |
| "entry_id_string_data_offset", |
| FieldType::offset( |
| self.entry_id_string_data_offset(), |
| self.entry_id_string_data(), |
| ), |
| )), |
| 6usize => Some(Field::new( |
| "uri_template_length", |
| self.uri_template_length(), |
| )), |
| 7usize => Some(Field::new("uri_template", self.uri_template())), |
| _ => None, |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> std::fmt::Debug for PatchMapFormat2<'a> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| (self as &dyn SomeTable<'a>).fmt(f) |
| } |
| } |
| |
| #[derive(Debug, Clone, Copy)] |
| #[doc(hidden)] |
| pub struct MappingEntriesMarker { |
| entry_data_byte_len: usize, |
| } |
| |
| impl MappingEntriesMarker { |
| pub fn entry_data_byte_range(&self) -> Range<usize> { |
| let start = 0; |
| start..start + self.entry_data_byte_len |
| } |
| } |
| |
| impl MinByteRange for MappingEntriesMarker { |
| fn min_byte_range(&self) -> Range<usize> { |
| 0..self.entry_data_byte_range().end |
| } |
| } |
| |
| impl<'a> FontRead<'a> for MappingEntries<'a> { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| let mut cursor = data.cursor(); |
| let entry_data_byte_len = cursor.remaining_bytes() / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN; |
| cursor.advance_by(entry_data_byte_len); |
| cursor.finish(MappingEntriesMarker { |
| entry_data_byte_len, |
| }) |
| } |
| } |
| |
| pub type MappingEntries<'a> = TableRef<'a, MappingEntriesMarker>; |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> MappingEntries<'a> { |
| pub fn entry_data(&self) -> &'a [u8] { |
| let range = self.shape.entry_data_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeTable<'a> for MappingEntries<'a> { |
| fn type_name(&self) -> &str { |
| "MappingEntries" |
| } |
| fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
| match idx { |
| 0usize => Some(Field::new("entry_data", self.entry_data())), |
| _ => None, |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> std::fmt::Debug for MappingEntries<'a> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| (self as &dyn SomeTable<'a>).fmt(f) |
| } |
| } |
| |
| #[derive(Debug, Clone, Copy)] |
| #[doc(hidden)] |
| pub struct EntryDataMarker { |
| entry_id_string_data_offset: Offset32, |
| feature_count_byte_start: Option<usize>, |
| feature_tags_byte_start: Option<usize>, |
| feature_tags_byte_len: Option<usize>, |
| design_space_count_byte_start: Option<usize>, |
| design_space_segments_byte_start: Option<usize>, |
| design_space_segments_byte_len: Option<usize>, |
| match_mode_and_count_byte_start: Option<usize>, |
| child_indices_byte_start: Option<usize>, |
| child_indices_byte_len: Option<usize>, |
| entry_id_delta_byte_start: Option<usize>, |
| entry_id_delta_byte_len: Option<usize>, |
| patch_format_byte_start: Option<usize>, |
| codepoint_data_byte_len: usize, |
| } |
| |
| impl EntryDataMarker { |
| pub fn format_flags_byte_range(&self) -> Range<usize> { |
| let start = 0; |
| start..start + EntryFormatFlags::RAW_BYTE_LEN |
| } |
| |
| pub fn feature_count_byte_range(&self) -> Option<Range<usize>> { |
| let start = self.feature_count_byte_start?; |
| Some(start..start + u8::RAW_BYTE_LEN) |
| } |
| |
| pub fn feature_tags_byte_range(&self) -> Option<Range<usize>> { |
| let start = self.feature_tags_byte_start?; |
| Some(start..start + self.feature_tags_byte_len?) |
| } |
| |
| pub fn design_space_count_byte_range(&self) -> Option<Range<usize>> { |
| let start = self.design_space_count_byte_start?; |
| Some(start..start + u16::RAW_BYTE_LEN) |
| } |
| |
| pub fn design_space_segments_byte_range(&self) -> Option<Range<usize>> { |
| let start = self.design_space_segments_byte_start?; |
| Some(start..start + self.design_space_segments_byte_len?) |
| } |
| |
| pub fn match_mode_and_count_byte_range(&self) -> Option<Range<usize>> { |
| let start = self.match_mode_and_count_byte_start?; |
| Some(start..start + MatchModeAndCount::RAW_BYTE_LEN) |
| } |
| |
| pub fn child_indices_byte_range(&self) -> Option<Range<usize>> { |
| let start = self.child_indices_byte_start?; |
| Some(start..start + self.child_indices_byte_len?) |
| } |
| |
| pub fn entry_id_delta_byte_range(&self) -> Option<Range<usize>> { |
| let start = self.entry_id_delta_byte_start?; |
| Some(start..start + self.entry_id_delta_byte_len?) |
| } |
| |
| pub fn patch_format_byte_range(&self) -> Option<Range<usize>> { |
| let start = self.patch_format_byte_start?; |
| Some(start..start + u8::RAW_BYTE_LEN) |
| } |
| |
| pub fn codepoint_data_byte_range(&self) -> Range<usize> { |
| let start = self . patch_format_byte_range () . map (| range | range . end) . unwrap_or_else (|| self . entry_id_delta_byte_range () . map (| range | range . end) . unwrap_or_else (|| self . child_indices_byte_range () . map (| range | range . end) . unwrap_or_else (|| self . match_mode_and_count_byte_range () . map (| range | range . end) . unwrap_or_else (|| self . design_space_segments_byte_range () . map (| range | range . end) . unwrap_or_else (|| self . design_space_count_byte_range () . map (| range | range . end) . unwrap_or_else (|| self . feature_tags_byte_range () . map (| range | range . end) . unwrap_or_else (|| self . feature_count_byte_range () . map (| range | range . end) . unwrap_or_else (|| self . format_flags_byte_range () . end)))))))) ; |
| start..start + self.codepoint_data_byte_len |
| } |
| } |
| |
| impl MinByteRange for EntryDataMarker { |
| fn min_byte_range(&self) -> Range<usize> { |
| 0..self.codepoint_data_byte_range().end |
| } |
| } |
| |
| impl ReadArgs for EntryData<'_> { |
| type Args = Offset32; |
| } |
| |
| impl<'a> FontReadWithArgs<'a> for EntryData<'a> { |
| fn read_with_args(data: FontData<'a>, args: &Offset32) -> Result<Self, ReadError> { |
| let entry_id_string_data_offset = *args; |
| let mut cursor = data.cursor(); |
| let format_flags: EntryFormatFlags = cursor.read()?; |
| let feature_count_byte_start = format_flags |
| .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE) |
| .then(|| cursor.position()) |
| .transpose()?; |
| let feature_count = format_flags |
| .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE) |
| .then(|| cursor.read::<u8>()) |
| .transpose()? |
| .unwrap_or_default(); |
| let feature_tags_byte_start = format_flags |
| .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE) |
| .then(|| cursor.position()) |
| .transpose()?; |
| let feature_tags_byte_len = format_flags |
| .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE) |
| .then_some( |
| (feature_count as usize) |
| .checked_mul(Tag::RAW_BYTE_LEN) |
| .ok_or(ReadError::OutOfBounds)?, |
| ); |
| if let Some(value) = feature_tags_byte_len { |
| cursor.advance_by(value); |
| } |
| let design_space_count_byte_start = format_flags |
| .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE) |
| .then(|| cursor.position()) |
| .transpose()?; |
| let design_space_count = format_flags |
| .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE) |
| .then(|| cursor.read::<u16>()) |
| .transpose()? |
| .unwrap_or_default(); |
| let design_space_segments_byte_start = format_flags |
| .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE) |
| .then(|| cursor.position()) |
| .transpose()?; |
| let design_space_segments_byte_len = format_flags |
| .contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE) |
| .then_some( |
| (design_space_count as usize) |
| .checked_mul(DesignSpaceSegment::RAW_BYTE_LEN) |
| .ok_or(ReadError::OutOfBounds)?, |
| ); |
| if let Some(value) = design_space_segments_byte_len { |
| cursor.advance_by(value); |
| } |
| let match_mode_and_count_byte_start = format_flags |
| .contains(EntryFormatFlags::CHILD_INDICES) |
| .then(|| cursor.position()) |
| .transpose()?; |
| let match_mode_and_count = format_flags |
| .contains(EntryFormatFlags::CHILD_INDICES) |
| .then(|| cursor.read::<MatchModeAndCount>()) |
| .transpose()? |
| .unwrap_or_default(); |
| let child_indices_byte_start = format_flags |
| .contains(EntryFormatFlags::CHILD_INDICES) |
| .then(|| cursor.position()) |
| .transpose()?; |
| let child_indices_byte_len = format_flags |
| .contains(EntryFormatFlags::CHILD_INDICES) |
| .then_some( |
| (usize::try_from(match_mode_and_count).unwrap_or_default()) |
| .checked_mul(Uint24::RAW_BYTE_LEN) |
| .ok_or(ReadError::OutOfBounds)?, |
| ); |
| if let Some(value) = child_indices_byte_len { |
| cursor.advance_by(value); |
| } |
| let entry_id_delta_byte_start = format_flags |
| .contains(EntryFormatFlags::ENTRY_ID_DELTA) |
| .then(|| cursor.position()) |
| .transpose()?; |
| let entry_id_delta_byte_len = format_flags |
| .contains(EntryFormatFlags::ENTRY_ID_DELTA) |
| .then_some(<IdDeltaOrLength as ComputeSize>::compute_size( |
| &entry_id_string_data_offset, |
| )?); |
| if let Some(value) = entry_id_delta_byte_len { |
| cursor.advance_by(value); |
| } |
| let patch_format_byte_start = format_flags |
| .contains(EntryFormatFlags::PATCH_FORMAT) |
| .then(|| cursor.position()) |
| .transpose()?; |
| format_flags |
| .contains(EntryFormatFlags::PATCH_FORMAT) |
| .then(|| cursor.advance::<u8>()); |
| let codepoint_data_byte_len = |
| cursor.remaining_bytes() / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN; |
| cursor.advance_by(codepoint_data_byte_len); |
| cursor.finish(EntryDataMarker { |
| entry_id_string_data_offset, |
| feature_count_byte_start, |
| feature_tags_byte_start, |
| feature_tags_byte_len, |
| design_space_count_byte_start, |
| design_space_segments_byte_start, |
| design_space_segments_byte_len, |
| match_mode_and_count_byte_start, |
| child_indices_byte_start, |
| child_indices_byte_len, |
| entry_id_delta_byte_start, |
| entry_id_delta_byte_len, |
| patch_format_byte_start, |
| codepoint_data_byte_len, |
| }) |
| } |
| } |
| |
| impl<'a> EntryData<'a> { |
| /// A constructor that requires additional arguments. |
| /// |
| /// This type requires some external state in order to be |
| /// parsed. |
| pub fn read( |
| data: FontData<'a>, |
| entry_id_string_data_offset: Offset32, |
| ) -> Result<Self, ReadError> { |
| let args = entry_id_string_data_offset; |
| Self::read_with_args(data, &args) |
| } |
| } |
| |
| pub type EntryData<'a> = TableRef<'a, EntryDataMarker>; |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> EntryData<'a> { |
| pub fn format_flags(&self) -> EntryFormatFlags { |
| let range = self.shape.format_flags_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| pub fn feature_count(&self) -> Option<u8> { |
| let range = self.shape.feature_count_byte_range()?; |
| Some(self.data.read_at(range.start).unwrap()) |
| } |
| |
| pub fn feature_tags(&self) -> Option<&'a [BigEndian<Tag>]> { |
| let range = self.shape.feature_tags_byte_range()?; |
| Some(self.data.read_array(range).unwrap()) |
| } |
| |
| pub fn design_space_count(&self) -> Option<u16> { |
| let range = self.shape.design_space_count_byte_range()?; |
| Some(self.data.read_at(range.start).unwrap()) |
| } |
| |
| pub fn design_space_segments(&self) -> Option<&'a [DesignSpaceSegment]> { |
| let range = self.shape.design_space_segments_byte_range()?; |
| Some(self.data.read_array(range).unwrap()) |
| } |
| |
| pub fn match_mode_and_count(&self) -> Option<MatchModeAndCount> { |
| let range = self.shape.match_mode_and_count_byte_range()?; |
| Some(self.data.read_at(range.start).unwrap()) |
| } |
| |
| pub fn child_indices(&self) -> Option<&'a [BigEndian<Uint24>]> { |
| let range = self.shape.child_indices_byte_range()?; |
| Some(self.data.read_array(range).unwrap()) |
| } |
| |
| pub fn entry_id_delta(&self) -> Option<IdDeltaOrLength> { |
| let range = self.shape.entry_id_delta_byte_range()?; |
| Some( |
| self.data |
| .read_with_args(range, &self.entry_id_string_data_offset()) |
| .unwrap(), |
| ) |
| } |
| |
| pub fn patch_format(&self) -> Option<u8> { |
| let range = self.shape.patch_format_byte_range()?; |
| Some(self.data.read_at(range.start).unwrap()) |
| } |
| |
| pub fn codepoint_data(&self) -> &'a [u8] { |
| let range = self.shape.codepoint_data_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| |
| pub(crate) fn entry_id_string_data_offset(&self) -> Offset32 { |
| self.shape.entry_id_string_data_offset |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeTable<'a> for EntryData<'a> { |
| fn type_name(&self) -> &str { |
| "EntryData" |
| } |
| fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
| let format_flags = self.format_flags(); |
| match idx { |
| 0usize => Some(Field::new("format_flags", self.format_flags())), |
| 1usize if format_flags.contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE) => { |
| Some(Field::new("feature_count", self.feature_count().unwrap())) |
| } |
| 2usize if format_flags.contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE) => { |
| Some(Field::new("feature_tags", self.feature_tags().unwrap())) |
| } |
| 3usize if format_flags.contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE) => Some( |
| Field::new("design_space_count", self.design_space_count().unwrap()), |
| ), |
| 4usize if format_flags.contains(EntryFormatFlags::FEATURES_AND_DESIGN_SPACE) => { |
| Some(Field::new( |
| "design_space_segments", |
| traversal::FieldType::array_of_records( |
| stringify!(DesignSpaceSegment), |
| self.design_space_segments().unwrap(), |
| self.offset_data(), |
| ), |
| )) |
| } |
| 5usize if format_flags.contains(EntryFormatFlags::CHILD_INDICES) => Some(Field::new( |
| "match_mode_and_count", |
| traversal::FieldType::Unknown, |
| )), |
| 6usize if format_flags.contains(EntryFormatFlags::CHILD_INDICES) => { |
| Some(Field::new("child_indices", self.child_indices().unwrap())) |
| } |
| 7usize if format_flags.contains(EntryFormatFlags::ENTRY_ID_DELTA) => { |
| Some(Field::new("entry_id_delta", traversal::FieldType::Unknown)) |
| } |
| 8usize if format_flags.contains(EntryFormatFlags::PATCH_FORMAT) => { |
| Some(Field::new("patch_format", self.patch_format().unwrap())) |
| } |
| 9usize => Some(Field::new("codepoint_data", self.codepoint_data())), |
| _ => None, |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> std::fmt::Debug for EntryData<'a> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| (self as &dyn SomeTable<'a>).fmt(f) |
| } |
| } |
| |
| #[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, bytemuck :: AnyBitPattern)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| #[repr(transparent)] |
| pub struct EntryFormatFlags { |
| bits: u8, |
| } |
| |
| impl EntryFormatFlags { |
| pub const FEATURES_AND_DESIGN_SPACE: Self = Self { bits: 0b00000001 }; |
| |
| pub const CHILD_INDICES: Self = Self { bits: 0b00000010 }; |
| |
| pub const ENTRY_ID_DELTA: Self = Self { bits: 0b00000100 }; |
| |
| pub const PATCH_FORMAT: Self = Self { bits: 0b00001000 }; |
| |
| pub const CODEPOINTS_BIT_1: Self = Self { bits: 0b00010000 }; |
| |
| pub const CODEPOINTS_BIT_2: Self = Self { bits: 0b00100000 }; |
| |
| pub const IGNORED: Self = Self { bits: 0b01000000 }; |
| |
| pub const RESERVED: Self = Self { bits: 0b10000000 }; |
| } |
| |
| impl EntryFormatFlags { |
| /// Returns an empty set of flags. |
| #[inline] |
| pub const fn empty() -> Self { |
| Self { bits: 0 } |
| } |
| |
| /// Returns the set containing all flags. |
| #[inline] |
| pub const fn all() -> Self { |
| Self { |
| bits: Self::FEATURES_AND_DESIGN_SPACE.bits |
| | Self::CHILD_INDICES.bits |
| | Self::ENTRY_ID_DELTA.bits |
| | Self::PATCH_FORMAT.bits |
| | Self::CODEPOINTS_BIT_1.bits |
| | Self::CODEPOINTS_BIT_2.bits |
| | Self::IGNORED.bits |
| | Self::RESERVED.bits, |
| } |
| } |
| |
| /// Returns the raw value of the flags currently stored. |
| #[inline] |
| pub const fn bits(&self) -> u8 { |
| self.bits |
| } |
| |
| /// Convert from underlying bit representation, unless that |
| /// representation contains bits that do not correspond to a flag. |
| #[inline] |
| pub const fn from_bits(bits: u8) -> Option<Self> { |
| if (bits & !Self::all().bits()) == 0 { |
| Some(Self { bits }) |
| } else { |
| None |
| } |
| } |
| |
| /// Convert from underlying bit representation, dropping any bits |
| /// that do not correspond to flags. |
| #[inline] |
| pub const fn from_bits_truncate(bits: u8) -> Self { |
| Self { |
| bits: bits & Self::all().bits, |
| } |
| } |
| |
| /// Returns `true` if no flags are currently stored. |
| #[inline] |
| pub const fn is_empty(&self) -> bool { |
| self.bits() == Self::empty().bits() |
| } |
| |
| /// Returns `true` if there are flags common to both `self` and `other`. |
| #[inline] |
| pub const fn intersects(&self, other: Self) -> bool { |
| !(Self { |
| bits: self.bits & other.bits, |
| }) |
| .is_empty() |
| } |
| |
| /// Returns `true` if all of the flags in `other` are contained within `self`. |
| #[inline] |
| pub const fn contains(&self, other: Self) -> bool { |
| (self.bits & other.bits) == other.bits |
| } |
| |
| /// Inserts the specified flags in-place. |
| #[inline] |
| pub fn insert(&mut self, other: Self) { |
| self.bits |= other.bits; |
| } |
| |
| /// Removes the specified flags in-place. |
| #[inline] |
| pub fn remove(&mut self, other: Self) { |
| self.bits &= !other.bits; |
| } |
| |
| /// Toggles the specified flags in-place. |
| #[inline] |
| pub fn toggle(&mut self, other: Self) { |
| self.bits ^= other.bits; |
| } |
| |
| /// Returns the intersection between the flags in `self` and |
| /// `other`. |
| /// |
| /// Specifically, the returned set contains only the flags which are |
| /// present in *both* `self` *and* `other`. |
| /// |
| /// This is equivalent to using the `&` operator (e.g. |
| /// [`ops::BitAnd`]), as in `flags & other`. |
| /// |
| /// [`ops::BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html |
| #[inline] |
| #[must_use] |
| pub const fn intersection(self, other: Self) -> Self { |
| Self { |
| bits: self.bits & other.bits, |
| } |
| } |
| |
| /// Returns the union of between the flags in `self` and `other`. |
| /// |
| /// Specifically, the returned set contains all flags which are |
| /// present in *either* `self` *or* `other`, including any which are |
| /// present in both. |
| /// |
| /// This is equivalent to using the `|` operator (e.g. |
| /// [`ops::BitOr`]), as in `flags | other`. |
| /// |
| /// [`ops::BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html |
| #[inline] |
| #[must_use] |
| pub const fn union(self, other: Self) -> Self { |
| Self { |
| bits: self.bits | other.bits, |
| } |
| } |
| |
| /// Returns the difference between the flags in `self` and `other`. |
| /// |
| /// Specifically, the returned set contains all flags present in |
| /// `self`, except for the ones present in `other`. |
| /// |
| /// It is also conceptually equivalent to the "bit-clear" operation: |
| /// `flags & !other` (and this syntax is also supported). |
| /// |
| /// This is equivalent to using the `-` operator (e.g. |
| /// [`ops::Sub`]), as in `flags - other`. |
| /// |
| /// [`ops::Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html |
| #[inline] |
| #[must_use] |
| pub const fn difference(self, other: Self) -> Self { |
| Self { |
| bits: self.bits & !other.bits, |
| } |
| } |
| } |
| |
| impl std::ops::BitOr for EntryFormatFlags { |
| type Output = Self; |
| |
| /// Returns the union of the two sets of flags. |
| #[inline] |
| fn bitor(self, other: EntryFormatFlags) -> Self { |
| Self { |
| bits: self.bits | other.bits, |
| } |
| } |
| } |
| |
| impl std::ops::BitOrAssign for EntryFormatFlags { |
| /// Adds the set of flags. |
| #[inline] |
| fn bitor_assign(&mut self, other: Self) { |
| self.bits |= other.bits; |
| } |
| } |
| |
| impl std::ops::BitXor for EntryFormatFlags { |
| type Output = Self; |
| |
| /// Returns the left flags, but with all the right flags toggled. |
| #[inline] |
| fn bitxor(self, other: Self) -> Self { |
| Self { |
| bits: self.bits ^ other.bits, |
| } |
| } |
| } |
| |
| impl std::ops::BitXorAssign for EntryFormatFlags { |
| /// Toggles the set of flags. |
| #[inline] |
| fn bitxor_assign(&mut self, other: Self) { |
| self.bits ^= other.bits; |
| } |
| } |
| |
| impl std::ops::BitAnd for EntryFormatFlags { |
| type Output = Self; |
| |
| /// Returns the intersection between the two sets of flags. |
| #[inline] |
| fn bitand(self, other: Self) -> Self { |
| Self { |
| bits: self.bits & other.bits, |
| } |
| } |
| } |
| |
| impl std::ops::BitAndAssign for EntryFormatFlags { |
| /// Disables all flags disabled in the set. |
| #[inline] |
| fn bitand_assign(&mut self, other: Self) { |
| self.bits &= other.bits; |
| } |
| } |
| |
| impl std::ops::Sub for EntryFormatFlags { |
| type Output = Self; |
| |
| /// Returns the set difference of the two sets of flags. |
| #[inline] |
| fn sub(self, other: Self) -> Self { |
| Self { |
| bits: self.bits & !other.bits, |
| } |
| } |
| } |
| |
| impl std::ops::SubAssign for EntryFormatFlags { |
| /// Disables all flags enabled in the set. |
| #[inline] |
| fn sub_assign(&mut self, other: Self) { |
| self.bits &= !other.bits; |
| } |
| } |
| |
| impl std::ops::Not for EntryFormatFlags { |
| type Output = Self; |
| |
| /// Returns the complement of this set of flags. |
| #[inline] |
| fn not(self) -> Self { |
| Self { bits: !self.bits } & Self::all() |
| } |
| } |
| |
| impl std::fmt::Debug for EntryFormatFlags { |
| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
| let members: &[(&str, Self)] = &[ |
| ("FEATURES_AND_DESIGN_SPACE", Self::FEATURES_AND_DESIGN_SPACE), |
| ("CHILD_INDICES", Self::CHILD_INDICES), |
| ("ENTRY_ID_DELTA", Self::ENTRY_ID_DELTA), |
| ("PATCH_FORMAT", Self::PATCH_FORMAT), |
| ("CODEPOINTS_BIT_1", Self::CODEPOINTS_BIT_1), |
| ("CODEPOINTS_BIT_2", Self::CODEPOINTS_BIT_2), |
| ("IGNORED", Self::IGNORED), |
| ("RESERVED", Self::RESERVED), |
| ]; |
| let mut first = true; |
| for (name, value) in members { |
| if self.contains(*value) { |
| if !first { |
| f.write_str(" | ")?; |
| } |
| first = false; |
| f.write_str(name)?; |
| } |
| } |
| if first { |
| f.write_str("(empty)")?; |
| } |
| Ok(()) |
| } |
| } |
| |
| impl std::fmt::Binary for EntryFormatFlags { |
| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
| std::fmt::Binary::fmt(&self.bits, f) |
| } |
| } |
| |
| impl std::fmt::Octal for EntryFormatFlags { |
| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
| std::fmt::Octal::fmt(&self.bits, f) |
| } |
| } |
| |
| impl std::fmt::LowerHex for EntryFormatFlags { |
| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
| std::fmt::LowerHex::fmt(&self.bits, f) |
| } |
| } |
| |
| impl std::fmt::UpperHex for EntryFormatFlags { |
| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
| std::fmt::UpperHex::fmt(&self.bits, f) |
| } |
| } |
| |
| impl font_types::Scalar for EntryFormatFlags { |
| type Raw = <u8 as font_types::Scalar>::Raw; |
| fn to_raw(self) -> Self::Raw { |
| self.bits().to_raw() |
| } |
| fn from_raw(raw: Self::Raw) -> Self { |
| let t = <u8>::from_raw(raw); |
| Self::from_bits_truncate(t) |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> From<EntryFormatFlags> for FieldType<'a> { |
| fn from(src: EntryFormatFlags) -> FieldType<'a> { |
| src.bits().into() |
| } |
| } |
| |
| #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)] |
| #[repr(C)] |
| #[repr(packed)] |
| pub struct DesignSpaceSegment { |
| pub axis_tag: BigEndian<Tag>, |
| pub start: BigEndian<Fixed>, |
| pub end: BigEndian<Fixed>, |
| } |
| |
| impl DesignSpaceSegment { |
| pub fn axis_tag(&self) -> Tag { |
| self.axis_tag.get() |
| } |
| |
| pub fn start(&self) -> Fixed { |
| self.start.get() |
| } |
| |
| pub fn end(&self) -> Fixed { |
| self.end.get() |
| } |
| } |
| |
| impl FixedSize for DesignSpaceSegment { |
| const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Fixed::RAW_BYTE_LEN + Fixed::RAW_BYTE_LEN; |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeRecord<'a> for DesignSpaceSegment { |
| fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> { |
| RecordResolver { |
| name: "DesignSpaceSegment", |
| get_field: Box::new(move |idx, _data| match idx { |
| 0usize => Some(Field::new("axis_tag", self.axis_tag())), |
| 1usize => Some(Field::new("start", self.start())), |
| 2usize => Some(Field::new("end", self.end())), |
| _ => None, |
| }), |
| data, |
| } |
| } |
| } |
| |
| #[derive(Debug, Clone, Copy)] |
| #[doc(hidden)] |
| pub struct IdStringDataMarker { |
| id_data_byte_len: usize, |
| } |
| |
| impl IdStringDataMarker { |
| pub fn id_data_byte_range(&self) -> Range<usize> { |
| let start = 0; |
| start..start + self.id_data_byte_len |
| } |
| } |
| |
| impl MinByteRange for IdStringDataMarker { |
| fn min_byte_range(&self) -> Range<usize> { |
| 0..self.id_data_byte_range().end |
| } |
| } |
| |
| impl<'a> FontRead<'a> for IdStringData<'a> { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| let mut cursor = data.cursor(); |
| let id_data_byte_len = cursor.remaining_bytes() / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN; |
| cursor.advance_by(id_data_byte_len); |
| cursor.finish(IdStringDataMarker { id_data_byte_len }) |
| } |
| } |
| |
| pub type IdStringData<'a> = TableRef<'a, IdStringDataMarker>; |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> IdStringData<'a> { |
| pub fn id_data(&self) -> &'a [u8] { |
| let range = self.shape.id_data_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeTable<'a> for IdStringData<'a> { |
| fn type_name(&self) -> &str { |
| "IdStringData" |
| } |
| fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
| match idx { |
| 0usize => Some(Field::new("id_data", self.id_data())), |
| _ => None, |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> std::fmt::Debug for IdStringData<'a> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| (self as &dyn SomeTable<'a>).fmt(f) |
| } |
| } |
| |
| /// [Table Keyed Patch](https://w3c.github.io/IFT/Overview.html#table-keyed) |
| #[derive(Debug, Clone, Copy)] |
| #[doc(hidden)] |
| pub struct TableKeyedPatchMarker { |
| patch_offsets_byte_len: usize, |
| } |
| |
| impl TableKeyedPatchMarker { |
| pub fn format_byte_range(&self) -> Range<usize> { |
| let start = 0; |
| start..start + Tag::RAW_BYTE_LEN |
| } |
| |
| pub fn _reserved_byte_range(&self) -> Range<usize> { |
| let start = self.format_byte_range().end; |
| start..start + u32::RAW_BYTE_LEN |
| } |
| |
| pub fn compatibility_id_byte_range(&self) -> Range<usize> { |
| let start = self._reserved_byte_range().end; |
| start..start + CompatibilityId::RAW_BYTE_LEN |
| } |
| |
| pub fn patches_count_byte_range(&self) -> Range<usize> { |
| let start = self.compatibility_id_byte_range().end; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn patch_offsets_byte_range(&self) -> Range<usize> { |
| let start = self.patches_count_byte_range().end; |
| start..start + self.patch_offsets_byte_len |
| } |
| } |
| |
| impl MinByteRange for TableKeyedPatchMarker { |
| fn min_byte_range(&self) -> Range<usize> { |
| 0..self.patch_offsets_byte_range().end |
| } |
| } |
| |
| impl<'a> FontRead<'a> for TableKeyedPatch<'a> { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| let mut cursor = data.cursor(); |
| cursor.advance::<Tag>(); |
| cursor.advance::<u32>(); |
| cursor.advance::<CompatibilityId>(); |
| let patches_count: u16 = cursor.read()?; |
| let patch_offsets_byte_len = (transforms::add(patches_count, 1_usize)) |
| .checked_mul(Offset32::RAW_BYTE_LEN) |
| .ok_or(ReadError::OutOfBounds)?; |
| cursor.advance_by(patch_offsets_byte_len); |
| cursor.finish(TableKeyedPatchMarker { |
| patch_offsets_byte_len, |
| }) |
| } |
| } |
| |
| /// [Table Keyed Patch](https://w3c.github.io/IFT/Overview.html#table-keyed) |
| pub type TableKeyedPatch<'a> = TableRef<'a, TableKeyedPatchMarker>; |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> TableKeyedPatch<'a> { |
| pub fn format(&self) -> Tag { |
| let range = self.shape.format_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Unique ID that identifies compatible patches. |
| pub fn compatibility_id(&self) -> CompatibilityId { |
| let range = self.shape.compatibility_id_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| pub fn patches_count(&self) -> u16 { |
| let range = self.shape.patches_count_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| pub fn patch_offsets(&self) -> &'a [BigEndian<Offset32>] { |
| let range = self.shape.patch_offsets_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| |
| /// A dynamically resolving wrapper for [`patch_offsets`][Self::patch_offsets]. |
| pub fn patches(&self) -> ArrayOfOffsets<'a, TablePatch<'a>, Offset32> { |
| let data = self.data; |
| let offsets = self.patch_offsets(); |
| ArrayOfOffsets::new(offsets, data, ()) |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeTable<'a> for TableKeyedPatch<'a> { |
| fn type_name(&self) -> &str { |
| "TableKeyedPatch" |
| } |
| fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
| match idx { |
| 0usize => Some(Field::new("format", self.format())), |
| 1usize => Some(Field::new( |
| "compatibility_id", |
| traversal::FieldType::Unknown, |
| )), |
| 2usize => Some(Field::new("patches_count", self.patches_count())), |
| 3usize => Some({ |
| let data = self.data; |
| Field::new( |
| "patch_offsets", |
| FieldType::array_of_offsets( |
| better_type_name::<TablePatch>(), |
| self.patch_offsets(), |
| move |off| { |
| let target = off.get().resolve::<TablePatch>(data); |
| FieldType::offset(off.get(), target) |
| }, |
| ), |
| ) |
| }), |
| _ => None, |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> std::fmt::Debug for TableKeyedPatch<'a> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| (self as &dyn SomeTable<'a>).fmt(f) |
| } |
| } |
| |
| /// [TablePatch](https://w3c.github.io/IFT/Overview.html#tablepatch) |
| #[derive(Debug, Clone, Copy)] |
| #[doc(hidden)] |
| pub struct TablePatchMarker { |
| brotli_stream_byte_len: usize, |
| } |
| |
| impl TablePatchMarker { |
| pub fn tag_byte_range(&self) -> Range<usize> { |
| let start = 0; |
| start..start + Tag::RAW_BYTE_LEN |
| } |
| |
| pub fn flags_byte_range(&self) -> Range<usize> { |
| let start = self.tag_byte_range().end; |
| start..start + TablePatchFlags::RAW_BYTE_LEN |
| } |
| |
| pub fn max_uncompressed_length_byte_range(&self) -> Range<usize> { |
| let start = self.flags_byte_range().end; |
| start..start + u32::RAW_BYTE_LEN |
| } |
| |
| pub fn brotli_stream_byte_range(&self) -> Range<usize> { |
| let start = self.max_uncompressed_length_byte_range().end; |
| start..start + self.brotli_stream_byte_len |
| } |
| } |
| |
| impl MinByteRange for TablePatchMarker { |
| fn min_byte_range(&self) -> Range<usize> { |
| 0..self.brotli_stream_byte_range().end |
| } |
| } |
| |
| impl<'a> FontRead<'a> for TablePatch<'a> { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| let mut cursor = data.cursor(); |
| cursor.advance::<Tag>(); |
| cursor.advance::<TablePatchFlags>(); |
| cursor.advance::<u32>(); |
| let brotli_stream_byte_len = cursor.remaining_bytes() / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN; |
| cursor.advance_by(brotli_stream_byte_len); |
| cursor.finish(TablePatchMarker { |
| brotli_stream_byte_len, |
| }) |
| } |
| } |
| |
| /// [TablePatch](https://w3c.github.io/IFT/Overview.html#tablepatch) |
| pub type TablePatch<'a> = TableRef<'a, TablePatchMarker>; |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> TablePatch<'a> { |
| pub fn tag(&self) -> Tag { |
| let range = self.shape.tag_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| pub fn flags(&self) -> TablePatchFlags { |
| let range = self.shape.flags_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| pub fn max_uncompressed_length(&self) -> u32 { |
| let range = self.shape.max_uncompressed_length_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| pub fn brotli_stream(&self) -> &'a [u8] { |
| let range = self.shape.brotli_stream_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeTable<'a> for TablePatch<'a> { |
| fn type_name(&self) -> &str { |
| "TablePatch" |
| } |
| fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
| match idx { |
| 0usize => Some(Field::new("tag", self.tag())), |
| 1usize => Some(Field::new("flags", self.flags())), |
| 2usize => Some(Field::new( |
| "max_uncompressed_length", |
| self.max_uncompressed_length(), |
| )), |
| 3usize => Some(Field::new("brotli_stream", self.brotli_stream())), |
| _ => None, |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> std::fmt::Debug for TablePatch<'a> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| (self as &dyn SomeTable<'a>).fmt(f) |
| } |
| } |
| |
| #[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, bytemuck :: AnyBitPattern)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| #[repr(transparent)] |
| pub struct TablePatchFlags { |
| bits: u8, |
| } |
| |
| impl TablePatchFlags { |
| pub const REPLACE_TABLE: Self = Self { bits: 0b01 }; |
| |
| pub const DROP_TABLE: Self = Self { bits: 0b10 }; |
| } |
| |
| impl TablePatchFlags { |
| /// Returns an empty set of flags. |
| #[inline] |
| pub const fn empty() -> Self { |
| Self { bits: 0 } |
| } |
| |
| /// Returns the set containing all flags. |
| #[inline] |
| pub const fn all() -> Self { |
| Self { |
| bits: Self::REPLACE_TABLE.bits | Self::DROP_TABLE.bits, |
| } |
| } |
| |
| /// Returns the raw value of the flags currently stored. |
| #[inline] |
| pub const fn bits(&self) -> u8 { |
| self.bits |
| } |
| |
| /// Convert from underlying bit representation, unless that |
| /// representation contains bits that do not correspond to a flag. |
| #[inline] |
| pub const fn from_bits(bits: u8) -> Option<Self> { |
| if (bits & !Self::all().bits()) == 0 { |
| Some(Self { bits }) |
| } else { |
| None |
| } |
| } |
| |
| /// Convert from underlying bit representation, dropping any bits |
| /// that do not correspond to flags. |
| #[inline] |
| pub const fn from_bits_truncate(bits: u8) -> Self { |
| Self { |
| bits: bits & Self::all().bits, |
| } |
| } |
| |
| /// Returns `true` if no flags are currently stored. |
| #[inline] |
| pub const fn is_empty(&self) -> bool { |
| self.bits() == Self::empty().bits() |
| } |
| |
| /// Returns `true` if there are flags common to both `self` and `other`. |
| #[inline] |
| pub const fn intersects(&self, other: Self) -> bool { |
| !(Self { |
| bits: self.bits & other.bits, |
| }) |
| .is_empty() |
| } |
| |
| /// Returns `true` if all of the flags in `other` are contained within `self`. |
| #[inline] |
| pub const fn contains(&self, other: Self) -> bool { |
| (self.bits & other.bits) == other.bits |
| } |
| |
| /// Inserts the specified flags in-place. |
| #[inline] |
| pub fn insert(&mut self, other: Self) { |
| self.bits |= other.bits; |
| } |
| |
| /// Removes the specified flags in-place. |
| #[inline] |
| pub fn remove(&mut self, other: Self) { |
| self.bits &= !other.bits; |
| } |
| |
| /// Toggles the specified flags in-place. |
| #[inline] |
| pub fn toggle(&mut self, other: Self) { |
| self.bits ^= other.bits; |
| } |
| |
| /// Returns the intersection between the flags in `self` and |
| /// `other`. |
| /// |
| /// Specifically, the returned set contains only the flags which are |
| /// present in *both* `self` *and* `other`. |
| /// |
| /// This is equivalent to using the `&` operator (e.g. |
| /// [`ops::BitAnd`]), as in `flags & other`. |
| /// |
| /// [`ops::BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html |
| #[inline] |
| #[must_use] |
| pub const fn intersection(self, other: Self) -> Self { |
| Self { |
| bits: self.bits & other.bits, |
| } |
| } |
| |
| /// Returns the union of between the flags in `self` and `other`. |
| /// |
| /// Specifically, the returned set contains all flags which are |
| /// present in *either* `self` *or* `other`, including any which are |
| /// present in both. |
| /// |
| /// This is equivalent to using the `|` operator (e.g. |
| /// [`ops::BitOr`]), as in `flags | other`. |
| /// |
| /// [`ops::BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html |
| #[inline] |
| #[must_use] |
| pub const fn union(self, other: Self) -> Self { |
| Self { |
| bits: self.bits | other.bits, |
| } |
| } |
| |
| /// Returns the difference between the flags in `self` and `other`. |
| /// |
| /// Specifically, the returned set contains all flags present in |
| /// `self`, except for the ones present in `other`. |
| /// |
| /// It is also conceptually equivalent to the "bit-clear" operation: |
| /// `flags & !other` (and this syntax is also supported). |
| /// |
| /// This is equivalent to using the `-` operator (e.g. |
| /// [`ops::Sub`]), as in `flags - other`. |
| /// |
| /// [`ops::Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html |
| #[inline] |
| #[must_use] |
| pub const fn difference(self, other: Self) -> Self { |
| Self { |
| bits: self.bits & !other.bits, |
| } |
| } |
| } |
| |
| impl std::ops::BitOr for TablePatchFlags { |
| type Output = Self; |
| |
| /// Returns the union of the two sets of flags. |
| #[inline] |
| fn bitor(self, other: TablePatchFlags) -> Self { |
| Self { |
| bits: self.bits | other.bits, |
| } |
| } |
| } |
| |
| impl std::ops::BitOrAssign for TablePatchFlags { |
| /// Adds the set of flags. |
| #[inline] |
| fn bitor_assign(&mut self, other: Self) { |
| self.bits |= other.bits; |
| } |
| } |
| |
| impl std::ops::BitXor for TablePatchFlags { |
| type Output = Self; |
| |
| /// Returns the left flags, but with all the right flags toggled. |
| #[inline] |
| fn bitxor(self, other: Self) -> Self { |
| Self { |
| bits: self.bits ^ other.bits, |
| } |
| } |
| } |
| |
| impl std::ops::BitXorAssign for TablePatchFlags { |
| /// Toggles the set of flags. |
| #[inline] |
| fn bitxor_assign(&mut self, other: Self) { |
| self.bits ^= other.bits; |
| } |
| } |
| |
| impl std::ops::BitAnd for TablePatchFlags { |
| type Output = Self; |
| |
| /// Returns the intersection between the two sets of flags. |
| #[inline] |
| fn bitand(self, other: Self) -> Self { |
| Self { |
| bits: self.bits & other.bits, |
| } |
| } |
| } |
| |
| impl std::ops::BitAndAssign for TablePatchFlags { |
| /// Disables all flags disabled in the set. |
| #[inline] |
| fn bitand_assign(&mut self, other: Self) { |
| self.bits &= other.bits; |
| } |
| } |
| |
| impl std::ops::Sub for TablePatchFlags { |
| type Output = Self; |
| |
| /// Returns the set difference of the two sets of flags. |
| #[inline] |
| fn sub(self, other: Self) -> Self { |
| Self { |
| bits: self.bits & !other.bits, |
| } |
| } |
| } |
| |
| impl std::ops::SubAssign for TablePatchFlags { |
| /// Disables all flags enabled in the set. |
| #[inline] |
| fn sub_assign(&mut self, other: Self) { |
| self.bits &= !other.bits; |
| } |
| } |
| |
| impl std::ops::Not for TablePatchFlags { |
| type Output = Self; |
| |
| /// Returns the complement of this set of flags. |
| #[inline] |
| fn not(self) -> Self { |
| Self { bits: !self.bits } & Self::all() |
| } |
| } |
| |
| impl std::fmt::Debug for TablePatchFlags { |
| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
| let members: &[(&str, Self)] = &[ |
| ("REPLACE_TABLE", Self::REPLACE_TABLE), |
| ("DROP_TABLE", Self::DROP_TABLE), |
| ]; |
| let mut first = true; |
| for (name, value) in members { |
| if self.contains(*value) { |
| if !first { |
| f.write_str(" | ")?; |
| } |
| first = false; |
| f.write_str(name)?; |
| } |
| } |
| if first { |
| f.write_str("(empty)")?; |
| } |
| Ok(()) |
| } |
| } |
| |
| impl std::fmt::Binary for TablePatchFlags { |
| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
| std::fmt::Binary::fmt(&self.bits, f) |
| } |
| } |
| |
| impl std::fmt::Octal for TablePatchFlags { |
| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
| std::fmt::Octal::fmt(&self.bits, f) |
| } |
| } |
| |
| impl std::fmt::LowerHex for TablePatchFlags { |
| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
| std::fmt::LowerHex::fmt(&self.bits, f) |
| } |
| } |
| |
| impl std::fmt::UpperHex for TablePatchFlags { |
| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
| std::fmt::UpperHex::fmt(&self.bits, f) |
| } |
| } |
| |
| impl font_types::Scalar for TablePatchFlags { |
| type Raw = <u8 as font_types::Scalar>::Raw; |
| fn to_raw(self) -> Self::Raw { |
| self.bits().to_raw() |
| } |
| fn from_raw(raw: Self::Raw) -> Self { |
| let t = <u8>::from_raw(raw); |
| Self::from_bits_truncate(t) |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> From<TablePatchFlags> for FieldType<'a> { |
| fn from(src: TablePatchFlags) -> FieldType<'a> { |
| src.bits().into() |
| } |
| } |
| |
| /// [Glyph Keyed Patch](https://w3c.github.io/IFT/Overview.html#glyph-keyed) |
| #[derive(Debug, Clone, Copy)] |
| #[doc(hidden)] |
| pub struct GlyphKeyedPatchMarker { |
| brotli_stream_byte_len: usize, |
| } |
| |
| impl GlyphKeyedPatchMarker { |
| pub fn format_byte_range(&self) -> Range<usize> { |
| let start = 0; |
| start..start + Tag::RAW_BYTE_LEN |
| } |
| |
| pub fn _reserved_byte_range(&self) -> Range<usize> { |
| let start = self.format_byte_range().end; |
| start..start + u32::RAW_BYTE_LEN |
| } |
| |
| pub fn flags_byte_range(&self) -> Range<usize> { |
| let start = self._reserved_byte_range().end; |
| start..start + GlyphKeyedFlags::RAW_BYTE_LEN |
| } |
| |
| pub fn compatibility_id_byte_range(&self) -> Range<usize> { |
| let start = self.flags_byte_range().end; |
| start..start + CompatibilityId::RAW_BYTE_LEN |
| } |
| |
| pub fn max_uncompressed_length_byte_range(&self) -> Range<usize> { |
| let start = self.compatibility_id_byte_range().end; |
| start..start + u32::RAW_BYTE_LEN |
| } |
| |
| pub fn brotli_stream_byte_range(&self) -> Range<usize> { |
| let start = self.max_uncompressed_length_byte_range().end; |
| start..start + self.brotli_stream_byte_len |
| } |
| } |
| |
| impl MinByteRange for GlyphKeyedPatchMarker { |
| fn min_byte_range(&self) -> Range<usize> { |
| 0..self.brotli_stream_byte_range().end |
| } |
| } |
| |
| impl<'a> FontRead<'a> for GlyphKeyedPatch<'a> { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| let mut cursor = data.cursor(); |
| cursor.advance::<Tag>(); |
| cursor.advance::<u32>(); |
| cursor.advance::<GlyphKeyedFlags>(); |
| cursor.advance::<CompatibilityId>(); |
| cursor.advance::<u32>(); |
| let brotli_stream_byte_len = cursor.remaining_bytes() / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN; |
| cursor.advance_by(brotli_stream_byte_len); |
| cursor.finish(GlyphKeyedPatchMarker { |
| brotli_stream_byte_len, |
| }) |
| } |
| } |
| |
| /// [Glyph Keyed Patch](https://w3c.github.io/IFT/Overview.html#glyph-keyed) |
| pub type GlyphKeyedPatch<'a> = TableRef<'a, GlyphKeyedPatchMarker>; |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> GlyphKeyedPatch<'a> { |
| pub fn format(&self) -> Tag { |
| let range = self.shape.format_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| pub fn flags(&self) -> GlyphKeyedFlags { |
| let range = self.shape.flags_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| pub fn compatibility_id(&self) -> CompatibilityId { |
| let range = self.shape.compatibility_id_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| pub fn max_uncompressed_length(&self) -> u32 { |
| let range = self.shape.max_uncompressed_length_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| pub fn brotli_stream(&self) -> &'a [u8] { |
| let range = self.shape.brotli_stream_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeTable<'a> for GlyphKeyedPatch<'a> { |
| fn type_name(&self) -> &str { |
| "GlyphKeyedPatch" |
| } |
| fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
| match idx { |
| 0usize => Some(Field::new("format", self.format())), |
| 1usize => Some(Field::new("flags", self.flags())), |
| 2usize => Some(Field::new( |
| "compatibility_id", |
| traversal::FieldType::Unknown, |
| )), |
| 3usize => Some(Field::new( |
| "max_uncompressed_length", |
| self.max_uncompressed_length(), |
| )), |
| 4usize => Some(Field::new("brotli_stream", self.brotli_stream())), |
| _ => None, |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> std::fmt::Debug for GlyphKeyedPatch<'a> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| (self as &dyn SomeTable<'a>).fmt(f) |
| } |
| } |
| |
| #[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, bytemuck :: AnyBitPattern)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| #[repr(transparent)] |
| pub struct GlyphKeyedFlags { |
| bits: u8, |
| } |
| |
| impl GlyphKeyedFlags { |
| pub const NONE: Self = Self { bits: 0b0 }; |
| |
| pub const WIDE_GLYPH_IDS: Self = Self { bits: 0b1 }; |
| } |
| |
| impl GlyphKeyedFlags { |
| /// Returns an empty set of flags. |
| #[inline] |
| pub const fn empty() -> Self { |
| Self { bits: 0 } |
| } |
| |
| /// Returns the set containing all flags. |
| #[inline] |
| pub const fn all() -> Self { |
| Self { |
| bits: Self::NONE.bits | Self::WIDE_GLYPH_IDS.bits, |
| } |
| } |
| |
| /// Returns the raw value of the flags currently stored. |
| #[inline] |
| pub const fn bits(&self) -> u8 { |
| self.bits |
| } |
| |
| /// Convert from underlying bit representation, unless that |
| /// representation contains bits that do not correspond to a flag. |
| #[inline] |
| pub const fn from_bits(bits: u8) -> Option<Self> { |
| if (bits & !Self::all().bits()) == 0 { |
| Some(Self { bits }) |
| } else { |
| None |
| } |
| } |
| |
| /// Convert from underlying bit representation, dropping any bits |
| /// that do not correspond to flags. |
| #[inline] |
| pub const fn from_bits_truncate(bits: u8) -> Self { |
| Self { |
| bits: bits & Self::all().bits, |
| } |
| } |
| |
| /// Returns `true` if no flags are currently stored. |
| #[inline] |
| pub const fn is_empty(&self) -> bool { |
| self.bits() == Self::empty().bits() |
| } |
| |
| /// Returns `true` if there are flags common to both `self` and `other`. |
| #[inline] |
| pub const fn intersects(&self, other: Self) -> bool { |
| !(Self { |
| bits: self.bits & other.bits, |
| }) |
| .is_empty() |
| } |
| |
| /// Returns `true` if all of the flags in `other` are contained within `self`. |
| #[inline] |
| pub const fn contains(&self, other: Self) -> bool { |
| (self.bits & other.bits) == other.bits |
| } |
| |
| /// Inserts the specified flags in-place. |
| #[inline] |
| pub fn insert(&mut self, other: Self) { |
| self.bits |= other.bits; |
| } |
| |
| /// Removes the specified flags in-place. |
| #[inline] |
| pub fn remove(&mut self, other: Self) { |
| self.bits &= !other.bits; |
| } |
| |
| /// Toggles the specified flags in-place. |
| #[inline] |
| pub fn toggle(&mut self, other: Self) { |
| self.bits ^= other.bits; |
| } |
| |
| /// Returns the intersection between the flags in `self` and |
| /// `other`. |
| /// |
| /// Specifically, the returned set contains only the flags which are |
| /// present in *both* `self` *and* `other`. |
| /// |
| /// This is equivalent to using the `&` operator (e.g. |
| /// [`ops::BitAnd`]), as in `flags & other`. |
| /// |
| /// [`ops::BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html |
| #[inline] |
| #[must_use] |
| pub const fn intersection(self, other: Self) -> Self { |
| Self { |
| bits: self.bits & other.bits, |
| } |
| } |
| |
| /// Returns the union of between the flags in `self` and `other`. |
| /// |
| /// Specifically, the returned set contains all flags which are |
| /// present in *either* `self` *or* `other`, including any which are |
| /// present in both. |
| /// |
| /// This is equivalent to using the `|` operator (e.g. |
| /// [`ops::BitOr`]), as in `flags | other`. |
| /// |
| /// [`ops::BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html |
| #[inline] |
| #[must_use] |
| pub const fn union(self, other: Self) -> Self { |
| Self { |
| bits: self.bits | other.bits, |
| } |
| } |
| |
| /// Returns the difference between the flags in `self` and `other`. |
| /// |
| /// Specifically, the returned set contains all flags present in |
| /// `self`, except for the ones present in `other`. |
| /// |
| /// It is also conceptually equivalent to the "bit-clear" operation: |
| /// `flags & !other` (and this syntax is also supported). |
| /// |
| /// This is equivalent to using the `-` operator (e.g. |
| /// [`ops::Sub`]), as in `flags - other`. |
| /// |
| /// [`ops::Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html |
| #[inline] |
| #[must_use] |
| pub const fn difference(self, other: Self) -> Self { |
| Self { |
| bits: self.bits & !other.bits, |
| } |
| } |
| } |
| |
| impl std::ops::BitOr for GlyphKeyedFlags { |
| type Output = Self; |
| |
| /// Returns the union of the two sets of flags. |
| #[inline] |
| fn bitor(self, other: GlyphKeyedFlags) -> Self { |
| Self { |
| bits: self.bits | other.bits, |
| } |
| } |
| } |
| |
| impl std::ops::BitOrAssign for GlyphKeyedFlags { |
| /// Adds the set of flags. |
| #[inline] |
| fn bitor_assign(&mut self, other: Self) { |
| self.bits |= other.bits; |
| } |
| } |
| |
| impl std::ops::BitXor for GlyphKeyedFlags { |
| type Output = Self; |
| |
| /// Returns the left flags, but with all the right flags toggled. |
| #[inline] |
| fn bitxor(self, other: Self) -> Self { |
| Self { |
| bits: self.bits ^ other.bits, |
| } |
| } |
| } |
| |
| impl std::ops::BitXorAssign for GlyphKeyedFlags { |
| /// Toggles the set of flags. |
| #[inline] |
| fn bitxor_assign(&mut self, other: Self) { |
| self.bits ^= other.bits; |
| } |
| } |
| |
| impl std::ops::BitAnd for GlyphKeyedFlags { |
| type Output = Self; |
| |
| /// Returns the intersection between the two sets of flags. |
| #[inline] |
| fn bitand(self, other: Self) -> Self { |
| Self { |
| bits: self.bits & other.bits, |
| } |
| } |
| } |
| |
| impl std::ops::BitAndAssign for GlyphKeyedFlags { |
| /// Disables all flags disabled in the set. |
| #[inline] |
| fn bitand_assign(&mut self, other: Self) { |
| self.bits &= other.bits; |
| } |
| } |
| |
| impl std::ops::Sub for GlyphKeyedFlags { |
| type Output = Self; |
| |
| /// Returns the set difference of the two sets of flags. |
| #[inline] |
| fn sub(self, other: Self) -> Self { |
| Self { |
| bits: self.bits & !other.bits, |
| } |
| } |
| } |
| |
| impl std::ops::SubAssign for GlyphKeyedFlags { |
| /// Disables all flags enabled in the set. |
| #[inline] |
| fn sub_assign(&mut self, other: Self) { |
| self.bits &= !other.bits; |
| } |
| } |
| |
| impl std::ops::Not for GlyphKeyedFlags { |
| type Output = Self; |
| |
| /// Returns the complement of this set of flags. |
| #[inline] |
| fn not(self) -> Self { |
| Self { bits: !self.bits } & Self::all() |
| } |
| } |
| |
| impl std::fmt::Debug for GlyphKeyedFlags { |
| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
| let members: &[(&str, Self)] = &[ |
| ("NONE", Self::NONE), |
| ("WIDE_GLYPH_IDS", Self::WIDE_GLYPH_IDS), |
| ]; |
| let mut first = true; |
| for (name, value) in members { |
| if self.contains(*value) { |
| if !first { |
| f.write_str(" | ")?; |
| } |
| first = false; |
| f.write_str(name)?; |
| } |
| } |
| if first { |
| f.write_str("(empty)")?; |
| } |
| Ok(()) |
| } |
| } |
| |
| impl std::fmt::Binary for GlyphKeyedFlags { |
| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
| std::fmt::Binary::fmt(&self.bits, f) |
| } |
| } |
| |
| impl std::fmt::Octal for GlyphKeyedFlags { |
| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
| std::fmt::Octal::fmt(&self.bits, f) |
| } |
| } |
| |
| impl std::fmt::LowerHex for GlyphKeyedFlags { |
| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
| std::fmt::LowerHex::fmt(&self.bits, f) |
| } |
| } |
| |
| impl std::fmt::UpperHex for GlyphKeyedFlags { |
| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
| std::fmt::UpperHex::fmt(&self.bits, f) |
| } |
| } |
| |
| impl font_types::Scalar for GlyphKeyedFlags { |
| type Raw = <u8 as font_types::Scalar>::Raw; |
| fn to_raw(self) -> Self::Raw { |
| self.bits().to_raw() |
| } |
| fn from_raw(raw: Self::Raw) -> Self { |
| let t = <u8>::from_raw(raw); |
| Self::from_bits_truncate(t) |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> From<GlyphKeyedFlags> for FieldType<'a> { |
| fn from(src: GlyphKeyedFlags) -> FieldType<'a> { |
| src.bits().into() |
| } |
| } |
| |
| /// [GlyphPatches](https://w3c.github.io/IFT/Overview.html#glyphpatches) |
| #[derive(Debug, Clone, Copy)] |
| #[doc(hidden)] |
| pub struct GlyphPatchesMarker { |
| flags: GlyphKeyedFlags, |
| glyph_ids_byte_len: usize, |
| tables_byte_len: usize, |
| glyph_data_offsets_byte_len: usize, |
| } |
| |
| impl GlyphPatchesMarker { |
| pub fn glyph_count_byte_range(&self) -> Range<usize> { |
| let start = 0; |
| start..start + u32::RAW_BYTE_LEN |
| } |
| |
| pub fn table_count_byte_range(&self) -> Range<usize> { |
| let start = self.glyph_count_byte_range().end; |
| start..start + u8::RAW_BYTE_LEN |
| } |
| |
| pub fn glyph_ids_byte_range(&self) -> Range<usize> { |
| let start = self.table_count_byte_range().end; |
| start..start + self.glyph_ids_byte_len |
| } |
| |
| pub fn tables_byte_range(&self) -> Range<usize> { |
| let start = self.glyph_ids_byte_range().end; |
| start..start + self.tables_byte_len |
| } |
| |
| pub fn glyph_data_offsets_byte_range(&self) -> Range<usize> { |
| let start = self.tables_byte_range().end; |
| start..start + self.glyph_data_offsets_byte_len |
| } |
| } |
| |
| impl MinByteRange for GlyphPatchesMarker { |
| fn min_byte_range(&self) -> Range<usize> { |
| 0..self.glyph_data_offsets_byte_range().end |
| } |
| } |
| |
| impl ReadArgs for GlyphPatches<'_> { |
| type Args = GlyphKeyedFlags; |
| } |
| |
| impl<'a> FontReadWithArgs<'a> for GlyphPatches<'a> { |
| fn read_with_args(data: FontData<'a>, args: &GlyphKeyedFlags) -> Result<Self, ReadError> { |
| let flags = *args; |
| let mut cursor = data.cursor(); |
| let glyph_count: u32 = cursor.read()?; |
| let table_count: u8 = cursor.read()?; |
| let glyph_ids_byte_len = (glyph_count as usize) |
| .checked_mul(<U16Or24 as ComputeSize>::compute_size(&flags)?) |
| .ok_or(ReadError::OutOfBounds)?; |
| cursor.advance_by(glyph_ids_byte_len); |
| let tables_byte_len = (table_count as usize) |
| .checked_mul(Tag::RAW_BYTE_LEN) |
| .ok_or(ReadError::OutOfBounds)?; |
| cursor.advance_by(tables_byte_len); |
| let glyph_data_offsets_byte_len = |
| (transforms::multiply_add(glyph_count, table_count, 1_usize)) |
| .checked_mul(Offset32::RAW_BYTE_LEN) |
| .ok_or(ReadError::OutOfBounds)?; |
| cursor.advance_by(glyph_data_offsets_byte_len); |
| cursor.finish(GlyphPatchesMarker { |
| flags, |
| glyph_ids_byte_len, |
| tables_byte_len, |
| glyph_data_offsets_byte_len, |
| }) |
| } |
| } |
| |
| impl<'a> GlyphPatches<'a> { |
| /// A constructor that requires additional arguments. |
| /// |
| /// This type requires some external state in order to be |
| /// parsed. |
| pub fn read(data: FontData<'a>, flags: GlyphKeyedFlags) -> Result<Self, ReadError> { |
| let args = flags; |
| Self::read_with_args(data, &args) |
| } |
| } |
| |
| /// [GlyphPatches](https://w3c.github.io/IFT/Overview.html#glyphpatches) |
| pub type GlyphPatches<'a> = TableRef<'a, GlyphPatchesMarker>; |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> GlyphPatches<'a> { |
| pub fn glyph_count(&self) -> u32 { |
| let range = self.shape.glyph_count_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| pub fn table_count(&self) -> u8 { |
| let range = self.shape.table_count_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| pub fn glyph_ids(&self) -> ComputedArray<'a, U16Or24> { |
| let range = self.shape.glyph_ids_byte_range(); |
| self.data.read_with_args(range, &self.flags()).unwrap() |
| } |
| |
| pub fn tables(&self) -> &'a [BigEndian<Tag>] { |
| let range = self.shape.tables_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| |
| pub fn glyph_data_offsets(&self) -> &'a [BigEndian<Offset32>] { |
| let range = self.shape.glyph_data_offsets_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| |
| /// A dynamically resolving wrapper for [`glyph_data_offsets`][Self::glyph_data_offsets]. |
| pub fn glyph_data(&self) -> ArrayOfOffsets<'a, GlyphData<'a>, Offset32> { |
| let data = self.data; |
| let offsets = self.glyph_data_offsets(); |
| ArrayOfOffsets::new(offsets, data, ()) |
| } |
| |
| pub(crate) fn flags(&self) -> GlyphKeyedFlags { |
| self.shape.flags |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeTable<'a> for GlyphPatches<'a> { |
| fn type_name(&self) -> &str { |
| "GlyphPatches" |
| } |
| fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
| match idx { |
| 0usize => Some(Field::new("glyph_count", self.glyph_count())), |
| 1usize => Some(Field::new("table_count", self.table_count())), |
| 2usize => Some(Field::new("glyph_ids", traversal::FieldType::Unknown)), |
| 3usize => Some(Field::new("tables", self.tables())), |
| 4usize => Some({ |
| let data = self.data; |
| Field::new( |
| "glyph_data_offsets", |
| FieldType::array_of_offsets( |
| better_type_name::<GlyphData>(), |
| self.glyph_data_offsets(), |
| move |off| { |
| let target = off.get().resolve::<GlyphData>(data); |
| FieldType::offset(off.get(), target) |
| }, |
| ), |
| ) |
| }), |
| _ => None, |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> std::fmt::Debug for GlyphPatches<'a> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| (self as &dyn SomeTable<'a>).fmt(f) |
| } |
| } |
| |
| #[derive(Debug, Clone, Copy)] |
| #[doc(hidden)] |
| pub struct GlyphDataMarker { |
| data_byte_len: usize, |
| } |
| |
| impl GlyphDataMarker { |
| pub fn data_byte_range(&self) -> Range<usize> { |
| let start = 0; |
| start..start + self.data_byte_len |
| } |
| } |
| |
| impl MinByteRange for GlyphDataMarker { |
| fn min_byte_range(&self) -> Range<usize> { |
| 0..self.data_byte_range().end |
| } |
| } |
| |
| impl<'a> FontRead<'a> for GlyphData<'a> { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| let mut cursor = data.cursor(); |
| let data_byte_len = cursor.remaining_bytes() / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN; |
| cursor.advance_by(data_byte_len); |
| cursor.finish(GlyphDataMarker { data_byte_len }) |
| } |
| } |
| |
| pub type GlyphData<'a> = TableRef<'a, GlyphDataMarker>; |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> GlyphData<'a> { |
| pub fn data(&self) -> &'a [u8] { |
| let range = self.shape.data_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeTable<'a> for GlyphData<'a> { |
| fn type_name(&self) -> &str { |
| "GlyphData" |
| } |
| fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
| match idx { |
| 0usize => Some(Field::new("data", self.data())), |
| _ => None, |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> std::fmt::Debug for GlyphData<'a> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| (self as &dyn SomeTable<'a>).fmt(f) |
| } |
| } |