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