1#[cfg(feature = "apple-layout")]
18use crate::aat;
19use crate::parser::{FromData, LazyArray16, NumFrom, Offset, Offset16, Stream};
20use crate::GlyphId;
21
22#[derive(Clone, Copy, Debug)]
23struct OTCoverage(u8);
24
25#[rustfmt::skip]
26impl OTCoverage {
27 #[inline] fn is_horizontal(self) -> bool { self.0 & (1 << 0) != 0 }
28 #[inline] fn has_cross_stream(self) -> bool { self.0 & (1 << 2) != 0 }
29}
30
31impl FromData for OTCoverage {
32 const SIZE: usize = 1;
33
34 #[inline]
35 fn parse(data: &[u8]) -> Option<Self> {
36 data.get(0).copied().map(OTCoverage)
37 }
38}
39
40#[derive(Clone, Copy, Debug)]
41struct AATCoverage(u8);
42
43#[rustfmt::skip]
44impl AATCoverage {
45 #[inline] fn is_horizontal(self) -> bool { self.0 & (1 << 7) == 0 }
46 #[inline] fn has_cross_stream(self) -> bool { self.0 & (1 << 6) != 0 }
47 #[inline] fn is_variable(self) -> bool { self.0 & (1 << 5) != 0 }
48}
49
50impl FromData for AATCoverage {
51 const SIZE: usize = 1;
52
53 #[inline]
54 fn parse(data: &[u8]) -> Option<Self> {
55 data.get(0).copied().map(AATCoverage)
56 }
57}
58
59#[derive(Clone, Copy, Debug)]
61pub struct KerningPair {
62 pub pair: u32,
67 pub value: i16,
69}
70
71impl KerningPair {
72 #[inline]
74 pub fn left(&self) -> GlyphId {
75 GlyphId((self.pair >> 16) as u16)
76 }
77
78 #[inline]
80 pub fn right(&self) -> GlyphId {
81 GlyphId(self.pair as u16)
82 }
83}
84
85impl FromData for KerningPair {
86 const SIZE: usize = 6;
87
88 #[inline]
89 fn parse(data: &[u8]) -> Option<Self> {
90 let mut s = Stream::new(data);
91 Some(KerningPair {
92 pair: s.read::<u32>()?,
93 value: s.read::<i16>()?,
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")]
104 Format1(aat::StateTable<'a>),
105 #[cfg(not(feature = "apple-layout"))]
106 Format1,
107 Format2(Subtable2<'a>),
108 Format3(Subtable3<'a>),
109}
110
111#[derive(Clone, Debug)]
113pub struct Subtable<'a> {
114 pub horizontal: bool,
116 pub variable: bool,
118 pub has_cross_stream: bool,
120 pub has_state_machine: bool,
124 pub format: Format<'a>,
126}
127
128impl<'a> Subtable<'a> {
129 #[inline]
133 pub fn glyphs_kerning(&self, left: GlyphId, right: GlyphId) -> Option<i16> {
134 match self.format {
135 Format::Format0(ref subtable) => subtable.glyphs_kerning(left, right),
136 Format::Format2(ref subtable) => subtable.glyphs_kerning(left, right),
137 Format::Format3(ref subtable) => subtable.glyphs_kerning(left, right),
138 _ => None,
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 pub fn is_empty(&self) -> bool {
165 self.count == 0
166 }
167}
168
169impl core::fmt::Debug for Subtables<'_> {
170 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
171 write!(f, "Subtables {{ ... }}")
172 }
173}
174
175impl<'a> IntoIterator for Subtables<'a> {
176 type Item = Subtable<'a>;
177 type IntoIter = SubtablesIter<'a>;
178
179 #[inline]
180 fn into_iter(self) -> Self::IntoIter {
181 SubtablesIter {
182 is_aat: self.is_aat,
183 table_index: 0,
184 number_of_tables: self.count,
185 stream: Stream::new(self.data),
186 }
187 }
188}
189
190#[allow(missing_debug_implementations)]
192#[derive(Clone, Default)]
193pub struct SubtablesIter<'a> {
194 is_aat: bool,
196 table_index: u32,
198 number_of_tables: u32,
200 stream: Stream<'a>,
202}
203
204impl<'a> Iterator for SubtablesIter<'a> {
205 type Item = Subtable<'a>;
206
207 fn next(&mut self) -> Option<Self::Item> {
208 if self.table_index == self.number_of_tables {
209 return None;
210 }
211
212 if self.stream.at_end() {
213 return None;
214 }
215
216 if self.is_aat {
217 const HEADER_SIZE: u8 = 8;
218
219 let table_len = self.stream.read::<u32>()?;
220 let coverage = self.stream.read::<AATCoverage>()?;
221 let format_id = self.stream.read::<u8>()?;
222 self.stream.skip::<u16>(); if format_id > 3 {
225 return None;
227 }
228
229 let data_len = usize::num_from(table_len).checked_sub(usize::from(HEADER_SIZE))?;
231 let data = self.stream.read_bytes(data_len)?;
232
233 let format = match format_id {
234 0 => Format::Format0(Subtable0::parse(data)?),
235 #[cfg(feature = "apple-layout")]
236 1 => Format::Format1(aat::StateTable::parse(data)?),
237 #[cfg(not(feature = "apple-layout"))]
238 1 => Format::Format1,
239 2 => Format::Format2(Subtable2::parse(HEADER_SIZE, data)?),
240 3 => Format::Format3(Subtable3::parse(data)?),
241 _ => return None,
242 };
243
244 Some(Subtable {
245 horizontal: coverage.is_horizontal(),
246 variable: coverage.is_variable(),
247 has_cross_stream: coverage.has_cross_stream(),
248 has_state_machine: format_id == 1,
249 format,
250 })
251 } else {
252 const HEADER_SIZE: u8 = 6;
253
254 self.stream.skip::<u16>(); let table_len = self.stream.read::<u16>()?;
256 let format_id = self.stream.read::<u8>()?;
258 let coverage = self.stream.read::<OTCoverage>()?;
259
260 if format_id != 0 && format_id != 2 {
261 return None;
263 }
264
265 let data_len = if self.number_of_tables == 1 {
266 self.stream.tail()?.len()
271 } else {
272 usize::from(table_len).checked_sub(usize::from(HEADER_SIZE))?
274 };
275
276 let data = self.stream.read_bytes(data_len)?;
277
278 let format = match format_id {
279 0 => Format::Format0(Subtable0::parse(data)?),
280 2 => Format::Format2(Subtable2::parse(HEADER_SIZE, data)?),
281 _ => return None,
282 };
283
284 Some(Subtable {
285 horizontal: coverage.is_horizontal(),
286 variable: false, has_cross_stream: coverage.has_cross_stream(),
288 has_state_machine: format_id == 1,
289 format,
290 })
291 }
292 }
293}
294
295#[derive(Clone, Copy, Debug)]
299pub struct Subtable0<'a> {
300 pub pairs: LazyArray16<'a, KerningPair>,
302}
303
304impl<'a> Subtable0<'a> {
305 pub fn parse(data: &'a [u8]) -> Option<Self> {
307 let mut s = Stream::new(data);
308 let number_of_pairs = s.read::<u16>()?;
309 s.advance(6); let pairs = s.read_array16::<KerningPair>(number_of_pairs)?;
311 Some(Self { pairs })
312 }
313
314 #[inline]
316 pub fn glyphs_kerning(&self, left: GlyphId, right: GlyphId) -> Option<i16> {
317 let needle = u32::from(left.0) << 16 | u32::from(right.0);
318 self.pairs
319 .binary_search_by(|v| v.pair.cmp(&needle))
320 .map(|(_, v)| v.value)
321 }
322}
323
324#[derive(Clone, Copy, Debug)]
328pub struct Subtable2<'a> {
329 data: &'a [u8],
331 header_len: u8,
332}
333
334impl<'a> Subtable2<'a> {
335 pub fn parse(header_len: u8, data: &'a [u8]) -> Option<Self> {
337 Some(Self { header_len, data })
338 }
339
340 pub fn glyphs_kerning(&self, left: GlyphId, right: GlyphId) -> Option<i16> {
342 let mut s = Stream::new(self.data);
343 s.skip::<u16>(); let header_len = usize::from(self.header_len);
348 let left_hand_table_offset = s.read::<Offset16>()?.to_usize().checked_sub(header_len)?;
349 let right_hand_table_offset = s.read::<Offset16>()?.to_usize().checked_sub(header_len)?;
350 let array_offset = s.read::<Offset16>()?.to_usize().checked_sub(header_len)?;
351
352 let left_class = get_format2_class(left.0, left_hand_table_offset, self.data).unwrap_or(0);
357 let right_class =
358 get_format2_class(right.0, right_hand_table_offset, self.data).unwrap_or(0);
359
360 if usize::from(left_class) < array_offset {
362 return None;
363 }
364
365 let index = usize::from(left_class) + usize::from(right_class);
367 let value_offset = index.checked_sub(header_len)?;
368 Stream::read_at::<i16>(self.data, value_offset)
369 }
370}
371
372pub(crate) fn get_format2_class(glyph_id: u16, offset: usize, data: &[u8]) -> Option<u16> {
373 let mut s = Stream::new_at(data, offset)?;
374 let first_glyph = s.read::<u16>()?;
375 let index = glyph_id.checked_sub(first_glyph)?;
376
377 let number_of_classes = s.read::<u16>()?;
378 let classes = s.read_array16::<u16>(number_of_classes)?;
379 classes.get(index)
380}
381
382#[derive(Clone, Copy, Debug)]
386pub struct Subtable3<'a> {
387 data: &'a [u8],
389}
390
391impl<'a> Subtable3<'a> {
392 pub fn parse(data: &'a [u8]) -> Option<Self> {
394 Some(Self { data })
395 }
396
397 #[inline]
399 pub fn glyphs_kerning(&self, left: GlyphId, right: GlyphId) -> Option<i16> {
400 let mut s = Stream::new(self.data);
401 let glyph_count = s.read::<u16>()?;
402 let kerning_values_count = s.read::<u8>()?;
403 let left_hand_classes_count = s.read::<u8>()?;
404 let right_hand_classes_count = s.read::<u8>()?;
405 s.skip::<u8>(); let indices_count =
407 u16::from(left_hand_classes_count) * u16::from(right_hand_classes_count);
408
409 let kerning_values = s.read_array16::<i16>(u16::from(kerning_values_count))?;
410 let left_hand_classes = s.read_array16::<u8>(glyph_count)?;
411 let right_hand_classes = s.read_array16::<u8>(glyph_count)?;
412 let indices = s.read_array16::<u8>(indices_count)?;
413
414 let left_class = left_hand_classes.get(left.0)?;
415 let right_class = right_hand_classes.get(right.0)?;
416
417 if left_class > left_hand_classes_count || right_class > right_hand_classes_count {
418 return None;
419 }
420
421 let index =
422 u16::from(left_class) * u16::from(right_hand_classes_count) + u16::from(right_class);
423 let index = indices.get(index)?;
424 kerning_values.get(u16::from(index))
425 }
426}
427
428#[derive(Clone, Copy, Debug)]
430pub struct Table<'a> {
431 pub subtables: Subtables<'a>,
433}
434
435impl<'a> Table<'a> {
436 pub fn parse(data: &'a [u8]) -> Option<Self> {
438 let mut s = Stream::new(data);
447 let version = s.read::<u16>()?;
448 let subtables = if version == 0 {
449 let count = s.read::<u16>()?;
450 Subtables {
451 is_aat: false,
452 count: u32::from(count),
453 data: s.tail()?,
454 }
455 } else {
456 s.skip::<u16>(); let count = s.read::<u32>()?;
459 Subtables {
460 is_aat: true,
461 count,
462 data: s.tail()?,
463 }
464 };
465
466 Some(Self { subtables })
467 }
468}