// 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 { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn num_tables_byte_range(&self) -> Range { let start = self.version_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn encoding_records_byte_range(&self) -> Range { 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 { 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 { let mut cursor = data.cursor(); cursor.advance::(); 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> { 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, /// Platform-specific encoding ID. pub encoding_id: BigEndian, /// Byte offset from beginning of the [`Cmap`] table to the subtable for this /// encoding. pub subtable_offset: BigEndian, } 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, 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, } } } /// #[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 = ::Raw; fn to_raw(self) -> Self::Raw { (self as u16).to_raw() } fn from_raw(raw: Self::Raw) -> Self { let t = ::from_raw(raw); Self::new(t) } } #[cfg(feature = "experimental_traverse")] impl<'a> From for FieldType<'a> { fn from(src: 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 { 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 { 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> { self.dyn_inner().get_field(idx) } } impl Format 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 { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn length_byte_range(&self) -> Range { let start = self.format_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn language_byte_range(&self) -> Range { let start = self.length_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn glyph_id_array_byte_range(&self) -> Range { 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 { 0..self.glyph_id_array_byte_range().end } } impl<'a> FontRead<'a> for Cmap0<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); cursor.advance::(); 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> { 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 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 { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn length_byte_range(&self) -> Range { let start = self.format_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn language_byte_range(&self) -> Range { let start = self.length_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn sub_header_keys_byte_range(&self) -> Range { 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 { 0..self.sub_header_keys_byte_range().end } } impl<'a> FontRead<'a> for Cmap2<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); cursor.advance::(); 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] { 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> { 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, /// Number of valid low bytes for this SubHeader. pub entry_count: BigEndian, /// See text below. pub id_delta: BigEndian, /// See text below. pub id_range_offset: BigEndian, } 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 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 { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn length_byte_range(&self) -> Range { let start = self.format_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn language_byte_range(&self) -> Range { let start = self.length_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn seg_count_x2_byte_range(&self) -> Range { let start = self.language_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn search_range_byte_range(&self) -> Range { let start = self.seg_count_x2_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn entry_selector_byte_range(&self) -> Range { let start = self.search_range_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn range_shift_byte_range(&self) -> Range { let start = self.entry_selector_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn end_code_byte_range(&self) -> Range { let start = self.range_shift_byte_range().end; start..start + self.end_code_byte_len } pub fn reserved_pad_byte_range(&self) -> Range { let start = self.end_code_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn start_code_byte_range(&self) -> Range { let start = self.reserved_pad_byte_range().end; start..start + self.start_code_byte_len } pub fn id_delta_byte_range(&self) -> Range { let start = self.start_code_byte_range().end; start..start + self.id_delta_byte_len } pub fn id_range_offsets_byte_range(&self) -> Range { 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 { 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 { 0..self.glyph_id_array_byte_range().end } } impl<'a> FontRead<'a> for Cmap4<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); cursor.advance::(); let seg_count_x2: u16 = cursor.read()?; cursor.advance::(); cursor.advance::(); cursor.advance::(); 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::(); 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] { 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] { 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] { 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] { 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] { 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> { 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 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 { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn length_byte_range(&self) -> Range { let start = self.format_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn language_byte_range(&self) -> Range { let start = self.length_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn first_code_byte_range(&self) -> Range { let start = self.language_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn entry_count_byte_range(&self) -> Range { let start = self.first_code_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn glyph_id_array_byte_range(&self) -> Range { 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 { 0..self.glyph_id_array_byte_range().end } } impl<'a> FontRead<'a> for Cmap6<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); cursor.advance::(); cursor.advance::(); 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] { 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> { 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 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 { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn reserved_byte_range(&self) -> Range { let start = self.format_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn length_byte_range(&self) -> Range { let start = self.reserved_byte_range().end; start..start + u32::RAW_BYTE_LEN } pub fn language_byte_range(&self) -> Range { let start = self.length_byte_range().end; start..start + u32::RAW_BYTE_LEN } pub fn is32_byte_range(&self) -> Range { let start = self.language_byte_range().end; start..start + self.is32_byte_len } pub fn num_groups_byte_range(&self) -> Range { let start = self.is32_byte_range().end; start..start + u32::RAW_BYTE_LEN } pub fn groups_byte_range(&self) -> Range { let start = self.num_groups_byte_range().end; start..start + self.groups_byte_len } } impl MinByteRange for Cmap8Marker { fn min_byte_range(&self) -> Range { 0..self.groups_byte_range().end } } impl<'a> FontRead<'a> for Cmap8<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); cursor.advance::(); cursor.advance::(); 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> { 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, /// Last character code in this group; same condition as listed /// above for the startCharCode pub end_char_code: BigEndian, /// Glyph index corresponding to the starting character code pub start_glyph_id: BigEndian, } 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 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 { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn reserved_byte_range(&self) -> Range { let start = self.format_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn length_byte_range(&self) -> Range { let start = self.reserved_byte_range().end; start..start + u32::RAW_BYTE_LEN } pub fn language_byte_range(&self) -> Range { let start = self.length_byte_range().end; start..start + u32::RAW_BYTE_LEN } pub fn start_char_code_byte_range(&self) -> Range { let start = self.language_byte_range().end; start..start + u32::RAW_BYTE_LEN } pub fn num_chars_byte_range(&self) -> Range { let start = self.start_char_code_byte_range().end; start..start + u32::RAW_BYTE_LEN } pub fn glyph_id_array_byte_range(&self) -> Range { 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 { 0..self.glyph_id_array_byte_range().end } } impl<'a> FontRead<'a> for Cmap10<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); cursor.advance::(); cursor.advance::(); cursor.advance::(); cursor.advance::(); 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] { 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> { 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 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 { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn reserved_byte_range(&self) -> Range { let start = self.format_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn length_byte_range(&self) -> Range { let start = self.reserved_byte_range().end; start..start + u32::RAW_BYTE_LEN } pub fn language_byte_range(&self) -> Range { let start = self.length_byte_range().end; start..start + u32::RAW_BYTE_LEN } pub fn num_groups_byte_range(&self) -> Range { let start = self.language_byte_range().end; start..start + u32::RAW_BYTE_LEN } pub fn groups_byte_range(&self) -> Range { let start = self.num_groups_byte_range().end; start..start + self.groups_byte_len } } impl MinByteRange for Cmap12Marker { fn min_byte_range(&self) -> Range { 0..self.groups_byte_range().end } } impl<'a> FontRead<'a> for Cmap12<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); cursor.advance::(); cursor.advance::(); 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> { 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 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 { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn reserved_byte_range(&self) -> Range { let start = self.format_byte_range().end; start..start + u16::RAW_BYTE_LEN } pub fn length_byte_range(&self) -> Range { let start = self.reserved_byte_range().end; start..start + u32::RAW_BYTE_LEN } pub fn language_byte_range(&self) -> Range { let start = self.length_byte_range().end; start..start + u32::RAW_BYTE_LEN } pub fn num_groups_byte_range(&self) -> Range { let start = self.language_byte_range().end; start..start + u32::RAW_BYTE_LEN } pub fn groups_byte_range(&self) -> Range { let start = self.num_groups_byte_range().end; start..start + self.groups_byte_len } } impl MinByteRange for Cmap13Marker { fn min_byte_range(&self) -> Range { 0..self.groups_byte_range().end } } impl<'a> FontRead<'a> for Cmap13<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); cursor.advance::(); cursor.advance::(); 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> { 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, /// Last character code in this group pub end_char_code: BigEndian, /// Glyph index to be used for all the characters in the group’s /// range. pub glyph_id: BigEndian, } 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 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 { let start = 0; start..start + u16::RAW_BYTE_LEN } pub fn length_byte_range(&self) -> Range { let start = self.format_byte_range().end; start..start + u32::RAW_BYTE_LEN } pub fn num_var_selector_records_byte_range(&self) -> Range { let start = self.length_byte_range().end; start..start + u32::RAW_BYTE_LEN } pub fn var_selector_byte_range(&self) -> Range { 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 { 0..self.var_selector_byte_range().end } } impl<'a> FontRead<'a> for Cmap14<'a> { fn read(data: FontData<'a>) -> Result { let mut cursor = data.cursor(); cursor.advance::(); cursor.advance::(); 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> { 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, /// Offset from the start of the [`Cmap14`] subtable to Default UVS /// Table. May be NULL. pub default_uvs_offset: BigEndian>, /// Offset from the start of the [`Cmap14`] subtable to Non-Default /// UVS Table. May be NULL. pub non_default_uvs_offset: BigEndian>, } 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 { 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, 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 { 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, 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 { let start = 0; start..start + u32::RAW_BYTE_LEN } pub fn ranges_byte_range(&self) -> Range { 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 { 0..self.ranges_byte_range().end } } impl<'a> FontRead<'a> for DefaultUvs<'a> { fn read(data: FontData<'a>) -> Result { 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> { 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 { let start = 0; start..start + u32::RAW_BYTE_LEN } pub fn uvs_mapping_byte_range(&self) -> Range { 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 { 0..self.uvs_mapping_byte_range().end } } impl<'a> FontRead<'a> for NonDefaultUvs<'a> { fn read(data: FontData<'a>) -> Result { 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> { 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, /// Glyph ID of the UVS pub glyph_id: BigEndian, } 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, /// 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, } } }