Skip to main content

read_fonts/generated/
generated_morx.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 Morx<'a> {
9    fn min_byte_range(&self) -> Range<usize> {
10        0..self.chains_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 Morx<'_> {
19    /// `morx`
20    const TAG: Tag = Tag::new(b"morx");
21}
22
23impl<'a> FontRead<'a> for Morx<'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 [morx (Extended Glyph Metamorphosis)](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html) table.
34#[derive(Clone)]
35pub struct Morx<'a> {
36    data: FontData<'a>,
37}
38
39#[allow(clippy::needless_lifetimes)]
40impl<'a> Morx<'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    /// Version number of the extended glyph metamorphosis table (either 2 or 3).
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    /// Number of metamorphosis chains contained in this table.
51    pub fn n_chains(&self) -> u32 {
52        let range = self.n_chains_byte_range();
53        self.data.read_at(range.start).ok().unwrap()
54    }
55
56    pub fn chains(&self) -> VarLenArray<'a, Chain<'a>> {
57        let range = self.chains_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 unused_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_chains_byte_range(&self) -> Range<usize> {
75        let start = self.unused_byte_range().end;
76        start..start + u32::RAW_BYTE_LEN
77    }
78
79    pub fn chains_byte_range(&self) -> Range<usize> {
80        let n_chains = self.n_chains();
81        let start = self.n_chains_byte_range().end;
82        start..start + {
83            let data = self.data.split_off(start).unwrap_or_default();
84            <Chain as VarSize>::total_len_for_count(data, n_chains as usize).unwrap_or(0)
85        }
86    }
87}
88
89#[cfg(feature = "experimental_traverse")]
90impl<'a> SomeTable<'a> for Morx<'a> {
91    fn type_name(&self) -> &str {
92        "Morx"
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_chains", self.n_chains())),
98            2usize => Some(Field::new(
99                "chains",
100                traversal::FieldType::var_array("Chain", self.chains(), 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 Morx<'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 Chain<'a> {
116    fn min_byte_range(&self) -> Range<usize> {
117        0..self.subtables_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 Chain<'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 chain in a `morx` table.
136#[derive(Clone)]
137pub struct Chain<'a> {
138    data: FontData<'a>,
139}
140
141#[allow(clippy::needless_lifetimes)]
142impl<'a> Chain<'a> {
143    pub const MIN_SIZE: usize =
144        (u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
145    basic_table_impls!(impl_the_methods);
146
147    /// The default specification for subtables.
148    pub fn default_flags(&self) -> u32 {
149        let range = self.default_flags_byte_range();
150        self.data.read_at(range.start).ok().unwrap()
151    }
152
153    /// Total byte count, including this header; must be a multiple of 4.
154    pub fn chain_length(&self) -> u32 {
155        let range = self.chain_length_byte_range();
156        self.data.read_at(range.start).ok().unwrap()
157    }
158
159    /// Number of feature subtable entries.
160    pub fn n_feature_entries(&self) -> u32 {
161        let range = self.n_feature_entries_byte_range();
162        self.data.read_at(range.start).ok().unwrap()
163    }
164
165    /// The number of subtables in the chain.
166    pub fn n_subtables(&self) -> u32 {
167        let range = self.n_subtables_byte_range();
168        self.data.read_at(range.start).ok().unwrap()
169    }
170
171    /// Feature entries for this chain.
172    pub fn features(&self) -> &'a [Feature] {
173        let range = self.features_byte_range();
174        self.data.read_array(range).ok().unwrap_or_default()
175    }
176
177    /// Array of chain subtables.
178    pub fn subtables(&self) -> VarLenArray<'a, Subtable<'a>> {
179        let range = self.subtables_byte_range();
180        self.data
181            .split_off(range.start)
182            .and_then(|d| VarLenArray::read(d).ok())
183            .unwrap_or_default()
184    }
185
186    pub fn default_flags_byte_range(&self) -> Range<usize> {
187        let start = 0;
188        start..start + u32::RAW_BYTE_LEN
189    }
190
191    pub fn chain_length_byte_range(&self) -> Range<usize> {
192        let start = self.default_flags_byte_range().end;
193        start..start + u32::RAW_BYTE_LEN
194    }
195
196    pub fn n_feature_entries_byte_range(&self) -> Range<usize> {
197        let start = self.chain_length_byte_range().end;
198        start..start + u32::RAW_BYTE_LEN
199    }
200
201    pub fn n_subtables_byte_range(&self) -> Range<usize> {
202        let start = self.n_feature_entries_byte_range().end;
203        start..start + u32::RAW_BYTE_LEN
204    }
205
206    pub fn features_byte_range(&self) -> Range<usize> {
207        let n_feature_entries = self.n_feature_entries();
208        let start = self.n_subtables_byte_range().end;
209        start..start + (n_feature_entries as usize).saturating_mul(Feature::RAW_BYTE_LEN)
210    }
211
212    pub fn subtables_byte_range(&self) -> Range<usize> {
213        let n_subtables = self.n_subtables();
214        let start = self.features_byte_range().end;
215        start..start + {
216            let data = self.data.split_off(start).unwrap_or_default();
217            <Subtable as VarSize>::total_len_for_count(data, n_subtables as usize).unwrap_or(0)
218        }
219    }
220}
221
222#[cfg(feature = "experimental_traverse")]
223impl<'a> SomeTable<'a> for Chain<'a> {
224    fn type_name(&self) -> &str {
225        "Chain"
226    }
227    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
228        match idx {
229            0usize => Some(Field::new("default_flags", self.default_flags())),
230            1usize => Some(Field::new("chain_length", self.chain_length())),
231            2usize => Some(Field::new("n_feature_entries", self.n_feature_entries())),
232            3usize => Some(Field::new("n_subtables", self.n_subtables())),
233            4usize => Some(Field::new(
234                "features",
235                traversal::FieldType::array_of_records(
236                    stringify!(Feature),
237                    self.features(),
238                    self.offset_data(),
239                ),
240            )),
241            5usize => Some(Field::new(
242                "subtables",
243                traversal::FieldType::var_array("Subtable", self.subtables(), self.offset_data()),
244            )),
245            _ => None,
246        }
247    }
248}
249
250#[cfg(feature = "experimental_traverse")]
251#[allow(clippy::needless_lifetimes)]
252impl<'a> std::fmt::Debug for Chain<'a> {
253    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
254        (self as &dyn SomeTable<'a>).fmt(f)
255    }
256}
257
258/// Used to compute the sub-feature flags for a list of requested features and settings.
259#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
260#[repr(C)]
261#[repr(packed)]
262pub struct Feature {
263    /// The type of feature.
264    pub feature_type: BigEndian<u16>,
265    /// The feature's setting (aka selector).
266    pub feature_settings: BigEndian<u16>,
267    /// Flags for the settings that this feature and setting enables.
268    pub enable_flags: BigEndian<u32>,
269    /// Complement of flags for the settings that this feature and setting disable.
270    pub disable_flags: BigEndian<u32>,
271}
272
273impl Feature {
274    /// The type of feature.
275    pub fn feature_type(&self) -> u16 {
276        self.feature_type.get()
277    }
278
279    /// The feature's setting (aka selector).
280    pub fn feature_settings(&self) -> u16 {
281        self.feature_settings.get()
282    }
283
284    /// Flags for the settings that this feature and setting enables.
285    pub fn enable_flags(&self) -> u32 {
286        self.enable_flags.get()
287    }
288
289    /// Complement of flags for the settings that this feature and setting disable.
290    pub fn disable_flags(&self) -> u32 {
291        self.disable_flags.get()
292    }
293}
294
295impl FixedSize for Feature {
296    const RAW_BYTE_LEN: usize =
297        u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN;
298}
299
300#[cfg(feature = "experimental_traverse")]
301impl<'a> SomeRecord<'a> for Feature {
302    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
303        RecordResolver {
304            name: "Feature",
305            get_field: Box::new(move |idx, _data| match idx {
306                0usize => Some(Field::new("feature_type", self.feature_type())),
307                1usize => Some(Field::new("feature_settings", self.feature_settings())),
308                2usize => Some(Field::new("enable_flags", self.enable_flags())),
309                3usize => Some(Field::new("disable_flags", self.disable_flags())),
310                _ => None,
311            }),
312            data,
313        }
314    }
315}
316
317impl<'a> MinByteRange<'a> for Subtable<'a> {
318    fn min_byte_range(&self) -> Range<usize> {
319        0..self.data_byte_range().end
320    }
321    fn min_table_bytes(&self) -> &'a [u8] {
322        let range = self.min_byte_range();
323        self.data.as_bytes().get(range).unwrap_or_default()
324    }
325}
326
327impl<'a> FontRead<'a> for Subtable<'a> {
328    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
329        #[allow(clippy::absurd_extreme_comparisons)]
330        if data.len() < Self::MIN_SIZE {
331            return Err(ReadError::OutOfBounds);
332        }
333        Ok(Self { data })
334    }
335}
336
337/// A subtable in a `morx` chain.
338#[derive(Clone)]
339pub struct Subtable<'a> {
340    data: FontData<'a>,
341}
342
343#[allow(clippy::needless_lifetimes)]
344impl<'a> Subtable<'a> {
345    pub const MIN_SIZE: usize = (u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
346    basic_table_impls!(impl_the_methods);
347
348    /// Total subtable length, including this header.
349    pub fn length(&self) -> u32 {
350        let range = self.length_byte_range();
351        self.data.read_at(range.start).ok().unwrap()
352    }
353
354    /// Coverage flags and subtable type.
355    pub fn coverage(&self) -> u32 {
356        let range = self.coverage_byte_range();
357        self.data.read_at(range.start).ok().unwrap()
358    }
359
360    /// The 32-bit mask identifying which subtable this is (the subtable being executed if the AND of this value and the processed defaultFlags is nonzero).
361    pub fn sub_feature_flags(&self) -> u32 {
362        let range = self.sub_feature_flags_byte_range();
363        self.data.read_at(range.start).ok().unwrap()
364    }
365
366    /// Data for specific subtable.
367    pub fn data(&self) -> &'a [u8] {
368        let range = self.data_byte_range();
369        self.data.read_array(range).ok().unwrap_or_default()
370    }
371
372    pub fn length_byte_range(&self) -> Range<usize> {
373        let start = 0;
374        start..start + u32::RAW_BYTE_LEN
375    }
376
377    pub fn coverage_byte_range(&self) -> Range<usize> {
378        let start = self.length_byte_range().end;
379        start..start + u32::RAW_BYTE_LEN
380    }
381
382    pub fn sub_feature_flags_byte_range(&self) -> Range<usize> {
383        let start = self.coverage_byte_range().end;
384        start..start + u32::RAW_BYTE_LEN
385    }
386
387    pub fn data_byte_range(&self) -> Range<usize> {
388        let start = self.sub_feature_flags_byte_range().end;
389        start..start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN
390    }
391}
392
393#[cfg(feature = "experimental_traverse")]
394impl<'a> SomeTable<'a> for Subtable<'a> {
395    fn type_name(&self) -> &str {
396        "Subtable"
397    }
398    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
399        match idx {
400            0usize => Some(Field::new("length", self.length())),
401            1usize => Some(Field::new("coverage", self.coverage())),
402            2usize => Some(Field::new("sub_feature_flags", self.sub_feature_flags())),
403            3usize => Some(Field::new("data", self.data())),
404            _ => None,
405        }
406    }
407}
408
409#[cfg(feature = "experimental_traverse")]
410#[allow(clippy::needless_lifetimes)]
411impl<'a> std::fmt::Debug for Subtable<'a> {
412    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
413        (self as &dyn SomeTable<'a>).fmt(f)
414    }
415}
416
417/// Entry payload in a contextual subtable state machine.
418#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
419#[repr(C)]
420#[repr(packed)]
421pub struct ContextualEntryData {
422    /// Index of the substitution table for the marked glyph (use 0xFFFF for
423    /// none).
424    pub mark_index: BigEndian<u16>,
425    /// Index of the substitution table for the current glyph (use 0xFFFF for
426    /// none)
427    pub current_index: BigEndian<u16>,
428}
429
430impl ContextualEntryData {
431    /// Index of the substitution table for the marked glyph (use 0xFFFF for
432    /// none).
433    pub fn mark_index(&self) -> u16 {
434        self.mark_index.get()
435    }
436
437    /// Index of the substitution table for the current glyph (use 0xFFFF for
438    /// none)
439    pub fn current_index(&self) -> u16 {
440        self.current_index.get()
441    }
442}
443
444impl FixedSize for ContextualEntryData {
445    const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
446}
447
448#[cfg(feature = "experimental_traverse")]
449impl<'a> SomeRecord<'a> for ContextualEntryData {
450    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
451        RecordResolver {
452            name: "ContextualEntryData",
453            get_field: Box::new(move |idx, _data| match idx {
454                0usize => Some(Field::new("mark_index", self.mark_index())),
455                1usize => Some(Field::new("current_index", self.current_index())),
456                _ => None,
457            }),
458            data,
459        }
460    }
461}
462
463/// Entry payload in an insertion subtable state machine.
464#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
465#[repr(C)]
466#[repr(packed)]
467pub struct InsertionEntryData {
468    /// Zero-based index into the insertion glyph table. The number of glyphs
469    /// to be inserted is contained in the currentInsertCount field in the
470    /// flags (see below). A value of 0xFFFF indicates no insertion is to be done.
471    pub current_insert_index: BigEndian<u16>,
472    /// Zero-based index into the insertion glyph table. The number of glyphs
473    /// to be inserted is contained in the markedInsertCount field in the
474    /// flags (see below). A value of 0xFFFF indicates no insertion is to be
475    /// done.
476    pub marked_insert_index: BigEndian<u16>,
477}
478
479impl InsertionEntryData {
480    /// Zero-based index into the insertion glyph table. The number of glyphs
481    /// to be inserted is contained in the currentInsertCount field in the
482    /// flags (see below). A value of 0xFFFF indicates no insertion is to be done.
483    pub fn current_insert_index(&self) -> u16 {
484        self.current_insert_index.get()
485    }
486
487    /// Zero-based index into the insertion glyph table. The number of glyphs
488    /// to be inserted is contained in the markedInsertCount field in the
489    /// flags (see below). A value of 0xFFFF indicates no insertion is to be
490    /// done.
491    pub fn marked_insert_index(&self) -> u16 {
492        self.marked_insert_index.get()
493    }
494}
495
496impl FixedSize for InsertionEntryData {
497    const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
498}
499
500#[cfg(feature = "experimental_traverse")]
501impl<'a> SomeRecord<'a> for InsertionEntryData {
502    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
503        RecordResolver {
504            name: "InsertionEntryData",
505            get_field: Box::new(move |idx, _data| match idx {
506                0usize => Some(Field::new(
507                    "current_insert_index",
508                    self.current_insert_index(),
509                )),
510                1usize => Some(Field::new(
511                    "marked_insert_index",
512                    self.marked_insert_index(),
513                )),
514                _ => None,
515            }),
516            data,
517        }
518    }
519}