1use crate::parser::{FromData, LazyArray16, Offset, Offset32, Stream};
12use crate::{name::PlatformId, GlyphId};
13
14mod format0;
15mod format10;
16mod format12;
17mod format13;
18mod format14;
19mod format2;
20mod format4;
21mod format6;
22
23pub use format0::Subtable0;
24pub use format10::Subtable10;
25pub use format12::Subtable12;
26pub use format13::Subtable13;
27pub use format14::{GlyphVariationResult, Subtable14};
28pub use format2::Subtable2;
29pub use format4::Subtable4;
30pub use format6::Subtable6;
31
32#[allow(missing_docs)]
34#[derive(Clone, Copy, Debug)]
35pub enum Format<'a> {
36    ByteEncodingTable(Subtable0<'a>),
37    HighByteMappingThroughTable(Subtable2<'a>),
38    SegmentMappingToDeltaValues(Subtable4<'a>),
39    TrimmedTableMapping(Subtable6<'a>),
40    MixedCoverage, TrimmedArray(Subtable10<'a>),
42    SegmentedCoverage(Subtable12<'a>),
43    ManyToOneRangeMappings(Subtable13<'a>),
44    UnicodeVariationSequences(Subtable14<'a>),
45}
46
47#[derive(Clone, Copy, Debug)]
49pub struct Subtable<'a> {
50    pub platform_id: PlatformId,
52    pub encoding_id: u16,
54    pub format: Format<'a>,
56}
57
58impl<'a> Subtable<'a> {
59    #[inline]
61    pub fn is_unicode(&self) -> bool {
62        const WINDOWS_UNICODE_BMP_ENCODING_ID: u16 = 1;
64        const WINDOWS_UNICODE_FULL_REPERTOIRE_ENCODING_ID: u16 = 10;
65
66        match self.platform_id {
67            PlatformId::Unicode => true,
68            PlatformId::Windows if self.encoding_id == WINDOWS_UNICODE_BMP_ENCODING_ID => true,
69            PlatformId::Windows => {
70                let is_format_12_compatible = matches!(
73                    self.format,
74                    Format::SegmentedCoverage(..) | Format::ManyToOneRangeMappings(..)
75                );
76
77                self.encoding_id == WINDOWS_UNICODE_FULL_REPERTOIRE_ENCODING_ID
81                    && is_format_12_compatible
82            }
83            _ => false,
84        }
85    }
86
87    #[inline]
98    pub fn glyph_index(&self, code_point: u32) -> Option<GlyphId> {
99        match self.format {
100            Format::ByteEncodingTable(ref subtable) => subtable.glyph_index(code_point),
101            Format::HighByteMappingThroughTable(ref subtable) => subtable.glyph_index(code_point),
102            Format::SegmentMappingToDeltaValues(ref subtable) => subtable.glyph_index(code_point),
103            Format::TrimmedTableMapping(ref subtable) => subtable.glyph_index(code_point),
104            Format::MixedCoverage => None,
105            Format::TrimmedArray(ref subtable) => subtable.glyph_index(code_point),
106            Format::SegmentedCoverage(ref subtable) => subtable.glyph_index(code_point),
107            Format::ManyToOneRangeMappings(ref subtable) => subtable.glyph_index(code_point),
108            Format::UnicodeVariationSequences(_) => None,
110        }
111    }
112
113    #[inline]
119    pub fn glyph_variation_index(
120        &self,
121        code_point: u32,
122        variation: u32,
123    ) -> Option<GlyphVariationResult> {
124        match self.format {
125            Format::UnicodeVariationSequences(ref subtable) => {
126                subtable.glyph_index(code_point, variation)
127            }
128            _ => None,
129        }
130    }
131
132    pub fn codepoints<F: FnMut(u32)>(&self, f: F) {
146        match self.format {
147            Format::ByteEncodingTable(ref subtable) => subtable.codepoints(f),
148            Format::HighByteMappingThroughTable(ref subtable) => subtable.codepoints(f),
149            Format::SegmentMappingToDeltaValues(ref subtable) => subtable.codepoints(f),
150            Format::TrimmedTableMapping(ref subtable) => subtable.codepoints(f),
151            Format::MixedCoverage => {} Format::TrimmedArray(ref subtable) => subtable.codepoints(f),
153            Format::SegmentedCoverage(ref subtable) => subtable.codepoints(f),
154            Format::ManyToOneRangeMappings(ref subtable) => subtable.codepoints(f),
155            Format::UnicodeVariationSequences(_) => {} };
157    }
158}
159
160#[derive(Clone, Copy)]
161struct EncodingRecord {
162    platform_id: PlatformId,
163    encoding_id: u16,
164    offset: Offset32,
165}
166
167impl FromData for EncodingRecord {
168    const SIZE: usize = 8;
169
170    #[inline]
171    fn parse(data: &[u8]) -> Option<Self> {
172        let mut s = Stream::new(data);
173        Some(EncodingRecord {
174            platform_id: s.read::<PlatformId>()?,
175            encoding_id: s.read::<u16>()?,
176            offset: s.read::<Offset32>()?,
177        })
178    }
179}
180
181#[derive(Clone, Copy, Default)]
183pub struct Subtables<'a> {
184    data: &'a [u8],
185    records: LazyArray16<'a, EncodingRecord>,
186}
187
188impl core::fmt::Debug for Subtables<'_> {
189    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
190        write!(f, "Subtables {{ ... }}")
191    }
192}
193
194impl<'a> Subtables<'a> {
195    pub fn get(&self, index: u16) -> Option<Subtable<'a>> {
197        let record = self.records.get(index)?;
198        let data = self.data.get(record.offset.to_usize()..)?;
199        let format = match Stream::read_at::<u16>(data, 0)? {
200            0 => Format::ByteEncodingTable(Subtable0::parse(data)?),
201            2 => Format::HighByteMappingThroughTable(Subtable2::parse(data)?),
202            4 => Format::SegmentMappingToDeltaValues(Subtable4::parse(data)?),
203            6 => Format::TrimmedTableMapping(Subtable6::parse(data)?),
204            8 => Format::MixedCoverage, 10 => Format::TrimmedArray(Subtable10::parse(data)?),
206            12 => Format::SegmentedCoverage(Subtable12::parse(data)?),
207            13 => Format::ManyToOneRangeMappings(Subtable13::parse(data)?),
208            14 => Format::UnicodeVariationSequences(Subtable14::parse(data)?),
209            _ => return None,
210        };
211
212        Some(Subtable {
213            platform_id: record.platform_id,
214            encoding_id: record.encoding_id,
215            format,
216        })
217    }
218
219    #[inline]
221    pub fn len(&self) -> u16 {
222        self.records.len()
223    }
224
225    pub fn is_empty(&self) -> bool {
227        self.records.is_empty()
228    }
229}
230
231impl<'a> IntoIterator for Subtables<'a> {
232    type Item = Subtable<'a>;
233    type IntoIter = SubtablesIter<'a>;
234
235    #[inline]
236    fn into_iter(self) -> Self::IntoIter {
237        SubtablesIter {
238            subtables: self,
239            index: 0,
240        }
241    }
242}
243
244#[allow(missing_debug_implementations)]
246pub struct SubtablesIter<'a> {
247    subtables: Subtables<'a>,
248    index: u16,
249}
250
251impl<'a> Iterator for SubtablesIter<'a> {
252    type Item = Subtable<'a>;
253
254    #[inline]
255    fn next(&mut self) -> Option<Self::Item> {
256        if self.index < self.subtables.len() {
257            self.index += 1;
258            self.subtables.get(self.index - 1)
259        } else {
260            None
261        }
262    }
263}
264
265#[derive(Clone, Copy, Debug)]
268pub struct Table<'a> {
269    pub subtables: Subtables<'a>,
271}
272
273impl<'a> Table<'a> {
274    pub fn parse(data: &'a [u8]) -> Option<Self> {
276        let mut s = Stream::new(data);
277        s.skip::<u16>(); let count = s.read::<u16>()?;
279        let records = s.read_array16::<EncodingRecord>(count)?;
280        Some(Table {
281            subtables: Subtables { data, records },
282        })
283    }
284}