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}