1use core::num::NonZeroU16;
9
10use crate::kern::KerningPair;
11use crate::parser::{FromData, LazyArray32, NumFrom, Offset, Offset32, Stream};
12use crate::{aat, GlyphId};
13
14const HEADER_SIZE: usize = 12;
15
16#[derive(Clone, Copy, Debug)]
22pub struct Subtable0<'a> {
23 pub pairs: LazyArray32<'a, KerningPair>,
25}
26
27impl<'a> Subtable0<'a> {
28 fn parse(data: &'a [u8]) -> Option<Self> {
30 let mut s = Stream::new(data);
31 let number_of_pairs = s.read::<u32>()?;
32 s.advance(12); let pairs = s.read_array32::<KerningPair>(number_of_pairs)?;
34 Some(Self { pairs })
35 }
36
37 #[inline]
39 pub fn glyphs_kerning(&self, left: GlyphId, right: GlyphId) -> Option<i16> {
40 let needle = u32::from(left.0) << 16 | u32::from(right.0);
41 self.pairs
42 .binary_search_by(|v| v.pair.cmp(&needle))
43 .map(|(_, v)| v.value)
44 }
45}
46
47#[derive(Clone, Copy, Debug)]
49pub struct EntryData {
50 pub action_index: u16,
52}
53
54impl FromData for EntryData {
55 const SIZE: usize = 2;
56
57 #[inline]
58 fn parse(data: &[u8]) -> Option<Self> {
59 let mut s = Stream::new(data);
60 Some(EntryData {
61 action_index: s.read::<u16>()?,
62 })
63 }
64}
65
66#[derive(Clone)]
70pub struct Subtable1<'a> {
71 pub state_table: aat::ExtendedStateTable<'a, EntryData>,
73 actions_data: &'a [u8],
74}
75
76impl<'a> Subtable1<'a> {
77 fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
78 let mut s = Stream::new(data);
79 let state_table = aat::ExtendedStateTable::parse(number_of_glyphs, &mut s)?;
80
81 let actions_offset = s.read::<Offset32>()?;
83 let actions_data = data.get(actions_offset.to_usize()..)?;
87
88 Some(Subtable1 {
89 state_table,
90 actions_data,
91 })
92 }
93
94 #[inline]
96 pub fn glyphs_kerning(&self, action_index: u16) -> Option<i16> {
97 Stream::read_at(self.actions_data, usize::from(action_index) * i16::SIZE)
98 }
99}
100
101impl<'a> core::ops::Deref for Subtable1<'a> {
102 type Target = aat::ExtendedStateTable<'a, EntryData>;
103
104 fn deref(&self) -> &Self::Target {
105 &self.state_table
106 }
107}
108
109impl core::fmt::Debug for Subtable1<'_> {
110 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
111 write!(f, "Subtable1 {{ ... }}")
112 }
113}
114
115#[derive(Clone, Copy)]
121pub struct Subtable2<'a>(&'a [u8]); impl<'a> Subtable2<'a> {
124 pub fn glyphs_kerning(&self, left: GlyphId, right: GlyphId) -> Option<i16> {
126 let mut s = Stream::new(self.0);
127 s.skip::<u32>(); let left_hand_table_offset = s.read::<Offset32>()?.to_usize().checked_sub(HEADER_SIZE)?;
132 let right_hand_table_offset = s.read::<Offset32>()?.to_usize().checked_sub(HEADER_SIZE)?;
133 let array_offset = s.read::<Offset32>()?.to_usize().checked_sub(HEADER_SIZE)?;
134
135 let left_class =
140 crate::kern::get_format2_class(left.0, left_hand_table_offset, self.0).unwrap_or(0);
141 let right_class =
142 crate::kern::get_format2_class(right.0, right_hand_table_offset, self.0).unwrap_or(0);
143
144 if usize::from(left_class) < array_offset {
146 return None;
147 }
148
149 let index = usize::from(left_class) + usize::from(right_class);
151 let value_offset = index.checked_sub(HEADER_SIZE)?;
152 Stream::read_at::<i16>(self.0, value_offset)
153 }
154}
155
156impl core::fmt::Debug for Subtable2<'_> {
157 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
158 write!(f, "Subtable2 {{ ... }}")
159 }
160}
161
162#[derive(Clone, Copy)]
164pub struct AnchorPoints<'a>(&'a [u8]);
165
166impl AnchorPoints<'_> {
167 pub fn get(&self, action_index: u16) -> Option<(u16, u16)> {
169 let offset = usize::from(action_index) * u16::SIZE * 2;
172 let mut s = Stream::new_at(self.0, offset)?;
173 Some((s.read::<u16>()?, s.read::<u16>()?))
174 }
175}
176
177impl core::fmt::Debug for AnchorPoints<'_> {
178 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
179 write!(f, "AnchorPoints {{ ... }}")
180 }
181}
182
183#[derive(Clone)]
191pub struct Subtable4<'a> {
192 pub state_table: aat::ExtendedStateTable<'a, EntryData>,
194 pub anchor_points: AnchorPoints<'a>,
196}
197
198impl<'a> Subtable4<'a> {
199 fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
200 let mut s = Stream::new(data);
201 let state_table = aat::ExtendedStateTable::parse(number_of_glyphs, &mut s)?;
202 let flags = s.read::<u32>()?;
203 let action_type = ((flags & 0xC0000000) >> 30) as u8;
204 let points_offset = usize::num_from(flags & 0x00FFFFFF);
205
206 if action_type != 1 {
208 return None;
209 }
210
211 Some(Self {
212 state_table,
213 anchor_points: AnchorPoints(data.get(points_offset..)?),
214 })
215 }
216}
217
218impl<'a> core::ops::Deref for Subtable4<'a> {
219 type Target = aat::ExtendedStateTable<'a, EntryData>;
220
221 fn deref(&self) -> &Self::Target {
222 &self.state_table
223 }
224}
225
226impl core::fmt::Debug for Subtable4<'_> {
227 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
228 write!(f, "Subtable4 {{ ... }}")
229 }
230}
231
232#[derive(Clone, Copy)]
236pub struct Subtable6<'a> {
237 data: &'a [u8],
238 number_of_glyphs: NonZeroU16,
239}
240
241impl<'a> Subtable6<'a> {
242 fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Self {
244 Subtable6 {
245 number_of_glyphs,
246 data,
247 }
248 }
249
250 pub fn glyphs_kerning(&self, left: GlyphId, right: GlyphId) -> Option<i16> {
252 use core::convert::TryFrom;
253
254 let mut s = Stream::new(self.data);
255 let flags = s.read::<u32>()?;
256 s.skip::<u16>(); s.skip::<u16>(); let row_index_table_offset = s.read::<Offset32>()?.to_usize().checked_sub(HEADER_SIZE)?;
260 let column_index_table_offset =
261 s.read::<Offset32>()?.to_usize().checked_sub(HEADER_SIZE)?;
262 let kerning_array_offset = s.read::<Offset32>()?.to_usize().checked_sub(HEADER_SIZE)?;
263 let kerning_vector_offset = s.read::<Offset32>()?.to_usize().checked_sub(HEADER_SIZE)?;
264
265 let row_index_table_data = self.data.get(row_index_table_offset..)?;
266 let column_index_table_data = self.data.get(column_index_table_offset..)?;
267 let kerning_array_data = self.data.get(kerning_array_offset..)?;
268 let kerning_vector_data = self.data.get(kerning_vector_offset..)?;
269
270 let has_long_values = flags & 0x00000001 != 0;
271 if has_long_values {
272 let l: u32 = aat::Lookup::parse(self.number_of_glyphs, row_index_table_data)?
273 .value(left)
274 .unwrap_or(0) as u32;
275
276 let r: u32 = aat::Lookup::parse(self.number_of_glyphs, column_index_table_data)?
277 .value(right)
278 .unwrap_or(0) as u32;
279
280 let array_offset = usize::try_from(l + r).ok()?.checked_mul(i32::SIZE)?;
281 let vector_offset: u32 = Stream::read_at(kerning_array_data, array_offset)?;
282
283 Stream::read_at(kerning_vector_data, usize::num_from(vector_offset))
284 } else {
285 let l: u16 = aat::Lookup::parse(self.number_of_glyphs, row_index_table_data)?
286 .value(left)
287 .unwrap_or(0);
288
289 let r: u16 = aat::Lookup::parse(self.number_of_glyphs, column_index_table_data)?
290 .value(right)
291 .unwrap_or(0);
292
293 let array_offset = usize::from(l + r).checked_mul(i16::SIZE)?;
294 let vector_offset: u16 = Stream::read_at(kerning_array_data, array_offset)?;
295
296 Stream::read_at(kerning_vector_data, usize::from(vector_offset))
297 }
298 }
299}
300
301impl core::fmt::Debug for Subtable6<'_> {
302 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
303 write!(f, "Subtable6 {{ ... }}")
304 }
305}
306
307#[allow(missing_docs)]
309#[derive(Clone, Debug)]
310pub enum Format<'a> {
311 Format0(Subtable0<'a>),
312 Format1(Subtable1<'a>),
313 Format2(Subtable2<'a>),
314 Format4(Subtable4<'a>),
315 Format6(Subtable6<'a>),
316}
317
318#[derive(Clone, Debug)]
320pub struct Subtable<'a> {
321 pub horizontal: bool,
323 pub variable: bool,
325 pub has_cross_stream: bool,
327 pub has_state_machine: bool,
331 pub tuple_count: u32,
335 pub format: Format<'a>,
337}
338
339impl<'a> Subtable<'a> {
340 #[inline]
344 pub fn glyphs_kerning(&self, left: GlyphId, right: GlyphId) -> Option<i16> {
345 match self.format {
346 Format::Format0(ref subtable) => subtable.glyphs_kerning(left, right),
347 Format::Format1(_) => None,
348 Format::Format2(ref subtable) => subtable.glyphs_kerning(left, right),
349 Format::Format4(_) => None,
350 Format::Format6(ref subtable) => subtable.glyphs_kerning(left, right),
351 }
352 }
353}
354
355#[derive(Clone, Copy, Debug)]
356struct Coverage(u8);
357
358#[rustfmt::skip]
359impl Coverage {
360 #[inline] pub fn is_horizontal(self) -> bool { self.0 & (1 << 7) == 0 }
362 #[inline] pub fn has_cross_stream(self) -> bool { self.0 & (1 << 6) != 0 }
363 #[inline] pub fn is_variable(self) -> bool { self.0 & (1 << 5) != 0 }
364}
365
366#[derive(Clone, Copy)]
371pub struct Subtables<'a> {
372 number_of_glyphs: NonZeroU16,
374 number_of_tables: u32,
376 data: &'a [u8],
378}
379
380impl core::fmt::Debug for Subtables<'_> {
381 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
382 write!(f, "Subtables {{ ... }}")
383 }
384}
385
386impl<'a> IntoIterator for Subtables<'a> {
387 type Item = Subtable<'a>;
388 type IntoIter = SubtablesIter<'a>;
389
390 #[inline]
391 fn into_iter(self) -> Self::IntoIter {
392 SubtablesIter {
393 number_of_glyphs: self.number_of_glyphs,
394 table_index: 0,
395 number_of_tables: self.number_of_tables,
396 stream: Stream::new(self.data),
397 }
398 }
399}
400
401#[allow(missing_debug_implementations)]
403#[derive(Clone)]
404pub struct SubtablesIter<'a> {
405 number_of_glyphs: NonZeroU16,
407 table_index: u32,
409 number_of_tables: u32,
411 stream: Stream<'a>,
413}
414
415impl<'a> Iterator for SubtablesIter<'a> {
416 type Item = Subtable<'a>;
417
418 fn next(&mut self) -> Option<Self::Item> {
419 if self.table_index == self.number_of_tables {
420 return None;
421 }
422
423 if self.stream.at_end() {
424 return None;
425 }
426
427 let s = &mut self.stream;
428
429 let table_len = s.read::<u32>()?;
430 let coverage = Coverage(s.read::<u8>()?);
431 s.skip::<u16>(); let raw_format = s.read::<u8>()?;
433 let tuple_count = s.read::<u32>()?;
434
435 let data_len = usize::num_from(table_len).checked_sub(HEADER_SIZE)?;
437 let data = s.read_bytes(data_len)?;
438
439 let format = match raw_format {
440 0 => Subtable0::parse(data).map(Format::Format0)?,
441 1 => Subtable1::parse(self.number_of_glyphs, data).map(Format::Format1)?,
442 2 => Format::Format2(Subtable2(data)),
443 4 => Subtable4::parse(self.number_of_glyphs, data).map(Format::Format4)?,
444 6 => Format::Format6(Subtable6::parse(self.number_of_glyphs, data)),
445 _ => {
446 return None;
448 }
449 };
450
451 self.table_index += 1;
452
453 Some(Subtable {
454 horizontal: coverage.is_horizontal(),
455 variable: coverage.is_variable(),
456 has_cross_stream: coverage.has_cross_stream(),
457 has_state_machine: raw_format == 1 || raw_format == 4,
458 tuple_count,
459 format,
460 })
461 }
462}
463
464#[derive(Clone, Copy, Debug)]
467pub struct Table<'a> {
468 pub subtables: Subtables<'a>,
470}
471
472impl<'a> Table<'a> {
473 pub fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
477 let mut s = Stream::new(data);
478 s.skip::<u16>(); s.skip::<u16>(); let number_of_tables = s.read::<u32>()?;
481 let subtables = Subtables {
482 number_of_glyphs,
483 number_of_tables,
484 data: s.tail()?,
485 };
486
487 Some(Table { subtables })
488 }
489}