1use crate::GlyphId;
18use crate::parser::{FromData, LazyArray16, NumFrom, Offset, Offset16, Stream};
19#[cfg(feature = "apple-layout")] use crate::aat;
20
21#[derive(Clone, Copy, Debug)]
22struct OTCoverage(u8);
23
24impl OTCoverage {
25    #[inline] fn is_horizontal(self) -> bool { self.0 & (1 << 0) != 0 }
26    #[inline] fn has_cross_stream(self) -> bool { self.0 & (1 << 2) != 0 }
27}
28
29impl FromData for OTCoverage {
30    const SIZE: usize = 1;
31
32    #[inline]
33    fn parse(data: &[u8]) -> Option<Self> {
34        data.get(0).copied().map(OTCoverage)
35    }
36}
37
38
39#[derive(Clone, Copy, Debug)]
40struct AATCoverage(u8);
41
42impl AATCoverage {
43    #[inline] fn is_horizontal(self) -> bool { self.0 & (1 << 7) == 0 }
44    #[inline] fn has_cross_stream(self) -> bool { self.0 & (1 << 6) != 0 }
45    #[inline] fn is_variable(self) -> bool { self.0 & (1 << 5) != 0 }
46}
47
48impl FromData for AATCoverage {
49    const SIZE: usize = 1;
50
51    #[inline]
52    fn parse(data: &[u8]) -> Option<Self> {
53        data.get(0).copied().map(AATCoverage)
54    }
55}
56
57
58#[derive(Clone, Copy, Debug)]
60pub struct KerningPair {
61    pub pair: u32,
66    pub value: i16,
68}
69
70impl KerningPair {
71    #[inline]
73    pub fn left(&self) -> GlyphId {
74        GlyphId((self.pair >> 16) as u16)
75    }
76
77    #[inline]
79    pub fn right(&self) -> GlyphId {
80        GlyphId(self.pair as u16)
81    }
82}
83
84impl FromData for KerningPair {
85    const SIZE: usize = 6;
86
87    #[inline]
88    fn parse(data: &[u8]) -> Option<Self> {
89        let mut s = Stream::new(data);
90        Some(KerningPair {
91            pair: s.read::<u32>()?,
92            value: s.read::<i16>()?,
93        })
94    }
95}
96
97
98#[allow(missing_docs)]
100#[derive(Clone, Debug)]
101pub enum Format<'a> {
102    Format0(Subtable0<'a>),
103    #[cfg(feature = "apple-layout")] Format1(aat::StateTable<'a>),
104    #[cfg(not(feature = "apple-layout"))] Format1,
105    Format2(Subtable2<'a>),
106    Format3(Subtable3<'a>),
107}
108
109
110#[derive(Clone, Debug)]
112pub struct Subtable<'a> {
113    pub horizontal: bool,
115    pub variable: bool,
117    pub has_cross_stream: bool,
119    pub has_state_machine: bool,
123    pub format: Format<'a>,
125}
126
127impl<'a> Subtable<'a> {
128    #[inline]
132    pub fn glyphs_kerning(&self, left: GlyphId, right: GlyphId) -> Option<i16> {
133        match self.format {
134            Format::Format0(ref subtable) => subtable.glyphs_kerning(left, right),
135            Format::Format2(ref subtable) => subtable.glyphs_kerning(left, right),
136            Format::Format3(ref subtable) => subtable.glyphs_kerning(left, right),
137            _ => None,
138        }
139    }
140}
141
142
143#[derive(Clone, Copy)]
148pub struct Subtables<'a> {
149    is_aat: bool,
151    count: u32,
153    data: &'a [u8],
155}
156
157impl<'a> Subtables<'a> {
158    pub fn len(&self) -> u32 {
160        self.count
161    }
162}
163
164impl core::fmt::Debug for Subtables<'_> {
165    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
166        write!(f, "Subtables {{ ... }}")
167    }
168}
169
170impl<'a> IntoIterator for Subtables<'a> {
171    type Item = Subtable<'a>;
172    type IntoIter = SubtablesIter<'a>;
173
174    #[inline]
175    fn into_iter(self) -> Self::IntoIter {
176        SubtablesIter {
177            is_aat: self.is_aat,
178            table_index: 0,
179            number_of_tables: self.count,
180            stream: Stream::new(self.data),
181        }
182    }
183}
184
185
186#[allow(missing_debug_implementations)]
188#[derive(Clone, Copy, Default)]
189pub struct SubtablesIter<'a> {
190    is_aat: bool,
192    table_index: u32,
194    number_of_tables: u32,
196    stream: Stream<'a>,
198}
199
200impl<'a> Iterator for SubtablesIter<'a> {
201    type Item = Subtable<'a>;
202
203    fn next(&mut self) -> Option<Self::Item> {
204        if self.table_index == self.number_of_tables {
205            return None;
206        }
207
208        if self.stream.at_end() {
209            return None;
210        }
211
212        if self.is_aat {
213            const HEADER_SIZE: u8 = 8;
214
215            let table_len = self.stream.read::<u32>()?;
216            let coverage = self.stream.read::<AATCoverage>()?;
217            let format_id = self.stream.read::<u8>()?;
218            self.stream.skip::<u16>(); if format_id > 3 {
221                return None;
223            }
224
225            let data_len = usize::num_from(table_len).checked_sub(usize::from(HEADER_SIZE))?;
227            let data = self.stream.read_bytes(data_len)?;
228
229            let format = match format_id {
230                0 => Format::Format0(Subtable0::parse(data)?),
231                #[cfg(feature = "apple-layout")]
232                1 => Format::Format1(aat::StateTable::parse(data)?),
233                #[cfg(not(feature = "apple-layout"))]
234                1 => Format::Format1,
235                2 => Format::Format2(Subtable2::parse(HEADER_SIZE, data)?),
236                3 => Format::Format3(Subtable3::parse(data)?),
237                _ => return None,
238            };
239
240            Some(Subtable {
241                horizontal: coverage.is_horizontal(),
242                variable: coverage.is_variable(),
243                has_cross_stream: coverage.has_cross_stream(),
244                has_state_machine: format_id == 1,
245                format,
246            })
247        } else {
248            const HEADER_SIZE: u8 = 6;
249
250            self.stream.skip::<u16>(); let table_len = self.stream.read::<u16>()?;
252            let format_id = self.stream.read::<u8>()?;
254            let coverage = self.stream.read::<OTCoverage>()?;
255
256            if format_id != 0 && format_id != 2 {
257                return None;
259            }
260
261            let data_len = if self.number_of_tables == 1 {
262                self.stream.tail()?.len()
267            } else {
268                usize::from(table_len).checked_sub(usize::from(HEADER_SIZE))?
270            };
271
272            let data = self.stream.read_bytes(data_len)?;
273
274            let format = match format_id {
275                0 => Format::Format0(Subtable0::parse(data)?),
276                2 => Format::Format2(Subtable2::parse(HEADER_SIZE, data)?),
277                _ => return None,
278            };
279
280            Some(Subtable {
281                horizontal: coverage.is_horizontal(),
282                variable: false, has_cross_stream: coverage.has_cross_stream(),
284                has_state_machine: format_id == 1,
285                format,
286            })
287        }
288    }
289}
290
291
292#[derive(Clone, Copy, Debug)]
296pub struct Subtable0<'a> {
297    pub pairs: LazyArray16<'a, KerningPair>,
299}
300
301impl<'a> Subtable0<'a> {
302    pub fn parse(data: &'a [u8]) -> Option<Self> {
304        let mut s = Stream::new(data);
305        let number_of_pairs = s.read::<u16>()?;
306        s.advance(6); let pairs = s.read_array16::<KerningPair>(number_of_pairs)?;
308        Some(Self { pairs })
309    }
310
311    #[inline]
313    pub fn glyphs_kerning(&self, left: GlyphId, right: GlyphId) -> Option<i16> {
314        let needle = u32::from(left.0) << 16 | u32::from(right.0);
315        self.pairs.binary_search_by(|v| v.pair.cmp(&needle)).map(|(_, v)| v.value)
316    }
317}
318
319
320#[derive(Clone, Copy, Debug)]
324pub struct Subtable2<'a> {
325    data: &'a [u8],
327    header_len: u8,
328}
329
330impl<'a> Subtable2<'a> {
331    pub fn parse(header_len: u8, data: &'a [u8]) -> Option<Self> {
333        Some(Self { header_len, data })
334    }
335
336    pub fn glyphs_kerning(&self, left: GlyphId, right: GlyphId) -> Option<i16> {
338        let mut s = Stream::new(self.data);
339        s.skip::<u16>(); let header_len = usize::from(self.header_len);
344        let left_hand_table_offset = s.read::<Offset16>()?.to_usize().checked_sub(header_len)?;
345        let right_hand_table_offset = s.read::<Offset16>()?.to_usize().checked_sub(header_len)?;
346        let array_offset = s.read::<Offset16>()?.to_usize().checked_sub(header_len)?;
347
348        let left_class = get_format2_class(left.0, left_hand_table_offset, self.data).unwrap_or(0);
353        let right_class = get_format2_class(right.0, right_hand_table_offset, self.data).unwrap_or(0);
354
355        if usize::from(left_class) < array_offset {
357            return None;
358        }
359
360        let index = usize::from(left_class) + usize::from(right_class);
362        let value_offset = index.checked_sub(header_len)?;
363        Stream::read_at::<i16>(self.data, value_offset)
364    }
365}
366
367pub(crate) fn get_format2_class(glyph_id: u16, offset: usize, data: &[u8]) -> Option<u16> {
368    let mut s = Stream::new_at(data, offset)?;
369    let first_glyph = s.read::<u16>()?;
370    let index = glyph_id.checked_sub(first_glyph)?;
371
372    let number_of_classes = s.read::<u16>()?;
373    let classes = s.read_array16::<u16>(number_of_classes)?;
374    classes.get(index)
375}
376
377
378#[derive(Clone, Copy, Debug)]
382pub struct Subtable3<'a> {
383    data: &'a [u8],
385}
386
387impl<'a> Subtable3<'a> {
388    pub fn parse(data: &'a [u8]) -> Option<Self> {
390        Some(Self { data })
391    }
392
393    #[inline]
395    pub fn glyphs_kerning(&self, left: GlyphId, right: GlyphId) -> Option<i16> {
396        let mut s = Stream::new(self.data);
397        let glyph_count = s.read::<u16>()?;
398        let kerning_values_count = s.read::<u8>()?;
399        let left_hand_classes_count = s.read::<u8>()?;
400        let right_hand_classes_count = s.read::<u8>()?;
401        s.skip::<u8>(); let indices_count = u16::from(left_hand_classes_count) * u16::from(right_hand_classes_count);
403
404        let kerning_values = s.read_array16::<i16>(u16::from(kerning_values_count))?;
405        let left_hand_classes = s.read_array16::<u8>(glyph_count)?;
406        let right_hand_classes = s.read_array16::<u8>(glyph_count)?;
407        let indices = s.read_array16::<u8>(indices_count)?;
408
409        let left_class = left_hand_classes.get(left.0)?;
410        let right_class = right_hand_classes.get(right.0)?;
411
412        if left_class > left_hand_classes_count || right_class > right_hand_classes_count {
413            return None;
414        }
415
416        let index = u16::from(left_class) * u16::from(right_hand_classes_count) + u16::from(right_class);
417        let index = indices.get(index)?;
418        kerning_values.get(u16::from(index))
419    }
420}
421
422
423#[derive(Clone, Copy, Debug)]
425pub struct Table<'a> {
426    pub subtables: Subtables<'a>,
428}
429
430impl<'a> Table<'a> {
431    pub fn parse(data: &'a [u8]) -> Option<Self> {
433        let mut s = Stream::new(data);
442        let version = s.read::<u16>()?;
443        let subtables = if version == 0 {
444            let count = s.read::<u16>()?;
445            Subtables {
446                is_aat: false,
447                count: u32::from(count),
448                data: s.tail()?,
449            }
450        } else {
451            s.skip::<u16>(); let count = s.read::<u32>()?;
454            Subtables {
455                is_aat: true,
456                count,
457                data: s.tail()?,
458            }
459        };
460
461        Some(Self { subtables })
462    }
463}