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::*;
#[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()
}
}
#[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),
}
#[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<u8> {
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()
}
}
#[derive(Clone, Copy)]
pub struct ContinuousSegment {
end_code: u16,
start_code: u16,
id_delta: i16,
}
impl ContinuousSegment {
pub fn chars(&self) -> RangeInclusive<u16> { 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<u16> {
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<Item = u16> + '_ {
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<u16> { 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<u16> {
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<Self::Item> {
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<usize>) {
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<Segment<'a>> {
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()
}
}
#[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) }
}
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()
}
}
#[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<u32> {
self.start_char()..=self.end_char()
}
pub fn glyphs(&self) -> RangeInclusive<u32> {
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() } pub fn groups(&self) -> &'a [SequentialMapGroup] { self.array(16, self.uint32(12) as usize) }
pub fn group_of(&self, value: u32) -> Option<&'a SequentialMapGroup> {
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()
}
}
#[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<Self, ReadError> {
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)),
}
}
}
#[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<Subtable<'a>, ReadError> {
Subtable::try_from(&self.0[record.subtable_offset() as usize..], record.encoding())
}
pub fn subtables(&self) -> impl ExactSizeIterator<Item = Result<Subtable<'a>, 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<Self, Self::Error> {
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)
}
}