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