Skip to main content

ttf_view/tables/cmap/
mod.rs

1use crate::types::{Offset32, Tag, tags, uint16, uint32};
2use std::mem::ManuallyDrop;
3
4mod codepoint;
5mod glyph_id;
6
7pub use codepoint::*;
8pub use glyph_id::*;
9
10pub mod format0;
11pub mod format2;
12pub mod format4;
13pub mod format6;
14pub mod format8;
15
16pub mod format10;
17pub mod format12;
18pub mod format13;
19pub mod format14;
20
21#[repr(C)]
22#[non_exhaustive]
23pub struct CmapTableRepr {
24    pub version: uint16,
25    pub num_tables: uint16,
26    encoding_records: [EncodingRecordRepr; 0],
27}
28#[repr(C)]
29pub struct EncodingRecordRepr {
30    pub platform_id: uint16,
31    pub encoding_id: uint16,
32    pub subtable_offset: Offset32,
33}
34
35impl super::Table for CmapTableRepr {
36    const TAG: Tag = tags::cmap;
37    type Handle<'a> = &'a Self;
38}
39
40impl CmapTableRepr {
41    pub const fn encodings(&self) -> &[EncodingRecordRepr] {
42        unsafe {
43            std::slice::from_raw_parts(self.encoding_records.as_ptr(), self.num_tables.get() as _)
44        }
45    }
46}
47impl EncodingRecordRepr {
48    pub const fn subtable<'a>(&'a self, cmap: &'a CmapTableRepr) -> &'a CmapSubtableRepr {
49        unsafe { &*std::ptr::from_ref(cmap).byte_add(self.subtable_offset.get() as _).cast() }
50    }
51}
52
53#[repr(C)]
54#[non_exhaustive]
55pub struct CmapSubtableRepr {
56    meta: SubtableMeta,
57}
58
59/// The offsets and sizes of `length` and `language` depend on the subtable's format:
60///
61/// ```text
62///                                        SubtableMeta
63///                ┌─────────────────────────────┐─────────────────────────────┐
64///                 0    1    2    3    4    5    6
65///  ShortMeta     ┌────┬────┬────┬────┬────┬────┐
66///  f 0,2,4,6     │ format  │ length  │language │
67///                └─────────┴─────────┴─────────┘
68///                 0    1    2    3    4    5    6    7    8    9    10   11   12
69///  LongMeta      ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
70///  f 8,10,12,13  │ format  │reserved │      length       │     language      │
71///                └─────────┴─────────┴───────────────────┴───────────────────┘
72///                 0    1    2    3    4    5    6
73///  LenOnlyMeta   ┌────┬────┬────┬────┬────┬────┐
74///  f 14          │ format  │      length       │
75///                └─────────┴───────────────────┘
76/// ```
77#[repr(C)]
78union SubtableMeta {
79    short: ManuallyDrop<ShortMeta>,
80    long: ManuallyDrop<LongMeta>,
81    len_only: ManuallyDrop<LenOnlyMeta>,
82}
83
84#[repr(C)]
85#[non_exhaustive]
86struct ShortMeta {
87    format: uint16,
88    length: uint16,
89    language: uint16,
90    data: [u8; 0],
91}
92#[repr(C)]
93#[non_exhaustive]
94struct LongMeta {
95    format: uint16,
96    reserved: uint16,
97    length: uint32,
98    language: uint32,
99    data: [u8; 0],
100}
101#[repr(C)]
102#[non_exhaustive]
103struct LenOnlyMeta {
104    format: uint16,
105    length: uint32,
106    data: [u8; 0],
107}
108
109impl CmapSubtableRepr {
110    pub const fn format(&self) -> u16 {
111        unsafe { self.meta.short.format.get() }
112    }
113    pub const fn length(&self) -> Option<u32> {
114        Some(match self.format() {
115            0 | 2 | 4 | 6 => unsafe { self.meta.short.length.get() as _ },
116            8 | 10 | 12 | 13 => unsafe { self.meta.long.length.get() },
117            14 => unsafe { self.meta.len_only.length.get() },
118            _ => return None,
119        })
120    }
121    pub const fn language(&self) -> Option<u32> {
122        Some(match self.format() {
123            0 | 2 | 4 | 6 => unsafe { self.meta.short.language.get() as _ },
124            8 | 10 | 12 | 13 => unsafe { self.meta.long.language.get() },
125            _ => return None,
126        })
127    }
128    pub const fn data_ptr(&self) -> Option<&u8> {
129        Some(match self.format() {
130            0 | 2 | 4 | 6 => unsafe { &*self.meta.short.data.as_ptr() },
131            8 | 10 | 12 | 13 => unsafe { &*self.meta.long.data.as_ptr() },
132            14 => unsafe { &*self.meta.len_only.data.as_ptr() },
133            _ => return None,
134        })
135    }
136    pub const fn data(&self) -> Option<&[u8]> {
137        match self.format() {
138            0 | 2 | 4 | 6 => unsafe {
139                let size = self.meta.short.length.get() as usize - size_of::<ShortMeta>();
140                Some(std::slice::from_raw_parts(self.meta.short.data.as_ptr(), size))
141            },
142            8 | 10 | 12 | 13 => unsafe {
143                let size = self.meta.long.length.get() as usize - size_of::<LongMeta>();
144                Some(std::slice::from_raw_parts(self.meta.long.data.as_ptr(), size))
145            },
146            14 => unsafe {
147                let size = self.meta.len_only.length.get() as usize - size_of::<LenOnlyMeta>();
148                Some(std::slice::from_raw_parts(self.meta.len_only.data.as_ptr(), size))
149            },
150            _ => None,
151        }
152    }
153}