Skip to main content

read_fonts/generated/
generated_kerx.rs

1// THIS FILE IS AUTOGENERATED.
2// Any changes to this file will be overwritten.
3// For more information about how codegen works, see font-codegen/README.md
4
5#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8impl<'a> MinByteRange<'a> for Kerx<'a> {
9    fn min_byte_range(&self) -> Range<usize> {
10        0..self.subtables_byte_range().end
11    }
12    fn min_table_bytes(&self) -> &'a [u8] {
13        let range = self.min_byte_range();
14        self.data.as_bytes().get(range).unwrap_or_default()
15    }
16}
17
18impl TopLevelTable for Kerx<'_> {
19    /// `kerx`
20    const TAG: Tag = Tag::new(b"kerx");
21}
22
23impl<'a> FontRead<'a> for Kerx<'a> {
24    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
25        #[allow(clippy::absurd_extreme_comparisons)]
26        if data.len() < Self::MIN_SIZE {
27            return Err(ReadError::OutOfBounds);
28        }
29        Ok(Self { data })
30    }
31}
32
33/// The [kerx (Extended Kerning)](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html) table.
34#[derive(Clone)]
35pub struct Kerx<'a> {
36    data: FontData<'a>,
37}
38
39#[allow(clippy::needless_lifetimes)]
40impl<'a> Kerx<'a> {
41    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
42    basic_table_impls!(impl_the_methods);
43
44    /// The version number of the extended kerning table (currently 2, 3, or 4)
45    pub fn version(&self) -> u16 {
46        let range = self.version_byte_range();
47        self.data.read_at(range.start).ok().unwrap()
48    }
49
50    /// The number of subtables included in the extended kerning table.
51    pub fn n_tables(&self) -> u32 {
52        let range = self.n_tables_byte_range();
53        self.data.read_at(range.start).ok().unwrap()
54    }
55
56    pub fn subtables(&self) -> VarLenArray<'a, Subtable<'a>> {
57        let range = self.subtables_byte_range();
58        self.data
59            .split_off(range.start)
60            .and_then(|d| VarLenArray::read(d).ok())
61            .unwrap_or_default()
62    }
63
64    pub fn version_byte_range(&self) -> Range<usize> {
65        let start = 0;
66        start..start + u16::RAW_BYTE_LEN
67    }
68
69    pub fn padding_byte_range(&self) -> Range<usize> {
70        let start = self.version_byte_range().end;
71        start..start + u16::RAW_BYTE_LEN
72    }
73
74    pub fn n_tables_byte_range(&self) -> Range<usize> {
75        let start = self.padding_byte_range().end;
76        start..start + u32::RAW_BYTE_LEN
77    }
78
79    pub fn subtables_byte_range(&self) -> Range<usize> {
80        let n_tables = self.n_tables();
81        let start = self.n_tables_byte_range().end;
82        start..start + {
83            let data = self.data.split_off(start).unwrap_or_default();
84            <Subtable as VarSize>::total_len_for_count(data, n_tables as usize).unwrap_or(0)
85        }
86    }
87}
88
89const _: () = assert!(FontData::default_data_long_enough(Kerx::MIN_SIZE));
90
91impl Default for Kerx<'_> {
92    fn default() -> Self {
93        Self {
94            data: FontData::default_table_data(),
95        }
96    }
97}
98
99#[cfg(feature = "experimental_traverse")]
100impl<'a> SomeTable<'a> for Kerx<'a> {
101    fn type_name(&self) -> &str {
102        "Kerx"
103    }
104    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
105        match idx {
106            0usize => Some(Field::new("version", self.version())),
107            1usize => Some(Field::new("n_tables", self.n_tables())),
108            2usize => Some(Field::new(
109                "subtables",
110                traversal::FieldType::var_array("Subtable", self.subtables(), self.offset_data()),
111            )),
112            _ => None,
113        }
114    }
115}
116
117#[cfg(feature = "experimental_traverse")]
118#[allow(clippy::needless_lifetimes)]
119impl<'a> std::fmt::Debug for Kerx<'a> {
120    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121        (self as &dyn SomeTable<'a>).fmt(f)
122    }
123}
124
125impl<'a> MinByteRange<'a> for Subtable<'a> {
126    fn min_byte_range(&self) -> Range<usize> {
127        0..self.data_byte_range().end
128    }
129    fn min_table_bytes(&self) -> &'a [u8] {
130        let range = self.min_byte_range();
131        self.data.as_bytes().get(range).unwrap_or_default()
132    }
133}
134
135impl<'a> FontRead<'a> for Subtable<'a> {
136    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
137        #[allow(clippy::absurd_extreme_comparisons)]
138        if data.len() < Self::MIN_SIZE {
139            return Err(ReadError::OutOfBounds);
140        }
141        Ok(Self { data })
142    }
143}
144
145/// A subtable in a `kerx` table.
146#[derive(Clone)]
147pub struct Subtable<'a> {
148    data: FontData<'a>,
149}
150
151#[allow(clippy::needless_lifetimes)]
152impl<'a> Subtable<'a> {
153    pub const MIN_SIZE: usize = (u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
154    basic_table_impls!(impl_the_methods);
155
156    /// The length of this subtable in bytes, including this header.
157    pub fn length(&self) -> u32 {
158        let range = self.length_byte_range();
159        self.data.read_at(range.start).ok().unwrap()
160    }
161
162    /// Circumstances under which this table is used.
163    pub fn coverage(&self) -> u32 {
164        let range = self.coverage_byte_range();
165        self.data.read_at(range.start).ok().unwrap()
166    }
167
168    /// The tuple count. This value is only used with variation fonts and should be 0 for all other fonts. The subtable's tupleCount will be ignored if the 'kerx' table version is less than 4.
169    pub fn tuple_count(&self) -> u32 {
170        let range = self.tuple_count_byte_range();
171        self.data.read_at(range.start).ok().unwrap()
172    }
173
174    /// Subtable specific data.
175    pub fn data(&self) -> &'a [u8] {
176        let range = self.data_byte_range();
177        self.data.read_array(range).ok().unwrap_or_default()
178    }
179
180    pub fn length_byte_range(&self) -> Range<usize> {
181        let start = 0;
182        start..start + u32::RAW_BYTE_LEN
183    }
184
185    pub fn coverage_byte_range(&self) -> Range<usize> {
186        let start = self.length_byte_range().end;
187        start..start + u32::RAW_BYTE_LEN
188    }
189
190    pub fn tuple_count_byte_range(&self) -> Range<usize> {
191        let start = self.coverage_byte_range().end;
192        start..start + u32::RAW_BYTE_LEN
193    }
194
195    pub fn data_byte_range(&self) -> Range<usize> {
196        let start = self.tuple_count_byte_range().end;
197        start..start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN
198    }
199}
200
201const _: () = assert!(FontData::default_data_long_enough(Subtable::MIN_SIZE));
202
203impl Default for Subtable<'_> {
204    fn default() -> Self {
205        Self {
206            data: FontData::default_table_data(),
207        }
208    }
209}
210
211#[cfg(feature = "experimental_traverse")]
212impl<'a> SomeTable<'a> for Subtable<'a> {
213    fn type_name(&self) -> &str {
214        "Subtable"
215    }
216    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
217        match idx {
218            0usize => Some(Field::new("length", self.length())),
219            1usize => Some(Field::new("coverage", self.coverage())),
220            2usize => Some(Field::new("tuple_count", self.tuple_count())),
221            3usize => Some(Field::new("data", self.data())),
222            _ => None,
223        }
224    }
225}
226
227#[cfg(feature = "experimental_traverse")]
228#[allow(clippy::needless_lifetimes)]
229impl<'a> std::fmt::Debug for Subtable<'a> {
230    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
231        (self as &dyn SomeTable<'a>).fmt(f)
232    }
233}
234
235impl<'a> MinByteRange<'a> for Subtable0<'a> {
236    fn min_byte_range(&self) -> Range<usize> {
237        0..self.pairs_byte_range().end
238    }
239    fn min_table_bytes(&self) -> &'a [u8] {
240        let range = self.min_byte_range();
241        self.data.as_bytes().get(range).unwrap_or_default()
242    }
243}
244
245impl<'a> FontRead<'a> for Subtable0<'a> {
246    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
247        #[allow(clippy::absurd_extreme_comparisons)]
248        if data.len() < Self::MIN_SIZE {
249            return Err(ReadError::OutOfBounds);
250        }
251        Ok(Self { data })
252    }
253}
254
255/// The type 0 `kerx` subtable.
256#[derive(Clone)]
257pub struct Subtable0<'a> {
258    data: FontData<'a>,
259}
260
261#[allow(clippy::needless_lifetimes)]
262impl<'a> Subtable0<'a> {
263    pub const MIN_SIZE: usize =
264        (u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
265    basic_table_impls!(impl_the_methods);
266
267    /// The number of kerning pairs in this subtable.
268    pub fn n_pairs(&self) -> u32 {
269        let range = self.n_pairs_byte_range();
270        self.data.read_at(range.start).ok().unwrap()
271    }
272
273    /// The largest power of two less than or equal to the value of nPairs, multiplied by the size in bytes of an entry in the subtable.
274    pub fn search_range(&self) -> u32 {
275        let range = self.search_range_byte_range();
276        self.data.read_at(range.start).ok().unwrap()
277    }
278
279    /// This is calculated as log2 of the largest power of two less than or equal to the value of nPairs. This value indicates how many iterations of the search loop have to be made. For example, in a list of eight items, there would be three iterations of the loop.
280    pub fn entry_selector(&self) -> u32 {
281        let range = self.entry_selector_byte_range();
282        self.data.read_at(range.start).ok().unwrap()
283    }
284
285    /// The value of nPairs minus the largest power of two less than or equal to nPairs. This is multiplied by the size in bytes of an entry in the table.
286    pub fn range_shift(&self) -> u32 {
287        let range = self.range_shift_byte_range();
288        self.data.read_at(range.start).ok().unwrap()
289    }
290
291    /// Kerning records.
292    pub fn pairs(&self) -> &'a [Subtable0Pair] {
293        let range = self.pairs_byte_range();
294        self.data.read_array(range).ok().unwrap_or_default()
295    }
296
297    pub fn n_pairs_byte_range(&self) -> Range<usize> {
298        let start = 0;
299        start..start + u32::RAW_BYTE_LEN
300    }
301
302    pub fn search_range_byte_range(&self) -> Range<usize> {
303        let start = self.n_pairs_byte_range().end;
304        start..start + u32::RAW_BYTE_LEN
305    }
306
307    pub fn entry_selector_byte_range(&self) -> Range<usize> {
308        let start = self.search_range_byte_range().end;
309        start..start + u32::RAW_BYTE_LEN
310    }
311
312    pub fn range_shift_byte_range(&self) -> Range<usize> {
313        let start = self.entry_selector_byte_range().end;
314        start..start + u32::RAW_BYTE_LEN
315    }
316
317    pub fn pairs_byte_range(&self) -> Range<usize> {
318        let n_pairs = self.n_pairs();
319        let start = self.range_shift_byte_range().end;
320        start..start + (n_pairs as usize).saturating_mul(Subtable0Pair::RAW_BYTE_LEN)
321    }
322}
323
324const _: () = assert!(FontData::default_data_long_enough(Subtable0::MIN_SIZE));
325
326impl Default for Subtable0<'_> {
327    fn default() -> Self {
328        Self {
329            data: FontData::default_table_data(),
330        }
331    }
332}
333
334#[cfg(feature = "experimental_traverse")]
335impl<'a> SomeTable<'a> for Subtable0<'a> {
336    fn type_name(&self) -> &str {
337        "Subtable0"
338    }
339    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
340        match idx {
341            0usize => Some(Field::new("n_pairs", self.n_pairs())),
342            1usize => Some(Field::new("search_range", self.search_range())),
343            2usize => Some(Field::new("entry_selector", self.entry_selector())),
344            3usize => Some(Field::new("range_shift", self.range_shift())),
345            4usize => Some(Field::new(
346                "pairs",
347                traversal::FieldType::array_of_records(
348                    stringify!(Subtable0Pair),
349                    self.pairs(),
350                    self.offset_data(),
351                ),
352            )),
353            _ => None,
354        }
355    }
356}
357
358#[cfg(feature = "experimental_traverse")]
359#[allow(clippy::needless_lifetimes)]
360impl<'a> std::fmt::Debug for Subtable0<'a> {
361    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
362        (self as &dyn SomeTable<'a>).fmt(f)
363    }
364}
365
366/// The type 0 `kerx` subtable kerning record.
367#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
368#[repr(C)]
369#[repr(packed)]
370pub struct Subtable0Pair {
371    /// The glyph index for the lefthand glyph in the kerning pair.
372    pub left: BigEndian<GlyphId16>,
373    /// The glyph index for the righthand glyph in the kerning pair.
374    pub right: BigEndian<GlyphId16>,
375    /// Kerning value.
376    pub value: BigEndian<i16>,
377}
378
379impl Subtable0Pair {
380    /// The glyph index for the lefthand glyph in the kerning pair.
381    pub fn left(&self) -> GlyphId16 {
382        self.left.get()
383    }
384
385    /// The glyph index for the righthand glyph in the kerning pair.
386    pub fn right(&self) -> GlyphId16 {
387        self.right.get()
388    }
389
390    /// Kerning value.
391    pub fn value(&self) -> i16 {
392        self.value.get()
393    }
394}
395
396impl FixedSize for Subtable0Pair {
397    const RAW_BYTE_LEN: usize =
398        GlyphId16::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN;
399}
400
401#[cfg(feature = "experimental_traverse")]
402impl<'a> SomeRecord<'a> for Subtable0Pair {
403    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
404        RecordResolver {
405            name: "Subtable0Pair",
406            get_field: Box::new(move |idx, _data| match idx {
407                0usize => Some(Field::new("left", self.left())),
408                1usize => Some(Field::new("right", self.right())),
409                2usize => Some(Field::new("value", self.value())),
410                _ => None,
411            }),
412            data,
413        }
414    }
415}