Skip to main content

read_fonts/generated/
generated_bitmap.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/// [BitmapSize](https://learn.microsoft.com/en-us/typography/opentype/spec/eblc#bitmapsize-record) record.
9#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
10#[repr(C)]
11#[repr(packed)]
12pub struct BitmapSize {
13    /// Offset to IndexSubtableList, from beginning of EBLC/CBLC.
14    pub index_subtable_list_offset: BigEndian<u32>,
15    /// Total size in bytes of the IndexSubtableList including its array of IndexSubtables.
16    pub index_subtable_list_size: BigEndian<u32>,
17    /// Number of IndexSubtables in the IndexSubtableList.
18    pub number_of_index_subtables: BigEndian<u32>,
19    /// Not used; set to 0.
20    pub color_ref: BigEndian<u32>,
21    /// Line metrics for text rendered horizontally.
22    pub hori: SbitLineMetrics,
23    /// Line metrics for text rendered vertically.
24    pub vert: SbitLineMetrics,
25    /// Lowest glyph index for this size.
26    pub start_glyph_index: BigEndian<GlyphId16>,
27    /// Highest glyph index for this size.
28    pub end_glyph_index: BigEndian<GlyphId16>,
29    /// Horizontal pixels per em.
30    pub ppem_x: u8,
31    /// Vertical pixels per em.
32    pub ppem_y: u8,
33    /// The Microsoft rasterizer v.1.7 or greater supports the following
34    /// bitDepth values, as described below: 1, 2, 4, and 8 (and 32 for CBLC).
35    pub bit_depth: u8,
36    /// Vertical or horizontal.
37    pub flags: BigEndian<BitmapFlags>,
38}
39
40impl BitmapSize {
41    /// Offset to IndexSubtableList, from beginning of EBLC/CBLC.
42    pub fn index_subtable_list_offset(&self) -> u32 {
43        self.index_subtable_list_offset.get()
44    }
45
46    /// Total size in bytes of the IndexSubtableList including its array of IndexSubtables.
47    pub fn index_subtable_list_size(&self) -> u32 {
48        self.index_subtable_list_size.get()
49    }
50
51    /// Number of IndexSubtables in the IndexSubtableList.
52    pub fn number_of_index_subtables(&self) -> u32 {
53        self.number_of_index_subtables.get()
54    }
55
56    /// Not used; set to 0.
57    pub fn color_ref(&self) -> u32 {
58        self.color_ref.get()
59    }
60
61    /// Line metrics for text rendered horizontally.
62    pub fn hori(&self) -> &SbitLineMetrics {
63        &self.hori
64    }
65
66    /// Line metrics for text rendered vertically.
67    pub fn vert(&self) -> &SbitLineMetrics {
68        &self.vert
69    }
70
71    /// Lowest glyph index for this size.
72    pub fn start_glyph_index(&self) -> GlyphId16 {
73        self.start_glyph_index.get()
74    }
75
76    /// Highest glyph index for this size.
77    pub fn end_glyph_index(&self) -> GlyphId16 {
78        self.end_glyph_index.get()
79    }
80
81    /// Horizontal pixels per em.
82    pub fn ppem_x(&self) -> u8 {
83        self.ppem_x
84    }
85
86    /// Vertical pixels per em.
87    pub fn ppem_y(&self) -> u8 {
88        self.ppem_y
89    }
90
91    /// The Microsoft rasterizer v.1.7 or greater supports the following
92    /// bitDepth values, as described below: 1, 2, 4, and 8 (and 32 for CBLC).
93    pub fn bit_depth(&self) -> u8 {
94        self.bit_depth
95    }
96
97    /// Vertical or horizontal.
98    pub fn flags(&self) -> BitmapFlags {
99        self.flags.get()
100    }
101}
102
103impl FixedSize for BitmapSize {
104    const RAW_BYTE_LEN: usize = u32::RAW_BYTE_LEN
105        + u32::RAW_BYTE_LEN
106        + u32::RAW_BYTE_LEN
107        + u32::RAW_BYTE_LEN
108        + SbitLineMetrics::RAW_BYTE_LEN
109        + SbitLineMetrics::RAW_BYTE_LEN
110        + GlyphId16::RAW_BYTE_LEN
111        + GlyphId16::RAW_BYTE_LEN
112        + u8::RAW_BYTE_LEN
113        + u8::RAW_BYTE_LEN
114        + u8::RAW_BYTE_LEN
115        + BitmapFlags::RAW_BYTE_LEN;
116}
117
118#[cfg(feature = "experimental_traverse")]
119impl<'a> SomeRecord<'a> for BitmapSize {
120    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
121        RecordResolver {
122            name: "BitmapSize",
123            get_field: Box::new(move |idx, _data| match idx {
124                0usize => Some(Field::new(
125                    "index_subtable_list_offset",
126                    self.index_subtable_list_offset(),
127                )),
128                1usize => Some(Field::new(
129                    "index_subtable_list_size",
130                    self.index_subtable_list_size(),
131                )),
132                2usize => Some(Field::new(
133                    "number_of_index_subtables",
134                    self.number_of_index_subtables(),
135                )),
136                3usize => Some(Field::new("color_ref", self.color_ref())),
137                4usize => Some(Field::new("hori", self.hori().traversal_type(_data))),
138                5usize => Some(Field::new("vert", self.vert().traversal_type(_data))),
139                6usize => Some(Field::new("start_glyph_index", self.start_glyph_index())),
140                7usize => Some(Field::new("end_glyph_index", self.end_glyph_index())),
141                8usize => Some(Field::new("ppem_x", self.ppem_x())),
142                9usize => Some(Field::new("ppem_y", self.ppem_y())),
143                10usize => Some(Field::new("bit_depth", self.bit_depth())),
144                11usize => Some(Field::new("flags", self.flags())),
145                _ => None,
146            }),
147            data,
148        }
149    }
150}
151
152/// [SbitLineMetrics](https://learn.microsoft.com/en-us/typography/opentype/spec/eblc#sbitlinemetrics-record) record.
153#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
154#[repr(C)]
155#[repr(packed)]
156pub struct SbitLineMetrics {
157    pub ascender: BigEndian<i8>,
158    pub descender: BigEndian<i8>,
159    pub width_max: u8,
160    pub caret_slope_numerator: BigEndian<i8>,
161    pub caret_slope_denominator: u8,
162    pub caret_offset: BigEndian<i8>,
163    pub min_origin_sb: BigEndian<i8>,
164    pub min_advance_sb: BigEndian<i8>,
165    pub max_before_bl: BigEndian<i8>,
166    pub min_after_bl: BigEndian<i8>,
167    pub pad1: BigEndian<i8>,
168    pub pad2: BigEndian<i8>,
169}
170
171impl SbitLineMetrics {
172    pub fn ascender(&self) -> i8 {
173        self.ascender.get()
174    }
175
176    pub fn descender(&self) -> i8 {
177        self.descender.get()
178    }
179
180    pub fn width_max(&self) -> u8 {
181        self.width_max
182    }
183
184    pub fn caret_slope_numerator(&self) -> i8 {
185        self.caret_slope_numerator.get()
186    }
187
188    pub fn caret_slope_denominator(&self) -> u8 {
189        self.caret_slope_denominator
190    }
191
192    pub fn caret_offset(&self) -> i8 {
193        self.caret_offset.get()
194    }
195
196    pub fn min_origin_sb(&self) -> i8 {
197        self.min_origin_sb.get()
198    }
199
200    pub fn min_advance_sb(&self) -> i8 {
201        self.min_advance_sb.get()
202    }
203
204    pub fn max_before_bl(&self) -> i8 {
205        self.max_before_bl.get()
206    }
207
208    pub fn min_after_bl(&self) -> i8 {
209        self.min_after_bl.get()
210    }
211
212    pub fn pad1(&self) -> i8 {
213        self.pad1.get()
214    }
215
216    pub fn pad2(&self) -> i8 {
217        self.pad2.get()
218    }
219}
220
221impl FixedSize for SbitLineMetrics {
222    const RAW_BYTE_LEN: usize = i8::RAW_BYTE_LEN
223        + i8::RAW_BYTE_LEN
224        + u8::RAW_BYTE_LEN
225        + i8::RAW_BYTE_LEN
226        + u8::RAW_BYTE_LEN
227        + i8::RAW_BYTE_LEN
228        + i8::RAW_BYTE_LEN
229        + i8::RAW_BYTE_LEN
230        + i8::RAW_BYTE_LEN
231        + i8::RAW_BYTE_LEN
232        + i8::RAW_BYTE_LEN
233        + i8::RAW_BYTE_LEN;
234}
235
236#[cfg(feature = "experimental_traverse")]
237impl<'a> SomeRecord<'a> for SbitLineMetrics {
238    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
239        RecordResolver {
240            name: "SbitLineMetrics",
241            get_field: Box::new(move |idx, _data| match idx {
242                0usize => Some(Field::new("ascender", self.ascender())),
243                1usize => Some(Field::new("descender", self.descender())),
244                2usize => Some(Field::new("width_max", self.width_max())),
245                3usize => Some(Field::new(
246                    "caret_slope_numerator",
247                    self.caret_slope_numerator(),
248                )),
249                4usize => Some(Field::new(
250                    "caret_slope_denominator",
251                    self.caret_slope_denominator(),
252                )),
253                5usize => Some(Field::new("caret_offset", self.caret_offset())),
254                6usize => Some(Field::new("min_origin_sb", self.min_origin_sb())),
255                7usize => Some(Field::new("min_advance_sb", self.min_advance_sb())),
256                8usize => Some(Field::new("max_before_bl", self.max_before_bl())),
257                9usize => Some(Field::new("min_after_bl", self.min_after_bl())),
258                10usize => Some(Field::new("pad1", self.pad1())),
259                11usize => Some(Field::new("pad2", self.pad2())),
260                _ => None,
261            }),
262            data,
263        }
264    }
265}
266
267/// [Bitmap flags](https://learn.microsoft.com/en-us/typography/opentype/spec/eblc#bitmap-flags).
268#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, bytemuck :: AnyBitPattern)]
269#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
270#[repr(transparent)]
271pub struct BitmapFlags {
272    bits: u8,
273}
274
275impl BitmapFlags {
276    /// Horizontal
277    pub const HORIZONTAL_METRICS: Self = Self { bits: 0x01 };
278
279    /// Vertical
280    pub const VERTICAL_METRICS: Self = Self { bits: 0x02 };
281}
282
283impl BitmapFlags {
284    ///  Returns an empty set of flags.
285    #[inline]
286    pub const fn empty() -> Self {
287        Self { bits: 0 }
288    }
289
290    /// Returns the set containing all flags.
291    #[inline]
292    pub const fn all() -> Self {
293        Self {
294            bits: Self::HORIZONTAL_METRICS.bits | Self::VERTICAL_METRICS.bits,
295        }
296    }
297
298    /// Returns the raw value of the flags currently stored.
299    #[inline]
300    pub const fn bits(&self) -> u8 {
301        self.bits
302    }
303
304    /// Convert from underlying bit representation, unless that
305    /// representation contains bits that do not correspond to a flag.
306    #[inline]
307    pub const fn from_bits(bits: u8) -> Option<Self> {
308        if (bits & !Self::all().bits()) == 0 {
309            Some(Self { bits })
310        } else {
311            None
312        }
313    }
314
315    /// Convert from underlying bit representation, dropping any bits
316    /// that do not correspond to flags.
317    #[inline]
318    pub const fn from_bits_truncate(bits: u8) -> Self {
319        Self {
320            bits: bits & Self::all().bits,
321        }
322    }
323
324    /// Returns `true` if no flags are currently stored.
325    #[inline]
326    pub const fn is_empty(&self) -> bool {
327        self.bits() == Self::empty().bits()
328    }
329
330    /// Returns `true` if there are flags common to both `self` and `other`.
331    #[inline]
332    pub const fn intersects(&self, other: Self) -> bool {
333        !(Self {
334            bits: self.bits & other.bits,
335        })
336        .is_empty()
337    }
338
339    /// Returns `true` if all of the flags in `other` are contained within `self`.
340    #[inline]
341    pub const fn contains(&self, other: Self) -> bool {
342        (self.bits & other.bits) == other.bits
343    }
344
345    /// Inserts the specified flags in-place.
346    #[inline]
347    pub fn insert(&mut self, other: Self) {
348        self.bits |= other.bits;
349    }
350
351    /// Removes the specified flags in-place.
352    #[inline]
353    pub fn remove(&mut self, other: Self) {
354        self.bits &= !other.bits;
355    }
356
357    /// Toggles the specified flags in-place.
358    #[inline]
359    pub fn toggle(&mut self, other: Self) {
360        self.bits ^= other.bits;
361    }
362
363    /// Returns the intersection between the flags in `self` and
364    /// `other`.
365    ///
366    /// Specifically, the returned set contains only the flags which are
367    /// present in *both* `self` *and* `other`.
368    ///
369    /// This is equivalent to using the `&` operator (e.g.
370    /// [`ops::BitAnd`]), as in `flags & other`.
371    ///
372    /// [`ops::BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html
373    #[inline]
374    #[must_use]
375    pub const fn intersection(self, other: Self) -> Self {
376        Self {
377            bits: self.bits & other.bits,
378        }
379    }
380
381    /// Returns the union of between the flags in `self` and `other`.
382    ///
383    /// Specifically, the returned set contains all flags which are
384    /// present in *either* `self` *or* `other`, including any which are
385    /// present in both.
386    ///
387    /// This is equivalent to using the `|` operator (e.g.
388    /// [`ops::BitOr`]), as in `flags | other`.
389    ///
390    /// [`ops::BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html
391    #[inline]
392    #[must_use]
393    pub const fn union(self, other: Self) -> Self {
394        Self {
395            bits: self.bits | other.bits,
396        }
397    }
398
399    /// Returns the difference between the flags in `self` and `other`.
400    ///
401    /// Specifically, the returned set contains all flags present in
402    /// `self`, except for the ones present in `other`.
403    ///
404    /// It is also conceptually equivalent to the "bit-clear" operation:
405    /// `flags & !other` (and this syntax is also supported).
406    ///
407    /// This is equivalent to using the `-` operator (e.g.
408    /// [`ops::Sub`]), as in `flags - other`.
409    ///
410    /// [`ops::Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html
411    #[inline]
412    #[must_use]
413    pub const fn difference(self, other: Self) -> Self {
414        Self {
415            bits: self.bits & !other.bits,
416        }
417    }
418}
419
420impl std::ops::BitOr for BitmapFlags {
421    type Output = Self;
422
423    /// Returns the union of the two sets of flags.
424    #[inline]
425    fn bitor(self, other: BitmapFlags) -> Self {
426        Self {
427            bits: self.bits | other.bits,
428        }
429    }
430}
431
432impl std::ops::BitOrAssign for BitmapFlags {
433    /// Adds the set of flags.
434    #[inline]
435    fn bitor_assign(&mut self, other: Self) {
436        self.bits |= other.bits;
437    }
438}
439
440impl std::ops::BitXor for BitmapFlags {
441    type Output = Self;
442
443    /// Returns the left flags, but with all the right flags toggled.
444    #[inline]
445    fn bitxor(self, other: Self) -> Self {
446        Self {
447            bits: self.bits ^ other.bits,
448        }
449    }
450}
451
452impl std::ops::BitXorAssign for BitmapFlags {
453    /// Toggles the set of flags.
454    #[inline]
455    fn bitxor_assign(&mut self, other: Self) {
456        self.bits ^= other.bits;
457    }
458}
459
460impl std::ops::BitAnd for BitmapFlags {
461    type Output = Self;
462
463    /// Returns the intersection between the two sets of flags.
464    #[inline]
465    fn bitand(self, other: Self) -> Self {
466        Self {
467            bits: self.bits & other.bits,
468        }
469    }
470}
471
472impl std::ops::BitAndAssign for BitmapFlags {
473    /// Disables all flags disabled in the set.
474    #[inline]
475    fn bitand_assign(&mut self, other: Self) {
476        self.bits &= other.bits;
477    }
478}
479
480impl std::ops::Sub for BitmapFlags {
481    type Output = Self;
482
483    /// Returns the set difference of the two sets of flags.
484    #[inline]
485    fn sub(self, other: Self) -> Self {
486        Self {
487            bits: self.bits & !other.bits,
488        }
489    }
490}
491
492impl std::ops::SubAssign for BitmapFlags {
493    /// Disables all flags enabled in the set.
494    #[inline]
495    fn sub_assign(&mut self, other: Self) {
496        self.bits &= !other.bits;
497    }
498}
499
500impl std::ops::Not for BitmapFlags {
501    type Output = Self;
502
503    /// Returns the complement of this set of flags.
504    #[inline]
505    fn not(self) -> Self {
506        Self { bits: !self.bits } & Self::all()
507    }
508}
509
510impl std::fmt::Debug for BitmapFlags {
511    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
512        let members: &[(&str, Self)] = &[
513            ("HORIZONTAL_METRICS", Self::HORIZONTAL_METRICS),
514            ("VERTICAL_METRICS", Self::VERTICAL_METRICS),
515        ];
516        let mut first = true;
517        for (name, value) in members {
518            if self.contains(*value) {
519                if !first {
520                    f.write_str(" | ")?;
521                }
522                first = false;
523                f.write_str(name)?;
524            }
525        }
526        if first {
527            f.write_str("(empty)")?;
528        }
529        Ok(())
530    }
531}
532
533impl std::fmt::Binary for BitmapFlags {
534    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
535        std::fmt::Binary::fmt(&self.bits, f)
536    }
537}
538
539impl std::fmt::Octal for BitmapFlags {
540    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
541        std::fmt::Octal::fmt(&self.bits, f)
542    }
543}
544
545impl std::fmt::LowerHex for BitmapFlags {
546    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
547        std::fmt::LowerHex::fmt(&self.bits, f)
548    }
549}
550
551impl std::fmt::UpperHex for BitmapFlags {
552    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
553        std::fmt::UpperHex::fmt(&self.bits, f)
554    }
555}
556
557impl font_types::Scalar for BitmapFlags {
558    type Raw = <u8 as font_types::Scalar>::Raw;
559    fn to_raw(self) -> Self::Raw {
560        self.bits().to_raw()
561    }
562    fn from_raw(raw: Self::Raw) -> Self {
563        let t = <u8>::from_raw(raw);
564        Self::from_bits_truncate(t)
565    }
566}
567
568#[cfg(feature = "experimental_traverse")]
569impl<'a> From<BitmapFlags> for FieldType<'a> {
570    fn from(src: BitmapFlags) -> FieldType<'a> {
571        src.bits().into()
572    }
573}
574
575/// [BigGlyphMetrics](https://learn.microsoft.com/en-us/typography/opentype/spec/eblc#bigglyphmetrics) record.
576#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
577#[repr(C)]
578#[repr(packed)]
579pub struct BigGlyphMetrics {
580    /// Number of rows of data.
581    pub height: u8,
582    /// Number of columns of data.
583    pub width: u8,
584    /// Distance in pixels from the horizontal origin to the left edge of the bitmap.
585    pub hori_bearing_x: BigEndian<i8>,
586    /// Distance in pixels from the horizontal origin to the top edge of the bitmap.
587    pub hori_bearing_y: BigEndian<i8>,
588    /// Horizontal advance width in pixels.
589    pub hori_advance: u8,
590    /// Distance in pixels from the vertical origin to the left edge of the bitmap.
591    pub vert_bearing_x: BigEndian<i8>,
592    /// Distance in pixels from the vertical origin to the top edge of the bitmap.
593    pub vert_bearing_y: BigEndian<i8>,
594    /// Vertical advance width in pixels.
595    pub vert_advance: u8,
596}
597
598impl BigGlyphMetrics {
599    /// Number of rows of data.
600    pub fn height(&self) -> u8 {
601        self.height
602    }
603
604    /// Number of columns of data.
605    pub fn width(&self) -> u8 {
606        self.width
607    }
608
609    /// Distance in pixels from the horizontal origin to the left edge of the bitmap.
610    pub fn hori_bearing_x(&self) -> i8 {
611        self.hori_bearing_x.get()
612    }
613
614    /// Distance in pixels from the horizontal origin to the top edge of the bitmap.
615    pub fn hori_bearing_y(&self) -> i8 {
616        self.hori_bearing_y.get()
617    }
618
619    /// Horizontal advance width in pixels.
620    pub fn hori_advance(&self) -> u8 {
621        self.hori_advance
622    }
623
624    /// Distance in pixels from the vertical origin to the left edge of the bitmap.
625    pub fn vert_bearing_x(&self) -> i8 {
626        self.vert_bearing_x.get()
627    }
628
629    /// Distance in pixels from the vertical origin to the top edge of the bitmap.
630    pub fn vert_bearing_y(&self) -> i8 {
631        self.vert_bearing_y.get()
632    }
633
634    /// Vertical advance width in pixels.
635    pub fn vert_advance(&self) -> u8 {
636        self.vert_advance
637    }
638}
639
640impl FixedSize for BigGlyphMetrics {
641    const RAW_BYTE_LEN: usize = u8::RAW_BYTE_LEN
642        + u8::RAW_BYTE_LEN
643        + i8::RAW_BYTE_LEN
644        + i8::RAW_BYTE_LEN
645        + u8::RAW_BYTE_LEN
646        + i8::RAW_BYTE_LEN
647        + i8::RAW_BYTE_LEN
648        + u8::RAW_BYTE_LEN;
649}
650
651#[cfg(feature = "experimental_traverse")]
652impl<'a> SomeRecord<'a> for BigGlyphMetrics {
653    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
654        RecordResolver {
655            name: "BigGlyphMetrics",
656            get_field: Box::new(move |idx, _data| match idx {
657                0usize => Some(Field::new("height", self.height())),
658                1usize => Some(Field::new("width", self.width())),
659                2usize => Some(Field::new("hori_bearing_x", self.hori_bearing_x())),
660                3usize => Some(Field::new("hori_bearing_y", self.hori_bearing_y())),
661                4usize => Some(Field::new("hori_advance", self.hori_advance())),
662                5usize => Some(Field::new("vert_bearing_x", self.vert_bearing_x())),
663                6usize => Some(Field::new("vert_bearing_y", self.vert_bearing_y())),
664                7usize => Some(Field::new("vert_advance", self.vert_advance())),
665                _ => None,
666            }),
667            data,
668        }
669    }
670}
671
672/// [SmallGlyphMetrics](https://learn.microsoft.com/en-us/typography/opentype/spec/eblc#smallglyphmetrics) record.
673#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
674#[repr(C)]
675#[repr(packed)]
676pub struct SmallGlyphMetrics {
677    /// Number of rows of data.
678    pub height: u8,
679    /// Number of columns of data.
680    pub width: u8,
681    /// Distance in pixels from the horizontal origin to the left edge of the bitmap (for horizontal text); or distance in pixels from the vertical origin to the top edge of the bitmap (for vertical text).
682    pub bearing_x: BigEndian<i8>,
683    /// Distance in pixels from the horizontal origin to the top edge of the bitmap (for horizontal text); or distance in pixels from the vertical origin to the left edge of the bitmap (for vertical text).
684    pub bearing_y: BigEndian<i8>,
685    /// Horizontal or vertical advance width in pixels.
686    pub advance: u8,
687}
688
689impl SmallGlyphMetrics {
690    /// Number of rows of data.
691    pub fn height(&self) -> u8 {
692        self.height
693    }
694
695    /// Number of columns of data.
696    pub fn width(&self) -> u8 {
697        self.width
698    }
699
700    /// Distance in pixels from the horizontal origin to the left edge of the bitmap (for horizontal text); or distance in pixels from the vertical origin to the top edge of the bitmap (for vertical text).
701    pub fn bearing_x(&self) -> i8 {
702        self.bearing_x.get()
703    }
704
705    /// Distance in pixels from the horizontal origin to the top edge of the bitmap (for horizontal text); or distance in pixels from the vertical origin to the left edge of the bitmap (for vertical text).
706    pub fn bearing_y(&self) -> i8 {
707        self.bearing_y.get()
708    }
709
710    /// Horizontal or vertical advance width in pixels.
711    pub fn advance(&self) -> u8 {
712        self.advance
713    }
714}
715
716impl FixedSize for SmallGlyphMetrics {
717    const RAW_BYTE_LEN: usize = u8::RAW_BYTE_LEN
718        + u8::RAW_BYTE_LEN
719        + i8::RAW_BYTE_LEN
720        + i8::RAW_BYTE_LEN
721        + u8::RAW_BYTE_LEN;
722}
723
724#[cfg(feature = "experimental_traverse")]
725impl<'a> SomeRecord<'a> for SmallGlyphMetrics {
726    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
727        RecordResolver {
728            name: "SmallGlyphMetrics",
729            get_field: Box::new(move |idx, _data| match idx {
730                0usize => Some(Field::new("height", self.height())),
731                1usize => Some(Field::new("width", self.width())),
732                2usize => Some(Field::new("bearing_x", self.bearing_x())),
733                3usize => Some(Field::new("bearing_y", self.bearing_y())),
734                4usize => Some(Field::new("advance", self.advance())),
735                _ => None,
736            }),
737            data,
738        }
739    }
740}
741
742impl<'a> MinByteRange<'a> for IndexSubtableList<'a> {
743    fn min_byte_range(&self) -> Range<usize> {
744        0..self.index_subtable_records_byte_range().end
745    }
746    fn min_table_bytes(&self) -> &'a [u8] {
747        let range = self.min_byte_range();
748        self.data.as_bytes().get(range).unwrap_or_default()
749    }
750}
751
752impl ReadArgs for IndexSubtableList<'_> {
753    type Args = u32;
754}
755
756impl<'a> FontRead<'a> for IndexSubtableList<'a> {
757    fn read_with_args(data: FontData<'a>, args: u32) -> Result<Self, ReadError> {
758        let number_of_index_subtables = args;
759
760        #[allow(clippy::absurd_extreme_comparisons)]
761        if data.len() < Self::MIN_SIZE {
762            return Err(ReadError::OutOfBounds);
763        }
764        Ok(Self {
765            data,
766            number_of_index_subtables,
767        })
768    }
769}
770
771impl<'a> IndexSubtableList<'a> {
772    /// A constructor that requires additional arguments.
773    ///
774    /// This type requires some external state in order to be
775    /// parsed.
776    pub fn read(data: FontData<'a>, number_of_index_subtables: u32) -> Result<Self, ReadError> {
777        let args = number_of_index_subtables;
778        Self::read_with_args(data, args)
779    }
780}
781
782/// [IndexSubtableList](https://learn.microsoft.com/en-us/typography/opentype/spec/eblc#indexsubtablelist) table.
783#[derive(Clone)]
784pub struct IndexSubtableList<'a> {
785    data: FontData<'a>,
786    number_of_index_subtables: u32,
787}
788
789#[allow(clippy::needless_lifetimes)]
790impl<'a> IndexSubtableList<'a> {
791    pub const MIN_SIZE: usize = 0;
792    basic_table_impls!(impl_the_methods);
793
794    /// Array of IndexSubtableRecords.
795    pub fn index_subtable_records(&self) -> &'a [IndexSubtableRecord] {
796        let range = self.index_subtable_records_byte_range();
797        self.data.read_array(range).ok().unwrap_or_default()
798    }
799
800    pub(crate) fn number_of_index_subtables(&self) -> u32 {
801        self.number_of_index_subtables
802    }
803
804    pub fn index_subtable_records_byte_range(&self) -> Range<usize> {
805        let number_of_index_subtables = self.number_of_index_subtables();
806        let start = 0;
807        let end = start
808            + (transforms::to_usize(number_of_index_subtables))
809                .saturating_mul(IndexSubtableRecord::RAW_BYTE_LEN);
810        start..end
811    }
812}
813
814#[allow(clippy::absurd_extreme_comparisons)]
815const _: () = assert!(FontData::default_data_long_enough(
816    IndexSubtableList::MIN_SIZE
817));
818
819impl Default for IndexSubtableList<'_> {
820    fn default() -> Self {
821        Self {
822            data: FontData::default_table_data(),
823            number_of_index_subtables: Default::default(),
824        }
825    }
826}
827
828#[cfg(feature = "experimental_traverse")]
829impl<'a> SomeTable<'a> for IndexSubtableList<'a> {
830    fn type_name(&self) -> &str {
831        "IndexSubtableList"
832    }
833    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
834        match idx {
835            0usize => Some(Field::new(
836                "index_subtable_records",
837                traversal::FieldType::array_of_records(
838                    stringify!(IndexSubtableRecord),
839                    self.index_subtable_records(),
840                    self.offset_data(),
841                ),
842            )),
843            _ => None,
844        }
845    }
846}
847
848#[cfg(feature = "experimental_traverse")]
849#[allow(clippy::needless_lifetimes)]
850impl<'a> std::fmt::Debug for IndexSubtableList<'a> {
851    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
852        (self as &dyn SomeTable<'a>).fmt(f)
853    }
854}
855
856#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
857#[repr(C)]
858#[repr(packed)]
859pub struct IndexSubtableRecord {
860    /// First glyph ID of this range.
861    pub first_glyph_index: BigEndian<GlyphId16>,
862    /// Last glyph ID of this range (inclusive).
863    pub last_glyph_index: BigEndian<GlyphId16>,
864    /// Offset to an IndexSubtable from the start of the IndexSubtableList.
865    pub index_subtable_offset: BigEndian<Offset32>,
866}
867
868impl IndexSubtableRecord {
869    /// First glyph ID of this range.
870    pub fn first_glyph_index(&self) -> GlyphId16 {
871        self.first_glyph_index.get()
872    }
873
874    /// Last glyph ID of this range (inclusive).
875    pub fn last_glyph_index(&self) -> GlyphId16 {
876        self.last_glyph_index.get()
877    }
878
879    /// Offset to an IndexSubtable from the start of the IndexSubtableList.
880    pub fn index_subtable_offset(&self) -> Offset32 {
881        self.index_subtable_offset.get()
882    }
883
884    /// Offset to an IndexSubtable from the start of the IndexSubtableList.
885    ///
886    /// The `data` argument should be retrieved from the parent table
887    /// By calling its `offset_data` method.
888    pub fn index_subtable<'a>(&self, data: FontData<'a>) -> Result<IndexSubtable<'a>, ReadError> {
889        let args = (self.last_glyph_index(), self.first_glyph_index());
890        self.index_subtable_offset().resolve_with_args(data, args)
891    }
892}
893
894impl FixedSize for IndexSubtableRecord {
895    const RAW_BYTE_LEN: usize =
896        GlyphId16::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
897}
898
899#[cfg(feature = "experimental_traverse")]
900impl<'a> SomeRecord<'a> for IndexSubtableRecord {
901    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
902        RecordResolver {
903            name: "IndexSubtableRecord",
904            get_field: Box::new(move |idx, _data| match idx {
905                0usize => Some(Field::new("first_glyph_index", self.first_glyph_index())),
906                1usize => Some(Field::new("last_glyph_index", self.last_glyph_index())),
907                2usize => Some(Field::new(
908                    "index_subtable_offset",
909                    FieldType::offset(self.index_subtable_offset(), self.index_subtable(_data)),
910                )),
911                _ => None,
912            }),
913            data,
914        }
915    }
916}
917
918impl Format<u16> for IndexSubtable1<'_> {
919    const FORMAT: u16 = 1;
920}
921
922impl<'a> MinByteRange<'a> for IndexSubtable1<'a> {
923    fn min_byte_range(&self) -> Range<usize> {
924        0..self.sbit_offsets_byte_range().end
925    }
926    fn min_table_bytes(&self) -> &'a [u8] {
927        let range = self.min_byte_range();
928        self.data.as_bytes().get(range).unwrap_or_default()
929    }
930}
931
932impl ReadArgs for IndexSubtable1<'_> {
933    type Args = (GlyphId16, GlyphId16);
934}
935
936impl<'a> FontRead<'a> for IndexSubtable1<'a> {
937    fn read_with_args(data: FontData<'a>, args: (GlyphId16, GlyphId16)) -> Result<Self, ReadError> {
938        let (last_glyph_index, first_glyph_index) = args;
939
940        #[allow(clippy::absurd_extreme_comparisons)]
941        if data.len() < Self::MIN_SIZE {
942            return Err(ReadError::OutOfBounds);
943        }
944        Ok(Self {
945            data,
946            last_glyph_index,
947            first_glyph_index,
948        })
949    }
950}
951
952impl<'a> IndexSubtable1<'a> {
953    /// A constructor that requires additional arguments.
954    ///
955    /// This type requires some external state in order to be
956    /// parsed.
957    pub fn read(
958        data: FontData<'a>,
959        last_glyph_index: GlyphId16,
960        first_glyph_index: GlyphId16,
961    ) -> Result<Self, ReadError> {
962        let args = (last_glyph_index, first_glyph_index);
963        Self::read_with_args(data, args)
964    }
965}
966
967/// [IndexSubTable1](https://learn.microsoft.com/en-us/typography/opentype/spec/eblc#indexsubtable1-variable-metrics-glyphs-with-4-byte-offsets): variable-metrics glyphs with 4-byte offsets.
968#[derive(Clone)]
969pub struct IndexSubtable1<'a> {
970    data: FontData<'a>,
971    last_glyph_index: GlyphId16,
972    first_glyph_index: GlyphId16,
973}
974
975#[allow(clippy::needless_lifetimes)]
976impl<'a> IndexSubtable1<'a> {
977    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
978    basic_table_impls!(impl_the_methods);
979
980    /// Format of this IndexSubTable.
981    pub fn index_format(&self) -> u16 {
982        let range = self.index_format_byte_range();
983        self.data.read_at(range.start).ok().unwrap()
984    }
985
986    /// Format of EBDT image data.
987    pub fn image_format(&self) -> u16 {
988        let range = self.image_format_byte_range();
989        self.data.read_at(range.start).ok().unwrap()
990    }
991
992    /// Offset to image data in EBDT table.
993    pub fn image_data_offset(&self) -> u32 {
994        let range = self.image_data_offset_byte_range();
995        self.data.read_at(range.start).ok().unwrap()
996    }
997
998    pub fn sbit_offsets(&self) -> &'a [BigEndian<u32>] {
999        let range = self.sbit_offsets_byte_range();
1000        self.data.read_array(range).ok().unwrap_or_default()
1001    }
1002
1003    pub(crate) fn last_glyph_index(&self) -> GlyphId16 {
1004        self.last_glyph_index
1005    }
1006
1007    pub(crate) fn first_glyph_index(&self) -> GlyphId16 {
1008        self.first_glyph_index
1009    }
1010
1011    pub fn index_format_byte_range(&self) -> Range<usize> {
1012        let start = 0;
1013        let end = start + u16::RAW_BYTE_LEN;
1014        start..end
1015    }
1016
1017    pub fn image_format_byte_range(&self) -> Range<usize> {
1018        let start = self.index_format_byte_range().end;
1019        let end = start + u16::RAW_BYTE_LEN;
1020        start..end
1021    }
1022
1023    pub fn image_data_offset_byte_range(&self) -> Range<usize> {
1024        let start = self.image_format_byte_range().end;
1025        let end = start + u32::RAW_BYTE_LEN;
1026        start..end
1027    }
1028
1029    pub fn sbit_offsets_byte_range(&self) -> Range<usize> {
1030        let last_glyph_index = self.last_glyph_index();
1031        let first_glyph_index = self.first_glyph_index();
1032        let start = self.image_data_offset_byte_range().end;
1033        let end = start
1034            + (transforms::subtract_add_two(last_glyph_index, first_glyph_index))
1035                .saturating_mul(u32::RAW_BYTE_LEN);
1036        start..end
1037    }
1038}
1039
1040const _: () = assert!(FontData::default_data_long_enough(IndexSubtable1::MIN_SIZE));
1041
1042impl Default for IndexSubtable1<'_> {
1043    fn default() -> Self {
1044        Self {
1045            data: FontData::default_format_1_u16_table_data(),
1046            last_glyph_index: Default::default(),
1047            first_glyph_index: Default::default(),
1048        }
1049    }
1050}
1051
1052#[cfg(feature = "experimental_traverse")]
1053impl<'a> SomeTable<'a> for IndexSubtable1<'a> {
1054    fn type_name(&self) -> &str {
1055        "IndexSubtable1"
1056    }
1057    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1058        match idx {
1059            0usize => Some(Field::new("index_format", self.index_format())),
1060            1usize => Some(Field::new("image_format", self.image_format())),
1061            2usize => Some(Field::new("image_data_offset", self.image_data_offset())),
1062            3usize => Some(Field::new("sbit_offsets", self.sbit_offsets())),
1063            _ => None,
1064        }
1065    }
1066}
1067
1068#[cfg(feature = "experimental_traverse")]
1069#[allow(clippy::needless_lifetimes)]
1070impl<'a> std::fmt::Debug for IndexSubtable1<'a> {
1071    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1072        (self as &dyn SomeTable<'a>).fmt(f)
1073    }
1074}
1075
1076impl Format<u16> for IndexSubtable2<'_> {
1077    const FORMAT: u16 = 2;
1078}
1079
1080impl<'a> MinByteRange<'a> for IndexSubtable2<'a> {
1081    fn min_byte_range(&self) -> Range<usize> {
1082        0..self.big_metrics_byte_range().end
1083    }
1084    fn min_table_bytes(&self) -> &'a [u8] {
1085        let range = self.min_byte_range();
1086        self.data.as_bytes().get(range).unwrap_or_default()
1087    }
1088}
1089
1090impl ReadArgs for IndexSubtable2<'_> {
1091    type Args = ();
1092}
1093
1094impl<'a> FontRead<'a> for IndexSubtable2<'a> {
1095    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1096        #[allow(clippy::absurd_extreme_comparisons)]
1097        if data.len() < Self::MIN_SIZE {
1098            return Err(ReadError::OutOfBounds);
1099        }
1100        Ok(Self { data })
1101    }
1102}
1103
1104/// [IndexSubTable2](https://learn.microsoft.com/en-us/typography/opentype/spec/eblc#indexsubtable2-all-glyphs-have-identical-metrics): all glyphs have identical metrics.
1105#[derive(Clone)]
1106pub struct IndexSubtable2<'a> {
1107    data: FontData<'a>,
1108}
1109
1110#[allow(clippy::needless_lifetimes)]
1111impl<'a> IndexSubtable2<'a> {
1112    pub const MIN_SIZE: usize =
1113        (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
1114    basic_table_impls!(impl_the_methods);
1115
1116    /// Format of this IndexSubTable.
1117    pub fn index_format(&self) -> u16 {
1118        let range = self.index_format_byte_range();
1119        self.data.read_at(range.start).ok().unwrap()
1120    }
1121
1122    /// Format of EBDT image data.
1123    pub fn image_format(&self) -> u16 {
1124        let range = self.image_format_byte_range();
1125        self.data.read_at(range.start).ok().unwrap()
1126    }
1127
1128    /// Offset to image data in EBDT table.
1129    pub fn image_data_offset(&self) -> u32 {
1130        let range = self.image_data_offset_byte_range();
1131        self.data.read_at(range.start).ok().unwrap()
1132    }
1133
1134    /// All the glyphs are of the same size.
1135    pub fn image_size(&self) -> u32 {
1136        let range = self.image_size_byte_range();
1137        self.data.read_at(range.start).ok().unwrap()
1138    }
1139
1140    /// All glyphs have the same metrics; glyph data may be compressed, byte-aligned, or bit-aligned.
1141    pub fn big_metrics(&self) -> &'a [BigGlyphMetrics] {
1142        let range = self.big_metrics_byte_range();
1143        self.data.read_array(range).ok().unwrap_or_default()
1144    }
1145
1146    pub fn index_format_byte_range(&self) -> Range<usize> {
1147        let start = 0;
1148        let end = start + u16::RAW_BYTE_LEN;
1149        start..end
1150    }
1151
1152    pub fn image_format_byte_range(&self) -> Range<usize> {
1153        let start = self.index_format_byte_range().end;
1154        let end = start + u16::RAW_BYTE_LEN;
1155        start..end
1156    }
1157
1158    pub fn image_data_offset_byte_range(&self) -> Range<usize> {
1159        let start = self.image_format_byte_range().end;
1160        let end = start + u32::RAW_BYTE_LEN;
1161        start..end
1162    }
1163
1164    pub fn image_size_byte_range(&self) -> Range<usize> {
1165        let start = self.image_data_offset_byte_range().end;
1166        let end = start + u32::RAW_BYTE_LEN;
1167        start..end
1168    }
1169
1170    pub fn big_metrics_byte_range(&self) -> Range<usize> {
1171        let start = self.image_size_byte_range().end;
1172        let end = start + BigGlyphMetrics::RAW_BYTE_LEN;
1173        start..end
1174    }
1175}
1176
1177#[cfg(feature = "experimental_traverse")]
1178impl<'a> SomeTable<'a> for IndexSubtable2<'a> {
1179    fn type_name(&self) -> &str {
1180        "IndexSubtable2"
1181    }
1182    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1183        match idx {
1184            0usize => Some(Field::new("index_format", self.index_format())),
1185            1usize => Some(Field::new("image_format", self.image_format())),
1186            2usize => Some(Field::new("image_data_offset", self.image_data_offset())),
1187            3usize => Some(Field::new("image_size", self.image_size())),
1188            4usize => Some(Field::new(
1189                "big_metrics",
1190                traversal::FieldType::array_of_records(
1191                    stringify!(BigGlyphMetrics),
1192                    self.big_metrics(),
1193                    self.offset_data(),
1194                ),
1195            )),
1196            _ => None,
1197        }
1198    }
1199}
1200
1201#[cfg(feature = "experimental_traverse")]
1202#[allow(clippy::needless_lifetimes)]
1203impl<'a> std::fmt::Debug for IndexSubtable2<'a> {
1204    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1205        (self as &dyn SomeTable<'a>).fmt(f)
1206    }
1207}
1208
1209impl Format<u16> for IndexSubtable3<'_> {
1210    const FORMAT: u16 = 3;
1211}
1212
1213impl<'a> MinByteRange<'a> for IndexSubtable3<'a> {
1214    fn min_byte_range(&self) -> Range<usize> {
1215        0..self.sbit_offsets_byte_range().end
1216    }
1217    fn min_table_bytes(&self) -> &'a [u8] {
1218        let range = self.min_byte_range();
1219        self.data.as_bytes().get(range).unwrap_or_default()
1220    }
1221}
1222
1223impl ReadArgs for IndexSubtable3<'_> {
1224    type Args = (GlyphId16, GlyphId16);
1225}
1226
1227impl<'a> FontRead<'a> for IndexSubtable3<'a> {
1228    fn read_with_args(data: FontData<'a>, args: (GlyphId16, GlyphId16)) -> Result<Self, ReadError> {
1229        let (last_glyph_index, first_glyph_index) = args;
1230
1231        #[allow(clippy::absurd_extreme_comparisons)]
1232        if data.len() < Self::MIN_SIZE {
1233            return Err(ReadError::OutOfBounds);
1234        }
1235        Ok(Self {
1236            data,
1237            last_glyph_index,
1238            first_glyph_index,
1239        })
1240    }
1241}
1242
1243impl<'a> IndexSubtable3<'a> {
1244    /// A constructor that requires additional arguments.
1245    ///
1246    /// This type requires some external state in order to be
1247    /// parsed.
1248    pub fn read(
1249        data: FontData<'a>,
1250        last_glyph_index: GlyphId16,
1251        first_glyph_index: GlyphId16,
1252    ) -> Result<Self, ReadError> {
1253        let args = (last_glyph_index, first_glyph_index);
1254        Self::read_with_args(data, args)
1255    }
1256}
1257
1258/// [IndexSubTable3](https://learn.microsoft.com/en-us/typography/opentype/spec/eblc#indexsubtable3-variable-metrics-glyphs-with-2-byte-offsets): variable-metrics glyphs with 2-byte offsets.
1259#[derive(Clone)]
1260pub struct IndexSubtable3<'a> {
1261    data: FontData<'a>,
1262    last_glyph_index: GlyphId16,
1263    first_glyph_index: GlyphId16,
1264}
1265
1266#[allow(clippy::needless_lifetimes)]
1267impl<'a> IndexSubtable3<'a> {
1268    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
1269    basic_table_impls!(impl_the_methods);
1270
1271    /// Format of this IndexSubTable.
1272    pub fn index_format(&self) -> u16 {
1273        let range = self.index_format_byte_range();
1274        self.data.read_at(range.start).ok().unwrap()
1275    }
1276
1277    /// Format of EBDT image data.
1278    pub fn image_format(&self) -> u16 {
1279        let range = self.image_format_byte_range();
1280        self.data.read_at(range.start).ok().unwrap()
1281    }
1282
1283    /// Offset to image data in EBDT table.
1284    pub fn image_data_offset(&self) -> u32 {
1285        let range = self.image_data_offset_byte_range();
1286        self.data.read_at(range.start).ok().unwrap()
1287    }
1288
1289    pub fn sbit_offsets(&self) -> &'a [BigEndian<u16>] {
1290        let range = self.sbit_offsets_byte_range();
1291        self.data.read_array(range).ok().unwrap_or_default()
1292    }
1293
1294    pub(crate) fn last_glyph_index(&self) -> GlyphId16 {
1295        self.last_glyph_index
1296    }
1297
1298    pub(crate) fn first_glyph_index(&self) -> GlyphId16 {
1299        self.first_glyph_index
1300    }
1301
1302    pub fn index_format_byte_range(&self) -> Range<usize> {
1303        let start = 0;
1304        let end = start + u16::RAW_BYTE_LEN;
1305        start..end
1306    }
1307
1308    pub fn image_format_byte_range(&self) -> Range<usize> {
1309        let start = self.index_format_byte_range().end;
1310        let end = start + u16::RAW_BYTE_LEN;
1311        start..end
1312    }
1313
1314    pub fn image_data_offset_byte_range(&self) -> Range<usize> {
1315        let start = self.image_format_byte_range().end;
1316        let end = start + u32::RAW_BYTE_LEN;
1317        start..end
1318    }
1319
1320    pub fn sbit_offsets_byte_range(&self) -> Range<usize> {
1321        let last_glyph_index = self.last_glyph_index();
1322        let first_glyph_index = self.first_glyph_index();
1323        let start = self.image_data_offset_byte_range().end;
1324        let end = start
1325            + (transforms::subtract_add_two(last_glyph_index, first_glyph_index))
1326                .saturating_mul(u16::RAW_BYTE_LEN);
1327        start..end
1328    }
1329}
1330
1331#[cfg(feature = "experimental_traverse")]
1332impl<'a> SomeTable<'a> for IndexSubtable3<'a> {
1333    fn type_name(&self) -> &str {
1334        "IndexSubtable3"
1335    }
1336    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1337        match idx {
1338            0usize => Some(Field::new("index_format", self.index_format())),
1339            1usize => Some(Field::new("image_format", self.image_format())),
1340            2usize => Some(Field::new("image_data_offset", self.image_data_offset())),
1341            3usize => Some(Field::new("sbit_offsets", self.sbit_offsets())),
1342            _ => None,
1343        }
1344    }
1345}
1346
1347#[cfg(feature = "experimental_traverse")]
1348#[allow(clippy::needless_lifetimes)]
1349impl<'a> std::fmt::Debug for IndexSubtable3<'a> {
1350    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1351        (self as &dyn SomeTable<'a>).fmt(f)
1352    }
1353}
1354
1355impl Format<u16> for IndexSubtable4<'_> {
1356    const FORMAT: u16 = 4;
1357}
1358
1359impl<'a> MinByteRange<'a> for IndexSubtable4<'a> {
1360    fn min_byte_range(&self) -> Range<usize> {
1361        0..self.glyph_array_byte_range().end
1362    }
1363    fn min_table_bytes(&self) -> &'a [u8] {
1364        let range = self.min_byte_range();
1365        self.data.as_bytes().get(range).unwrap_or_default()
1366    }
1367}
1368
1369impl ReadArgs for IndexSubtable4<'_> {
1370    type Args = ();
1371}
1372
1373impl<'a> FontRead<'a> for IndexSubtable4<'a> {
1374    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1375        #[allow(clippy::absurd_extreme_comparisons)]
1376        if data.len() < Self::MIN_SIZE {
1377            return Err(ReadError::OutOfBounds);
1378        }
1379        Ok(Self { data })
1380    }
1381}
1382
1383/// [IndexSubTable4](https://learn.microsoft.com/en-us/typography/opentype/spec/eblc#indexsubtable3-variable-metrics-glyphs-with-2-byte-offsets): variable-metrics glyphs with sparse glyph codes.
1384#[derive(Clone)]
1385pub struct IndexSubtable4<'a> {
1386    data: FontData<'a>,
1387}
1388
1389#[allow(clippy::needless_lifetimes)]
1390impl<'a> IndexSubtable4<'a> {
1391    pub const MIN_SIZE: usize =
1392        (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
1393    basic_table_impls!(impl_the_methods);
1394
1395    /// Format of this IndexSubTable.
1396    pub fn index_format(&self) -> u16 {
1397        let range = self.index_format_byte_range();
1398        self.data.read_at(range.start).ok().unwrap()
1399    }
1400
1401    /// Format of EBDT image data.
1402    pub fn image_format(&self) -> u16 {
1403        let range = self.image_format_byte_range();
1404        self.data.read_at(range.start).ok().unwrap()
1405    }
1406
1407    /// Offset to image data in EBDT table.
1408    pub fn image_data_offset(&self) -> u32 {
1409        let range = self.image_data_offset_byte_range();
1410        self.data.read_at(range.start).ok().unwrap()
1411    }
1412
1413    /// Array length.
1414    pub fn num_glyphs(&self) -> u32 {
1415        let range = self.num_glyphs_byte_range();
1416        self.data.read_at(range.start).ok().unwrap()
1417    }
1418
1419    /// One per glyph.
1420    pub fn glyph_array(&self) -> &'a [GlyphIdOffsetPair] {
1421        let range = self.glyph_array_byte_range();
1422        self.data.read_array(range).ok().unwrap_or_default()
1423    }
1424
1425    pub fn index_format_byte_range(&self) -> Range<usize> {
1426        let start = 0;
1427        let end = start + u16::RAW_BYTE_LEN;
1428        start..end
1429    }
1430
1431    pub fn image_format_byte_range(&self) -> Range<usize> {
1432        let start = self.index_format_byte_range().end;
1433        let end = start + u16::RAW_BYTE_LEN;
1434        start..end
1435    }
1436
1437    pub fn image_data_offset_byte_range(&self) -> Range<usize> {
1438        let start = self.image_format_byte_range().end;
1439        let end = start + u32::RAW_BYTE_LEN;
1440        start..end
1441    }
1442
1443    pub fn num_glyphs_byte_range(&self) -> Range<usize> {
1444        let start = self.image_data_offset_byte_range().end;
1445        let end = start + u32::RAW_BYTE_LEN;
1446        start..end
1447    }
1448
1449    pub fn glyph_array_byte_range(&self) -> Range<usize> {
1450        let num_glyphs = self.num_glyphs();
1451        let start = self.num_glyphs_byte_range().end;
1452        let end = start
1453            + (transforms::add(num_glyphs, 1_usize))
1454                .saturating_mul(GlyphIdOffsetPair::RAW_BYTE_LEN);
1455        start..end
1456    }
1457}
1458
1459#[cfg(feature = "experimental_traverse")]
1460impl<'a> SomeTable<'a> for IndexSubtable4<'a> {
1461    fn type_name(&self) -> &str {
1462        "IndexSubtable4"
1463    }
1464    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1465        match idx {
1466            0usize => Some(Field::new("index_format", self.index_format())),
1467            1usize => Some(Field::new("image_format", self.image_format())),
1468            2usize => Some(Field::new("image_data_offset", self.image_data_offset())),
1469            3usize => Some(Field::new("num_glyphs", self.num_glyphs())),
1470            4usize => Some(Field::new(
1471                "glyph_array",
1472                traversal::FieldType::array_of_records(
1473                    stringify!(GlyphIdOffsetPair),
1474                    self.glyph_array(),
1475                    self.offset_data(),
1476                ),
1477            )),
1478            _ => None,
1479        }
1480    }
1481}
1482
1483#[cfg(feature = "experimental_traverse")]
1484#[allow(clippy::needless_lifetimes)]
1485impl<'a> std::fmt::Debug for IndexSubtable4<'a> {
1486    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1487        (self as &dyn SomeTable<'a>).fmt(f)
1488    }
1489}
1490
1491/// [GlyphIdOffsetPair](https://learn.microsoft.com/en-us/typography/opentype/spec/eblc#glyphidoffsetpair-record) record.
1492#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1493#[repr(C)]
1494#[repr(packed)]
1495pub struct GlyphIdOffsetPair {
1496    /// Glyph ID of glyph present.
1497    pub glyph_id: BigEndian<GlyphId16>,
1498    /// Location in EBDT.
1499    pub sbit_offset: BigEndian<u16>,
1500}
1501
1502impl GlyphIdOffsetPair {
1503    /// Glyph ID of glyph present.
1504    pub fn glyph_id(&self) -> GlyphId16 {
1505        self.glyph_id.get()
1506    }
1507
1508    /// Location in EBDT.
1509    pub fn sbit_offset(&self) -> u16 {
1510        self.sbit_offset.get()
1511    }
1512}
1513
1514impl FixedSize for GlyphIdOffsetPair {
1515    const RAW_BYTE_LEN: usize = GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
1516}
1517
1518#[cfg(feature = "experimental_traverse")]
1519impl<'a> SomeRecord<'a> for GlyphIdOffsetPair {
1520    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1521        RecordResolver {
1522            name: "GlyphIdOffsetPair",
1523            get_field: Box::new(move |idx, _data| match idx {
1524                0usize => Some(Field::new("glyph_id", self.glyph_id())),
1525                1usize => Some(Field::new("sbit_offset", self.sbit_offset())),
1526                _ => None,
1527            }),
1528            data,
1529        }
1530    }
1531}
1532
1533impl Format<u16> for IndexSubtable5<'_> {
1534    const FORMAT: u16 = 5;
1535}
1536
1537impl<'a> MinByteRange<'a> for IndexSubtable5<'a> {
1538    fn min_byte_range(&self) -> Range<usize> {
1539        0..self.glyph_array_byte_range().end
1540    }
1541    fn min_table_bytes(&self) -> &'a [u8] {
1542        let range = self.min_byte_range();
1543        self.data.as_bytes().get(range).unwrap_or_default()
1544    }
1545}
1546
1547impl ReadArgs for IndexSubtable5<'_> {
1548    type Args = ();
1549}
1550
1551impl<'a> FontRead<'a> for IndexSubtable5<'a> {
1552    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1553        #[allow(clippy::absurd_extreme_comparisons)]
1554        if data.len() < Self::MIN_SIZE {
1555            return Err(ReadError::OutOfBounds);
1556        }
1557        Ok(Self { data })
1558    }
1559}
1560
1561/// [IndexSubTable5](https://learn.microsoft.com/en-us/typography/opentype/spec/eblc#indexsubtable5-constant-metrics-glyphs-with-sparse-glyph-codes): constant-metrics glyphs with sparse glyph codes
1562#[derive(Clone)]
1563pub struct IndexSubtable5<'a> {
1564    data: FontData<'a>,
1565}
1566
1567#[allow(clippy::needless_lifetimes)]
1568impl<'a> IndexSubtable5<'a> {
1569    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1570        + u16::RAW_BYTE_LEN
1571        + u32::RAW_BYTE_LEN
1572        + u32::RAW_BYTE_LEN
1573        + u32::RAW_BYTE_LEN);
1574    basic_table_impls!(impl_the_methods);
1575
1576    /// Format of this IndexSubTable.
1577    pub fn index_format(&self) -> u16 {
1578        let range = self.index_format_byte_range();
1579        self.data.read_at(range.start).ok().unwrap()
1580    }
1581
1582    /// Format of EBDT image data.
1583    pub fn image_format(&self) -> u16 {
1584        let range = self.image_format_byte_range();
1585        self.data.read_at(range.start).ok().unwrap()
1586    }
1587
1588    /// Offset to image data in EBDT table.
1589    pub fn image_data_offset(&self) -> u32 {
1590        let range = self.image_data_offset_byte_range();
1591        self.data.read_at(range.start).ok().unwrap()
1592    }
1593
1594    /// All glyphs have the same data size.
1595    pub fn image_size(&self) -> u32 {
1596        let range = self.image_size_byte_range();
1597        self.data.read_at(range.start).ok().unwrap()
1598    }
1599
1600    /// All glyphs have the same metrics.
1601    pub fn big_metrics(&self) -> &'a [BigGlyphMetrics] {
1602        let range = self.big_metrics_byte_range();
1603        self.data.read_array(range).ok().unwrap_or_default()
1604    }
1605
1606    /// Array length.
1607    pub fn num_glyphs(&self) -> u32 {
1608        let range = self.num_glyphs_byte_range();
1609        self.data.read_at(range.start).ok().unwrap_or_default()
1610    }
1611
1612    /// One per glyph, sorted by glyhph ID.
1613    pub fn glyph_array(&self) -> &'a [BigEndian<GlyphId16>] {
1614        let range = self.glyph_array_byte_range();
1615        self.data.read_array(range).ok().unwrap_or_default()
1616    }
1617
1618    pub fn index_format_byte_range(&self) -> Range<usize> {
1619        let start = 0;
1620        let end = start + u16::RAW_BYTE_LEN;
1621        start..end
1622    }
1623
1624    pub fn image_format_byte_range(&self) -> Range<usize> {
1625        let start = self.index_format_byte_range().end;
1626        let end = start + u16::RAW_BYTE_LEN;
1627        start..end
1628    }
1629
1630    pub fn image_data_offset_byte_range(&self) -> Range<usize> {
1631        let start = self.image_format_byte_range().end;
1632        let end = start + u32::RAW_BYTE_LEN;
1633        start..end
1634    }
1635
1636    pub fn image_size_byte_range(&self) -> Range<usize> {
1637        let start = self.image_data_offset_byte_range().end;
1638        let end = start + u32::RAW_BYTE_LEN;
1639        start..end
1640    }
1641
1642    pub fn big_metrics_byte_range(&self) -> Range<usize> {
1643        let start = self.image_size_byte_range().end;
1644        let end = start + BigGlyphMetrics::RAW_BYTE_LEN;
1645        start..end
1646    }
1647
1648    pub fn num_glyphs_byte_range(&self) -> Range<usize> {
1649        let start = self.big_metrics_byte_range().end;
1650        let end = start + u32::RAW_BYTE_LEN;
1651        start..end
1652    }
1653
1654    pub fn glyph_array_byte_range(&self) -> Range<usize> {
1655        let num_glyphs = self.num_glyphs();
1656        let start = self.num_glyphs_byte_range().end;
1657        let end =
1658            start + (transforms::to_usize(num_glyphs)).saturating_mul(GlyphId16::RAW_BYTE_LEN);
1659        start..end
1660    }
1661}
1662
1663#[cfg(feature = "experimental_traverse")]
1664impl<'a> SomeTable<'a> for IndexSubtable5<'a> {
1665    fn type_name(&self) -> &str {
1666        "IndexSubtable5"
1667    }
1668    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1669        match idx {
1670            0usize => Some(Field::new("index_format", self.index_format())),
1671            1usize => Some(Field::new("image_format", self.image_format())),
1672            2usize => Some(Field::new("image_data_offset", self.image_data_offset())),
1673            3usize => Some(Field::new("image_size", self.image_size())),
1674            4usize => Some(Field::new(
1675                "big_metrics",
1676                traversal::FieldType::array_of_records(
1677                    stringify!(BigGlyphMetrics),
1678                    self.big_metrics(),
1679                    self.offset_data(),
1680                ),
1681            )),
1682            5usize => Some(Field::new("num_glyphs", self.num_glyphs())),
1683            6usize => Some(Field::new("glyph_array", self.glyph_array())),
1684            _ => None,
1685        }
1686    }
1687}
1688
1689#[cfg(feature = "experimental_traverse")]
1690#[allow(clippy::needless_lifetimes)]
1691impl<'a> std::fmt::Debug for IndexSubtable5<'a> {
1692    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1693        (self as &dyn SomeTable<'a>).fmt(f)
1694    }
1695}
1696
1697/// [EbdtComponent](https://learn.microsoft.com/en-us/typography/opentype/spec/ebdt#ebdtcomponent-record) record.
1698#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1699#[repr(C)]
1700#[repr(packed)]
1701pub struct BdtComponent {
1702    /// Component glyph ID.
1703    pub glyph_id: BigEndian<GlyphId16>,
1704    /// Position of component left.
1705    pub x_offset: BigEndian<i8>,
1706    /// Position of component top.
1707    pub y_offset: BigEndian<i8>,
1708}
1709
1710impl BdtComponent {
1711    /// Component glyph ID.
1712    pub fn glyph_id(&self) -> GlyphId16 {
1713        self.glyph_id.get()
1714    }
1715
1716    /// Position of component left.
1717    pub fn x_offset(&self) -> i8 {
1718        self.x_offset.get()
1719    }
1720
1721    /// Position of component top.
1722    pub fn y_offset(&self) -> i8 {
1723        self.y_offset.get()
1724    }
1725}
1726
1727impl FixedSize for BdtComponent {
1728    const RAW_BYTE_LEN: usize = GlyphId16::RAW_BYTE_LEN + i8::RAW_BYTE_LEN + i8::RAW_BYTE_LEN;
1729}
1730
1731#[cfg(feature = "experimental_traverse")]
1732impl<'a> SomeRecord<'a> for BdtComponent {
1733    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1734        RecordResolver {
1735            name: "BdtComponent",
1736            get_field: Box::new(move |idx, _data| match idx {
1737                0usize => Some(Field::new("glyph_id", self.glyph_id())),
1738                1usize => Some(Field::new("x_offset", self.x_offset())),
1739                2usize => Some(Field::new("y_offset", self.y_offset())),
1740                _ => None,
1741            }),
1742            data,
1743        }
1744    }
1745}