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