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