| // 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::*; |
| |
| /// [cmap](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#overview) |
| #[derive(Debug, Clone, Copy)] |
| #[doc(hidden)] |
| pub struct CmapMarker { |
| encoding_records_byte_len: usize, |
| } |
| |
| impl CmapMarker { |
| pub fn version_byte_range(&self) -> Range<usize> { |
| let start = 0; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn num_tables_byte_range(&self) -> Range<usize> { |
| let start = self.version_byte_range().end; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn encoding_records_byte_range(&self) -> Range<usize> { |
| let start = self.num_tables_byte_range().end; |
| start..start + self.encoding_records_byte_len |
| } |
| } |
| |
| impl MinByteRange for CmapMarker { |
| fn min_byte_range(&self) -> Range<usize> { |
| 0..self.encoding_records_byte_range().end |
| } |
| } |
| |
| impl TopLevelTable for Cmap<'_> { |
| /// `cmap` |
| const TAG: Tag = Tag::new(b"cmap"); |
| } |
| |
| impl<'a> FontRead<'a> for Cmap<'a> { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| let mut cursor = data.cursor(); |
| cursor.advance::<u16>(); |
| let num_tables: u16 = cursor.read()?; |
| let encoding_records_byte_len = (num_tables as usize) |
| .checked_mul(EncodingRecord::RAW_BYTE_LEN) |
| .ok_or(ReadError::OutOfBounds)?; |
| cursor.advance_by(encoding_records_byte_len); |
| cursor.finish(CmapMarker { |
| encoding_records_byte_len, |
| }) |
| } |
| } |
| |
| /// [cmap](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#overview) |
| pub type Cmap<'a> = TableRef<'a, CmapMarker>; |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> Cmap<'a> { |
| /// Table version number (0). |
| pub fn version(&self) -> u16 { |
| let range = self.shape.version_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Number of encoding tables that follow. |
| pub fn num_tables(&self) -> u16 { |
| let range = self.shape.num_tables_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| pub fn encoding_records(&self) -> &'a [EncodingRecord] { |
| let range = self.shape.encoding_records_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeTable<'a> for Cmap<'a> { |
| fn type_name(&self) -> &str { |
| "Cmap" |
| } |
| fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
| match idx { |
| 0usize => Some(Field::new("version", self.version())), |
| 1usize => Some(Field::new("num_tables", self.num_tables())), |
| 2usize => Some(Field::new( |
| "encoding_records", |
| traversal::FieldType::array_of_records( |
| stringify!(EncodingRecord), |
| self.encoding_records(), |
| self.offset_data(), |
| ), |
| )), |
| _ => None, |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> std::fmt::Debug for Cmap<'a> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| (self as &dyn SomeTable<'a>).fmt(f) |
| } |
| } |
| |
| /// [Encoding Record](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#encoding-records-and-encodings) |
| #[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)] |
| #[repr(C)] |
| #[repr(packed)] |
| pub struct EncodingRecord { |
| /// Platform ID. |
| pub platform_id: BigEndian<PlatformId>, |
| /// Platform-specific encoding ID. |
| pub encoding_id: BigEndian<u16>, |
| /// Byte offset from beginning of the [`Cmap`] table to the subtable for this |
| /// encoding. |
| pub subtable_offset: BigEndian<Offset32>, |
| } |
| |
| impl EncodingRecord { |
| /// Platform ID. |
| pub fn platform_id(&self) -> PlatformId { |
| self.platform_id.get() |
| } |
| |
| /// Platform-specific encoding ID. |
| pub fn encoding_id(&self) -> u16 { |
| self.encoding_id.get() |
| } |
| |
| /// Byte offset from beginning of the [`Cmap`] table to the subtable for this |
| /// encoding. |
| pub fn subtable_offset(&self) -> Offset32 { |
| self.subtable_offset.get() |
| } |
| |
| /// Byte offset from beginning of the [`Cmap`] table to the subtable for this |
| /// encoding. |
| /// |
| /// The `data` argument should be retrieved from the parent table |
| /// By calling its `offset_data` method. |
| pub fn subtable<'a>(&self, data: FontData<'a>) -> Result<CmapSubtable<'a>, ReadError> { |
| self.subtable_offset().resolve(data) |
| } |
| } |
| |
| impl FixedSize for EncodingRecord { |
| const RAW_BYTE_LEN: usize = |
| PlatformId::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN; |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeRecord<'a> for EncodingRecord { |
| fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> { |
| RecordResolver { |
| name: "EncodingRecord", |
| get_field: Box::new(move |idx, _data| match idx { |
| 0usize => Some(Field::new("platform_id", self.platform_id())), |
| 1usize => Some(Field::new("encoding_id", self.encoding_id())), |
| 2usize => Some(Field::new( |
| "subtable_offset", |
| FieldType::offset(self.subtable_offset(), self.subtable(_data)), |
| )), |
| _ => None, |
| }), |
| data, |
| } |
| } |
| } |
| |
| /// <https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#platform-ids> |
| #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)] |
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| #[repr(u16)] |
| #[allow(clippy::manual_non_exhaustive)] |
| pub enum PlatformId { |
| #[default] |
| Unicode = 0, |
| Macintosh = 1, |
| ISO = 2, |
| Windows = 3, |
| Custom = 4, |
| #[doc(hidden)] |
| /// If font data is malformed we will map unknown values to this variant |
| Unknown, |
| } |
| |
| impl PlatformId { |
| /// Create from a raw scalar. |
| /// |
| /// This will never fail; unknown values will be mapped to the `Unknown` variant |
| pub fn new(raw: u16) -> Self { |
| match raw { |
| 0 => Self::Unicode, |
| 1 => Self::Macintosh, |
| 2 => Self::ISO, |
| 3 => Self::Windows, |
| 4 => Self::Custom, |
| _ => Self::Unknown, |
| } |
| } |
| } |
| |
| impl font_types::Scalar for PlatformId { |
| type Raw = <u16 as font_types::Scalar>::Raw; |
| fn to_raw(self) -> Self::Raw { |
| (self as u16).to_raw() |
| } |
| fn from_raw(raw: Self::Raw) -> Self { |
| let t = <u16>::from_raw(raw); |
| Self::new(t) |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> From<PlatformId> for FieldType<'a> { |
| fn from(src: PlatformId) -> FieldType<'a> { |
| (src as u16).into() |
| } |
| } |
| |
| /// The different cmap subtable formats. |
| #[derive(Clone)] |
| pub enum CmapSubtable<'a> { |
| Format0(Cmap0<'a>), |
| Format2(Cmap2<'a>), |
| Format4(Cmap4<'a>), |
| Format6(Cmap6<'a>), |
| Format8(Cmap8<'a>), |
| Format10(Cmap10<'a>), |
| Format12(Cmap12<'a>), |
| Format13(Cmap13<'a>), |
| Format14(Cmap14<'a>), |
| } |
| |
| impl<'a> CmapSubtable<'a> { |
| ///Return the `FontData` used to resolve offsets for this table. |
| pub fn offset_data(&self) -> FontData<'a> { |
| match self { |
| Self::Format0(item) => item.offset_data(), |
| Self::Format2(item) => item.offset_data(), |
| Self::Format4(item) => item.offset_data(), |
| Self::Format6(item) => item.offset_data(), |
| Self::Format8(item) => item.offset_data(), |
| Self::Format10(item) => item.offset_data(), |
| Self::Format12(item) => item.offset_data(), |
| Self::Format13(item) => item.offset_data(), |
| Self::Format14(item) => item.offset_data(), |
| } |
| } |
| |
| /// Format number is set to 0. |
| pub fn format(&self) -> u16 { |
| match self { |
| Self::Format0(item) => item.format(), |
| Self::Format2(item) => item.format(), |
| Self::Format4(item) => item.format(), |
| Self::Format6(item) => item.format(), |
| Self::Format8(item) => item.format(), |
| Self::Format10(item) => item.format(), |
| Self::Format12(item) => item.format(), |
| Self::Format13(item) => item.format(), |
| Self::Format14(item) => item.format(), |
| } |
| } |
| } |
| |
| impl<'a> FontRead<'a> for CmapSubtable<'a> { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| let format: u16 = data.read_at(0usize)?; |
| match format { |
| Cmap0Marker::FORMAT => Ok(Self::Format0(FontRead::read(data)?)), |
| Cmap2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)), |
| Cmap4Marker::FORMAT => Ok(Self::Format4(FontRead::read(data)?)), |
| Cmap6Marker::FORMAT => Ok(Self::Format6(FontRead::read(data)?)), |
| Cmap8Marker::FORMAT => Ok(Self::Format8(FontRead::read(data)?)), |
| Cmap10Marker::FORMAT => Ok(Self::Format10(FontRead::read(data)?)), |
| Cmap12Marker::FORMAT => Ok(Self::Format12(FontRead::read(data)?)), |
| Cmap13Marker::FORMAT => Ok(Self::Format13(FontRead::read(data)?)), |
| Cmap14Marker::FORMAT => Ok(Self::Format14(FontRead::read(data)?)), |
| other => Err(ReadError::InvalidFormat(other.into())), |
| } |
| } |
| } |
| |
| impl MinByteRange for CmapSubtable<'_> { |
| fn min_byte_range(&self) -> Range<usize> { |
| match self { |
| Self::Format0(item) => item.min_byte_range(), |
| Self::Format2(item) => item.min_byte_range(), |
| Self::Format4(item) => item.min_byte_range(), |
| Self::Format6(item) => item.min_byte_range(), |
| Self::Format8(item) => item.min_byte_range(), |
| Self::Format10(item) => item.min_byte_range(), |
| Self::Format12(item) => item.min_byte_range(), |
| Self::Format13(item) => item.min_byte_range(), |
| Self::Format14(item) => item.min_byte_range(), |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> CmapSubtable<'a> { |
| fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> { |
| match self { |
| Self::Format0(table) => table, |
| Self::Format2(table) => table, |
| Self::Format4(table) => table, |
| Self::Format6(table) => table, |
| Self::Format8(table) => table, |
| Self::Format10(table) => table, |
| Self::Format12(table) => table, |
| Self::Format13(table) => table, |
| Self::Format14(table) => table, |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl std::fmt::Debug for CmapSubtable<'_> { |
| 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 CmapSubtable<'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<u16> for Cmap0Marker { |
| const FORMAT: u16 = 0; |
| } |
| |
| /// [cmap Format 0](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-0-byte-encoding-table): Byte encoding table |
| #[derive(Debug, Clone, Copy)] |
| #[doc(hidden)] |
| pub struct Cmap0Marker { |
| glyph_id_array_byte_len: usize, |
| } |
| |
| impl Cmap0Marker { |
| pub fn format_byte_range(&self) -> Range<usize> { |
| let start = 0; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn length_byte_range(&self) -> Range<usize> { |
| let start = self.format_byte_range().end; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn language_byte_range(&self) -> Range<usize> { |
| let start = self.length_byte_range().end; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn glyph_id_array_byte_range(&self) -> Range<usize> { |
| let start = self.language_byte_range().end; |
| start..start + self.glyph_id_array_byte_len |
| } |
| } |
| |
| impl MinByteRange for Cmap0Marker { |
| fn min_byte_range(&self) -> Range<usize> { |
| 0..self.glyph_id_array_byte_range().end |
| } |
| } |
| |
| impl<'a> FontRead<'a> for Cmap0<'a> { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| let mut cursor = data.cursor(); |
| cursor.advance::<u16>(); |
| cursor.advance::<u16>(); |
| cursor.advance::<u16>(); |
| let glyph_id_array_byte_len = (256_usize) |
| .checked_mul(u8::RAW_BYTE_LEN) |
| .ok_or(ReadError::OutOfBounds)?; |
| cursor.advance_by(glyph_id_array_byte_len); |
| cursor.finish(Cmap0Marker { |
| glyph_id_array_byte_len, |
| }) |
| } |
| } |
| |
| /// [cmap Format 0](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-0-byte-encoding-table): Byte encoding table |
| pub type Cmap0<'a> = TableRef<'a, Cmap0Marker>; |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> Cmap0<'a> { |
| /// Format number is set to 0. |
| pub fn format(&self) -> u16 { |
| let range = self.shape.format_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// This is the length in bytes of the subtable. |
| pub fn length(&self) -> u16 { |
| let range = self.shape.length_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// For requirements on use of the language field, see “Use of |
| /// the language field in 'cmap' subtables” in this document. |
| pub fn language(&self) -> u16 { |
| let range = self.shape.language_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// An array that maps character codes to glyph index values. |
| pub fn glyph_id_array(&self) -> &'a [u8] { |
| let range = self.shape.glyph_id_array_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeTable<'a> for Cmap0<'a> { |
| fn type_name(&self) -> &str { |
| "Cmap0" |
| } |
| fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
| match idx { |
| 0usize => Some(Field::new("format", self.format())), |
| 1usize => Some(Field::new("length", self.length())), |
| 2usize => Some(Field::new("language", self.language())), |
| 3usize => Some(Field::new("glyph_id_array", self.glyph_id_array())), |
| _ => None, |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> std::fmt::Debug for Cmap0<'a> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| (self as &dyn SomeTable<'a>).fmt(f) |
| } |
| } |
| |
| impl Format<u16> for Cmap2Marker { |
| const FORMAT: u16 = 2; |
| } |
| |
| /// [cmap Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-2-high-byte-mapping-through-table): High-byte mapping through table |
| #[derive(Debug, Clone, Copy)] |
| #[doc(hidden)] |
| pub struct Cmap2Marker { |
| sub_header_keys_byte_len: usize, |
| } |
| |
| impl Cmap2Marker { |
| pub fn format_byte_range(&self) -> Range<usize> { |
| let start = 0; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn length_byte_range(&self) -> Range<usize> { |
| let start = self.format_byte_range().end; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn language_byte_range(&self) -> Range<usize> { |
| let start = self.length_byte_range().end; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn sub_header_keys_byte_range(&self) -> Range<usize> { |
| let start = self.language_byte_range().end; |
| start..start + self.sub_header_keys_byte_len |
| } |
| } |
| |
| impl MinByteRange for Cmap2Marker { |
| fn min_byte_range(&self) -> Range<usize> { |
| 0..self.sub_header_keys_byte_range().end |
| } |
| } |
| |
| impl<'a> FontRead<'a> for Cmap2<'a> { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| let mut cursor = data.cursor(); |
| cursor.advance::<u16>(); |
| cursor.advance::<u16>(); |
| cursor.advance::<u16>(); |
| let sub_header_keys_byte_len = (256_usize) |
| .checked_mul(u16::RAW_BYTE_LEN) |
| .ok_or(ReadError::OutOfBounds)?; |
| cursor.advance_by(sub_header_keys_byte_len); |
| cursor.finish(Cmap2Marker { |
| sub_header_keys_byte_len, |
| }) |
| } |
| } |
| |
| /// [cmap Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-2-high-byte-mapping-through-table): High-byte mapping through table |
| pub type Cmap2<'a> = TableRef<'a, Cmap2Marker>; |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> Cmap2<'a> { |
| /// Format number is set to 2. |
| pub fn format(&self) -> u16 { |
| let range = self.shape.format_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// This is the length in bytes of the subtable. |
| pub fn length(&self) -> u16 { |
| let range = self.shape.length_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// For requirements on use of the language field, see “Use of |
| /// the language field in 'cmap' subtables” in this document. |
| pub fn language(&self) -> u16 { |
| let range = self.shape.language_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Array that maps high bytes to subHeaders: value is subHeader |
| /// index × 8. |
| pub fn sub_header_keys(&self) -> &'a [BigEndian<u16>] { |
| let range = self.shape.sub_header_keys_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeTable<'a> for Cmap2<'a> { |
| fn type_name(&self) -> &str { |
| "Cmap2" |
| } |
| fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
| match idx { |
| 0usize => Some(Field::new("format", self.format())), |
| 1usize => Some(Field::new("length", self.length())), |
| 2usize => Some(Field::new("language", self.language())), |
| 3usize => Some(Field::new("sub_header_keys", self.sub_header_keys())), |
| _ => None, |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> std::fmt::Debug for Cmap2<'a> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| (self as &dyn SomeTable<'a>).fmt(f) |
| } |
| } |
| |
| /// Part of [Cmap2] |
| #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)] |
| #[repr(C)] |
| #[repr(packed)] |
| pub struct SubHeader { |
| /// First valid low byte for this SubHeader. |
| pub first_code: BigEndian<u16>, |
| /// Number of valid low bytes for this SubHeader. |
| pub entry_count: BigEndian<u16>, |
| /// See text below. |
| pub id_delta: BigEndian<i16>, |
| /// See text below. |
| pub id_range_offset: BigEndian<u16>, |
| } |
| |
| impl SubHeader { |
| /// First valid low byte for this SubHeader. |
| pub fn first_code(&self) -> u16 { |
| self.first_code.get() |
| } |
| |
| /// Number of valid low bytes for this SubHeader. |
| pub fn entry_count(&self) -> u16 { |
| self.entry_count.get() |
| } |
| |
| /// See text below. |
| pub fn id_delta(&self) -> i16 { |
| self.id_delta.get() |
| } |
| |
| /// See text below. |
| pub fn id_range_offset(&self) -> u16 { |
| self.id_range_offset.get() |
| } |
| } |
| |
| impl FixedSize for SubHeader { |
| const RAW_BYTE_LEN: usize = |
| u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN; |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeRecord<'a> for SubHeader { |
| fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> { |
| RecordResolver { |
| name: "SubHeader", |
| get_field: Box::new(move |idx, _data| match idx { |
| 0usize => Some(Field::new("first_code", self.first_code())), |
| 1usize => Some(Field::new("entry_count", self.entry_count())), |
| 2usize => Some(Field::new("id_delta", self.id_delta())), |
| 3usize => Some(Field::new("id_range_offset", self.id_range_offset())), |
| _ => None, |
| }), |
| data, |
| } |
| } |
| } |
| |
| impl Format<u16> for Cmap4Marker { |
| const FORMAT: u16 = 4; |
| } |
| |
| /// [cmap Format 4](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-4-segment-mapping-to-delta-values): Segment mapping to delta values |
| #[derive(Debug, Clone, Copy)] |
| #[doc(hidden)] |
| pub struct Cmap4Marker { |
| end_code_byte_len: usize, |
| start_code_byte_len: usize, |
| id_delta_byte_len: usize, |
| id_range_offsets_byte_len: usize, |
| glyph_id_array_byte_len: usize, |
| } |
| |
| impl Cmap4Marker { |
| pub fn format_byte_range(&self) -> Range<usize> { |
| let start = 0; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn length_byte_range(&self) -> Range<usize> { |
| let start = self.format_byte_range().end; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn language_byte_range(&self) -> Range<usize> { |
| let start = self.length_byte_range().end; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn seg_count_x2_byte_range(&self) -> Range<usize> { |
| let start = self.language_byte_range().end; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn search_range_byte_range(&self) -> Range<usize> { |
| let start = self.seg_count_x2_byte_range().end; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn entry_selector_byte_range(&self) -> Range<usize> { |
| let start = self.search_range_byte_range().end; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn range_shift_byte_range(&self) -> Range<usize> { |
| let start = self.entry_selector_byte_range().end; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn end_code_byte_range(&self) -> Range<usize> { |
| let start = self.range_shift_byte_range().end; |
| start..start + self.end_code_byte_len |
| } |
| |
| pub fn reserved_pad_byte_range(&self) -> Range<usize> { |
| let start = self.end_code_byte_range().end; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn start_code_byte_range(&self) -> Range<usize> { |
| let start = self.reserved_pad_byte_range().end; |
| start..start + self.start_code_byte_len |
| } |
| |
| pub fn id_delta_byte_range(&self) -> Range<usize> { |
| let start = self.start_code_byte_range().end; |
| start..start + self.id_delta_byte_len |
| } |
| |
| pub fn id_range_offsets_byte_range(&self) -> Range<usize> { |
| let start = self.id_delta_byte_range().end; |
| start..start + self.id_range_offsets_byte_len |
| } |
| |
| pub fn glyph_id_array_byte_range(&self) -> Range<usize> { |
| let start = self.id_range_offsets_byte_range().end; |
| start..start + self.glyph_id_array_byte_len |
| } |
| } |
| |
| impl MinByteRange for Cmap4Marker { |
| fn min_byte_range(&self) -> Range<usize> { |
| 0..self.glyph_id_array_byte_range().end |
| } |
| } |
| |
| impl<'a> FontRead<'a> for Cmap4<'a> { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| let mut cursor = data.cursor(); |
| cursor.advance::<u16>(); |
| cursor.advance::<u16>(); |
| cursor.advance::<u16>(); |
| let seg_count_x2: u16 = cursor.read()?; |
| cursor.advance::<u16>(); |
| cursor.advance::<u16>(); |
| cursor.advance::<u16>(); |
| let end_code_byte_len = (transforms::half(seg_count_x2)) |
| .checked_mul(u16::RAW_BYTE_LEN) |
| .ok_or(ReadError::OutOfBounds)?; |
| cursor.advance_by(end_code_byte_len); |
| cursor.advance::<u16>(); |
| let start_code_byte_len = (transforms::half(seg_count_x2)) |
| .checked_mul(u16::RAW_BYTE_LEN) |
| .ok_or(ReadError::OutOfBounds)?; |
| cursor.advance_by(start_code_byte_len); |
| let id_delta_byte_len = (transforms::half(seg_count_x2)) |
| .checked_mul(i16::RAW_BYTE_LEN) |
| .ok_or(ReadError::OutOfBounds)?; |
| cursor.advance_by(id_delta_byte_len); |
| let id_range_offsets_byte_len = (transforms::half(seg_count_x2)) |
| .checked_mul(u16::RAW_BYTE_LEN) |
| .ok_or(ReadError::OutOfBounds)?; |
| cursor.advance_by(id_range_offsets_byte_len); |
| let glyph_id_array_byte_len = |
| cursor.remaining_bytes() / u16::RAW_BYTE_LEN * u16::RAW_BYTE_LEN; |
| cursor.advance_by(glyph_id_array_byte_len); |
| cursor.finish(Cmap4Marker { |
| end_code_byte_len, |
| start_code_byte_len, |
| id_delta_byte_len, |
| id_range_offsets_byte_len, |
| glyph_id_array_byte_len, |
| }) |
| } |
| } |
| |
| /// [cmap Format 4](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-4-segment-mapping-to-delta-values): Segment mapping to delta values |
| pub type Cmap4<'a> = TableRef<'a, Cmap4Marker>; |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> Cmap4<'a> { |
| /// Format number is set to 4. |
| pub fn format(&self) -> u16 { |
| let range = self.shape.format_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// This is the length in bytes of the subtable. |
| pub fn length(&self) -> u16 { |
| let range = self.shape.length_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// For requirements on use of the language field, see “Use of |
| /// the language field in 'cmap' subtables” in this document. |
| pub fn language(&self) -> u16 { |
| let range = self.shape.language_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// 2 × segCount. |
| pub fn seg_count_x2(&self) -> u16 { |
| let range = self.shape.seg_count_x2_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Maximum power of 2 less than or equal to segCount, times 2 |
| /// ((2**floor(log2(segCount))) * 2, where “**” is an |
| /// exponentiation operator) |
| pub fn search_range(&self) -> u16 { |
| let range = self.shape.search_range_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Log2 of the maximum power of 2 less than or equal to numTables |
| /// (log2(searchRange/2), which is equal to floor(log2(segCount))) |
| pub fn entry_selector(&self) -> u16 { |
| let range = self.shape.entry_selector_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// segCount times 2, minus searchRange ((segCount * 2) - |
| /// searchRange) |
| pub fn range_shift(&self) -> u16 { |
| let range = self.shape.range_shift_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// End characterCode for each segment, last=0xFFFF. |
| pub fn end_code(&self) -> &'a [BigEndian<u16>] { |
| let range = self.shape.end_code_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| |
| /// Start character code for each segment. |
| pub fn start_code(&self) -> &'a [BigEndian<u16>] { |
| let range = self.shape.start_code_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| |
| /// Delta for all character codes in segment. |
| pub fn id_delta(&self) -> &'a [BigEndian<i16>] { |
| let range = self.shape.id_delta_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| |
| /// Offsets into glyphIdArray or 0 |
| pub fn id_range_offsets(&self) -> &'a [BigEndian<u16>] { |
| let range = self.shape.id_range_offsets_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| |
| /// Glyph index array (arbitrary length) |
| pub fn glyph_id_array(&self) -> &'a [BigEndian<u16>] { |
| let range = self.shape.glyph_id_array_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeTable<'a> for Cmap4<'a> { |
| fn type_name(&self) -> &str { |
| "Cmap4" |
| } |
| fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
| match idx { |
| 0usize => Some(Field::new("format", self.format())), |
| 1usize => Some(Field::new("length", self.length())), |
| 2usize => Some(Field::new("language", self.language())), |
| 3usize => Some(Field::new("seg_count_x2", self.seg_count_x2())), |
| 4usize => Some(Field::new("search_range", self.search_range())), |
| 5usize => Some(Field::new("entry_selector", self.entry_selector())), |
| 6usize => Some(Field::new("range_shift", self.range_shift())), |
| 7usize => Some(Field::new("end_code", self.end_code())), |
| 8usize => Some(Field::new("start_code", self.start_code())), |
| 9usize => Some(Field::new("id_delta", self.id_delta())), |
| 10usize => Some(Field::new("id_range_offsets", self.id_range_offsets())), |
| 11usize => Some(Field::new("glyph_id_array", self.glyph_id_array())), |
| _ => None, |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> std::fmt::Debug for Cmap4<'a> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| (self as &dyn SomeTable<'a>).fmt(f) |
| } |
| } |
| |
| impl Format<u16> for Cmap6Marker { |
| const FORMAT: u16 = 6; |
| } |
| |
| /// [cmap Format 6](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-6-trimmed-table-mapping): Trimmed table mapping |
| #[derive(Debug, Clone, Copy)] |
| #[doc(hidden)] |
| pub struct Cmap6Marker { |
| glyph_id_array_byte_len: usize, |
| } |
| |
| impl Cmap6Marker { |
| pub fn format_byte_range(&self) -> Range<usize> { |
| let start = 0; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn length_byte_range(&self) -> Range<usize> { |
| let start = self.format_byte_range().end; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn language_byte_range(&self) -> Range<usize> { |
| let start = self.length_byte_range().end; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn first_code_byte_range(&self) -> Range<usize> { |
| let start = self.language_byte_range().end; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn entry_count_byte_range(&self) -> Range<usize> { |
| let start = self.first_code_byte_range().end; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn glyph_id_array_byte_range(&self) -> Range<usize> { |
| let start = self.entry_count_byte_range().end; |
| start..start + self.glyph_id_array_byte_len |
| } |
| } |
| |
| impl MinByteRange for Cmap6Marker { |
| fn min_byte_range(&self) -> Range<usize> { |
| 0..self.glyph_id_array_byte_range().end |
| } |
| } |
| |
| impl<'a> FontRead<'a> for Cmap6<'a> { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| let mut cursor = data.cursor(); |
| cursor.advance::<u16>(); |
| cursor.advance::<u16>(); |
| cursor.advance::<u16>(); |
| cursor.advance::<u16>(); |
| let entry_count: u16 = cursor.read()?; |
| let glyph_id_array_byte_len = (entry_count as usize) |
| .checked_mul(u16::RAW_BYTE_LEN) |
| .ok_or(ReadError::OutOfBounds)?; |
| cursor.advance_by(glyph_id_array_byte_len); |
| cursor.finish(Cmap6Marker { |
| glyph_id_array_byte_len, |
| }) |
| } |
| } |
| |
| /// [cmap Format 6](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-6-trimmed-table-mapping): Trimmed table mapping |
| pub type Cmap6<'a> = TableRef<'a, Cmap6Marker>; |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> Cmap6<'a> { |
| /// Format number is set to 6. |
| pub fn format(&self) -> u16 { |
| let range = self.shape.format_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// This is the length in bytes of the subtable. |
| pub fn length(&self) -> u16 { |
| let range = self.shape.length_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// For requirements on use of the language field, see “Use of |
| /// the language field in 'cmap' subtables” in this document. |
| pub fn language(&self) -> u16 { |
| let range = self.shape.language_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// First character code of subrange. |
| pub fn first_code(&self) -> u16 { |
| let range = self.shape.first_code_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Number of character codes in subrange. |
| pub fn entry_count(&self) -> u16 { |
| let range = self.shape.entry_count_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Array of glyph index values for character codes in the range. |
| pub fn glyph_id_array(&self) -> &'a [BigEndian<u16>] { |
| let range = self.shape.glyph_id_array_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeTable<'a> for Cmap6<'a> { |
| fn type_name(&self) -> &str { |
| "Cmap6" |
| } |
| fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
| match idx { |
| 0usize => Some(Field::new("format", self.format())), |
| 1usize => Some(Field::new("length", self.length())), |
| 2usize => Some(Field::new("language", self.language())), |
| 3usize => Some(Field::new("first_code", self.first_code())), |
| 4usize => Some(Field::new("entry_count", self.entry_count())), |
| 5usize => Some(Field::new("glyph_id_array", self.glyph_id_array())), |
| _ => None, |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> std::fmt::Debug for Cmap6<'a> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| (self as &dyn SomeTable<'a>).fmt(f) |
| } |
| } |
| |
| impl Format<u16> for Cmap8Marker { |
| const FORMAT: u16 = 8; |
| } |
| |
| /// [cmap Format 8](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-8-mixed-16-bit-and-32-bit-coverage): mixed 16-bit and 32-bit coverage |
| #[derive(Debug, Clone, Copy)] |
| #[doc(hidden)] |
| pub struct Cmap8Marker { |
| is32_byte_len: usize, |
| groups_byte_len: usize, |
| } |
| |
| impl Cmap8Marker { |
| pub fn format_byte_range(&self) -> Range<usize> { |
| let start = 0; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn reserved_byte_range(&self) -> Range<usize> { |
| let start = self.format_byte_range().end; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn length_byte_range(&self) -> Range<usize> { |
| let start = self.reserved_byte_range().end; |
| start..start + u32::RAW_BYTE_LEN |
| } |
| |
| pub fn language_byte_range(&self) -> Range<usize> { |
| let start = self.length_byte_range().end; |
| start..start + u32::RAW_BYTE_LEN |
| } |
| |
| pub fn is32_byte_range(&self) -> Range<usize> { |
| let start = self.language_byte_range().end; |
| start..start + self.is32_byte_len |
| } |
| |
| pub fn num_groups_byte_range(&self) -> Range<usize> { |
| let start = self.is32_byte_range().end; |
| start..start + u32::RAW_BYTE_LEN |
| } |
| |
| pub fn groups_byte_range(&self) -> Range<usize> { |
| let start = self.num_groups_byte_range().end; |
| start..start + self.groups_byte_len |
| } |
| } |
| |
| impl MinByteRange for Cmap8Marker { |
| fn min_byte_range(&self) -> Range<usize> { |
| 0..self.groups_byte_range().end |
| } |
| } |
| |
| impl<'a> FontRead<'a> for Cmap8<'a> { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| let mut cursor = data.cursor(); |
| cursor.advance::<u16>(); |
| cursor.advance::<u16>(); |
| cursor.advance::<u32>(); |
| cursor.advance::<u32>(); |
| let is32_byte_len = (8192_usize) |
| .checked_mul(u8::RAW_BYTE_LEN) |
| .ok_or(ReadError::OutOfBounds)?; |
| cursor.advance_by(is32_byte_len); |
| let num_groups: u32 = cursor.read()?; |
| let groups_byte_len = (num_groups as usize) |
| .checked_mul(SequentialMapGroup::RAW_BYTE_LEN) |
| .ok_or(ReadError::OutOfBounds)?; |
| cursor.advance_by(groups_byte_len); |
| cursor.finish(Cmap8Marker { |
| is32_byte_len, |
| groups_byte_len, |
| }) |
| } |
| } |
| |
| /// [cmap Format 8](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-8-mixed-16-bit-and-32-bit-coverage): mixed 16-bit and 32-bit coverage |
| pub type Cmap8<'a> = TableRef<'a, Cmap8Marker>; |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> Cmap8<'a> { |
| /// Subtable format; set to 8. |
| pub fn format(&self) -> u16 { |
| let range = self.shape.format_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Byte length of this subtable (including the header) |
| pub fn length(&self) -> u32 { |
| let range = self.shape.length_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// For requirements on use of the language field, see “Use of |
| /// the language field in 'cmap' subtables” in this document. |
| pub fn language(&self) -> u32 { |
| let range = self.shape.language_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Tightly packed array of bits (8K bytes total) indicating |
| /// whether the particular 16-bit (index) value is the start of a |
| /// 32-bit character code |
| pub fn is32(&self) -> &'a [u8] { |
| let range = self.shape.is32_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| |
| /// Number of groupings which follow |
| pub fn num_groups(&self) -> u32 { |
| let range = self.shape.num_groups_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Array of SequentialMapGroup records. |
| pub fn groups(&self) -> &'a [SequentialMapGroup] { |
| let range = self.shape.groups_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeTable<'a> for Cmap8<'a> { |
| fn type_name(&self) -> &str { |
| "Cmap8" |
| } |
| fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
| match idx { |
| 0usize => Some(Field::new("format", self.format())), |
| 1usize => Some(Field::new("length", self.length())), |
| 2usize => Some(Field::new("language", self.language())), |
| 3usize => Some(Field::new("is32", self.is32())), |
| 4usize => Some(Field::new("num_groups", self.num_groups())), |
| 5usize => Some(Field::new( |
| "groups", |
| traversal::FieldType::array_of_records( |
| stringify!(SequentialMapGroup), |
| self.groups(), |
| self.offset_data(), |
| ), |
| )), |
| _ => None, |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> std::fmt::Debug for Cmap8<'a> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| (self as &dyn SomeTable<'a>).fmt(f) |
| } |
| } |
| |
| /// Used in [Cmap8] and [Cmap12] |
| #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)] |
| #[repr(C)] |
| #[repr(packed)] |
| pub struct SequentialMapGroup { |
| /// First character code in this group; note that if this group is |
| /// for one or more 16-bit character codes (which is determined |
| /// from the is32 array), this 32-bit value will have the high |
| /// 16-bits set to zero |
| pub start_char_code: BigEndian<u32>, |
| /// Last character code in this group; same condition as listed |
| /// above for the startCharCode |
| pub end_char_code: BigEndian<u32>, |
| /// Glyph index corresponding to the starting character code |
| pub start_glyph_id: BigEndian<u32>, |
| } |
| |
| impl SequentialMapGroup { |
| /// First character code in this group; note that if this group is |
| /// for one or more 16-bit character codes (which is determined |
| /// from the is32 array), this 32-bit value will have the high |
| /// 16-bits set to zero |
| pub fn start_char_code(&self) -> u32 { |
| self.start_char_code.get() |
| } |
| |
| /// Last character code in this group; same condition as listed |
| /// above for the startCharCode |
| pub fn end_char_code(&self) -> u32 { |
| self.end_char_code.get() |
| } |
| |
| /// Glyph index corresponding to the starting character code |
| pub fn start_glyph_id(&self) -> u32 { |
| self.start_glyph_id.get() |
| } |
| } |
| |
| impl FixedSize for SequentialMapGroup { |
| const RAW_BYTE_LEN: usize = u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN; |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeRecord<'a> for SequentialMapGroup { |
| fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> { |
| RecordResolver { |
| name: "SequentialMapGroup", |
| get_field: Box::new(move |idx, _data| match idx { |
| 0usize => Some(Field::new("start_char_code", self.start_char_code())), |
| 1usize => Some(Field::new("end_char_code", self.end_char_code())), |
| 2usize => Some(Field::new("start_glyph_id", self.start_glyph_id())), |
| _ => None, |
| }), |
| data, |
| } |
| } |
| } |
| |
| impl Format<u16> for Cmap10Marker { |
| const FORMAT: u16 = 10; |
| } |
| |
| /// [cmap Format 10](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-10-trimmed-array): Tr |
| #[derive(Debug, Clone, Copy)] |
| #[doc(hidden)] |
| pub struct Cmap10Marker { |
| glyph_id_array_byte_len: usize, |
| } |
| |
| impl Cmap10Marker { |
| pub fn format_byte_range(&self) -> Range<usize> { |
| let start = 0; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn reserved_byte_range(&self) -> Range<usize> { |
| let start = self.format_byte_range().end; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn length_byte_range(&self) -> Range<usize> { |
| let start = self.reserved_byte_range().end; |
| start..start + u32::RAW_BYTE_LEN |
| } |
| |
| pub fn language_byte_range(&self) -> Range<usize> { |
| let start = self.length_byte_range().end; |
| start..start + u32::RAW_BYTE_LEN |
| } |
| |
| pub fn start_char_code_byte_range(&self) -> Range<usize> { |
| let start = self.language_byte_range().end; |
| start..start + u32::RAW_BYTE_LEN |
| } |
| |
| pub fn num_chars_byte_range(&self) -> Range<usize> { |
| let start = self.start_char_code_byte_range().end; |
| start..start + u32::RAW_BYTE_LEN |
| } |
| |
| pub fn glyph_id_array_byte_range(&self) -> Range<usize> { |
| let start = self.num_chars_byte_range().end; |
| start..start + self.glyph_id_array_byte_len |
| } |
| } |
| |
| impl MinByteRange for Cmap10Marker { |
| fn min_byte_range(&self) -> Range<usize> { |
| 0..self.glyph_id_array_byte_range().end |
| } |
| } |
| |
| impl<'a> FontRead<'a> for Cmap10<'a> { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| let mut cursor = data.cursor(); |
| cursor.advance::<u16>(); |
| cursor.advance::<u16>(); |
| cursor.advance::<u32>(); |
| cursor.advance::<u32>(); |
| cursor.advance::<u32>(); |
| cursor.advance::<u32>(); |
| let glyph_id_array_byte_len = |
| cursor.remaining_bytes() / u16::RAW_BYTE_LEN * u16::RAW_BYTE_LEN; |
| cursor.advance_by(glyph_id_array_byte_len); |
| cursor.finish(Cmap10Marker { |
| glyph_id_array_byte_len, |
| }) |
| } |
| } |
| |
| /// [cmap Format 10](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-10-trimmed-array): Tr |
| pub type Cmap10<'a> = TableRef<'a, Cmap10Marker>; |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> Cmap10<'a> { |
| /// Subtable format; set to 10. |
| pub fn format(&self) -> u16 { |
| let range = self.shape.format_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Byte length of this subtable (including the header) |
| pub fn length(&self) -> u32 { |
| let range = self.shape.length_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// For requirements on use of the language field, see “Use of |
| /// the language field in 'cmap' subtables” in this document. |
| pub fn language(&self) -> u32 { |
| let range = self.shape.language_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// First character code covered |
| pub fn start_char_code(&self) -> u32 { |
| let range = self.shape.start_char_code_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Number of character codes covered |
| pub fn num_chars(&self) -> u32 { |
| let range = self.shape.num_chars_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Array of glyph indices for the character codes covered |
| pub fn glyph_id_array(&self) -> &'a [BigEndian<u16>] { |
| let range = self.shape.glyph_id_array_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeTable<'a> for Cmap10<'a> { |
| fn type_name(&self) -> &str { |
| "Cmap10" |
| } |
| fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
| match idx { |
| 0usize => Some(Field::new("format", self.format())), |
| 1usize => Some(Field::new("length", self.length())), |
| 2usize => Some(Field::new("language", self.language())), |
| 3usize => Some(Field::new("start_char_code", self.start_char_code())), |
| 4usize => Some(Field::new("num_chars", self.num_chars())), |
| 5usize => Some(Field::new("glyph_id_array", self.glyph_id_array())), |
| _ => None, |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> std::fmt::Debug for Cmap10<'a> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| (self as &dyn SomeTable<'a>).fmt(f) |
| } |
| } |
| |
| impl Format<u16> for Cmap12Marker { |
| const FORMAT: u16 = 12; |
| } |
| |
| /// [cmap Format 12](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-12-segmented-coverage): Segmented coverage |
| #[derive(Debug, Clone, Copy)] |
| #[doc(hidden)] |
| pub struct Cmap12Marker { |
| groups_byte_len: usize, |
| } |
| |
| impl Cmap12Marker { |
| pub fn format_byte_range(&self) -> Range<usize> { |
| let start = 0; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn reserved_byte_range(&self) -> Range<usize> { |
| let start = self.format_byte_range().end; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn length_byte_range(&self) -> Range<usize> { |
| let start = self.reserved_byte_range().end; |
| start..start + u32::RAW_BYTE_LEN |
| } |
| |
| pub fn language_byte_range(&self) -> Range<usize> { |
| let start = self.length_byte_range().end; |
| start..start + u32::RAW_BYTE_LEN |
| } |
| |
| pub fn num_groups_byte_range(&self) -> Range<usize> { |
| let start = self.language_byte_range().end; |
| start..start + u32::RAW_BYTE_LEN |
| } |
| |
| pub fn groups_byte_range(&self) -> Range<usize> { |
| let start = self.num_groups_byte_range().end; |
| start..start + self.groups_byte_len |
| } |
| } |
| |
| impl MinByteRange for Cmap12Marker { |
| fn min_byte_range(&self) -> Range<usize> { |
| 0..self.groups_byte_range().end |
| } |
| } |
| |
| impl<'a> FontRead<'a> for Cmap12<'a> { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| let mut cursor = data.cursor(); |
| cursor.advance::<u16>(); |
| cursor.advance::<u16>(); |
| cursor.advance::<u32>(); |
| cursor.advance::<u32>(); |
| let num_groups: u32 = cursor.read()?; |
| let groups_byte_len = (num_groups as usize) |
| .checked_mul(SequentialMapGroup::RAW_BYTE_LEN) |
| .ok_or(ReadError::OutOfBounds)?; |
| cursor.advance_by(groups_byte_len); |
| cursor.finish(Cmap12Marker { groups_byte_len }) |
| } |
| } |
| |
| /// [cmap Format 12](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-12-segmented-coverage): Segmented coverage |
| pub type Cmap12<'a> = TableRef<'a, Cmap12Marker>; |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> Cmap12<'a> { |
| /// Subtable format; set to 12. |
| pub fn format(&self) -> u16 { |
| let range = self.shape.format_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Byte length of this subtable (including the header) |
| pub fn length(&self) -> u32 { |
| let range = self.shape.length_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// For requirements on use of the language field, see “Use of |
| /// the language field in 'cmap' subtables” in this document. |
| pub fn language(&self) -> u32 { |
| let range = self.shape.language_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Number of groupings which follow |
| pub fn num_groups(&self) -> u32 { |
| let range = self.shape.num_groups_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Array of SequentialMapGroup records. |
| pub fn groups(&self) -> &'a [SequentialMapGroup] { |
| let range = self.shape.groups_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeTable<'a> for Cmap12<'a> { |
| fn type_name(&self) -> &str { |
| "Cmap12" |
| } |
| fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
| match idx { |
| 0usize => Some(Field::new("format", self.format())), |
| 1usize => Some(Field::new("length", self.length())), |
| 2usize => Some(Field::new("language", self.language())), |
| 3usize => Some(Field::new("num_groups", self.num_groups())), |
| 4usize => Some(Field::new( |
| "groups", |
| traversal::FieldType::array_of_records( |
| stringify!(SequentialMapGroup), |
| self.groups(), |
| self.offset_data(), |
| ), |
| )), |
| _ => None, |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> std::fmt::Debug for Cmap12<'a> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| (self as &dyn SomeTable<'a>).fmt(f) |
| } |
| } |
| |
| impl Format<u16> for Cmap13Marker { |
| const FORMAT: u16 = 13; |
| } |
| |
| /// [cmap Format 13](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-13-many-to-one-range-mappings): Many-to-one range mappings |
| #[derive(Debug, Clone, Copy)] |
| #[doc(hidden)] |
| pub struct Cmap13Marker { |
| groups_byte_len: usize, |
| } |
| |
| impl Cmap13Marker { |
| pub fn format_byte_range(&self) -> Range<usize> { |
| let start = 0; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn reserved_byte_range(&self) -> Range<usize> { |
| let start = self.format_byte_range().end; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn length_byte_range(&self) -> Range<usize> { |
| let start = self.reserved_byte_range().end; |
| start..start + u32::RAW_BYTE_LEN |
| } |
| |
| pub fn language_byte_range(&self) -> Range<usize> { |
| let start = self.length_byte_range().end; |
| start..start + u32::RAW_BYTE_LEN |
| } |
| |
| pub fn num_groups_byte_range(&self) -> Range<usize> { |
| let start = self.language_byte_range().end; |
| start..start + u32::RAW_BYTE_LEN |
| } |
| |
| pub fn groups_byte_range(&self) -> Range<usize> { |
| let start = self.num_groups_byte_range().end; |
| start..start + self.groups_byte_len |
| } |
| } |
| |
| impl MinByteRange for Cmap13Marker { |
| fn min_byte_range(&self) -> Range<usize> { |
| 0..self.groups_byte_range().end |
| } |
| } |
| |
| impl<'a> FontRead<'a> for Cmap13<'a> { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| let mut cursor = data.cursor(); |
| cursor.advance::<u16>(); |
| cursor.advance::<u16>(); |
| cursor.advance::<u32>(); |
| cursor.advance::<u32>(); |
| let num_groups: u32 = cursor.read()?; |
| let groups_byte_len = (num_groups as usize) |
| .checked_mul(ConstantMapGroup::RAW_BYTE_LEN) |
| .ok_or(ReadError::OutOfBounds)?; |
| cursor.advance_by(groups_byte_len); |
| cursor.finish(Cmap13Marker { groups_byte_len }) |
| } |
| } |
| |
| /// [cmap Format 13](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-13-many-to-one-range-mappings): Many-to-one range mappings |
| pub type Cmap13<'a> = TableRef<'a, Cmap13Marker>; |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> Cmap13<'a> { |
| /// Subtable format; set to 13. |
| pub fn format(&self) -> u16 { |
| let range = self.shape.format_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Byte length of this subtable (including the header) |
| pub fn length(&self) -> u32 { |
| let range = self.shape.length_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// For requirements on use of the language field, see “Use of |
| /// the language field in 'cmap' subtables” in this document. |
| pub fn language(&self) -> u32 { |
| let range = self.shape.language_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Number of groupings which follow |
| pub fn num_groups(&self) -> u32 { |
| let range = self.shape.num_groups_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Array of ConstantMapGroup records. |
| pub fn groups(&self) -> &'a [ConstantMapGroup] { |
| let range = self.shape.groups_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeTable<'a> for Cmap13<'a> { |
| fn type_name(&self) -> &str { |
| "Cmap13" |
| } |
| fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
| match idx { |
| 0usize => Some(Field::new("format", self.format())), |
| 1usize => Some(Field::new("length", self.length())), |
| 2usize => Some(Field::new("language", self.language())), |
| 3usize => Some(Field::new("num_groups", self.num_groups())), |
| 4usize => Some(Field::new( |
| "groups", |
| traversal::FieldType::array_of_records( |
| stringify!(ConstantMapGroup), |
| self.groups(), |
| self.offset_data(), |
| ), |
| )), |
| _ => None, |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> std::fmt::Debug for Cmap13<'a> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| (self as &dyn SomeTable<'a>).fmt(f) |
| } |
| } |
| |
| /// Part of [Cmap13] |
| #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)] |
| #[repr(C)] |
| #[repr(packed)] |
| pub struct ConstantMapGroup { |
| /// First character code in this group |
| pub start_char_code: BigEndian<u32>, |
| /// Last character code in this group |
| pub end_char_code: BigEndian<u32>, |
| /// Glyph index to be used for all the characters in the group’s |
| /// range. |
| pub glyph_id: BigEndian<u32>, |
| } |
| |
| impl ConstantMapGroup { |
| /// First character code in this group |
| pub fn start_char_code(&self) -> u32 { |
| self.start_char_code.get() |
| } |
| |
| /// Last character code in this group |
| pub fn end_char_code(&self) -> u32 { |
| self.end_char_code.get() |
| } |
| |
| /// Glyph index to be used for all the characters in the group’s |
| /// range. |
| pub fn glyph_id(&self) -> u32 { |
| self.glyph_id.get() |
| } |
| } |
| |
| impl FixedSize for ConstantMapGroup { |
| const RAW_BYTE_LEN: usize = u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN; |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeRecord<'a> for ConstantMapGroup { |
| fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> { |
| RecordResolver { |
| name: "ConstantMapGroup", |
| get_field: Box::new(move |idx, _data| match idx { |
| 0usize => Some(Field::new("start_char_code", self.start_char_code())), |
| 1usize => Some(Field::new("end_char_code", self.end_char_code())), |
| 2usize => Some(Field::new("glyph_id", self.glyph_id())), |
| _ => None, |
| }), |
| data, |
| } |
| } |
| } |
| |
| impl Format<u16> for Cmap14Marker { |
| const FORMAT: u16 = 14; |
| } |
| |
| /// [cmap Format 14](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-14-unicode-variation-sequences): Unicode Variation Sequences |
| #[derive(Debug, Clone, Copy)] |
| #[doc(hidden)] |
| pub struct Cmap14Marker { |
| var_selector_byte_len: usize, |
| } |
| |
| impl Cmap14Marker { |
| pub fn format_byte_range(&self) -> Range<usize> { |
| let start = 0; |
| start..start + u16::RAW_BYTE_LEN |
| } |
| |
| pub fn length_byte_range(&self) -> Range<usize> { |
| let start = self.format_byte_range().end; |
| start..start + u32::RAW_BYTE_LEN |
| } |
| |
| pub fn num_var_selector_records_byte_range(&self) -> Range<usize> { |
| let start = self.length_byte_range().end; |
| start..start + u32::RAW_BYTE_LEN |
| } |
| |
| pub fn var_selector_byte_range(&self) -> Range<usize> { |
| let start = self.num_var_selector_records_byte_range().end; |
| start..start + self.var_selector_byte_len |
| } |
| } |
| |
| impl MinByteRange for Cmap14Marker { |
| fn min_byte_range(&self) -> Range<usize> { |
| 0..self.var_selector_byte_range().end |
| } |
| } |
| |
| impl<'a> FontRead<'a> for Cmap14<'a> { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| let mut cursor = data.cursor(); |
| cursor.advance::<u16>(); |
| cursor.advance::<u32>(); |
| let num_var_selector_records: u32 = cursor.read()?; |
| let var_selector_byte_len = (num_var_selector_records as usize) |
| .checked_mul(VariationSelector::RAW_BYTE_LEN) |
| .ok_or(ReadError::OutOfBounds)?; |
| cursor.advance_by(var_selector_byte_len); |
| cursor.finish(Cmap14Marker { |
| var_selector_byte_len, |
| }) |
| } |
| } |
| |
| /// [cmap Format 14](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-14-unicode-variation-sequences): Unicode Variation Sequences |
| pub type Cmap14<'a> = TableRef<'a, Cmap14Marker>; |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> Cmap14<'a> { |
| /// Subtable format. Set to 14. |
| pub fn format(&self) -> u16 { |
| let range = self.shape.format_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Byte length of this subtable (including this header) |
| pub fn length(&self) -> u32 { |
| let range = self.shape.length_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Number of variation Selector Records |
| pub fn num_var_selector_records(&self) -> u32 { |
| let range = self.shape.num_var_selector_records_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Array of VariationSelector records. |
| pub fn var_selector(&self) -> &'a [VariationSelector] { |
| let range = self.shape.var_selector_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeTable<'a> for Cmap14<'a> { |
| fn type_name(&self) -> &str { |
| "Cmap14" |
| } |
| fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
| match idx { |
| 0usize => Some(Field::new("format", self.format())), |
| 1usize => Some(Field::new("length", self.length())), |
| 2usize => Some(Field::new( |
| "num_var_selector_records", |
| self.num_var_selector_records(), |
| )), |
| 3usize => Some(Field::new( |
| "var_selector", |
| traversal::FieldType::array_of_records( |
| stringify!(VariationSelector), |
| self.var_selector(), |
| self.offset_data(), |
| ), |
| )), |
| _ => None, |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> std::fmt::Debug for Cmap14<'a> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| (self as &dyn SomeTable<'a>).fmt(f) |
| } |
| } |
| |
| /// Part of [Cmap14] |
| #[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)] |
| #[repr(C)] |
| #[repr(packed)] |
| pub struct VariationSelector { |
| /// Variation selector |
| pub var_selector: BigEndian<Uint24>, |
| /// Offset from the start of the [`Cmap14`] subtable to Default UVS |
| /// Table. May be NULL. |
| pub default_uvs_offset: BigEndian<Nullable<Offset32>>, |
| /// Offset from the start of the [`Cmap14`] subtable to Non-Default |
| /// UVS Table. May be NULL. |
| pub non_default_uvs_offset: BigEndian<Nullable<Offset32>>, |
| } |
| |
| impl VariationSelector { |
| /// Variation selector |
| pub fn var_selector(&self) -> Uint24 { |
| self.var_selector.get() |
| } |
| |
| /// Offset from the start of the [`Cmap14`] subtable to Default UVS |
| /// Table. May be NULL. |
| pub fn default_uvs_offset(&self) -> Nullable<Offset32> { |
| self.default_uvs_offset.get() |
| } |
| |
| /// Offset from the start of the [`Cmap14`] subtable to Default UVS |
| /// Table. May be NULL. |
| /// |
| /// The `data` argument should be retrieved from the parent table |
| /// By calling its `offset_data` method. |
| pub fn default_uvs<'a>(&self, data: FontData<'a>) -> Option<Result<DefaultUvs<'a>, ReadError>> { |
| self.default_uvs_offset().resolve(data) |
| } |
| |
| /// Offset from the start of the [`Cmap14`] subtable to Non-Default |
| /// UVS Table. May be NULL. |
| pub fn non_default_uvs_offset(&self) -> Nullable<Offset32> { |
| self.non_default_uvs_offset.get() |
| } |
| |
| /// Offset from the start of the [`Cmap14`] subtable to Non-Default |
| /// UVS Table. May be NULL. |
| /// |
| /// The `data` argument should be retrieved from the parent table |
| /// By calling its `offset_data` method. |
| pub fn non_default_uvs<'a>( |
| &self, |
| data: FontData<'a>, |
| ) -> Option<Result<NonDefaultUvs<'a>, ReadError>> { |
| self.non_default_uvs_offset().resolve(data) |
| } |
| } |
| |
| impl FixedSize for VariationSelector { |
| const RAW_BYTE_LEN: usize = |
| Uint24::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN; |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeRecord<'a> for VariationSelector { |
| fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> { |
| RecordResolver { |
| name: "VariationSelector", |
| get_field: Box::new(move |idx, _data| match idx { |
| 0usize => Some(Field::new("var_selector", self.var_selector())), |
| 1usize => Some(Field::new( |
| "default_uvs_offset", |
| FieldType::offset(self.default_uvs_offset(), self.default_uvs(_data)), |
| )), |
| 2usize => Some(Field::new( |
| "non_default_uvs_offset", |
| FieldType::offset(self.non_default_uvs_offset(), self.non_default_uvs(_data)), |
| )), |
| _ => None, |
| }), |
| data, |
| } |
| } |
| } |
| |
| /// [Default UVS table](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#default-uvs-table) |
| #[derive(Debug, Clone, Copy)] |
| #[doc(hidden)] |
| pub struct DefaultUvsMarker { |
| ranges_byte_len: usize, |
| } |
| |
| impl DefaultUvsMarker { |
| pub fn num_unicode_value_ranges_byte_range(&self) -> Range<usize> { |
| let start = 0; |
| start..start + u32::RAW_BYTE_LEN |
| } |
| |
| pub fn ranges_byte_range(&self) -> Range<usize> { |
| let start = self.num_unicode_value_ranges_byte_range().end; |
| start..start + self.ranges_byte_len |
| } |
| } |
| |
| impl MinByteRange for DefaultUvsMarker { |
| fn min_byte_range(&self) -> Range<usize> { |
| 0..self.ranges_byte_range().end |
| } |
| } |
| |
| impl<'a> FontRead<'a> for DefaultUvs<'a> { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| let mut cursor = data.cursor(); |
| let num_unicode_value_ranges: u32 = cursor.read()?; |
| let ranges_byte_len = (num_unicode_value_ranges as usize) |
| .checked_mul(UnicodeRange::RAW_BYTE_LEN) |
| .ok_or(ReadError::OutOfBounds)?; |
| cursor.advance_by(ranges_byte_len); |
| cursor.finish(DefaultUvsMarker { ranges_byte_len }) |
| } |
| } |
| |
| /// [Default UVS table](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#default-uvs-table) |
| pub type DefaultUvs<'a> = TableRef<'a, DefaultUvsMarker>; |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> DefaultUvs<'a> { |
| /// Number of Unicode character ranges. |
| pub fn num_unicode_value_ranges(&self) -> u32 { |
| let range = self.shape.num_unicode_value_ranges_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| /// Array of UnicodeRange records. |
| pub fn ranges(&self) -> &'a [UnicodeRange] { |
| let range = self.shape.ranges_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeTable<'a> for DefaultUvs<'a> { |
| fn type_name(&self) -> &str { |
| "DefaultUvs" |
| } |
| fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
| match idx { |
| 0usize => Some(Field::new( |
| "num_unicode_value_ranges", |
| self.num_unicode_value_ranges(), |
| )), |
| 1usize => Some(Field::new( |
| "ranges", |
| traversal::FieldType::array_of_records( |
| stringify!(UnicodeRange), |
| self.ranges(), |
| self.offset_data(), |
| ), |
| )), |
| _ => None, |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> std::fmt::Debug for DefaultUvs<'a> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| (self as &dyn SomeTable<'a>).fmt(f) |
| } |
| } |
| |
| /// [Non-Default UVS table](https://learn.microsoft.com/en-us/typography/opentype/spec/cmap#non-default-uvs-table) |
| #[derive(Debug, Clone, Copy)] |
| #[doc(hidden)] |
| pub struct NonDefaultUvsMarker { |
| uvs_mapping_byte_len: usize, |
| } |
| |
| impl NonDefaultUvsMarker { |
| pub fn num_uvs_mappings_byte_range(&self) -> Range<usize> { |
| let start = 0; |
| start..start + u32::RAW_BYTE_LEN |
| } |
| |
| pub fn uvs_mapping_byte_range(&self) -> Range<usize> { |
| let start = self.num_uvs_mappings_byte_range().end; |
| start..start + self.uvs_mapping_byte_len |
| } |
| } |
| |
| impl MinByteRange for NonDefaultUvsMarker { |
| fn min_byte_range(&self) -> Range<usize> { |
| 0..self.uvs_mapping_byte_range().end |
| } |
| } |
| |
| impl<'a> FontRead<'a> for NonDefaultUvs<'a> { |
| fn read(data: FontData<'a>) -> Result<Self, ReadError> { |
| let mut cursor = data.cursor(); |
| let num_uvs_mappings: u32 = cursor.read()?; |
| let uvs_mapping_byte_len = (num_uvs_mappings as usize) |
| .checked_mul(UvsMapping::RAW_BYTE_LEN) |
| .ok_or(ReadError::OutOfBounds)?; |
| cursor.advance_by(uvs_mapping_byte_len); |
| cursor.finish(NonDefaultUvsMarker { |
| uvs_mapping_byte_len, |
| }) |
| } |
| } |
| |
| /// [Non-Default UVS table](https://learn.microsoft.com/en-us/typography/opentype/spec/cmap#non-default-uvs-table) |
| pub type NonDefaultUvs<'a> = TableRef<'a, NonDefaultUvsMarker>; |
| |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> NonDefaultUvs<'a> { |
| pub fn num_uvs_mappings(&self) -> u32 { |
| let range = self.shape.num_uvs_mappings_byte_range(); |
| self.data.read_at(range.start).unwrap() |
| } |
| |
| pub fn uvs_mapping(&self) -> &'a [UvsMapping] { |
| let range = self.shape.uvs_mapping_byte_range(); |
| self.data.read_array(range).unwrap() |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeTable<'a> for NonDefaultUvs<'a> { |
| fn type_name(&self) -> &str { |
| "NonDefaultUvs" |
| } |
| fn get_field(&self, idx: usize) -> Option<Field<'a>> { |
| match idx { |
| 0usize => Some(Field::new("num_uvs_mappings", self.num_uvs_mappings())), |
| 1usize => Some(Field::new( |
| "uvs_mapping", |
| traversal::FieldType::array_of_records( |
| stringify!(UvsMapping), |
| self.uvs_mapping(), |
| self.offset_data(), |
| ), |
| )), |
| _ => None, |
| } |
| } |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| #[allow(clippy::needless_lifetimes)] |
| impl<'a> std::fmt::Debug for NonDefaultUvs<'a> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| (self as &dyn SomeTable<'a>).fmt(f) |
| } |
| } |
| |
| /// Part of [Cmap14] |
| #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)] |
| #[repr(C)] |
| #[repr(packed)] |
| pub struct UvsMapping { |
| /// Base Unicode value of the UVS |
| pub unicode_value: BigEndian<Uint24>, |
| /// Glyph ID of the UVS |
| pub glyph_id: BigEndian<u16>, |
| } |
| |
| impl UvsMapping { |
| /// Base Unicode value of the UVS |
| pub fn unicode_value(&self) -> Uint24 { |
| self.unicode_value.get() |
| } |
| |
| /// Glyph ID of the UVS |
| pub fn glyph_id(&self) -> u16 { |
| self.glyph_id.get() |
| } |
| } |
| |
| impl FixedSize for UvsMapping { |
| const RAW_BYTE_LEN: usize = Uint24::RAW_BYTE_LEN + u16::RAW_BYTE_LEN; |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeRecord<'a> for UvsMapping { |
| fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> { |
| RecordResolver { |
| name: "UvsMapping", |
| get_field: Box::new(move |idx, _data| match idx { |
| 0usize => Some(Field::new("unicode_value", self.unicode_value())), |
| 1usize => Some(Field::new("glyph_id", self.glyph_id())), |
| _ => None, |
| }), |
| data, |
| } |
| } |
| } |
| |
| /// Part of [Cmap14] |
| #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)] |
| #[repr(C)] |
| #[repr(packed)] |
| pub struct UnicodeRange { |
| /// First value in this range |
| pub start_unicode_value: BigEndian<Uint24>, |
| /// Number of additional values in this range |
| pub additional_count: u8, |
| } |
| |
| impl UnicodeRange { |
| /// First value in this range |
| pub fn start_unicode_value(&self) -> Uint24 { |
| self.start_unicode_value.get() |
| } |
| |
| /// Number of additional values in this range |
| pub fn additional_count(&self) -> u8 { |
| self.additional_count |
| } |
| } |
| |
| impl FixedSize for UnicodeRange { |
| const RAW_BYTE_LEN: usize = Uint24::RAW_BYTE_LEN + u8::RAW_BYTE_LEN; |
| } |
| |
| #[cfg(feature = "experimental_traverse")] |
| impl<'a> SomeRecord<'a> for UnicodeRange { |
| fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> { |
| RecordResolver { |
| name: "UnicodeRange", |
| get_field: Box::new(move |idx, _data| match idx { |
| 0usize => Some(Field::new( |
| "start_unicode_value", |
| self.start_unicode_value(), |
| )), |
| 1usize => Some(Field::new("additional_count", self.additional_count())), |
| _ => None, |
| }), |
| data, |
| } |
| } |
| } |