use std::ops::RangeInclusive; use std::fmt::{ Debug, Formatter, Result as FmtResult }; use num_enum::{ FromPrimitive, IntoPrimitive }; use bytemuck::{ Zeroable, Pod }; use super::ReadError; use super::core::*; use super::common::*; // Encoding Record #[derive(Clone, Copy, Zeroable, Pod)] #[repr(transparent)] pub struct EncodingRecord([u8; 8]); impl<'a> RandomAccess<'a> for &'a EncodingRecord { fn bytes(&self) -> &'a [u8] { &self.0 } } impl EncodingRecord { pub fn platform(&self) -> Platform { self.uint16(0).into() } pub fn encoding(&self) -> PlatformEncoding { (self.platform(), self.uint16(2)).into() } pub fn subtable_offset(&self) -> u32 { self.uint32(4) } } impl Debug for EncodingRecord { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_struct("EncodingRecord") .field("platform", &self.platform()) .field("encoding", &self.encoding()) .field("subtable_offset", &self.subtable_offset()) .finish() } } // Format #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(FromPrimitive, IntoPrimitive)] #[repr(u16)] pub enum Format { ByteEncodingTable = 0, HighByteMappingTable = 2, SegmentMappingTable = 4, TrimmedMappingTable = 6, MixedCoverageTable = 8, TrimmedArrayTable = 10, SegmentCoverageTable = 12, ManyToOneRangeMappingTable = 13, UnicodeVariationSequenceTable = 14, #[num_enum(catch_all)] Unknown(u16), } // Byte Encoding Table #[derive(Clone, Copy)] pub struct ByteEncodingTable<'a> { encoding: PlatformEncoding, data: &'a [u8], } impl<'a> RandomAccess<'a> for ByteEncodingTable<'a> { fn bytes(&self) -> &'a [u8] { self.data } } impl<'a> ByteEncodingTable<'a> { pub fn format(&self) -> Format { self.uint16(0).into() } pub fn length(&self) -> u16 { self.uint16(2) } pub fn encoding_and_language(&self) -> PlatformEncodingAndLanguage { (self.encoding, self.uint16(4)).into() } pub fn glyph_ids(&self) -> &'a [u8] { self.array(6, self.length() as usize - 6) } pub fn map(&self, value: u8) -> Option { let ids = self.glyph_ids(); let value = value as usize; if value < ids.len() { Some(ids[value]) } else { None } } } impl<'a> Debug for ByteEncodingTable<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_struct("ByteEncodingTable") .field("encoding_and_language", &self.encoding_and_language()) .field("glyph_ids", &self.glyph_ids()) .finish() } } // Segment Mapping Table #[derive(Clone, Copy)] pub struct ContinuousSegment { end_code: u16, start_code: u16, id_delta: i16, } impl ContinuousSegment { pub fn chars(&self) -> RangeInclusive { self.start_code..=self.end_code } pub fn contains(&self, c: u16) -> bool { c >= self.start_code && c <= self.end_code } pub fn glyphs(&self) -> RangeInclusive { let start = self.start_code as i32 + self.id_delta as i32; let stop = self.end_code as i32 + self.id_delta as i32; (start as u16)..=(stop as u16) } pub fn map(&self, c: u16) -> u16 { if !self.contains(c) { return 0; } let value = c as i32 + self.id_delta as i32; value as u16 } } impl Debug for ContinuousSegment { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_struct("ContinuousSegment") .field("chars", &self.chars()) .field("glyphs", &self.glyphs()) .finish() } } #[derive(Clone, Copy)] pub struct GlyphDeltaMapping<'a> { glyph_ids: U16Array<'a>, id_delta: i16, } impl<'a> GlyphDeltaMapping<'a> { pub fn len(&self) -> usize { self.glyph_ids.len() } pub fn is_empty(&self) -> bool { self.len() == 0 } pub fn get(&self, index: usize) -> u16 { let glyph_id = self.glyph_ids.get(index); if glyph_id == 0 { return 0; } let value = glyph_id as i32 + self.id_delta as i32; value as u16 } pub fn iter(&self) -> impl ExactSizeIterator + '_ { self.glyph_ids.iter().map(|x| match x { 0 => 0, x => (x as i32 + self.id_delta as i32) as u16, }) } } impl<'a> Debug for GlyphDeltaMapping<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_list() .entries(self.iter()) .finish() } } #[derive(Clone, Copy)] pub struct TableSegment<'a> { end_code: u16, start_code: u16, glyphs: GlyphDeltaMapping<'a>, } impl<'a> TableSegment<'a> { pub fn chars(&self) -> RangeInclusive { self.start_code..=self.end_code } pub fn contains(&self, c: u16) -> bool { c >= self.start_code && c <= self.end_code } pub fn glyphs(&self) -> GlyphDeltaMapping<'a> { self.glyphs } pub fn map(&self, c: u16) -> u16 { if !self.contains(c) { return 0; } let index = (c - self.start_code) as usize; self.glyphs.get(index) } } impl<'a> Debug for TableSegment<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_struct("TableSegment") .field("chars", &self.chars()) .field("glyphs", &self.glyphs()) .finish() } } #[derive(Clone, Copy)] pub enum Segment<'a> { Continuous(ContinuousSegment), Table(TableSegment<'a>), } impl<'a> Segment<'a> { pub fn chars(&self) -> RangeInclusive { match self { Self::Continuous(x) => x.chars(), Self::Table(x) => x.chars(), } } pub fn contains(&self, c: u16) -> bool { match self { Self::Continuous(x) => x.contains(c), Self::Table(x) => x.contains(c), } } pub fn map(&self, c: u16) -> u16 { match self { Self::Continuous(x) => x.map(c), Self::Table(x) => x.map(c), } } } impl<'a> Debug for Segment<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { match self { Self::Continuous(x) => x.fmt(f), Self::Table(x) => x.fmt(f), } } } #[derive(Clone)] pub struct Segments<'a> { table: SegmentMappingTable<'a>, index: u16, } impl<'a> Iterator for Segments<'a> { type Item = Segment<'a>; fn next(&mut self) -> Option { if self.index < self.table.segment_count() { let segment = self.table.segment(self.index); self.index += 1; Some(segment) } else { None } } fn size_hint(&self) -> (usize, Option) { let len = self.table.length() as usize; (len, Some(len)) } } impl<'a> ExactSizeIterator for Segments<'a> {} impl<'a> Debug for Segments<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_list() .entries(self.clone()) .finish() } } #[derive(Clone, Copy)] pub struct SegmentMappingTable<'a> { encoding: PlatformEncoding, data: &'a [u8], } impl<'a> RandomAccess<'a> for SegmentMappingTable<'a> { fn bytes(&self) -> &'a [u8] { self.data } } impl<'a> SegmentMappingTable<'a> { pub fn format(&self) -> Format { self.uint16(0).into() } pub fn length(&self) -> u16 { self.uint16(2) } pub fn encoding_and_language(&self) -> PlatformEncodingAndLanguage { (self.encoding, self.uint16(4)).into() } pub fn segment_count_x2(&self) -> u16 { self.uint16(6) } pub fn segment_count(&self) -> u16 { self.segment_count_x2() >> 1 } pub fn search_range(&self) -> u16 { self.uint16(8) } pub fn entry_selector(&self) -> u16 { self.uint16(10) } pub fn range_shift(&self) -> u16 { self.uint16(12) } pub fn end_codes(&self) -> U16Array<'a> { self.uint16_array(14, self.segment_count() as usize) } pub fn segment(&self, index: u16) -> Segment<'a> { let size = self.segment_count_x2() as usize; let offset = 14 + ((index as usize) << 1); let end_code = self.uint16(offset); let offset = offset + 2 + size; let start_code = self.uint16(offset); let offset = offset + size; let id_delta = self.int16(offset); let offset = offset + size; let id_range_offset = self.uint16(offset); if id_range_offset == 0 { Segment::Continuous(ContinuousSegment { end_code, start_code, id_delta, }) } else { let offset = offset + id_range_offset as usize; let count = (end_code - start_code + 1) as usize; let glyph_ids = self.uint16_array(offset, count); Segment::Table(TableSegment { end_code, start_code, glyphs: GlyphDeltaMapping { glyph_ids, id_delta, }, }) } } pub fn segments(&self) -> Segments<'a> { Segments { table: *self, index: 0 } } pub fn segment_of(&self, value: u16) -> Option> { // TODO binary search for (i, stop) in self.end_codes().iter().enumerate() { if value <= stop { let seg = self.segment(i as u16); return if seg.contains(value) { Some(seg) } else { None }; } } None } pub fn map(&self, value: u16) -> u16 { self.segment_of(value).map(|x| x.map(value)).unwrap_or_default() } } impl<'a> Debug for SegmentMappingTable<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_struct("SegmentMappingTable") .field("encoding_and_language", &self.encoding_and_language()) .field("segments", &self.segments()) .finish() } } // Trimmed Mapping Table #[derive(Clone, Copy)] pub struct TrimmedMappingTable<'a> { encoding: PlatformEncoding, data: &'a [u8], } impl<'a> RandomAccess<'a> for TrimmedMappingTable<'a> { fn bytes(&self) -> &'a [u8] { self.data } } impl<'a> TrimmedMappingTable<'a> { pub fn format(&self) -> Format { self.uint16(0).into() } pub fn length(&self) -> u16 { self.uint16(2) } pub fn encoding_and_language(&self) -> PlatformEncodingAndLanguage { (self.encoding, self.uint16(4)).into() } pub fn first_code(&self) -> u16 { self.uint16(6) } pub fn entry_count(&self) -> u16 { self.uint16(8) } pub fn glyph_ids(&self) -> U16Array<'a> { self.uint16_array(10, self.entry_count() as usize) } // TODO } impl<'a> Debug for TrimmedMappingTable<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_struct("TrimmedMappingTable") .field("encoding_and_language", &self.encoding_and_language()) .field("first_code", &self.first_code()) .field("glyph_ids", &self.glyph_ids()) .finish() } } // Segment Coverage Table #[derive(Clone, Copy, Zeroable, Pod)] #[repr(transparent)] pub struct SequentialMapGroup([u8; 12]); impl<'a> RandomAccess<'a> for &'a SequentialMapGroup { fn bytes(&self) -> &'a [u8] { &self.0 } } impl SequentialMapGroup { pub fn start_char(&self) -> u32 { self.uint32(0) } pub fn end_char(&self) -> u32 { self.uint32(4) } pub fn start_glyph(&self) -> u32 { self.uint32(8) } pub fn chars(&self) -> RangeInclusive { self.start_char()..=self.end_char() } pub fn glyphs(&self) -> RangeInclusive { let chars = self.chars(); let start = self.start_glyph(); let stop = start + chars.end() - chars.start(); start..=stop } pub fn contains(&self, c: u32) -> bool { let chars = self.chars(); c >= *chars.start() && c <= *chars.end() } pub fn map(&self, c: u32) -> u32 { let chars = self.chars(); if c >= *chars.start() && c <= *chars.end() { self.start_glyph() + c - *chars.start() } else { 0 } } } impl Debug for SequentialMapGroup { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_struct("SequentialMapGroup") .field("chars", &self.chars()) .field("glyphs", &self.glyphs()) .finish() } } #[derive(Clone, Copy)] pub struct SegmentCoverageTable<'a> { encoding: PlatformEncoding, data: &'a [u8], } impl<'a> RandomAccess<'a> for SegmentCoverageTable<'a> { fn bytes(&self) -> &'a [u8] { self.data } } impl<'a> SegmentCoverageTable<'a> { pub fn format(&self) -> Format { self.uint16(0).into() } pub fn length(&self) -> u32 { self.uint32(4) } pub fn encoding_and_language(&self) -> PlatformEncodingAndLanguage { (self.encoding, self.uint32(8) as u16).into() } // TODO check if upper bits have a meaning pub fn groups(&self) -> &'a [SequentialMapGroup] { self.array(16, self.uint32(12) as usize) } pub fn group_of(&self, value: u32) -> Option<&'a SequentialMapGroup> { // TODO binary search for group in self.groups() { if value <= group.end_char() { return if value >= group.start_char() { Some(group) } else { None }; } } None } pub fn map(&self, value: u32) -> u32 { self.group_of(value).map(|x| x.map(value)).unwrap_or_default() } } impl<'a> Debug for SegmentCoverageTable<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_struct("SegmentCoverageTable") .field("encoding_and_language", &self.encoding_and_language()) .field("groups", &self.groups()) .finish() } } // Generic Subtable #[derive(Clone, Copy)] pub enum Subtable<'a> { ByteEncodingTable(ByteEncodingTable<'a>), SegmentMappingTable(SegmentMappingTable<'a>), TrimmedMappingTable(TrimmedMappingTable<'a>), SegmentCoverageTable(SegmentCoverageTable<'a>), } impl<'a> RandomAccess<'a> for Subtable<'a> { fn bytes(&self) -> &'a [u8] { match self { Self::ByteEncodingTable(x) => x.bytes(), Self::SegmentMappingTable(x) => x.bytes(), Self::TrimmedMappingTable(x) => x.bytes(), Self::SegmentCoverageTable(x) => x.bytes(), } } } impl<'a> Subtable<'a> { pub fn format(&self) -> Format { self.uint16(0).into() } pub fn encoding_and_language(&self) -> PlatformEncodingAndLanguage { match self { Self::ByteEncodingTable(x) => x.encoding_and_language(), Self::SegmentMappingTable(x) => x.encoding_and_language(), Self::TrimmedMappingTable(x) => x.encoding_and_language(), Self::SegmentCoverageTable(x) => x.encoding_and_language(), } } } impl<'a> Debug for Subtable<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { match self { Self::ByteEncodingTable(x) => x.fmt(f), Self::SegmentMappingTable(x) => x.fmt(f), Self::TrimmedMappingTable(x) => x.fmt(f), Self::SegmentCoverageTable(x) => x.fmt(f), } } } impl<'a> Subtable<'a> { pub fn try_from(data: &'a [u8], encoding: PlatformEncoding) -> Result { if data.len() < 6 { return Err(ReadError::UnexpectedEof); } let format: Format = data.uint16(0).into(); match format { Format::ByteEncodingTable => { let length = data.uint16(2); let data = &data[0..length as usize]; Ok(Self::ByteEncodingTable(ByteEncodingTable { encoding, data })) }, Format::SegmentMappingTable => { let length = data.uint16(2); let data = &data[0..length as usize]; Ok(Self::SegmentMappingTable(SegmentMappingTable { encoding, data })) }, Format::TrimmedMappingTable => { let length = data.uint16(2); let data = &data[0..length as usize]; Ok(Self::TrimmedMappingTable(TrimmedMappingTable { encoding, data })) }, Format::SegmentCoverageTable => { let length = data.uint32(4); let data = &data[0..length as usize]; Ok(Self::SegmentCoverageTable(SegmentCoverageTable { encoding, data })) }, Format::Unknown(x) => Err(ReadError::UnknownCmapFormat(x)), x => Err(ReadError::UnsupportedCmapFormat(x)), } } } // Character To Glyph Map #[derive(Clone, Copy)] #[repr(transparent)] pub struct CharacterToGlyphMap<'a>(&'a [u8]); impl<'a> RandomAccess<'a> for CharacterToGlyphMap<'a> { fn bytes(&self) -> &'a [u8] { self.0 } } impl<'a> CharacterToGlyphMap<'a> { pub fn version(&self) -> u16 { self.uint16(0) } pub fn subtable_count(&self) -> u16 { self.uint16(2) } pub fn encoding_records(&self) -> &'a [EncodingRecord] { self.array(4, self.subtable_count() as usize) } pub fn subtable(&self, record: &EncodingRecord) -> Result, ReadError> { Subtable::try_from(&self.0[record.subtable_offset() as usize..], record.encoding()) } pub fn subtables(&self) -> impl ExactSizeIterator, ReadError>> + '_ { self.encoding_records().iter().map(|x| self.subtable(x)) } } impl<'a> Debug for CharacterToGlyphMap<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_list() .entries(self.subtables()) .finish() } } impl<'a> TryFrom<&'a [u8]> for CharacterToGlyphMap<'a> { type Error = ReadError; fn try_from(value: &'a [u8]) -> Result { if value.len() < 4 { return Err(ReadError::UnexpectedEof); } let value = CharacterToGlyphMap(value); let version = value.version(); if version != 0 { return Err(ReadError::UnsupportedTableVersionSingle(version)); } if value.bytes().len() < 4 + value.subtable_count() as usize * 8 { return Err(ReadError::UnexpectedEof); } Ok(value) } }