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