Skip to main content

ttf_view/tables/cmap/
mod.rs

1use crate::{
2    types::{Offset32, Tag, tags, uint16, uint32},
3    util::iterator_map,
4};
5use std::mem::ManuallyDrop;
6
7mod codepoint;
8mod glyph_id;
9
10pub use codepoint::*;
11pub use glyph_id::*;
12
13pub mod format0;
14pub mod format2;
15pub mod format4;
16pub mod format6;
17pub mod format8;
18
19pub mod format10;
20pub mod format12;
21pub mod format13;
22pub mod format14;
23
24#[repr(C)]
25#[non_exhaustive]
26pub struct CmapTableRepr {
27    pub version: uint16,
28    pub num_tables: uint16,
29    encoding_records: [EncodingRecordRepr; 0],
30}
31#[repr(C)]
32pub struct EncodingRecordRepr {
33    pub platform_id: uint16,
34    pub encoding_id: uint16,
35    pub subtable_offset: Offset32,
36}
37
38impl super::Table for CmapTableRepr {
39    const TAG: Tag = tags::cmap;
40    type Handle<'a> = &'a Self;
41}
42
43impl CmapTableRepr {
44    pub const fn encoding_records(&self) -> &[EncodingRecordRepr] {
45        let len = self.num_tables.get() as usize;
46        unsafe { std::slice::from_raw_parts(self.encoding_records.as_ptr(), len) }
47    }
48    pub const fn encodings(&self) -> EncodingsIter<'_> {
49        EncodingsIter::new(self)
50    }
51}
52
53#[derive(Copy)]
54#[derive_const(Clone)]
55pub struct EncodingHandle<'a>(&'a CmapTableRepr, &'a EncodingRecordRepr);
56
57const impl std::ops::Deref for EncodingHandle<'_> {
58    type Target = EncodingRecordRepr;
59    fn deref(&self) -> &Self::Target {
60        self.1
61    }
62}
63impl<'a> EncodingHandle<'a> {
64    pub const fn subtable(&self) -> &'a CmapSubtableRepr {
65        let offset = self.1.subtable_offset.get() as _;
66        unsafe { &*std::ptr::from_ref(self.0).cast::<u8>().byte_add(offset).cast() }
67    }
68}
69
70// TODO: When std::slice::Iter's Clone is constified, make the derive const
71pub struct EncodingsIter<'a> {
72    cmap: &'a CmapTableRepr,
73    inner: std::slice::Iter<'a, EncodingRecordRepr>,
74}
75impl<'a> EncodingsIter<'a> {
76    pub const fn new(cmap: &'a CmapTableRepr) -> Self {
77        Self { cmap, inner: cmap.encoding_records().iter() }
78    }
79    // TODO: When std::slice::Iter's as_slice() is constified, constify as_records()
80    pub fn as_records(&self) -> &'a [EncodingRecordRepr] {
81        self.inner.as_slice()
82    }
83}
84iterator_map!(EncodingsIter<'a> {
85    type Item = EncodingHandle<'a>;
86    |this, x| EncodingHandle(this.cmap, x)
87});
88
89#[repr(C)]
90#[non_exhaustive]
91pub struct CmapSubtableRepr {
92    meta: SubtableMeta,
93    // : <format-specific data: use meta.*.data to point to>,
94}
95
96/// The offsets and sizes of `length` and `language` depend on the subtable's format:
97///
98/// ```text
99///                                        SubtableMeta
100///                ┌─────────────────────────────┐─────────────────────────────┐
101///                 0    1    2    3    4    5    6
102///  ShortMeta     ┌────┬────┬────┬────┬────┬────┐
103///  f 0,2,4,6     │ format  │ length  │language │
104///                └─────────┴─────────┴─────────┘
105///                 0    1    2    3    4    5    6    7    8    9    10   11   12
106///  LongMeta      ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
107///  f 8,10,12,13  │ format  │reserved │      length       │     language      │
108///                └─────────┴─────────┴───────────────────┴───────────────────┘
109///                 0    1    2    3    4    5    6
110///  LenOnlyMeta   ┌────┬────┬────┬────┬────┬────┐
111///  f 14          │ format  │      length       │
112///                └─────────┴───────────────────┘
113/// ```
114#[repr(C)]
115union SubtableMeta {
116    short: ManuallyDrop<ShortMeta>,
117    long: ManuallyDrop<LongMeta>,
118    len_only: ManuallyDrop<LenOnlyMeta>,
119}
120
121#[repr(C)]
122#[non_exhaustive]
123struct ShortMeta {
124    format: uint16,
125    length: uint16,
126    language: uint16,
127    data: [u8; 0],
128}
129#[repr(C)]
130#[non_exhaustive]
131struct LongMeta {
132    format: uint16,
133    reserved: uint16,
134    length: uint32,
135    language: uint32,
136    data: [u8; 0],
137}
138#[repr(C)]
139#[non_exhaustive]
140struct LenOnlyMeta {
141    format: uint16,
142    length: uint32,
143    data: [u8; 0],
144}
145
146impl CmapSubtableRepr {
147    pub const fn format(&self) -> u16 {
148        unsafe { self.meta.short.format.get() }
149    }
150    pub const fn length(&self) -> Option<u32> {
151        Some(match self.format() {
152            0 | 2 | 4 | 6 => unsafe { self.meta.short.length.get() as _ },
153            8 | 10 | 12 | 13 => unsafe { self.meta.long.length.get() },
154            14 => unsafe { self.meta.len_only.length.get() },
155            _ => return None,
156        })
157    }
158    pub const fn language(&self) -> Option<u32> {
159        Some(match self.format() {
160            0 | 2 | 4 | 6 => unsafe { self.meta.short.language.get() as _ },
161            8 | 10 | 12 | 13 => unsafe { self.meta.long.language.get() },
162            _ => return None,
163        })
164    }
165    const fn data_ptr(&self) -> Option<&u8> {
166        Some(match self.format() {
167            0 | 2 | 4 | 6 => unsafe { &*self.meta.short.data.as_ptr() },
168            8 | 10 | 12 | 13 => unsafe { &*self.meta.long.data.as_ptr() },
169            14 => unsafe { &*self.meta.len_only.data.as_ptr() },
170            _ => return None,
171        })
172    }
173
174    pub const fn get_as_bytes(&self) -> Option<&[u8]> {
175        match self.format() {
176            0 | 2 | 4 | 6 => unsafe {
177                let size = self.meta.short.length.get() as usize - size_of::<ShortMeta>();
178                Some(std::slice::from_raw_parts(self.meta.short.data.as_ptr(), size))
179            },
180            8 | 10 | 12 | 13 => unsafe {
181                let size = self.meta.long.length.get() as usize - size_of::<LongMeta>();
182                Some(std::slice::from_raw_parts(self.meta.long.data.as_ptr(), size))
183            },
184            14 => unsafe {
185                let size = self.meta.len_only.length.get() as usize - size_of::<LenOnlyMeta>();
186                Some(std::slice::from_raw_parts(self.meta.len_only.data.as_ptr(), size))
187            },
188            _ => None,
189        }
190    }
191    pub const fn get_as<T: CmapSubtableTrait>(&self) -> Option<&T> {
192        if self.format() == T::FORMAT { Some(unsafe { self.get_as_unchecked() }) } else { None }
193    }
194    pub const unsafe fn get_as_unchecked<T: CmapSubtableTrait>(&self) -> &T {
195        debug_assert!(self.format() == T::FORMAT);
196        unsafe { &*std::ptr::from_ref(self.data_ptr().unwrap()).cast() }
197    }
198
199    pub const fn as_format0(&self) -> Option<&format0::CmapSubtableFormat0Repr> {
200        self.get_as()
201    }
202    pub const fn as_format2(&self) -> Option<&format2::CmapSubtableFormat2Repr> {
203        self.get_as()
204    }
205    pub const fn as_format4(&self) -> Option<&format4::CmapSubtableFormat4Repr> {
206        self.get_as()
207    }
208    pub const fn as_format6(&self) -> Option<&format6::CmapSubtableFormat6Repr> {
209        self.get_as()
210    }
211    pub const fn as_format8(&self) -> Option<&format8::CmapSubtableFormat8Repr> {
212        self.get_as()
213    }
214    pub const fn as_format10(&self) -> Option<&format10::CmapSubtableFormat10Repr> {
215        self.get_as()
216    }
217    pub const fn as_format12(&self) -> Option<&format12::CmapSubtableFormat12Repr> {
218        self.get_as()
219    }
220    pub const fn as_format13(&self) -> Option<&format13::CmapSubtableFormat13Repr> {
221        self.get_as()
222    }
223    pub const fn as_format14(&self) -> Option<&format14::CmapSubtableFormat14Repr> {
224        self.get_as()
225    }
226}
227
228pub trait CmapSubtableTrait {
229    const FORMAT: u16;
230}