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
89#[cfg(feature = "experimental_traverse")]
90impl<'a> SomeTable<'a> for Kerx<'a> {
91    fn type_name(&self) -> &str {
92        "Kerx"
93    }
94    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
95        match idx {
96            0usize => Some(Field::new("version", self.version())),
97            1usize => Some(Field::new("n_tables", self.n_tables())),
98            2usize => Some(Field::new(
99                "subtables",
100                traversal::FieldType::var_array("Subtable", self.subtables(), self.offset_data()),
101            )),
102            _ => None,
103        }
104    }
105}
106
107#[cfg(feature = "experimental_traverse")]
108#[allow(clippy::needless_lifetimes)]
109impl<'a> std::fmt::Debug for Kerx<'a> {
110    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111        (self as &dyn SomeTable<'a>).fmt(f)
112    }
113}
114
115impl<'a> MinByteRange<'a> for Subtable<'a> {
116    fn min_byte_range(&self) -> Range<usize> {
117        0..self.data_byte_range().end
118    }
119    fn min_table_bytes(&self) -> &'a [u8] {
120        let range = self.min_byte_range();
121        self.data.as_bytes().get(range).unwrap_or_default()
122    }
123}
124
125impl<'a> FontRead<'a> for Subtable<'a> {
126    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
127        #[allow(clippy::absurd_extreme_comparisons)]
128        if data.len() < Self::MIN_SIZE {
129            return Err(ReadError::OutOfBounds);
130        }
131        Ok(Self { data })
132    }
133}
134
135/// A subtable in a `kerx` table.
136#[derive(Clone)]
137pub struct Subtable<'a> {
138    data: FontData<'a>,
139}
140
141#[allow(clippy::needless_lifetimes)]
142impl<'a> Subtable<'a> {
143    pub const MIN_SIZE: usize = (u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
144    basic_table_impls!(impl_the_methods);
145
146    /// The length of this subtable in bytes, including this header.
147    pub fn length(&self) -> u32 {
148        let range = self.length_byte_range();
149        self.data.read_at(range.start).ok().unwrap()
150    }
151
152    /// Circumstances under which this table is used.
153    pub fn coverage(&self) -> u32 {
154        let range = self.coverage_byte_range();
155        self.data.read_at(range.start).ok().unwrap()
156    }
157
158    /// 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.
159    pub fn tuple_count(&self) -> u32 {
160        let range = self.tuple_count_byte_range();
161        self.data.read_at(range.start).ok().unwrap()
162    }
163
164    /// Subtable specific data.
165    pub fn data(&self) -> &'a [u8] {
166        let range = self.data_byte_range();
167        self.data.read_array(range).ok().unwrap_or_default()
168    }
169
170    pub fn length_byte_range(&self) -> Range<usize> {
171        let start = 0;
172        start..start + u32::RAW_BYTE_LEN
173    }
174
175    pub fn coverage_byte_range(&self) -> Range<usize> {
176        let start = self.length_byte_range().end;
177        start..start + u32::RAW_BYTE_LEN
178    }
179
180    pub fn tuple_count_byte_range(&self) -> Range<usize> {
181        let start = self.coverage_byte_range().end;
182        start..start + u32::RAW_BYTE_LEN
183    }
184
185    pub fn data_byte_range(&self) -> Range<usize> {
186        let start = self.tuple_count_byte_range().end;
187        start..start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN
188    }
189}
190
191#[cfg(feature = "experimental_traverse")]
192impl<'a> SomeTable<'a> for Subtable<'a> {
193    fn type_name(&self) -> &str {
194        "Subtable"
195    }
196    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
197        match idx {
198            0usize => Some(Field::new("length", self.length())),
199            1usize => Some(Field::new("coverage", self.coverage())),
200            2usize => Some(Field::new("tuple_count", self.tuple_count())),
201            3usize => Some(Field::new("data", self.data())),
202            _ => None,
203        }
204    }
205}
206
207#[cfg(feature = "experimental_traverse")]
208#[allow(clippy::needless_lifetimes)]
209impl<'a> std::fmt::Debug for Subtable<'a> {
210    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
211        (self as &dyn SomeTable<'a>).fmt(f)
212    }
213}
214
215impl<'a> MinByteRange<'a> for Subtable0<'a> {
216    fn min_byte_range(&self) -> Range<usize> {
217        0..self.pairs_byte_range().end
218    }
219    fn min_table_bytes(&self) -> &'a [u8] {
220        let range = self.min_byte_range();
221        self.data.as_bytes().get(range).unwrap_or_default()
222    }
223}
224
225impl<'a> FontRead<'a> for Subtable0<'a> {
226    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
227        #[allow(clippy::absurd_extreme_comparisons)]
228        if data.len() < Self::MIN_SIZE {
229            return Err(ReadError::OutOfBounds);
230        }
231        Ok(Self { data })
232    }
233}
234
235/// The type 0 `kerx` subtable.
236#[derive(Clone)]
237pub struct Subtable0<'a> {
238    data: FontData<'a>,
239}
240
241#[allow(clippy::needless_lifetimes)]
242impl<'a> Subtable0<'a> {
243    pub const MIN_SIZE: usize =
244        (u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
245    basic_table_impls!(impl_the_methods);
246
247    /// The number of kerning pairs in this subtable.
248    pub fn n_pairs(&self) -> u32 {
249        let range = self.n_pairs_byte_range();
250        self.data.read_at(range.start).ok().unwrap()
251    }
252
253    /// 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.
254    pub fn search_range(&self) -> u32 {
255        let range = self.search_range_byte_range();
256        self.data.read_at(range.start).ok().unwrap()
257    }
258
259    /// 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.
260    pub fn entry_selector(&self) -> u32 {
261        let range = self.entry_selector_byte_range();
262        self.data.read_at(range.start).ok().unwrap()
263    }
264
265    /// 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.
266    pub fn range_shift(&self) -> u32 {
267        let range = self.range_shift_byte_range();
268        self.data.read_at(range.start).ok().unwrap()
269    }
270
271    /// Kerning records.
272    pub fn pairs(&self) -> &'a [Subtable0Pair] {
273        let range = self.pairs_byte_range();
274        self.data.read_array(range).ok().unwrap_or_default()
275    }
276
277    pub fn n_pairs_byte_range(&self) -> Range<usize> {
278        let start = 0;
279        start..start + u32::RAW_BYTE_LEN
280    }
281
282    pub fn search_range_byte_range(&self) -> Range<usize> {
283        let start = self.n_pairs_byte_range().end;
284        start..start + u32::RAW_BYTE_LEN
285    }
286
287    pub fn entry_selector_byte_range(&self) -> Range<usize> {
288        let start = self.search_range_byte_range().end;
289        start..start + u32::RAW_BYTE_LEN
290    }
291
292    pub fn range_shift_byte_range(&self) -> Range<usize> {
293        let start = self.entry_selector_byte_range().end;
294        start..start + u32::RAW_BYTE_LEN
295    }
296
297    pub fn pairs_byte_range(&self) -> Range<usize> {
298        let n_pairs = self.n_pairs();
299        let start = self.range_shift_byte_range().end;
300        start..start + (n_pairs as usize).saturating_mul(Subtable0Pair::RAW_BYTE_LEN)
301    }
302}
303
304#[cfg(feature = "experimental_traverse")]
305impl<'a> SomeTable<'a> for Subtable0<'a> {
306    fn type_name(&self) -> &str {
307        "Subtable0"
308    }
309    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
310        match idx {
311            0usize => Some(Field::new("n_pairs", self.n_pairs())),
312            1usize => Some(Field::new("search_range", self.search_range())),
313            2usize => Some(Field::new("entry_selector", self.entry_selector())),
314            3usize => Some(Field::new("range_shift", self.range_shift())),
315            4usize => Some(Field::new(
316                "pairs",
317                traversal::FieldType::array_of_records(
318                    stringify!(Subtable0Pair),
319                    self.pairs(),
320                    self.offset_data(),
321                ),
322            )),
323            _ => None,
324        }
325    }
326}
327
328#[cfg(feature = "experimental_traverse")]
329#[allow(clippy::needless_lifetimes)]
330impl<'a> std::fmt::Debug for Subtable0<'a> {
331    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
332        (self as &dyn SomeTable<'a>).fmt(f)
333    }
334}
335
336/// The type 0 `kerx` subtable kerning record.
337#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
338#[repr(C)]
339#[repr(packed)]
340pub struct Subtable0Pair {
341    /// The glyph index for the lefthand glyph in the kerning pair.
342    pub left: BigEndian<GlyphId16>,
343    /// The glyph index for the righthand glyph in the kerning pair.
344    pub right: BigEndian<GlyphId16>,
345    /// Kerning value.
346    pub value: BigEndian<i16>,
347}
348
349impl Subtable0Pair {
350    /// The glyph index for the lefthand glyph in the kerning pair.
351    pub fn left(&self) -> GlyphId16 {
352        self.left.get()
353    }
354
355    /// The glyph index for the righthand glyph in the kerning pair.
356    pub fn right(&self) -> GlyphId16 {
357        self.right.get()
358    }
359
360    /// Kerning value.
361    pub fn value(&self) -> i16 {
362        self.value.get()
363    }
364}
365
366impl FixedSize for Subtable0Pair {
367    const RAW_BYTE_LEN: usize =
368        GlyphId16::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN;
369}
370
371#[cfg(feature = "experimental_traverse")]
372impl<'a> SomeRecord<'a> for Subtable0Pair {
373    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
374        RecordResolver {
375            name: "Subtable0Pair",
376            get_field: Box::new(move |idx, _data| match idx {
377                0usize => Some(Field::new("left", self.left())),
378                1usize => Some(Field::new("right", self.right())),
379                2usize => Some(Field::new("value", self.value())),
380                _ => None,
381            }),
382            data,
383        }
384    }
385}