Skip to main content

read_fonts/generated/
generated_colr.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 Colr<'a> {
9    fn min_byte_range(&self) -> Range<usize> {
10        0..self.num_layer_records_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 Colr<'_> {
19    /// `COLR`
20    const TAG: Tag = Tag::new(b"COLR");
21}
22
23impl<'a> FontRead<'a> for Colr<'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/// [COLR (Color)](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#colr-header) table
34#[derive(Clone)]
35pub struct Colr<'a> {
36    data: FontData<'a>,
37}
38
39#[allow(clippy::needless_lifetimes)]
40impl<'a> Colr<'a> {
41    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
42        + u16::RAW_BYTE_LEN
43        + Offset32::RAW_BYTE_LEN
44        + Offset32::RAW_BYTE_LEN
45        + u16::RAW_BYTE_LEN);
46    basic_table_impls!(impl_the_methods);
47
48    /// Table version number - set to 0 or 1.
49    pub fn version(&self) -> u16 {
50        let range = self.version_byte_range();
51        self.data.read_at(range.start).ok().unwrap()
52    }
53
54    /// Number of BaseGlyph records; may be 0 in a version 1 table.
55    pub fn num_base_glyph_records(&self) -> u16 {
56        let range = self.num_base_glyph_records_byte_range();
57        self.data.read_at(range.start).ok().unwrap()
58    }
59
60    /// Offset to baseGlyphRecords array (may be NULL).
61    pub fn base_glyph_records_offset(&self) -> Nullable<Offset32> {
62        let range = self.base_glyph_records_offset_byte_range();
63        self.data.read_at(range.start).ok().unwrap()
64    }
65
66    /// Attempt to resolve [`base_glyph_records_offset`][Self::base_glyph_records_offset].
67    pub fn base_glyph_records(&self) -> Option<Result<&'a [BaseGlyph], ReadError>> {
68        let data = self.data;
69        let args = self.num_base_glyph_records();
70        self.base_glyph_records_offset()
71            .resolve_with_args(data, &args)
72    }
73
74    /// Offset to layerRecords array (may be NULL).
75    pub fn layer_records_offset(&self) -> Nullable<Offset32> {
76        let range = self.layer_records_offset_byte_range();
77        self.data.read_at(range.start).ok().unwrap()
78    }
79
80    /// Attempt to resolve [`layer_records_offset`][Self::layer_records_offset].
81    pub fn layer_records(&self) -> Option<Result<&'a [Layer], ReadError>> {
82        let data = self.data;
83        let args = self.num_layer_records();
84        self.layer_records_offset().resolve_with_args(data, &args)
85    }
86
87    /// Number of Layer records; may be 0 in a version 1 table.
88    pub fn num_layer_records(&self) -> u16 {
89        let range = self.num_layer_records_byte_range();
90        self.data.read_at(range.start).ok().unwrap()
91    }
92
93    /// Offset to BaseGlyphList table.
94    pub fn base_glyph_list_offset(&self) -> Option<Nullable<Offset32>> {
95        let range = self.base_glyph_list_offset_byte_range();
96        (!range.is_empty())
97            .then(|| self.data.read_at(range.start).ok())
98            .flatten()
99    }
100
101    /// Attempt to resolve [`base_glyph_list_offset`][Self::base_glyph_list_offset].
102    pub fn base_glyph_list(&self) -> Option<Result<BaseGlyphList<'a>, ReadError>> {
103        let data = self.data;
104        self.base_glyph_list_offset().map(|x| x.resolve(data))?
105    }
106
107    /// Offset to LayerList table (may be NULL).
108    pub fn layer_list_offset(&self) -> Option<Nullable<Offset32>> {
109        let range = self.layer_list_offset_byte_range();
110        (!range.is_empty())
111            .then(|| self.data.read_at(range.start).ok())
112            .flatten()
113    }
114
115    /// Attempt to resolve [`layer_list_offset`][Self::layer_list_offset].
116    pub fn layer_list(&self) -> Option<Result<LayerList<'a>, ReadError>> {
117        let data = self.data;
118        self.layer_list_offset().map(|x| x.resolve(data))?
119    }
120
121    /// Offset to ClipList table (may be NULL).
122    pub fn clip_list_offset(&self) -> Option<Nullable<Offset32>> {
123        let range = self.clip_list_offset_byte_range();
124        (!range.is_empty())
125            .then(|| self.data.read_at(range.start).ok())
126            .flatten()
127    }
128
129    /// Attempt to resolve [`clip_list_offset`][Self::clip_list_offset].
130    pub fn clip_list(&self) -> Option<Result<ClipList<'a>, ReadError>> {
131        let data = self.data;
132        self.clip_list_offset().map(|x| x.resolve(data))?
133    }
134
135    /// Offset to DeltaSetIndexMap table (may be NULL).
136    pub fn var_index_map_offset(&self) -> Option<Nullable<Offset32>> {
137        let range = self.var_index_map_offset_byte_range();
138        (!range.is_empty())
139            .then(|| self.data.read_at(range.start).ok())
140            .flatten()
141    }
142
143    /// Attempt to resolve [`var_index_map_offset`][Self::var_index_map_offset].
144    pub fn var_index_map(&self) -> Option<Result<DeltaSetIndexMap<'a>, ReadError>> {
145        let data = self.data;
146        self.var_index_map_offset().map(|x| x.resolve(data))?
147    }
148
149    /// Offset to ItemVariationStore (may be NULL).
150    pub fn item_variation_store_offset(&self) -> Option<Nullable<Offset32>> {
151        let range = self.item_variation_store_offset_byte_range();
152        (!range.is_empty())
153            .then(|| self.data.read_at(range.start).ok())
154            .flatten()
155    }
156
157    /// Attempt to resolve [`item_variation_store_offset`][Self::item_variation_store_offset].
158    pub fn item_variation_store(&self) -> Option<Result<ItemVariationStore<'a>, ReadError>> {
159        let data = self.data;
160        self.item_variation_store_offset()
161            .map(|x| x.resolve(data))?
162    }
163
164    pub fn version_byte_range(&self) -> Range<usize> {
165        let start = 0;
166        start..start + u16::RAW_BYTE_LEN
167    }
168
169    pub fn num_base_glyph_records_byte_range(&self) -> Range<usize> {
170        let start = self.version_byte_range().end;
171        start..start + u16::RAW_BYTE_LEN
172    }
173
174    pub fn base_glyph_records_offset_byte_range(&self) -> Range<usize> {
175        let start = self.num_base_glyph_records_byte_range().end;
176        start..start + Offset32::RAW_BYTE_LEN
177    }
178
179    pub fn layer_records_offset_byte_range(&self) -> Range<usize> {
180        let start = self.base_glyph_records_offset_byte_range().end;
181        start..start + Offset32::RAW_BYTE_LEN
182    }
183
184    pub fn num_layer_records_byte_range(&self) -> Range<usize> {
185        let start = self.layer_records_offset_byte_range().end;
186        start..start + u16::RAW_BYTE_LEN
187    }
188
189    pub fn base_glyph_list_offset_byte_range(&self) -> Range<usize> {
190        let start = self.num_layer_records_byte_range().end;
191        start
192            ..(self.version().compatible(1u16))
193                .then(|| start + Offset32::RAW_BYTE_LEN)
194                .unwrap_or(start)
195    }
196
197    pub fn layer_list_offset_byte_range(&self) -> Range<usize> {
198        let start = self.base_glyph_list_offset_byte_range().end;
199        start
200            ..(self.version().compatible(1u16))
201                .then(|| start + Offset32::RAW_BYTE_LEN)
202                .unwrap_or(start)
203    }
204
205    pub fn clip_list_offset_byte_range(&self) -> Range<usize> {
206        let start = self.layer_list_offset_byte_range().end;
207        start
208            ..(self.version().compatible(1u16))
209                .then(|| start + Offset32::RAW_BYTE_LEN)
210                .unwrap_or(start)
211    }
212
213    pub fn var_index_map_offset_byte_range(&self) -> Range<usize> {
214        let start = self.clip_list_offset_byte_range().end;
215        start
216            ..(self.version().compatible(1u16))
217                .then(|| start + Offset32::RAW_BYTE_LEN)
218                .unwrap_or(start)
219    }
220
221    pub fn item_variation_store_offset_byte_range(&self) -> Range<usize> {
222        let start = self.var_index_map_offset_byte_range().end;
223        start
224            ..(self.version().compatible(1u16))
225                .then(|| start + Offset32::RAW_BYTE_LEN)
226                .unwrap_or(start)
227    }
228}
229
230#[cfg(feature = "experimental_traverse")]
231impl<'a> SomeTable<'a> for Colr<'a> {
232    fn type_name(&self) -> &str {
233        "Colr"
234    }
235    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
236        match idx {
237            0usize => Some(Field::new("version", self.version())),
238            1usize => Some(Field::new(
239                "num_base_glyph_records",
240                self.num_base_glyph_records(),
241            )),
242            2usize => Some(Field::new(
243                "base_glyph_records_offset",
244                traversal::FieldType::offset_to_array_of_records(
245                    self.base_glyph_records_offset(),
246                    self.base_glyph_records(),
247                    stringify!(BaseGlyph),
248                    self.offset_data(),
249                ),
250            )),
251            3usize => Some(Field::new(
252                "layer_records_offset",
253                traversal::FieldType::offset_to_array_of_records(
254                    self.layer_records_offset(),
255                    self.layer_records(),
256                    stringify!(Layer),
257                    self.offset_data(),
258                ),
259            )),
260            4usize => Some(Field::new("num_layer_records", self.num_layer_records())),
261            5usize if self.version().compatible(1u16) => Some(Field::new(
262                "base_glyph_list_offset",
263                FieldType::offset(
264                    self.base_glyph_list_offset().unwrap(),
265                    self.base_glyph_list(),
266                ),
267            )),
268            6usize if self.version().compatible(1u16) => Some(Field::new(
269                "layer_list_offset",
270                FieldType::offset(self.layer_list_offset().unwrap(), self.layer_list()),
271            )),
272            7usize if self.version().compatible(1u16) => Some(Field::new(
273                "clip_list_offset",
274                FieldType::offset(self.clip_list_offset().unwrap(), self.clip_list()),
275            )),
276            8usize if self.version().compatible(1u16) => Some(Field::new(
277                "var_index_map_offset",
278                FieldType::offset(self.var_index_map_offset().unwrap(), self.var_index_map()),
279            )),
280            9usize if self.version().compatible(1u16) => Some(Field::new(
281                "item_variation_store_offset",
282                FieldType::offset(
283                    self.item_variation_store_offset().unwrap(),
284                    self.item_variation_store(),
285                ),
286            )),
287            _ => None,
288        }
289    }
290}
291
292#[cfg(feature = "experimental_traverse")]
293#[allow(clippy::needless_lifetimes)]
294impl<'a> std::fmt::Debug for Colr<'a> {
295    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
296        (self as &dyn SomeTable<'a>).fmt(f)
297    }
298}
299
300/// [BaseGlyph](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#baseglyph-and-layer-records) record
301#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
302#[repr(C)]
303#[repr(packed)]
304pub struct BaseGlyph {
305    /// Glyph ID of the base glyph.
306    pub glyph_id: BigEndian<GlyphId16>,
307    /// Index (base 0) into the layerRecords array.
308    pub first_layer_index: BigEndian<u16>,
309    /// Number of color layers associated with this glyph.
310    pub num_layers: BigEndian<u16>,
311}
312
313impl BaseGlyph {
314    /// Glyph ID of the base glyph.
315    pub fn glyph_id(&self) -> GlyphId16 {
316        self.glyph_id.get()
317    }
318
319    /// Index (base 0) into the layerRecords array.
320    pub fn first_layer_index(&self) -> u16 {
321        self.first_layer_index.get()
322    }
323
324    /// Number of color layers associated with this glyph.
325    pub fn num_layers(&self) -> u16 {
326        self.num_layers.get()
327    }
328}
329
330impl FixedSize for BaseGlyph {
331    const RAW_BYTE_LEN: usize = GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
332}
333
334#[cfg(feature = "experimental_traverse")]
335impl<'a> SomeRecord<'a> for BaseGlyph {
336    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
337        RecordResolver {
338            name: "BaseGlyph",
339            get_field: Box::new(move |idx, _data| match idx {
340                0usize => Some(Field::new("glyph_id", self.glyph_id())),
341                1usize => Some(Field::new("first_layer_index", self.first_layer_index())),
342                2usize => Some(Field::new("num_layers", self.num_layers())),
343                _ => None,
344            }),
345            data,
346        }
347    }
348}
349
350/// [Layer](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#baseglyph-and-layer-records) record
351#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
352#[repr(C)]
353#[repr(packed)]
354pub struct Layer {
355    /// Glyph ID of the glyph used for a given layer.
356    pub glyph_id: BigEndian<GlyphId16>,
357    /// Index (base 0) for a palette entry in the CPAL table.
358    pub palette_index: BigEndian<u16>,
359}
360
361impl Layer {
362    /// Glyph ID of the glyph used for a given layer.
363    pub fn glyph_id(&self) -> GlyphId16 {
364        self.glyph_id.get()
365    }
366
367    /// Index (base 0) for a palette entry in the CPAL table.
368    pub fn palette_index(&self) -> u16 {
369        self.palette_index.get()
370    }
371}
372
373impl FixedSize for Layer {
374    const RAW_BYTE_LEN: usize = GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
375}
376
377#[cfg(feature = "experimental_traverse")]
378impl<'a> SomeRecord<'a> for Layer {
379    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
380        RecordResolver {
381            name: "Layer",
382            get_field: Box::new(move |idx, _data| match idx {
383                0usize => Some(Field::new("glyph_id", self.glyph_id())),
384                1usize => Some(Field::new("palette_index", self.palette_index())),
385                _ => None,
386            }),
387            data,
388        }
389    }
390}
391
392impl<'a> MinByteRange<'a> for BaseGlyphList<'a> {
393    fn min_byte_range(&self) -> Range<usize> {
394        0..self.base_glyph_paint_records_byte_range().end
395    }
396    fn min_table_bytes(&self) -> &'a [u8] {
397        let range = self.min_byte_range();
398        self.data.as_bytes().get(range).unwrap_or_default()
399    }
400}
401
402impl<'a> FontRead<'a> for BaseGlyphList<'a> {
403    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
404        #[allow(clippy::absurd_extreme_comparisons)]
405        if data.len() < Self::MIN_SIZE {
406            return Err(ReadError::OutOfBounds);
407        }
408        Ok(Self { data })
409    }
410}
411
412/// [BaseGlyphList](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#baseglyphlist-layerlist-and-cliplist) table
413#[derive(Clone)]
414pub struct BaseGlyphList<'a> {
415    data: FontData<'a>,
416}
417
418#[allow(clippy::needless_lifetimes)]
419impl<'a> BaseGlyphList<'a> {
420    pub const MIN_SIZE: usize = u32::RAW_BYTE_LEN;
421    basic_table_impls!(impl_the_methods);
422
423    pub fn num_base_glyph_paint_records(&self) -> u32 {
424        let range = self.num_base_glyph_paint_records_byte_range();
425        self.data.read_at(range.start).ok().unwrap()
426    }
427
428    pub fn base_glyph_paint_records(&self) -> &'a [BaseGlyphPaint] {
429        let range = self.base_glyph_paint_records_byte_range();
430        self.data.read_array(range).ok().unwrap_or_default()
431    }
432
433    pub fn num_base_glyph_paint_records_byte_range(&self) -> Range<usize> {
434        let start = 0;
435        start..start + u32::RAW_BYTE_LEN
436    }
437
438    pub fn base_glyph_paint_records_byte_range(&self) -> Range<usize> {
439        let num_base_glyph_paint_records = self.num_base_glyph_paint_records();
440        let start = self.num_base_glyph_paint_records_byte_range().end;
441        start
442            ..start
443                + (num_base_glyph_paint_records as usize)
444                    .saturating_mul(BaseGlyphPaint::RAW_BYTE_LEN)
445    }
446}
447
448#[cfg(feature = "experimental_traverse")]
449impl<'a> SomeTable<'a> for BaseGlyphList<'a> {
450    fn type_name(&self) -> &str {
451        "BaseGlyphList"
452    }
453    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
454        match idx {
455            0usize => Some(Field::new(
456                "num_base_glyph_paint_records",
457                self.num_base_glyph_paint_records(),
458            )),
459            1usize => Some(Field::new(
460                "base_glyph_paint_records",
461                traversal::FieldType::array_of_records(
462                    stringify!(BaseGlyphPaint),
463                    self.base_glyph_paint_records(),
464                    self.offset_data(),
465                ),
466            )),
467            _ => None,
468        }
469    }
470}
471
472#[cfg(feature = "experimental_traverse")]
473#[allow(clippy::needless_lifetimes)]
474impl<'a> std::fmt::Debug for BaseGlyphList<'a> {
475    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
476        (self as &dyn SomeTable<'a>).fmt(f)
477    }
478}
479
480/// [BaseGlyphPaint](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#baseglyphlist-layerlist-and-cliplist) record
481#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
482#[repr(C)]
483#[repr(packed)]
484pub struct BaseGlyphPaint {
485    /// Glyph ID of the base glyph.
486    pub glyph_id: BigEndian<GlyphId16>,
487    /// Offset to a Paint table, from the beginning of the [`BaseGlyphList`] table.
488    pub paint_offset: BigEndian<Offset32>,
489}
490
491impl BaseGlyphPaint {
492    /// Glyph ID of the base glyph.
493    pub fn glyph_id(&self) -> GlyphId16 {
494        self.glyph_id.get()
495    }
496
497    /// Offset to a Paint table, from the beginning of the [`BaseGlyphList`] table.
498    pub fn paint_offset(&self) -> Offset32 {
499        self.paint_offset.get()
500    }
501
502    /// Offset to a Paint table, from the beginning of the [`BaseGlyphList`] table.
503    ///
504    /// The `data` argument should be retrieved from the parent table
505    /// By calling its `offset_data` method.
506    pub fn paint<'a>(&self, data: FontData<'a>) -> Result<Paint<'a>, ReadError> {
507        self.paint_offset().resolve(data)
508    }
509}
510
511impl FixedSize for BaseGlyphPaint {
512    const RAW_BYTE_LEN: usize = GlyphId16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
513}
514
515#[cfg(feature = "experimental_traverse")]
516impl<'a> SomeRecord<'a> for BaseGlyphPaint {
517    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
518        RecordResolver {
519            name: "BaseGlyphPaint",
520            get_field: Box::new(move |idx, _data| match idx {
521                0usize => Some(Field::new("glyph_id", self.glyph_id())),
522                1usize => Some(Field::new(
523                    "paint_offset",
524                    FieldType::offset(self.paint_offset(), self.paint(_data)),
525                )),
526                _ => None,
527            }),
528            data,
529        }
530    }
531}
532
533impl<'a> MinByteRange<'a> for LayerList<'a> {
534    fn min_byte_range(&self) -> Range<usize> {
535        0..self.paint_offsets_byte_range().end
536    }
537    fn min_table_bytes(&self) -> &'a [u8] {
538        let range = self.min_byte_range();
539        self.data.as_bytes().get(range).unwrap_or_default()
540    }
541}
542
543impl<'a> FontRead<'a> for LayerList<'a> {
544    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
545        #[allow(clippy::absurd_extreme_comparisons)]
546        if data.len() < Self::MIN_SIZE {
547            return Err(ReadError::OutOfBounds);
548        }
549        Ok(Self { data })
550    }
551}
552
553/// [LayerList](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#baseglyphlist-layerlist-and-cliplist) table
554#[derive(Clone)]
555pub struct LayerList<'a> {
556    data: FontData<'a>,
557}
558
559#[allow(clippy::needless_lifetimes)]
560impl<'a> LayerList<'a> {
561    pub const MIN_SIZE: usize = u32::RAW_BYTE_LEN;
562    basic_table_impls!(impl_the_methods);
563
564    pub fn num_layers(&self) -> u32 {
565        let range = self.num_layers_byte_range();
566        self.data.read_at(range.start).ok().unwrap()
567    }
568
569    /// Offsets to Paint tables.
570    pub fn paint_offsets(&self) -> &'a [BigEndian<Offset32>] {
571        let range = self.paint_offsets_byte_range();
572        self.data.read_array(range).ok().unwrap_or_default()
573    }
574
575    /// A dynamically resolving wrapper for [`paint_offsets`][Self::paint_offsets].
576    pub fn paints(&self) -> ArrayOfOffsets<'a, Paint<'a>, Offset32> {
577        let data = self.data;
578        let offsets = self.paint_offsets();
579        ArrayOfOffsets::new(offsets, data, ())
580    }
581
582    pub fn num_layers_byte_range(&self) -> Range<usize> {
583        let start = 0;
584        start..start + u32::RAW_BYTE_LEN
585    }
586
587    pub fn paint_offsets_byte_range(&self) -> Range<usize> {
588        let num_layers = self.num_layers();
589        let start = self.num_layers_byte_range().end;
590        start..start + (num_layers as usize).saturating_mul(Offset32::RAW_BYTE_LEN)
591    }
592}
593
594#[cfg(feature = "experimental_traverse")]
595impl<'a> SomeTable<'a> for LayerList<'a> {
596    fn type_name(&self) -> &str {
597        "LayerList"
598    }
599    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
600        match idx {
601            0usize => Some(Field::new("num_layers", self.num_layers())),
602            1usize => Some({
603                let data = self.data;
604                Field::new(
605                    "paint_offsets",
606                    FieldType::array_of_offsets(
607                        better_type_name::<Paint>(),
608                        self.paint_offsets(),
609                        move |off| {
610                            let target = off.get().resolve::<Paint>(data);
611                            FieldType::offset(off.get(), target)
612                        },
613                    ),
614                )
615            }),
616            _ => None,
617        }
618    }
619}
620
621#[cfg(feature = "experimental_traverse")]
622#[allow(clippy::needless_lifetimes)]
623impl<'a> std::fmt::Debug for LayerList<'a> {
624    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
625        (self as &dyn SomeTable<'a>).fmt(f)
626    }
627}
628
629impl<'a> MinByteRange<'a> for ClipList<'a> {
630    fn min_byte_range(&self) -> Range<usize> {
631        0..self.clips_byte_range().end
632    }
633    fn min_table_bytes(&self) -> &'a [u8] {
634        let range = self.min_byte_range();
635        self.data.as_bytes().get(range).unwrap_or_default()
636    }
637}
638
639impl<'a> FontRead<'a> for ClipList<'a> {
640    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
641        #[allow(clippy::absurd_extreme_comparisons)]
642        if data.len() < Self::MIN_SIZE {
643            return Err(ReadError::OutOfBounds);
644        }
645        Ok(Self { data })
646    }
647}
648
649/// [ClipList](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#baseglyphlist-layerlist-and-cliplist) table
650#[derive(Clone)]
651pub struct ClipList<'a> {
652    data: FontData<'a>,
653}
654
655#[allow(clippy::needless_lifetimes)]
656impl<'a> ClipList<'a> {
657    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
658    basic_table_impls!(impl_the_methods);
659
660    /// Set to 1.
661    pub fn format(&self) -> u8 {
662        let range = self.format_byte_range();
663        self.data.read_at(range.start).ok().unwrap()
664    }
665
666    /// Number of Clip records.
667    pub fn num_clips(&self) -> u32 {
668        let range = self.num_clips_byte_range();
669        self.data.read_at(range.start).ok().unwrap()
670    }
671
672    /// Clip records. Sorted by startGlyphID.
673    pub fn clips(&self) -> &'a [Clip] {
674        let range = self.clips_byte_range();
675        self.data.read_array(range).ok().unwrap_or_default()
676    }
677
678    pub fn format_byte_range(&self) -> Range<usize> {
679        let start = 0;
680        start..start + u8::RAW_BYTE_LEN
681    }
682
683    pub fn num_clips_byte_range(&self) -> Range<usize> {
684        let start = self.format_byte_range().end;
685        start..start + u32::RAW_BYTE_LEN
686    }
687
688    pub fn clips_byte_range(&self) -> Range<usize> {
689        let num_clips = self.num_clips();
690        let start = self.num_clips_byte_range().end;
691        start..start + (num_clips as usize).saturating_mul(Clip::RAW_BYTE_LEN)
692    }
693}
694
695#[cfg(feature = "experimental_traverse")]
696impl<'a> SomeTable<'a> for ClipList<'a> {
697    fn type_name(&self) -> &str {
698        "ClipList"
699    }
700    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
701        match idx {
702            0usize => Some(Field::new("format", self.format())),
703            1usize => Some(Field::new("num_clips", self.num_clips())),
704            2usize => Some(Field::new(
705                "clips",
706                traversal::FieldType::array_of_records(
707                    stringify!(Clip),
708                    self.clips(),
709                    self.offset_data(),
710                ),
711            )),
712            _ => None,
713        }
714    }
715}
716
717#[cfg(feature = "experimental_traverse")]
718#[allow(clippy::needless_lifetimes)]
719impl<'a> std::fmt::Debug for ClipList<'a> {
720    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
721        (self as &dyn SomeTable<'a>).fmt(f)
722    }
723}
724
725/// [Clip](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#baseglyphlist-layerlist-and-cliplist) record
726#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
727#[repr(C)]
728#[repr(packed)]
729pub struct Clip {
730    /// First glyph ID in the range.
731    pub start_glyph_id: BigEndian<GlyphId16>,
732    /// Last glyph ID in the range.
733    pub end_glyph_id: BigEndian<GlyphId16>,
734    /// Offset to a ClipBox table, from the beginning of the [`ClipList`] table.
735    pub clip_box_offset: BigEndian<Offset24>,
736}
737
738impl Clip {
739    /// First glyph ID in the range.
740    pub fn start_glyph_id(&self) -> GlyphId16 {
741        self.start_glyph_id.get()
742    }
743
744    /// Last glyph ID in the range.
745    pub fn end_glyph_id(&self) -> GlyphId16 {
746        self.end_glyph_id.get()
747    }
748
749    /// Offset to a ClipBox table, from the beginning of the [`ClipList`] table.
750    pub fn clip_box_offset(&self) -> Offset24 {
751        self.clip_box_offset.get()
752    }
753
754    /// Offset to a ClipBox table, from the beginning of the [`ClipList`] table.
755    ///
756    /// The `data` argument should be retrieved from the parent table
757    /// By calling its `offset_data` method.
758    pub fn clip_box<'a>(&self, data: FontData<'a>) -> Result<ClipBox<'a>, ReadError> {
759        self.clip_box_offset().resolve(data)
760    }
761}
762
763impl FixedSize for Clip {
764    const RAW_BYTE_LEN: usize =
765        GlyphId16::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN + Offset24::RAW_BYTE_LEN;
766}
767
768#[cfg(feature = "experimental_traverse")]
769impl<'a> SomeRecord<'a> for Clip {
770    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
771        RecordResolver {
772            name: "Clip",
773            get_field: Box::new(move |idx, _data| match idx {
774                0usize => Some(Field::new("start_glyph_id", self.start_glyph_id())),
775                1usize => Some(Field::new("end_glyph_id", self.end_glyph_id())),
776                2usize => Some(Field::new(
777                    "clip_box_offset",
778                    FieldType::offset(self.clip_box_offset(), self.clip_box(_data)),
779                )),
780                _ => None,
781            }),
782            data,
783        }
784    }
785}
786
787/// [ClipBox](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#baseglyphlist-layerlist-and-cliplist) table
788#[derive(Clone)]
789pub enum ClipBox<'a> {
790    Format1(ClipBoxFormat1<'a>),
791    Format2(ClipBoxFormat2<'a>),
792}
793
794impl<'a> ClipBox<'a> {
795    ///Return the `FontData` used to resolve offsets for this table.
796    pub fn offset_data(&self) -> FontData<'a> {
797        match self {
798            Self::Format1(item) => item.offset_data(),
799            Self::Format2(item) => item.offset_data(),
800        }
801    }
802
803    /// Set to 1.
804    pub fn format(&self) -> u8 {
805        match self {
806            Self::Format1(item) => item.format(),
807            Self::Format2(item) => item.format(),
808        }
809    }
810
811    /// Minimum x of clip box.
812    pub fn x_min(&self) -> FWord {
813        match self {
814            Self::Format1(item) => item.x_min(),
815            Self::Format2(item) => item.x_min(),
816        }
817    }
818
819    /// Minimum y of clip box.
820    pub fn y_min(&self) -> FWord {
821        match self {
822            Self::Format1(item) => item.y_min(),
823            Self::Format2(item) => item.y_min(),
824        }
825    }
826
827    /// Maximum x of clip box.
828    pub fn x_max(&self) -> FWord {
829        match self {
830            Self::Format1(item) => item.x_max(),
831            Self::Format2(item) => item.x_max(),
832        }
833    }
834
835    /// Maximum y of clip box.
836    pub fn y_max(&self) -> FWord {
837        match self {
838            Self::Format1(item) => item.y_max(),
839            Self::Format2(item) => item.y_max(),
840        }
841    }
842}
843
844impl<'a> FontRead<'a> for ClipBox<'a> {
845    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
846        let format: u8 = data.read_at(0usize)?;
847        match format {
848            ClipBoxFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
849            ClipBoxFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
850            other => Err(ReadError::InvalidFormat(other.into())),
851        }
852    }
853}
854
855impl<'a> MinByteRange<'a> for ClipBox<'a> {
856    fn min_byte_range(&self) -> Range<usize> {
857        match self {
858            Self::Format1(item) => item.min_byte_range(),
859            Self::Format2(item) => item.min_byte_range(),
860        }
861    }
862    fn min_table_bytes(&self) -> &'a [u8] {
863        match self {
864            Self::Format1(item) => item.min_table_bytes(),
865            Self::Format2(item) => item.min_table_bytes(),
866        }
867    }
868}
869
870#[cfg(feature = "experimental_traverse")]
871impl<'a> ClipBox<'a> {
872    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
873        match self {
874            Self::Format1(table) => table,
875            Self::Format2(table) => table,
876        }
877    }
878}
879
880#[cfg(feature = "experimental_traverse")]
881impl std::fmt::Debug for ClipBox<'_> {
882    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
883        self.dyn_inner().fmt(f)
884    }
885}
886
887#[cfg(feature = "experimental_traverse")]
888impl<'a> SomeTable<'a> for ClipBox<'a> {
889    fn type_name(&self) -> &str {
890        self.dyn_inner().type_name()
891    }
892    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
893        self.dyn_inner().get_field(idx)
894    }
895}
896
897impl Format<u8> for ClipBoxFormat1<'_> {
898    const FORMAT: u8 = 1;
899}
900
901impl<'a> MinByteRange<'a> for ClipBoxFormat1<'a> {
902    fn min_byte_range(&self) -> Range<usize> {
903        0..self.y_max_byte_range().end
904    }
905    fn min_table_bytes(&self) -> &'a [u8] {
906        let range = self.min_byte_range();
907        self.data.as_bytes().get(range).unwrap_or_default()
908    }
909}
910
911impl<'a> FontRead<'a> for ClipBoxFormat1<'a> {
912    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
913        #[allow(clippy::absurd_extreme_comparisons)]
914        if data.len() < Self::MIN_SIZE {
915            return Err(ReadError::OutOfBounds);
916        }
917        Ok(Self { data })
918    }
919}
920
921/// [ClipBoxFormat1](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#baseglyphlist-layerlist-and-cliplist) record
922#[derive(Clone)]
923pub struct ClipBoxFormat1<'a> {
924    data: FontData<'a>,
925}
926
927#[allow(clippy::needless_lifetimes)]
928impl<'a> ClipBoxFormat1<'a> {
929    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN
930        + FWord::RAW_BYTE_LEN
931        + FWord::RAW_BYTE_LEN
932        + FWord::RAW_BYTE_LEN
933        + FWord::RAW_BYTE_LEN);
934    basic_table_impls!(impl_the_methods);
935
936    /// Set to 1.
937    pub fn format(&self) -> u8 {
938        let range = self.format_byte_range();
939        self.data.read_at(range.start).ok().unwrap()
940    }
941
942    /// Minimum x of clip box.
943    pub fn x_min(&self) -> FWord {
944        let range = self.x_min_byte_range();
945        self.data.read_at(range.start).ok().unwrap()
946    }
947
948    /// Minimum y of clip box.
949    pub fn y_min(&self) -> FWord {
950        let range = self.y_min_byte_range();
951        self.data.read_at(range.start).ok().unwrap()
952    }
953
954    /// Maximum x of clip box.
955    pub fn x_max(&self) -> FWord {
956        let range = self.x_max_byte_range();
957        self.data.read_at(range.start).ok().unwrap()
958    }
959
960    /// Maximum y of clip box.
961    pub fn y_max(&self) -> FWord {
962        let range = self.y_max_byte_range();
963        self.data.read_at(range.start).ok().unwrap()
964    }
965
966    pub fn format_byte_range(&self) -> Range<usize> {
967        let start = 0;
968        start..start + u8::RAW_BYTE_LEN
969    }
970
971    pub fn x_min_byte_range(&self) -> Range<usize> {
972        let start = self.format_byte_range().end;
973        start..start + FWord::RAW_BYTE_LEN
974    }
975
976    pub fn y_min_byte_range(&self) -> Range<usize> {
977        let start = self.x_min_byte_range().end;
978        start..start + FWord::RAW_BYTE_LEN
979    }
980
981    pub fn x_max_byte_range(&self) -> Range<usize> {
982        let start = self.y_min_byte_range().end;
983        start..start + FWord::RAW_BYTE_LEN
984    }
985
986    pub fn y_max_byte_range(&self) -> Range<usize> {
987        let start = self.x_max_byte_range().end;
988        start..start + FWord::RAW_BYTE_LEN
989    }
990}
991
992#[cfg(feature = "experimental_traverse")]
993impl<'a> SomeTable<'a> for ClipBoxFormat1<'a> {
994    fn type_name(&self) -> &str {
995        "ClipBoxFormat1"
996    }
997    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
998        match idx {
999            0usize => Some(Field::new("format", self.format())),
1000            1usize => Some(Field::new("x_min", self.x_min())),
1001            2usize => Some(Field::new("y_min", self.y_min())),
1002            3usize => Some(Field::new("x_max", self.x_max())),
1003            4usize => Some(Field::new("y_max", self.y_max())),
1004            _ => None,
1005        }
1006    }
1007}
1008
1009#[cfg(feature = "experimental_traverse")]
1010#[allow(clippy::needless_lifetimes)]
1011impl<'a> std::fmt::Debug for ClipBoxFormat1<'a> {
1012    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1013        (self as &dyn SomeTable<'a>).fmt(f)
1014    }
1015}
1016
1017impl Format<u8> for ClipBoxFormat2<'_> {
1018    const FORMAT: u8 = 2;
1019}
1020
1021impl<'a> MinByteRange<'a> for ClipBoxFormat2<'a> {
1022    fn min_byte_range(&self) -> Range<usize> {
1023        0..self.var_index_base_byte_range().end
1024    }
1025    fn min_table_bytes(&self) -> &'a [u8] {
1026        let range = self.min_byte_range();
1027        self.data.as_bytes().get(range).unwrap_or_default()
1028    }
1029}
1030
1031impl<'a> FontRead<'a> for ClipBoxFormat2<'a> {
1032    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1033        #[allow(clippy::absurd_extreme_comparisons)]
1034        if data.len() < Self::MIN_SIZE {
1035            return Err(ReadError::OutOfBounds);
1036        }
1037        Ok(Self { data })
1038    }
1039}
1040
1041/// [ClipBoxFormat2](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#baseglyphlist-layerlist-and-cliplist) record
1042#[derive(Clone)]
1043pub struct ClipBoxFormat2<'a> {
1044    data: FontData<'a>,
1045}
1046
1047#[allow(clippy::needless_lifetimes)]
1048impl<'a> ClipBoxFormat2<'a> {
1049    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN
1050        + FWord::RAW_BYTE_LEN
1051        + FWord::RAW_BYTE_LEN
1052        + FWord::RAW_BYTE_LEN
1053        + FWord::RAW_BYTE_LEN
1054        + u32::RAW_BYTE_LEN);
1055    basic_table_impls!(impl_the_methods);
1056
1057    /// Set to 2.
1058    pub fn format(&self) -> u8 {
1059        let range = self.format_byte_range();
1060        self.data.read_at(range.start).ok().unwrap()
1061    }
1062
1063    /// Minimum x of clip box. For variation, use varIndexBase + 0.
1064    pub fn x_min(&self) -> FWord {
1065        let range = self.x_min_byte_range();
1066        self.data.read_at(range.start).ok().unwrap()
1067    }
1068
1069    /// Minimum y of clip box. For variation, use varIndexBase + 1.
1070    pub fn y_min(&self) -> FWord {
1071        let range = self.y_min_byte_range();
1072        self.data.read_at(range.start).ok().unwrap()
1073    }
1074
1075    /// Maximum x of clip box. For variation, use varIndexBase + 2.
1076    pub fn x_max(&self) -> FWord {
1077        let range = self.x_max_byte_range();
1078        self.data.read_at(range.start).ok().unwrap()
1079    }
1080
1081    /// Maximum y of clip box. For variation, use varIndexBase + 3.
1082    pub fn y_max(&self) -> FWord {
1083        let range = self.y_max_byte_range();
1084        self.data.read_at(range.start).ok().unwrap()
1085    }
1086
1087    /// Base index into DeltaSetIndexMap.
1088    pub fn var_index_base(&self) -> u32 {
1089        let range = self.var_index_base_byte_range();
1090        self.data.read_at(range.start).ok().unwrap()
1091    }
1092
1093    pub fn format_byte_range(&self) -> Range<usize> {
1094        let start = 0;
1095        start..start + u8::RAW_BYTE_LEN
1096    }
1097
1098    pub fn x_min_byte_range(&self) -> Range<usize> {
1099        let start = self.format_byte_range().end;
1100        start..start + FWord::RAW_BYTE_LEN
1101    }
1102
1103    pub fn y_min_byte_range(&self) -> Range<usize> {
1104        let start = self.x_min_byte_range().end;
1105        start..start + FWord::RAW_BYTE_LEN
1106    }
1107
1108    pub fn x_max_byte_range(&self) -> Range<usize> {
1109        let start = self.y_min_byte_range().end;
1110        start..start + FWord::RAW_BYTE_LEN
1111    }
1112
1113    pub fn y_max_byte_range(&self) -> Range<usize> {
1114        let start = self.x_max_byte_range().end;
1115        start..start + FWord::RAW_BYTE_LEN
1116    }
1117
1118    pub fn var_index_base_byte_range(&self) -> Range<usize> {
1119        let start = self.y_max_byte_range().end;
1120        start..start + u32::RAW_BYTE_LEN
1121    }
1122}
1123
1124#[cfg(feature = "experimental_traverse")]
1125impl<'a> SomeTable<'a> for ClipBoxFormat2<'a> {
1126    fn type_name(&self) -> &str {
1127        "ClipBoxFormat2"
1128    }
1129    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1130        match idx {
1131            0usize => Some(Field::new("format", self.format())),
1132            1usize => Some(Field::new("x_min", self.x_min())),
1133            2usize => Some(Field::new("y_min", self.y_min())),
1134            3usize => Some(Field::new("x_max", self.x_max())),
1135            4usize => Some(Field::new("y_max", self.y_max())),
1136            5usize => Some(Field::new("var_index_base", self.var_index_base())),
1137            _ => None,
1138        }
1139    }
1140}
1141
1142#[cfg(feature = "experimental_traverse")]
1143#[allow(clippy::needless_lifetimes)]
1144impl<'a> std::fmt::Debug for ClipBoxFormat2<'a> {
1145    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1146        (self as &dyn SomeTable<'a>).fmt(f)
1147    }
1148}
1149
1150/// [ColorIndex](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#color-references-colorstop-and-colorline) record
1151#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1152#[repr(C)]
1153#[repr(packed)]
1154pub struct ColorIndex {
1155    /// Index for a CPAL palette entry.
1156    pub palette_index: BigEndian<u16>,
1157    /// Alpha value.
1158    pub alpha: BigEndian<F2Dot14>,
1159}
1160
1161impl ColorIndex {
1162    /// Index for a CPAL palette entry.
1163    pub fn palette_index(&self) -> u16 {
1164        self.palette_index.get()
1165    }
1166
1167    /// Alpha value.
1168    pub fn alpha(&self) -> F2Dot14 {
1169        self.alpha.get()
1170    }
1171}
1172
1173impl FixedSize for ColorIndex {
1174    const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN;
1175}
1176
1177#[cfg(feature = "experimental_traverse")]
1178impl<'a> SomeRecord<'a> for ColorIndex {
1179    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1180        RecordResolver {
1181            name: "ColorIndex",
1182            get_field: Box::new(move |idx, _data| match idx {
1183                0usize => Some(Field::new("palette_index", self.palette_index())),
1184                1usize => Some(Field::new("alpha", self.alpha())),
1185                _ => None,
1186            }),
1187            data,
1188        }
1189    }
1190}
1191
1192/// [VarColorIndex](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#color-references-colorstop-and-colorline) record
1193#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1194#[repr(C)]
1195#[repr(packed)]
1196pub struct VarColorIndex {
1197    /// Index for a CPAL palette entry.
1198    pub palette_index: BigEndian<u16>,
1199    /// Alpha value. For variation, use varIndexBase + 0.
1200    pub alpha: BigEndian<F2Dot14>,
1201    /// Base index into DeltaSetIndexMap.
1202    pub var_index_base: BigEndian<u32>,
1203}
1204
1205impl VarColorIndex {
1206    /// Index for a CPAL palette entry.
1207    pub fn palette_index(&self) -> u16 {
1208        self.palette_index.get()
1209    }
1210
1211    /// Alpha value. For variation, use varIndexBase + 0.
1212    pub fn alpha(&self) -> F2Dot14 {
1213        self.alpha.get()
1214    }
1215
1216    /// Base index into DeltaSetIndexMap.
1217    pub fn var_index_base(&self) -> u32 {
1218        self.var_index_base.get()
1219    }
1220}
1221
1222impl FixedSize for VarColorIndex {
1223    const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN + u32::RAW_BYTE_LEN;
1224}
1225
1226#[cfg(feature = "experimental_traverse")]
1227impl<'a> SomeRecord<'a> for VarColorIndex {
1228    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1229        RecordResolver {
1230            name: "VarColorIndex",
1231            get_field: Box::new(move |idx, _data| match idx {
1232                0usize => Some(Field::new("palette_index", self.palette_index())),
1233                1usize => Some(Field::new("alpha", self.alpha())),
1234                2usize => Some(Field::new("var_index_base", self.var_index_base())),
1235                _ => None,
1236            }),
1237            data,
1238        }
1239    }
1240}
1241
1242/// [ColorStop](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#color-references-colorstop-and-colorline) record
1243#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1244#[repr(C)]
1245#[repr(packed)]
1246pub struct ColorStop {
1247    /// Position on a color line.
1248    pub stop_offset: BigEndian<F2Dot14>,
1249    /// Index for a CPAL palette entry.
1250    pub palette_index: BigEndian<u16>,
1251    /// Alpha value.
1252    pub alpha: BigEndian<F2Dot14>,
1253}
1254
1255impl ColorStop {
1256    /// Position on a color line.
1257    pub fn stop_offset(&self) -> F2Dot14 {
1258        self.stop_offset.get()
1259    }
1260
1261    /// Index for a CPAL palette entry.
1262    pub fn palette_index(&self) -> u16 {
1263        self.palette_index.get()
1264    }
1265
1266    /// Alpha value.
1267    pub fn alpha(&self) -> F2Dot14 {
1268        self.alpha.get()
1269    }
1270}
1271
1272impl FixedSize for ColorStop {
1273    const RAW_BYTE_LEN: usize = F2Dot14::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN;
1274}
1275
1276#[cfg(feature = "experimental_traverse")]
1277impl<'a> SomeRecord<'a> for ColorStop {
1278    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1279        RecordResolver {
1280            name: "ColorStop",
1281            get_field: Box::new(move |idx, _data| match idx {
1282                0usize => Some(Field::new("stop_offset", self.stop_offset())),
1283                1usize => Some(Field::new("palette_index", self.palette_index())),
1284                2usize => Some(Field::new("alpha", self.alpha())),
1285                _ => None,
1286            }),
1287            data,
1288        }
1289    }
1290}
1291
1292/// [VarColorStop](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#color-references-colorstop-and-colorline) record
1293#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1294#[repr(C)]
1295#[repr(packed)]
1296pub struct VarColorStop {
1297    /// Position on a color line. For variation, use varIndexBase + 0.
1298    pub stop_offset: BigEndian<F2Dot14>,
1299    /// Index for a CPAL palette entry.
1300    pub palette_index: BigEndian<u16>,
1301    /// Alpha value. For variation, use varIndexBase + 1.
1302    pub alpha: BigEndian<F2Dot14>,
1303    /// Base index into DeltaSetIndexMap.
1304    pub var_index_base: BigEndian<u32>,
1305}
1306
1307impl VarColorStop {
1308    /// Position on a color line. For variation, use varIndexBase + 0.
1309    pub fn stop_offset(&self) -> F2Dot14 {
1310        self.stop_offset.get()
1311    }
1312
1313    /// Index for a CPAL palette entry.
1314    pub fn palette_index(&self) -> u16 {
1315        self.palette_index.get()
1316    }
1317
1318    /// Alpha value. For variation, use varIndexBase + 1.
1319    pub fn alpha(&self) -> F2Dot14 {
1320        self.alpha.get()
1321    }
1322
1323    /// Base index into DeltaSetIndexMap.
1324    pub fn var_index_base(&self) -> u32 {
1325        self.var_index_base.get()
1326    }
1327}
1328
1329impl FixedSize for VarColorStop {
1330    const RAW_BYTE_LEN: usize =
1331        F2Dot14::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN + u32::RAW_BYTE_LEN;
1332}
1333
1334#[cfg(feature = "experimental_traverse")]
1335impl<'a> SomeRecord<'a> for VarColorStop {
1336    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1337        RecordResolver {
1338            name: "VarColorStop",
1339            get_field: Box::new(move |idx, _data| match idx {
1340                0usize => Some(Field::new("stop_offset", self.stop_offset())),
1341                1usize => Some(Field::new("palette_index", self.palette_index())),
1342                2usize => Some(Field::new("alpha", self.alpha())),
1343                3usize => Some(Field::new("var_index_base", self.var_index_base())),
1344                _ => None,
1345            }),
1346            data,
1347        }
1348    }
1349}
1350
1351impl<'a> MinByteRange<'a> for ColorLine<'a> {
1352    fn min_byte_range(&self) -> Range<usize> {
1353        0..self.color_stops_byte_range().end
1354    }
1355    fn min_table_bytes(&self) -> &'a [u8] {
1356        let range = self.min_byte_range();
1357        self.data.as_bytes().get(range).unwrap_or_default()
1358    }
1359}
1360
1361impl<'a> FontRead<'a> for ColorLine<'a> {
1362    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1363        #[allow(clippy::absurd_extreme_comparisons)]
1364        if data.len() < Self::MIN_SIZE {
1365            return Err(ReadError::OutOfBounds);
1366        }
1367        Ok(Self { data })
1368    }
1369}
1370
1371/// [ColorLine](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#color-references-colorstop-and-colorline) table
1372#[derive(Clone)]
1373pub struct ColorLine<'a> {
1374    data: FontData<'a>,
1375}
1376
1377#[allow(clippy::needless_lifetimes)]
1378impl<'a> ColorLine<'a> {
1379    pub const MIN_SIZE: usize = (Extend::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1380    basic_table_impls!(impl_the_methods);
1381
1382    /// An Extend enum value.
1383    pub fn extend(&self) -> Extend {
1384        let range = self.extend_byte_range();
1385        self.data.read_at(range.start).ok().unwrap()
1386    }
1387
1388    /// Number of ColorStop records.
1389    pub fn num_stops(&self) -> u16 {
1390        let range = self.num_stops_byte_range();
1391        self.data.read_at(range.start).ok().unwrap()
1392    }
1393
1394    pub fn color_stops(&self) -> &'a [ColorStop] {
1395        let range = self.color_stops_byte_range();
1396        self.data.read_array(range).ok().unwrap_or_default()
1397    }
1398
1399    pub fn extend_byte_range(&self) -> Range<usize> {
1400        let start = 0;
1401        start..start + Extend::RAW_BYTE_LEN
1402    }
1403
1404    pub fn num_stops_byte_range(&self) -> Range<usize> {
1405        let start = self.extend_byte_range().end;
1406        start..start + u16::RAW_BYTE_LEN
1407    }
1408
1409    pub fn color_stops_byte_range(&self) -> Range<usize> {
1410        let num_stops = self.num_stops();
1411        let start = self.num_stops_byte_range().end;
1412        start..start + (num_stops as usize).saturating_mul(ColorStop::RAW_BYTE_LEN)
1413    }
1414}
1415
1416#[cfg(feature = "experimental_traverse")]
1417impl<'a> SomeTable<'a> for ColorLine<'a> {
1418    fn type_name(&self) -> &str {
1419        "ColorLine"
1420    }
1421    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1422        match idx {
1423            0usize => Some(Field::new("extend", self.extend())),
1424            1usize => Some(Field::new("num_stops", self.num_stops())),
1425            2usize => Some(Field::new(
1426                "color_stops",
1427                traversal::FieldType::array_of_records(
1428                    stringify!(ColorStop),
1429                    self.color_stops(),
1430                    self.offset_data(),
1431                ),
1432            )),
1433            _ => None,
1434        }
1435    }
1436}
1437
1438#[cfg(feature = "experimental_traverse")]
1439#[allow(clippy::needless_lifetimes)]
1440impl<'a> std::fmt::Debug for ColorLine<'a> {
1441    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1442        (self as &dyn SomeTable<'a>).fmt(f)
1443    }
1444}
1445
1446impl<'a> MinByteRange<'a> for VarColorLine<'a> {
1447    fn min_byte_range(&self) -> Range<usize> {
1448        0..self.color_stops_byte_range().end
1449    }
1450    fn min_table_bytes(&self) -> &'a [u8] {
1451        let range = self.min_byte_range();
1452        self.data.as_bytes().get(range).unwrap_or_default()
1453    }
1454}
1455
1456impl<'a> FontRead<'a> for VarColorLine<'a> {
1457    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1458        #[allow(clippy::absurd_extreme_comparisons)]
1459        if data.len() < Self::MIN_SIZE {
1460            return Err(ReadError::OutOfBounds);
1461        }
1462        Ok(Self { data })
1463    }
1464}
1465
1466/// [VarColorLine](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#color-references-colorstop-and-colorline) table
1467#[derive(Clone)]
1468pub struct VarColorLine<'a> {
1469    data: FontData<'a>,
1470}
1471
1472#[allow(clippy::needless_lifetimes)]
1473impl<'a> VarColorLine<'a> {
1474    pub const MIN_SIZE: usize = (Extend::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1475    basic_table_impls!(impl_the_methods);
1476
1477    /// An Extend enum value.
1478    pub fn extend(&self) -> Extend {
1479        let range = self.extend_byte_range();
1480        self.data.read_at(range.start).ok().unwrap()
1481    }
1482
1483    /// Number of ColorStop records.
1484    pub fn num_stops(&self) -> u16 {
1485        let range = self.num_stops_byte_range();
1486        self.data.read_at(range.start).ok().unwrap()
1487    }
1488
1489    /// Allows for variations.
1490    pub fn color_stops(&self) -> &'a [VarColorStop] {
1491        let range = self.color_stops_byte_range();
1492        self.data.read_array(range).ok().unwrap_or_default()
1493    }
1494
1495    pub fn extend_byte_range(&self) -> Range<usize> {
1496        let start = 0;
1497        start..start + Extend::RAW_BYTE_LEN
1498    }
1499
1500    pub fn num_stops_byte_range(&self) -> Range<usize> {
1501        let start = self.extend_byte_range().end;
1502        start..start + u16::RAW_BYTE_LEN
1503    }
1504
1505    pub fn color_stops_byte_range(&self) -> Range<usize> {
1506        let num_stops = self.num_stops();
1507        let start = self.num_stops_byte_range().end;
1508        start..start + (num_stops as usize).saturating_mul(VarColorStop::RAW_BYTE_LEN)
1509    }
1510}
1511
1512#[cfg(feature = "experimental_traverse")]
1513impl<'a> SomeTable<'a> for VarColorLine<'a> {
1514    fn type_name(&self) -> &str {
1515        "VarColorLine"
1516    }
1517    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1518        match idx {
1519            0usize => Some(Field::new("extend", self.extend())),
1520            1usize => Some(Field::new("num_stops", self.num_stops())),
1521            2usize => Some(Field::new(
1522                "color_stops",
1523                traversal::FieldType::array_of_records(
1524                    stringify!(VarColorStop),
1525                    self.color_stops(),
1526                    self.offset_data(),
1527                ),
1528            )),
1529            _ => None,
1530        }
1531    }
1532}
1533
1534#[cfg(feature = "experimental_traverse")]
1535#[allow(clippy::needless_lifetimes)]
1536impl<'a> std::fmt::Debug for VarColorLine<'a> {
1537    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1538        (self as &dyn SomeTable<'a>).fmt(f)
1539    }
1540}
1541
1542/// [Extend](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#color-references-colorstop-and-colorline) enumeration
1543#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
1544#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1545#[repr(u8)]
1546#[allow(clippy::manual_non_exhaustive)]
1547pub enum Extend {
1548    #[default]
1549    Pad = 0,
1550    Repeat = 1,
1551    Reflect = 2,
1552    #[doc(hidden)]
1553    /// If font data is malformed we will map unknown values to this variant
1554    Unknown,
1555}
1556
1557impl Extend {
1558    /// Create from a raw scalar.
1559    ///
1560    /// This will never fail; unknown values will be mapped to the `Unknown` variant
1561    pub fn new(raw: u8) -> Self {
1562        match raw {
1563            0 => Self::Pad,
1564            1 => Self::Repeat,
1565            2 => Self::Reflect,
1566            _ => Self::Unknown,
1567        }
1568    }
1569}
1570
1571impl font_types::Scalar for Extend {
1572    type Raw = <u8 as font_types::Scalar>::Raw;
1573    fn to_raw(self) -> Self::Raw {
1574        (self as u8).to_raw()
1575    }
1576    fn from_raw(raw: Self::Raw) -> Self {
1577        let t = <u8>::from_raw(raw);
1578        Self::new(t)
1579    }
1580}
1581
1582#[cfg(feature = "experimental_traverse")]
1583impl<'a> From<Extend> for FieldType<'a> {
1584    fn from(src: Extend) -> FieldType<'a> {
1585        (src as u8).into()
1586    }
1587}
1588
1589/// [Paint](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#paint-tables) tables
1590#[derive(Clone)]
1591pub enum Paint<'a> {
1592    ColrLayers(PaintColrLayers<'a>),
1593    Solid(PaintSolid<'a>),
1594    VarSolid(PaintVarSolid<'a>),
1595    LinearGradient(PaintLinearGradient<'a>),
1596    VarLinearGradient(PaintVarLinearGradient<'a>),
1597    RadialGradient(PaintRadialGradient<'a>),
1598    VarRadialGradient(PaintVarRadialGradient<'a>),
1599    SweepGradient(PaintSweepGradient<'a>),
1600    VarSweepGradient(PaintVarSweepGradient<'a>),
1601    Glyph(PaintGlyph<'a>),
1602    ColrGlyph(PaintColrGlyph<'a>),
1603    Transform(PaintTransform<'a>),
1604    VarTransform(PaintVarTransform<'a>),
1605    Translate(PaintTranslate<'a>),
1606    VarTranslate(PaintVarTranslate<'a>),
1607    Scale(PaintScale<'a>),
1608    VarScale(PaintVarScale<'a>),
1609    ScaleAroundCenter(PaintScaleAroundCenter<'a>),
1610    VarScaleAroundCenter(PaintVarScaleAroundCenter<'a>),
1611    ScaleUniform(PaintScaleUniform<'a>),
1612    VarScaleUniform(PaintVarScaleUniform<'a>),
1613    ScaleUniformAroundCenter(PaintScaleUniformAroundCenter<'a>),
1614    VarScaleUniformAroundCenter(PaintVarScaleUniformAroundCenter<'a>),
1615    Rotate(PaintRotate<'a>),
1616    VarRotate(PaintVarRotate<'a>),
1617    RotateAroundCenter(PaintRotateAroundCenter<'a>),
1618    VarRotateAroundCenter(PaintVarRotateAroundCenter<'a>),
1619    Skew(PaintSkew<'a>),
1620    VarSkew(PaintVarSkew<'a>),
1621    SkewAroundCenter(PaintSkewAroundCenter<'a>),
1622    VarSkewAroundCenter(PaintVarSkewAroundCenter<'a>),
1623    Composite(PaintComposite<'a>),
1624}
1625
1626impl<'a> Paint<'a> {
1627    ///Return the `FontData` used to resolve offsets for this table.
1628    pub fn offset_data(&self) -> FontData<'a> {
1629        match self {
1630            Self::ColrLayers(item) => item.offset_data(),
1631            Self::Solid(item) => item.offset_data(),
1632            Self::VarSolid(item) => item.offset_data(),
1633            Self::LinearGradient(item) => item.offset_data(),
1634            Self::VarLinearGradient(item) => item.offset_data(),
1635            Self::RadialGradient(item) => item.offset_data(),
1636            Self::VarRadialGradient(item) => item.offset_data(),
1637            Self::SweepGradient(item) => item.offset_data(),
1638            Self::VarSweepGradient(item) => item.offset_data(),
1639            Self::Glyph(item) => item.offset_data(),
1640            Self::ColrGlyph(item) => item.offset_data(),
1641            Self::Transform(item) => item.offset_data(),
1642            Self::VarTransform(item) => item.offset_data(),
1643            Self::Translate(item) => item.offset_data(),
1644            Self::VarTranslate(item) => item.offset_data(),
1645            Self::Scale(item) => item.offset_data(),
1646            Self::VarScale(item) => item.offset_data(),
1647            Self::ScaleAroundCenter(item) => item.offset_data(),
1648            Self::VarScaleAroundCenter(item) => item.offset_data(),
1649            Self::ScaleUniform(item) => item.offset_data(),
1650            Self::VarScaleUniform(item) => item.offset_data(),
1651            Self::ScaleUniformAroundCenter(item) => item.offset_data(),
1652            Self::VarScaleUniformAroundCenter(item) => item.offset_data(),
1653            Self::Rotate(item) => item.offset_data(),
1654            Self::VarRotate(item) => item.offset_data(),
1655            Self::RotateAroundCenter(item) => item.offset_data(),
1656            Self::VarRotateAroundCenter(item) => item.offset_data(),
1657            Self::Skew(item) => item.offset_data(),
1658            Self::VarSkew(item) => item.offset_data(),
1659            Self::SkewAroundCenter(item) => item.offset_data(),
1660            Self::VarSkewAroundCenter(item) => item.offset_data(),
1661            Self::Composite(item) => item.offset_data(),
1662        }
1663    }
1664
1665    /// Set to 1.
1666    pub fn format(&self) -> u8 {
1667        match self {
1668            Self::ColrLayers(item) => item.format(),
1669            Self::Solid(item) => item.format(),
1670            Self::VarSolid(item) => item.format(),
1671            Self::LinearGradient(item) => item.format(),
1672            Self::VarLinearGradient(item) => item.format(),
1673            Self::RadialGradient(item) => item.format(),
1674            Self::VarRadialGradient(item) => item.format(),
1675            Self::SweepGradient(item) => item.format(),
1676            Self::VarSweepGradient(item) => item.format(),
1677            Self::Glyph(item) => item.format(),
1678            Self::ColrGlyph(item) => item.format(),
1679            Self::Transform(item) => item.format(),
1680            Self::VarTransform(item) => item.format(),
1681            Self::Translate(item) => item.format(),
1682            Self::VarTranslate(item) => item.format(),
1683            Self::Scale(item) => item.format(),
1684            Self::VarScale(item) => item.format(),
1685            Self::ScaleAroundCenter(item) => item.format(),
1686            Self::VarScaleAroundCenter(item) => item.format(),
1687            Self::ScaleUniform(item) => item.format(),
1688            Self::VarScaleUniform(item) => item.format(),
1689            Self::ScaleUniformAroundCenter(item) => item.format(),
1690            Self::VarScaleUniformAroundCenter(item) => item.format(),
1691            Self::Rotate(item) => item.format(),
1692            Self::VarRotate(item) => item.format(),
1693            Self::RotateAroundCenter(item) => item.format(),
1694            Self::VarRotateAroundCenter(item) => item.format(),
1695            Self::Skew(item) => item.format(),
1696            Self::VarSkew(item) => item.format(),
1697            Self::SkewAroundCenter(item) => item.format(),
1698            Self::VarSkewAroundCenter(item) => item.format(),
1699            Self::Composite(item) => item.format(),
1700        }
1701    }
1702}
1703
1704impl<'a> FontRead<'a> for Paint<'a> {
1705    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1706        let format: u8 = data.read_at(0usize)?;
1707        match format {
1708            PaintColrLayers::FORMAT => Ok(Self::ColrLayers(FontRead::read(data)?)),
1709            PaintSolid::FORMAT => Ok(Self::Solid(FontRead::read(data)?)),
1710            PaintVarSolid::FORMAT => Ok(Self::VarSolid(FontRead::read(data)?)),
1711            PaintLinearGradient::FORMAT => Ok(Self::LinearGradient(FontRead::read(data)?)),
1712            PaintVarLinearGradient::FORMAT => Ok(Self::VarLinearGradient(FontRead::read(data)?)),
1713            PaintRadialGradient::FORMAT => Ok(Self::RadialGradient(FontRead::read(data)?)),
1714            PaintVarRadialGradient::FORMAT => Ok(Self::VarRadialGradient(FontRead::read(data)?)),
1715            PaintSweepGradient::FORMAT => Ok(Self::SweepGradient(FontRead::read(data)?)),
1716            PaintVarSweepGradient::FORMAT => Ok(Self::VarSweepGradient(FontRead::read(data)?)),
1717            PaintGlyph::FORMAT => Ok(Self::Glyph(FontRead::read(data)?)),
1718            PaintColrGlyph::FORMAT => Ok(Self::ColrGlyph(FontRead::read(data)?)),
1719            PaintTransform::FORMAT => Ok(Self::Transform(FontRead::read(data)?)),
1720            PaintVarTransform::FORMAT => Ok(Self::VarTransform(FontRead::read(data)?)),
1721            PaintTranslate::FORMAT => Ok(Self::Translate(FontRead::read(data)?)),
1722            PaintVarTranslate::FORMAT => Ok(Self::VarTranslate(FontRead::read(data)?)),
1723            PaintScale::FORMAT => Ok(Self::Scale(FontRead::read(data)?)),
1724            PaintVarScale::FORMAT => Ok(Self::VarScale(FontRead::read(data)?)),
1725            PaintScaleAroundCenter::FORMAT => Ok(Self::ScaleAroundCenter(FontRead::read(data)?)),
1726            PaintVarScaleAroundCenter::FORMAT => {
1727                Ok(Self::VarScaleAroundCenter(FontRead::read(data)?))
1728            }
1729            PaintScaleUniform::FORMAT => Ok(Self::ScaleUniform(FontRead::read(data)?)),
1730            PaintVarScaleUniform::FORMAT => Ok(Self::VarScaleUniform(FontRead::read(data)?)),
1731            PaintScaleUniformAroundCenter::FORMAT => {
1732                Ok(Self::ScaleUniformAroundCenter(FontRead::read(data)?))
1733            }
1734            PaintVarScaleUniformAroundCenter::FORMAT => {
1735                Ok(Self::VarScaleUniformAroundCenter(FontRead::read(data)?))
1736            }
1737            PaintRotate::FORMAT => Ok(Self::Rotate(FontRead::read(data)?)),
1738            PaintVarRotate::FORMAT => Ok(Self::VarRotate(FontRead::read(data)?)),
1739            PaintRotateAroundCenter::FORMAT => Ok(Self::RotateAroundCenter(FontRead::read(data)?)),
1740            PaintVarRotateAroundCenter::FORMAT => {
1741                Ok(Self::VarRotateAroundCenter(FontRead::read(data)?))
1742            }
1743            PaintSkew::FORMAT => Ok(Self::Skew(FontRead::read(data)?)),
1744            PaintVarSkew::FORMAT => Ok(Self::VarSkew(FontRead::read(data)?)),
1745            PaintSkewAroundCenter::FORMAT => Ok(Self::SkewAroundCenter(FontRead::read(data)?)),
1746            PaintVarSkewAroundCenter::FORMAT => {
1747                Ok(Self::VarSkewAroundCenter(FontRead::read(data)?))
1748            }
1749            PaintComposite::FORMAT => Ok(Self::Composite(FontRead::read(data)?)),
1750            other => Err(ReadError::InvalidFormat(other.into())),
1751        }
1752    }
1753}
1754
1755impl<'a> MinByteRange<'a> for Paint<'a> {
1756    fn min_byte_range(&self) -> Range<usize> {
1757        match self {
1758            Self::ColrLayers(item) => item.min_byte_range(),
1759            Self::Solid(item) => item.min_byte_range(),
1760            Self::VarSolid(item) => item.min_byte_range(),
1761            Self::LinearGradient(item) => item.min_byte_range(),
1762            Self::VarLinearGradient(item) => item.min_byte_range(),
1763            Self::RadialGradient(item) => item.min_byte_range(),
1764            Self::VarRadialGradient(item) => item.min_byte_range(),
1765            Self::SweepGradient(item) => item.min_byte_range(),
1766            Self::VarSweepGradient(item) => item.min_byte_range(),
1767            Self::Glyph(item) => item.min_byte_range(),
1768            Self::ColrGlyph(item) => item.min_byte_range(),
1769            Self::Transform(item) => item.min_byte_range(),
1770            Self::VarTransform(item) => item.min_byte_range(),
1771            Self::Translate(item) => item.min_byte_range(),
1772            Self::VarTranslate(item) => item.min_byte_range(),
1773            Self::Scale(item) => item.min_byte_range(),
1774            Self::VarScale(item) => item.min_byte_range(),
1775            Self::ScaleAroundCenter(item) => item.min_byte_range(),
1776            Self::VarScaleAroundCenter(item) => item.min_byte_range(),
1777            Self::ScaleUniform(item) => item.min_byte_range(),
1778            Self::VarScaleUniform(item) => item.min_byte_range(),
1779            Self::ScaleUniformAroundCenter(item) => item.min_byte_range(),
1780            Self::VarScaleUniformAroundCenter(item) => item.min_byte_range(),
1781            Self::Rotate(item) => item.min_byte_range(),
1782            Self::VarRotate(item) => item.min_byte_range(),
1783            Self::RotateAroundCenter(item) => item.min_byte_range(),
1784            Self::VarRotateAroundCenter(item) => item.min_byte_range(),
1785            Self::Skew(item) => item.min_byte_range(),
1786            Self::VarSkew(item) => item.min_byte_range(),
1787            Self::SkewAroundCenter(item) => item.min_byte_range(),
1788            Self::VarSkewAroundCenter(item) => item.min_byte_range(),
1789            Self::Composite(item) => item.min_byte_range(),
1790        }
1791    }
1792    fn min_table_bytes(&self) -> &'a [u8] {
1793        match self {
1794            Self::ColrLayers(item) => item.min_table_bytes(),
1795            Self::Solid(item) => item.min_table_bytes(),
1796            Self::VarSolid(item) => item.min_table_bytes(),
1797            Self::LinearGradient(item) => item.min_table_bytes(),
1798            Self::VarLinearGradient(item) => item.min_table_bytes(),
1799            Self::RadialGradient(item) => item.min_table_bytes(),
1800            Self::VarRadialGradient(item) => item.min_table_bytes(),
1801            Self::SweepGradient(item) => item.min_table_bytes(),
1802            Self::VarSweepGradient(item) => item.min_table_bytes(),
1803            Self::Glyph(item) => item.min_table_bytes(),
1804            Self::ColrGlyph(item) => item.min_table_bytes(),
1805            Self::Transform(item) => item.min_table_bytes(),
1806            Self::VarTransform(item) => item.min_table_bytes(),
1807            Self::Translate(item) => item.min_table_bytes(),
1808            Self::VarTranslate(item) => item.min_table_bytes(),
1809            Self::Scale(item) => item.min_table_bytes(),
1810            Self::VarScale(item) => item.min_table_bytes(),
1811            Self::ScaleAroundCenter(item) => item.min_table_bytes(),
1812            Self::VarScaleAroundCenter(item) => item.min_table_bytes(),
1813            Self::ScaleUniform(item) => item.min_table_bytes(),
1814            Self::VarScaleUniform(item) => item.min_table_bytes(),
1815            Self::ScaleUniformAroundCenter(item) => item.min_table_bytes(),
1816            Self::VarScaleUniformAroundCenter(item) => item.min_table_bytes(),
1817            Self::Rotate(item) => item.min_table_bytes(),
1818            Self::VarRotate(item) => item.min_table_bytes(),
1819            Self::RotateAroundCenter(item) => item.min_table_bytes(),
1820            Self::VarRotateAroundCenter(item) => item.min_table_bytes(),
1821            Self::Skew(item) => item.min_table_bytes(),
1822            Self::VarSkew(item) => item.min_table_bytes(),
1823            Self::SkewAroundCenter(item) => item.min_table_bytes(),
1824            Self::VarSkewAroundCenter(item) => item.min_table_bytes(),
1825            Self::Composite(item) => item.min_table_bytes(),
1826        }
1827    }
1828}
1829
1830#[cfg(feature = "experimental_traverse")]
1831impl<'a> Paint<'a> {
1832    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
1833        match self {
1834            Self::ColrLayers(table) => table,
1835            Self::Solid(table) => table,
1836            Self::VarSolid(table) => table,
1837            Self::LinearGradient(table) => table,
1838            Self::VarLinearGradient(table) => table,
1839            Self::RadialGradient(table) => table,
1840            Self::VarRadialGradient(table) => table,
1841            Self::SweepGradient(table) => table,
1842            Self::VarSweepGradient(table) => table,
1843            Self::Glyph(table) => table,
1844            Self::ColrGlyph(table) => table,
1845            Self::Transform(table) => table,
1846            Self::VarTransform(table) => table,
1847            Self::Translate(table) => table,
1848            Self::VarTranslate(table) => table,
1849            Self::Scale(table) => table,
1850            Self::VarScale(table) => table,
1851            Self::ScaleAroundCenter(table) => table,
1852            Self::VarScaleAroundCenter(table) => table,
1853            Self::ScaleUniform(table) => table,
1854            Self::VarScaleUniform(table) => table,
1855            Self::ScaleUniformAroundCenter(table) => table,
1856            Self::VarScaleUniformAroundCenter(table) => table,
1857            Self::Rotate(table) => table,
1858            Self::VarRotate(table) => table,
1859            Self::RotateAroundCenter(table) => table,
1860            Self::VarRotateAroundCenter(table) => table,
1861            Self::Skew(table) => table,
1862            Self::VarSkew(table) => table,
1863            Self::SkewAroundCenter(table) => table,
1864            Self::VarSkewAroundCenter(table) => table,
1865            Self::Composite(table) => table,
1866        }
1867    }
1868}
1869
1870#[cfg(feature = "experimental_traverse")]
1871impl std::fmt::Debug for Paint<'_> {
1872    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1873        self.dyn_inner().fmt(f)
1874    }
1875}
1876
1877#[cfg(feature = "experimental_traverse")]
1878impl<'a> SomeTable<'a> for Paint<'a> {
1879    fn type_name(&self) -> &str {
1880        self.dyn_inner().type_name()
1881    }
1882    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1883        self.dyn_inner().get_field(idx)
1884    }
1885}
1886
1887impl Format<u8> for PaintColrLayers<'_> {
1888    const FORMAT: u8 = 1;
1889}
1890
1891impl<'a> MinByteRange<'a> for PaintColrLayers<'a> {
1892    fn min_byte_range(&self) -> Range<usize> {
1893        0..self.first_layer_index_byte_range().end
1894    }
1895    fn min_table_bytes(&self) -> &'a [u8] {
1896        let range = self.min_byte_range();
1897        self.data.as_bytes().get(range).unwrap_or_default()
1898    }
1899}
1900
1901impl<'a> FontRead<'a> for PaintColrLayers<'a> {
1902    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1903        #[allow(clippy::absurd_extreme_comparisons)]
1904        if data.len() < Self::MIN_SIZE {
1905            return Err(ReadError::OutOfBounds);
1906        }
1907        Ok(Self { data })
1908    }
1909}
1910
1911/// [PaintColrLayers](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#format-1-paintcolrlayers) table
1912#[derive(Clone)]
1913pub struct PaintColrLayers<'a> {
1914    data: FontData<'a>,
1915}
1916
1917#[allow(clippy::needless_lifetimes)]
1918impl<'a> PaintColrLayers<'a> {
1919    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN + u8::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
1920    basic_table_impls!(impl_the_methods);
1921
1922    /// Set to 1.
1923    pub fn format(&self) -> u8 {
1924        let range = self.format_byte_range();
1925        self.data.read_at(range.start).ok().unwrap()
1926    }
1927
1928    /// Number of offsets to paint tables to read from LayerList.
1929    pub fn num_layers(&self) -> u8 {
1930        let range = self.num_layers_byte_range();
1931        self.data.read_at(range.start).ok().unwrap()
1932    }
1933
1934    /// Index (base 0) into the LayerList.
1935    pub fn first_layer_index(&self) -> u32 {
1936        let range = self.first_layer_index_byte_range();
1937        self.data.read_at(range.start).ok().unwrap()
1938    }
1939
1940    pub fn format_byte_range(&self) -> Range<usize> {
1941        let start = 0;
1942        start..start + u8::RAW_BYTE_LEN
1943    }
1944
1945    pub fn num_layers_byte_range(&self) -> Range<usize> {
1946        let start = self.format_byte_range().end;
1947        start..start + u8::RAW_BYTE_LEN
1948    }
1949
1950    pub fn first_layer_index_byte_range(&self) -> Range<usize> {
1951        let start = self.num_layers_byte_range().end;
1952        start..start + u32::RAW_BYTE_LEN
1953    }
1954}
1955
1956#[cfg(feature = "experimental_traverse")]
1957impl<'a> SomeTable<'a> for PaintColrLayers<'a> {
1958    fn type_name(&self) -> &str {
1959        "PaintColrLayers"
1960    }
1961    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1962        match idx {
1963            0usize => Some(Field::new("format", self.format())),
1964            1usize => Some(Field::new("num_layers", self.num_layers())),
1965            2usize => Some(Field::new("first_layer_index", self.first_layer_index())),
1966            _ => None,
1967        }
1968    }
1969}
1970
1971#[cfg(feature = "experimental_traverse")]
1972#[allow(clippy::needless_lifetimes)]
1973impl<'a> std::fmt::Debug for PaintColrLayers<'a> {
1974    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1975        (self as &dyn SomeTable<'a>).fmt(f)
1976    }
1977}
1978
1979impl Format<u8> for PaintSolid<'_> {
1980    const FORMAT: u8 = 2;
1981}
1982
1983impl<'a> MinByteRange<'a> for PaintSolid<'a> {
1984    fn min_byte_range(&self) -> Range<usize> {
1985        0..self.alpha_byte_range().end
1986    }
1987    fn min_table_bytes(&self) -> &'a [u8] {
1988        let range = self.min_byte_range();
1989        self.data.as_bytes().get(range).unwrap_or_default()
1990    }
1991}
1992
1993impl<'a> FontRead<'a> for PaintSolid<'a> {
1994    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1995        #[allow(clippy::absurd_extreme_comparisons)]
1996        if data.len() < Self::MIN_SIZE {
1997            return Err(ReadError::OutOfBounds);
1998        }
1999        Ok(Self { data })
2000    }
2001}
2002
2003/// [PaintSolid](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-2-and-3-paintsolid-paintvarsolid) table
2004#[derive(Clone)]
2005pub struct PaintSolid<'a> {
2006    data: FontData<'a>,
2007}
2008
2009#[allow(clippy::needless_lifetimes)]
2010impl<'a> PaintSolid<'a> {
2011    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN);
2012    basic_table_impls!(impl_the_methods);
2013
2014    /// Set to 2.
2015    pub fn format(&self) -> u8 {
2016        let range = self.format_byte_range();
2017        self.data.read_at(range.start).ok().unwrap()
2018    }
2019
2020    /// Index for a CPAL palette entry.
2021    pub fn palette_index(&self) -> u16 {
2022        let range = self.palette_index_byte_range();
2023        self.data.read_at(range.start).ok().unwrap()
2024    }
2025
2026    /// Alpha value.
2027    pub fn alpha(&self) -> F2Dot14 {
2028        let range = self.alpha_byte_range();
2029        self.data.read_at(range.start).ok().unwrap()
2030    }
2031
2032    pub fn format_byte_range(&self) -> Range<usize> {
2033        let start = 0;
2034        start..start + u8::RAW_BYTE_LEN
2035    }
2036
2037    pub fn palette_index_byte_range(&self) -> Range<usize> {
2038        let start = self.format_byte_range().end;
2039        start..start + u16::RAW_BYTE_LEN
2040    }
2041
2042    pub fn alpha_byte_range(&self) -> Range<usize> {
2043        let start = self.palette_index_byte_range().end;
2044        start..start + F2Dot14::RAW_BYTE_LEN
2045    }
2046}
2047
2048#[cfg(feature = "experimental_traverse")]
2049impl<'a> SomeTable<'a> for PaintSolid<'a> {
2050    fn type_name(&self) -> &str {
2051        "PaintSolid"
2052    }
2053    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2054        match idx {
2055            0usize => Some(Field::new("format", self.format())),
2056            1usize => Some(Field::new("palette_index", self.palette_index())),
2057            2usize => Some(Field::new("alpha", self.alpha())),
2058            _ => None,
2059        }
2060    }
2061}
2062
2063#[cfg(feature = "experimental_traverse")]
2064#[allow(clippy::needless_lifetimes)]
2065impl<'a> std::fmt::Debug for PaintSolid<'a> {
2066    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2067        (self as &dyn SomeTable<'a>).fmt(f)
2068    }
2069}
2070
2071impl Format<u8> for PaintVarSolid<'_> {
2072    const FORMAT: u8 = 3;
2073}
2074
2075impl<'a> MinByteRange<'a> for PaintVarSolid<'a> {
2076    fn min_byte_range(&self) -> Range<usize> {
2077        0..self.var_index_base_byte_range().end
2078    }
2079    fn min_table_bytes(&self) -> &'a [u8] {
2080        let range = self.min_byte_range();
2081        self.data.as_bytes().get(range).unwrap_or_default()
2082    }
2083}
2084
2085impl<'a> FontRead<'a> for PaintVarSolid<'a> {
2086    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2087        #[allow(clippy::absurd_extreme_comparisons)]
2088        if data.len() < Self::MIN_SIZE {
2089            return Err(ReadError::OutOfBounds);
2090        }
2091        Ok(Self { data })
2092    }
2093}
2094
2095/// [PaintVarSolid](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-2-and-3-paintsolid-paintvarsolid) table
2096#[derive(Clone)]
2097pub struct PaintVarSolid<'a> {
2098    data: FontData<'a>,
2099}
2100
2101#[allow(clippy::needless_lifetimes)]
2102impl<'a> PaintVarSolid<'a> {
2103    pub const MIN_SIZE: usize =
2104        (u8::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
2105    basic_table_impls!(impl_the_methods);
2106
2107    /// Set to 3.
2108    pub fn format(&self) -> u8 {
2109        let range = self.format_byte_range();
2110        self.data.read_at(range.start).ok().unwrap()
2111    }
2112
2113    /// Index for a CPAL palette entry.
2114    pub fn palette_index(&self) -> u16 {
2115        let range = self.palette_index_byte_range();
2116        self.data.read_at(range.start).ok().unwrap()
2117    }
2118
2119    /// Alpha value. For variation, use varIndexBase + 0.
2120    pub fn alpha(&self) -> F2Dot14 {
2121        let range = self.alpha_byte_range();
2122        self.data.read_at(range.start).ok().unwrap()
2123    }
2124
2125    /// Base index into DeltaSetIndexMap.
2126    pub fn var_index_base(&self) -> u32 {
2127        let range = self.var_index_base_byte_range();
2128        self.data.read_at(range.start).ok().unwrap()
2129    }
2130
2131    pub fn format_byte_range(&self) -> Range<usize> {
2132        let start = 0;
2133        start..start + u8::RAW_BYTE_LEN
2134    }
2135
2136    pub fn palette_index_byte_range(&self) -> Range<usize> {
2137        let start = self.format_byte_range().end;
2138        start..start + u16::RAW_BYTE_LEN
2139    }
2140
2141    pub fn alpha_byte_range(&self) -> Range<usize> {
2142        let start = self.palette_index_byte_range().end;
2143        start..start + F2Dot14::RAW_BYTE_LEN
2144    }
2145
2146    pub fn var_index_base_byte_range(&self) -> Range<usize> {
2147        let start = self.alpha_byte_range().end;
2148        start..start + u32::RAW_BYTE_LEN
2149    }
2150}
2151
2152#[cfg(feature = "experimental_traverse")]
2153impl<'a> SomeTable<'a> for PaintVarSolid<'a> {
2154    fn type_name(&self) -> &str {
2155        "PaintVarSolid"
2156    }
2157    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2158        match idx {
2159            0usize => Some(Field::new("format", self.format())),
2160            1usize => Some(Field::new("palette_index", self.palette_index())),
2161            2usize => Some(Field::new("alpha", self.alpha())),
2162            3usize => Some(Field::new("var_index_base", self.var_index_base())),
2163            _ => None,
2164        }
2165    }
2166}
2167
2168#[cfg(feature = "experimental_traverse")]
2169#[allow(clippy::needless_lifetimes)]
2170impl<'a> std::fmt::Debug for PaintVarSolid<'a> {
2171    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2172        (self as &dyn SomeTable<'a>).fmt(f)
2173    }
2174}
2175
2176impl Format<u8> for PaintLinearGradient<'_> {
2177    const FORMAT: u8 = 4;
2178}
2179
2180impl<'a> MinByteRange<'a> for PaintLinearGradient<'a> {
2181    fn min_byte_range(&self) -> Range<usize> {
2182        0..self.y2_byte_range().end
2183    }
2184    fn min_table_bytes(&self) -> &'a [u8] {
2185        let range = self.min_byte_range();
2186        self.data.as_bytes().get(range).unwrap_or_default()
2187    }
2188}
2189
2190impl<'a> FontRead<'a> for PaintLinearGradient<'a> {
2191    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2192        #[allow(clippy::absurd_extreme_comparisons)]
2193        if data.len() < Self::MIN_SIZE {
2194            return Err(ReadError::OutOfBounds);
2195        }
2196        Ok(Self { data })
2197    }
2198}
2199
2200/// [PaintLinearGradient](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-4-and-5-paintlineargradient-paintvarlineargradient) table
2201#[derive(Clone)]
2202pub struct PaintLinearGradient<'a> {
2203    data: FontData<'a>,
2204}
2205
2206#[allow(clippy::needless_lifetimes)]
2207impl<'a> PaintLinearGradient<'a> {
2208    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN
2209        + Offset24::RAW_BYTE_LEN
2210        + FWord::RAW_BYTE_LEN
2211        + FWord::RAW_BYTE_LEN
2212        + FWord::RAW_BYTE_LEN
2213        + FWord::RAW_BYTE_LEN
2214        + FWord::RAW_BYTE_LEN
2215        + FWord::RAW_BYTE_LEN);
2216    basic_table_impls!(impl_the_methods);
2217
2218    /// Set to 4.
2219    pub fn format(&self) -> u8 {
2220        let range = self.format_byte_range();
2221        self.data.read_at(range.start).ok().unwrap()
2222    }
2223
2224    /// Offset to ColorLine table.
2225    pub fn color_line_offset(&self) -> Offset24 {
2226        let range = self.color_line_offset_byte_range();
2227        self.data.read_at(range.start).ok().unwrap()
2228    }
2229
2230    /// Attempt to resolve [`color_line_offset`][Self::color_line_offset].
2231    pub fn color_line(&self) -> Result<ColorLine<'a>, ReadError> {
2232        let data = self.data;
2233        self.color_line_offset().resolve(data)
2234    }
2235
2236    /// Start point (p₀) x coordinate.
2237    pub fn x0(&self) -> FWord {
2238        let range = self.x0_byte_range();
2239        self.data.read_at(range.start).ok().unwrap()
2240    }
2241
2242    /// Start point (p₀) y coordinate.
2243    pub fn y0(&self) -> FWord {
2244        let range = self.y0_byte_range();
2245        self.data.read_at(range.start).ok().unwrap()
2246    }
2247
2248    /// End point (p₁) x coordinate.
2249    pub fn x1(&self) -> FWord {
2250        let range = self.x1_byte_range();
2251        self.data.read_at(range.start).ok().unwrap()
2252    }
2253
2254    /// End point (p₁) y coordinate.
2255    pub fn y1(&self) -> FWord {
2256        let range = self.y1_byte_range();
2257        self.data.read_at(range.start).ok().unwrap()
2258    }
2259
2260    /// Rotation point (p₂) x coordinate.
2261    pub fn x2(&self) -> FWord {
2262        let range = self.x2_byte_range();
2263        self.data.read_at(range.start).ok().unwrap()
2264    }
2265
2266    /// Rotation point (p₂) y coordinate.
2267    pub fn y2(&self) -> FWord {
2268        let range = self.y2_byte_range();
2269        self.data.read_at(range.start).ok().unwrap()
2270    }
2271
2272    pub fn format_byte_range(&self) -> Range<usize> {
2273        let start = 0;
2274        start..start + u8::RAW_BYTE_LEN
2275    }
2276
2277    pub fn color_line_offset_byte_range(&self) -> Range<usize> {
2278        let start = self.format_byte_range().end;
2279        start..start + Offset24::RAW_BYTE_LEN
2280    }
2281
2282    pub fn x0_byte_range(&self) -> Range<usize> {
2283        let start = self.color_line_offset_byte_range().end;
2284        start..start + FWord::RAW_BYTE_LEN
2285    }
2286
2287    pub fn y0_byte_range(&self) -> Range<usize> {
2288        let start = self.x0_byte_range().end;
2289        start..start + FWord::RAW_BYTE_LEN
2290    }
2291
2292    pub fn x1_byte_range(&self) -> Range<usize> {
2293        let start = self.y0_byte_range().end;
2294        start..start + FWord::RAW_BYTE_LEN
2295    }
2296
2297    pub fn y1_byte_range(&self) -> Range<usize> {
2298        let start = self.x1_byte_range().end;
2299        start..start + FWord::RAW_BYTE_LEN
2300    }
2301
2302    pub fn x2_byte_range(&self) -> Range<usize> {
2303        let start = self.y1_byte_range().end;
2304        start..start + FWord::RAW_BYTE_LEN
2305    }
2306
2307    pub fn y2_byte_range(&self) -> Range<usize> {
2308        let start = self.x2_byte_range().end;
2309        start..start + FWord::RAW_BYTE_LEN
2310    }
2311}
2312
2313#[cfg(feature = "experimental_traverse")]
2314impl<'a> SomeTable<'a> for PaintLinearGradient<'a> {
2315    fn type_name(&self) -> &str {
2316        "PaintLinearGradient"
2317    }
2318    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2319        match idx {
2320            0usize => Some(Field::new("format", self.format())),
2321            1usize => Some(Field::new(
2322                "color_line_offset",
2323                FieldType::offset(self.color_line_offset(), self.color_line()),
2324            )),
2325            2usize => Some(Field::new("x0", self.x0())),
2326            3usize => Some(Field::new("y0", self.y0())),
2327            4usize => Some(Field::new("x1", self.x1())),
2328            5usize => Some(Field::new("y1", self.y1())),
2329            6usize => Some(Field::new("x2", self.x2())),
2330            7usize => Some(Field::new("y2", self.y2())),
2331            _ => None,
2332        }
2333    }
2334}
2335
2336#[cfg(feature = "experimental_traverse")]
2337#[allow(clippy::needless_lifetimes)]
2338impl<'a> std::fmt::Debug for PaintLinearGradient<'a> {
2339    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2340        (self as &dyn SomeTable<'a>).fmt(f)
2341    }
2342}
2343
2344impl Format<u8> for PaintVarLinearGradient<'_> {
2345    const FORMAT: u8 = 5;
2346}
2347
2348impl<'a> MinByteRange<'a> for PaintVarLinearGradient<'a> {
2349    fn min_byte_range(&self) -> Range<usize> {
2350        0..self.var_index_base_byte_range().end
2351    }
2352    fn min_table_bytes(&self) -> &'a [u8] {
2353        let range = self.min_byte_range();
2354        self.data.as_bytes().get(range).unwrap_or_default()
2355    }
2356}
2357
2358impl<'a> FontRead<'a> for PaintVarLinearGradient<'a> {
2359    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2360        #[allow(clippy::absurd_extreme_comparisons)]
2361        if data.len() < Self::MIN_SIZE {
2362            return Err(ReadError::OutOfBounds);
2363        }
2364        Ok(Self { data })
2365    }
2366}
2367
2368/// [PaintVarLinearGradient](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-4-and-5-paintlineargradient-paintvarlineargradient) table
2369#[derive(Clone)]
2370pub struct PaintVarLinearGradient<'a> {
2371    data: FontData<'a>,
2372}
2373
2374#[allow(clippy::needless_lifetimes)]
2375impl<'a> PaintVarLinearGradient<'a> {
2376    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN
2377        + Offset24::RAW_BYTE_LEN
2378        + FWord::RAW_BYTE_LEN
2379        + FWord::RAW_BYTE_LEN
2380        + FWord::RAW_BYTE_LEN
2381        + FWord::RAW_BYTE_LEN
2382        + FWord::RAW_BYTE_LEN
2383        + FWord::RAW_BYTE_LEN
2384        + u32::RAW_BYTE_LEN);
2385    basic_table_impls!(impl_the_methods);
2386
2387    /// Set to 5.
2388    pub fn format(&self) -> u8 {
2389        let range = self.format_byte_range();
2390        self.data.read_at(range.start).ok().unwrap()
2391    }
2392
2393    /// Offset to VarColorLine table.
2394    pub fn color_line_offset(&self) -> Offset24 {
2395        let range = self.color_line_offset_byte_range();
2396        self.data.read_at(range.start).ok().unwrap()
2397    }
2398
2399    /// Attempt to resolve [`color_line_offset`][Self::color_line_offset].
2400    pub fn color_line(&self) -> Result<VarColorLine<'a>, ReadError> {
2401        let data = self.data;
2402        self.color_line_offset().resolve(data)
2403    }
2404
2405    /// Start point (p₀) x coordinate. For variation, use
2406    /// varIndexBase + 0.
2407    pub fn x0(&self) -> FWord {
2408        let range = self.x0_byte_range();
2409        self.data.read_at(range.start).ok().unwrap()
2410    }
2411
2412    /// Start point (p₀) y coordinate. For variation, use
2413    /// varIndexBase + 1.
2414    pub fn y0(&self) -> FWord {
2415        let range = self.y0_byte_range();
2416        self.data.read_at(range.start).ok().unwrap()
2417    }
2418
2419    /// End point (p₁) x coordinate. For variation, use varIndexBase
2420    /// + 2.
2421    pub fn x1(&self) -> FWord {
2422        let range = self.x1_byte_range();
2423        self.data.read_at(range.start).ok().unwrap()
2424    }
2425
2426    /// End point (p₁) y coordinate. For variation, use varIndexBase
2427    /// + 3.
2428    pub fn y1(&self) -> FWord {
2429        let range = self.y1_byte_range();
2430        self.data.read_at(range.start).ok().unwrap()
2431    }
2432
2433    /// Rotation point (p₂) x coordinate. For variation, use
2434    /// varIndexBase + 4.
2435    pub fn x2(&self) -> FWord {
2436        let range = self.x2_byte_range();
2437        self.data.read_at(range.start).ok().unwrap()
2438    }
2439
2440    /// Rotation point (p₂) y coordinate. For variation, use
2441    /// varIndexBase + 5.
2442    pub fn y2(&self) -> FWord {
2443        let range = self.y2_byte_range();
2444        self.data.read_at(range.start).ok().unwrap()
2445    }
2446
2447    /// Base index into DeltaSetIndexMap.
2448    pub fn var_index_base(&self) -> u32 {
2449        let range = self.var_index_base_byte_range();
2450        self.data.read_at(range.start).ok().unwrap()
2451    }
2452
2453    pub fn format_byte_range(&self) -> Range<usize> {
2454        let start = 0;
2455        start..start + u8::RAW_BYTE_LEN
2456    }
2457
2458    pub fn color_line_offset_byte_range(&self) -> Range<usize> {
2459        let start = self.format_byte_range().end;
2460        start..start + Offset24::RAW_BYTE_LEN
2461    }
2462
2463    pub fn x0_byte_range(&self) -> Range<usize> {
2464        let start = self.color_line_offset_byte_range().end;
2465        start..start + FWord::RAW_BYTE_LEN
2466    }
2467
2468    pub fn y0_byte_range(&self) -> Range<usize> {
2469        let start = self.x0_byte_range().end;
2470        start..start + FWord::RAW_BYTE_LEN
2471    }
2472
2473    pub fn x1_byte_range(&self) -> Range<usize> {
2474        let start = self.y0_byte_range().end;
2475        start..start + FWord::RAW_BYTE_LEN
2476    }
2477
2478    pub fn y1_byte_range(&self) -> Range<usize> {
2479        let start = self.x1_byte_range().end;
2480        start..start + FWord::RAW_BYTE_LEN
2481    }
2482
2483    pub fn x2_byte_range(&self) -> Range<usize> {
2484        let start = self.y1_byte_range().end;
2485        start..start + FWord::RAW_BYTE_LEN
2486    }
2487
2488    pub fn y2_byte_range(&self) -> Range<usize> {
2489        let start = self.x2_byte_range().end;
2490        start..start + FWord::RAW_BYTE_LEN
2491    }
2492
2493    pub fn var_index_base_byte_range(&self) -> Range<usize> {
2494        let start = self.y2_byte_range().end;
2495        start..start + u32::RAW_BYTE_LEN
2496    }
2497}
2498
2499#[cfg(feature = "experimental_traverse")]
2500impl<'a> SomeTable<'a> for PaintVarLinearGradient<'a> {
2501    fn type_name(&self) -> &str {
2502        "PaintVarLinearGradient"
2503    }
2504    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2505        match idx {
2506            0usize => Some(Field::new("format", self.format())),
2507            1usize => Some(Field::new(
2508                "color_line_offset",
2509                FieldType::offset(self.color_line_offset(), self.color_line()),
2510            )),
2511            2usize => Some(Field::new("x0", self.x0())),
2512            3usize => Some(Field::new("y0", self.y0())),
2513            4usize => Some(Field::new("x1", self.x1())),
2514            5usize => Some(Field::new("y1", self.y1())),
2515            6usize => Some(Field::new("x2", self.x2())),
2516            7usize => Some(Field::new("y2", self.y2())),
2517            8usize => Some(Field::new("var_index_base", self.var_index_base())),
2518            _ => None,
2519        }
2520    }
2521}
2522
2523#[cfg(feature = "experimental_traverse")]
2524#[allow(clippy::needless_lifetimes)]
2525impl<'a> std::fmt::Debug for PaintVarLinearGradient<'a> {
2526    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2527        (self as &dyn SomeTable<'a>).fmt(f)
2528    }
2529}
2530
2531impl Format<u8> for PaintRadialGradient<'_> {
2532    const FORMAT: u8 = 6;
2533}
2534
2535impl<'a> MinByteRange<'a> for PaintRadialGradient<'a> {
2536    fn min_byte_range(&self) -> Range<usize> {
2537        0..self.radius1_byte_range().end
2538    }
2539    fn min_table_bytes(&self) -> &'a [u8] {
2540        let range = self.min_byte_range();
2541        self.data.as_bytes().get(range).unwrap_or_default()
2542    }
2543}
2544
2545impl<'a> FontRead<'a> for PaintRadialGradient<'a> {
2546    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2547        #[allow(clippy::absurd_extreme_comparisons)]
2548        if data.len() < Self::MIN_SIZE {
2549            return Err(ReadError::OutOfBounds);
2550        }
2551        Ok(Self { data })
2552    }
2553}
2554
2555/// [PaintRadialGradient](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-6-and-7-paintradialgradient-paintvarradialgradient) table
2556#[derive(Clone)]
2557pub struct PaintRadialGradient<'a> {
2558    data: FontData<'a>,
2559}
2560
2561#[allow(clippy::needless_lifetimes)]
2562impl<'a> PaintRadialGradient<'a> {
2563    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN
2564        + Offset24::RAW_BYTE_LEN
2565        + FWord::RAW_BYTE_LEN
2566        + FWord::RAW_BYTE_LEN
2567        + UfWord::RAW_BYTE_LEN
2568        + FWord::RAW_BYTE_LEN
2569        + FWord::RAW_BYTE_LEN
2570        + UfWord::RAW_BYTE_LEN);
2571    basic_table_impls!(impl_the_methods);
2572
2573    /// Set to 6.
2574    pub fn format(&self) -> u8 {
2575        let range = self.format_byte_range();
2576        self.data.read_at(range.start).ok().unwrap()
2577    }
2578
2579    /// Offset to ColorLine table.
2580    pub fn color_line_offset(&self) -> Offset24 {
2581        let range = self.color_line_offset_byte_range();
2582        self.data.read_at(range.start).ok().unwrap()
2583    }
2584
2585    /// Attempt to resolve [`color_line_offset`][Self::color_line_offset].
2586    pub fn color_line(&self) -> Result<ColorLine<'a>, ReadError> {
2587        let data = self.data;
2588        self.color_line_offset().resolve(data)
2589    }
2590
2591    /// Start circle center x coordinate.
2592    pub fn x0(&self) -> FWord {
2593        let range = self.x0_byte_range();
2594        self.data.read_at(range.start).ok().unwrap()
2595    }
2596
2597    /// Start circle center y coordinate.
2598    pub fn y0(&self) -> FWord {
2599        let range = self.y0_byte_range();
2600        self.data.read_at(range.start).ok().unwrap()
2601    }
2602
2603    /// Start circle radius.
2604    pub fn radius0(&self) -> UfWord {
2605        let range = self.radius0_byte_range();
2606        self.data.read_at(range.start).ok().unwrap()
2607    }
2608
2609    /// End circle center x coordinate.
2610    pub fn x1(&self) -> FWord {
2611        let range = self.x1_byte_range();
2612        self.data.read_at(range.start).ok().unwrap()
2613    }
2614
2615    /// End circle center y coordinate.
2616    pub fn y1(&self) -> FWord {
2617        let range = self.y1_byte_range();
2618        self.data.read_at(range.start).ok().unwrap()
2619    }
2620
2621    /// End circle radius.
2622    pub fn radius1(&self) -> UfWord {
2623        let range = self.radius1_byte_range();
2624        self.data.read_at(range.start).ok().unwrap()
2625    }
2626
2627    pub fn format_byte_range(&self) -> Range<usize> {
2628        let start = 0;
2629        start..start + u8::RAW_BYTE_LEN
2630    }
2631
2632    pub fn color_line_offset_byte_range(&self) -> Range<usize> {
2633        let start = self.format_byte_range().end;
2634        start..start + Offset24::RAW_BYTE_LEN
2635    }
2636
2637    pub fn x0_byte_range(&self) -> Range<usize> {
2638        let start = self.color_line_offset_byte_range().end;
2639        start..start + FWord::RAW_BYTE_LEN
2640    }
2641
2642    pub fn y0_byte_range(&self) -> Range<usize> {
2643        let start = self.x0_byte_range().end;
2644        start..start + FWord::RAW_BYTE_LEN
2645    }
2646
2647    pub fn radius0_byte_range(&self) -> Range<usize> {
2648        let start = self.y0_byte_range().end;
2649        start..start + UfWord::RAW_BYTE_LEN
2650    }
2651
2652    pub fn x1_byte_range(&self) -> Range<usize> {
2653        let start = self.radius0_byte_range().end;
2654        start..start + FWord::RAW_BYTE_LEN
2655    }
2656
2657    pub fn y1_byte_range(&self) -> Range<usize> {
2658        let start = self.x1_byte_range().end;
2659        start..start + FWord::RAW_BYTE_LEN
2660    }
2661
2662    pub fn radius1_byte_range(&self) -> Range<usize> {
2663        let start = self.y1_byte_range().end;
2664        start..start + UfWord::RAW_BYTE_LEN
2665    }
2666}
2667
2668#[cfg(feature = "experimental_traverse")]
2669impl<'a> SomeTable<'a> for PaintRadialGradient<'a> {
2670    fn type_name(&self) -> &str {
2671        "PaintRadialGradient"
2672    }
2673    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2674        match idx {
2675            0usize => Some(Field::new("format", self.format())),
2676            1usize => Some(Field::new(
2677                "color_line_offset",
2678                FieldType::offset(self.color_line_offset(), self.color_line()),
2679            )),
2680            2usize => Some(Field::new("x0", self.x0())),
2681            3usize => Some(Field::new("y0", self.y0())),
2682            4usize => Some(Field::new("radius0", self.radius0())),
2683            5usize => Some(Field::new("x1", self.x1())),
2684            6usize => Some(Field::new("y1", self.y1())),
2685            7usize => Some(Field::new("radius1", self.radius1())),
2686            _ => None,
2687        }
2688    }
2689}
2690
2691#[cfg(feature = "experimental_traverse")]
2692#[allow(clippy::needless_lifetimes)]
2693impl<'a> std::fmt::Debug for PaintRadialGradient<'a> {
2694    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2695        (self as &dyn SomeTable<'a>).fmt(f)
2696    }
2697}
2698
2699impl Format<u8> for PaintVarRadialGradient<'_> {
2700    const FORMAT: u8 = 7;
2701}
2702
2703impl<'a> MinByteRange<'a> for PaintVarRadialGradient<'a> {
2704    fn min_byte_range(&self) -> Range<usize> {
2705        0..self.var_index_base_byte_range().end
2706    }
2707    fn min_table_bytes(&self) -> &'a [u8] {
2708        let range = self.min_byte_range();
2709        self.data.as_bytes().get(range).unwrap_or_default()
2710    }
2711}
2712
2713impl<'a> FontRead<'a> for PaintVarRadialGradient<'a> {
2714    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2715        #[allow(clippy::absurd_extreme_comparisons)]
2716        if data.len() < Self::MIN_SIZE {
2717            return Err(ReadError::OutOfBounds);
2718        }
2719        Ok(Self { data })
2720    }
2721}
2722
2723/// [PaintVarRadialGradient](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-6-and-7-paintradialgradient-paintvarradialgradient) table
2724#[derive(Clone)]
2725pub struct PaintVarRadialGradient<'a> {
2726    data: FontData<'a>,
2727}
2728
2729#[allow(clippy::needless_lifetimes)]
2730impl<'a> PaintVarRadialGradient<'a> {
2731    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN
2732        + Offset24::RAW_BYTE_LEN
2733        + FWord::RAW_BYTE_LEN
2734        + FWord::RAW_BYTE_LEN
2735        + UfWord::RAW_BYTE_LEN
2736        + FWord::RAW_BYTE_LEN
2737        + FWord::RAW_BYTE_LEN
2738        + UfWord::RAW_BYTE_LEN
2739        + u32::RAW_BYTE_LEN);
2740    basic_table_impls!(impl_the_methods);
2741
2742    /// Set to 7.
2743    pub fn format(&self) -> u8 {
2744        let range = self.format_byte_range();
2745        self.data.read_at(range.start).ok().unwrap()
2746    }
2747
2748    /// Offset to VarColorLine table.
2749    pub fn color_line_offset(&self) -> Offset24 {
2750        let range = self.color_line_offset_byte_range();
2751        self.data.read_at(range.start).ok().unwrap()
2752    }
2753
2754    /// Attempt to resolve [`color_line_offset`][Self::color_line_offset].
2755    pub fn color_line(&self) -> Result<VarColorLine<'a>, ReadError> {
2756        let data = self.data;
2757        self.color_line_offset().resolve(data)
2758    }
2759
2760    /// Start circle center x coordinate. For variation, use
2761    /// varIndexBase + 0.
2762    pub fn x0(&self) -> FWord {
2763        let range = self.x0_byte_range();
2764        self.data.read_at(range.start).ok().unwrap()
2765    }
2766
2767    /// Start circle center y coordinate. For variation, use
2768    /// varIndexBase + 1.
2769    pub fn y0(&self) -> FWord {
2770        let range = self.y0_byte_range();
2771        self.data.read_at(range.start).ok().unwrap()
2772    }
2773
2774    /// Start circle radius. For variation, use varIndexBase + 2.
2775    pub fn radius0(&self) -> UfWord {
2776        let range = self.radius0_byte_range();
2777        self.data.read_at(range.start).ok().unwrap()
2778    }
2779
2780    /// End circle center x coordinate. For variation, use varIndexBase
2781    /// + 3.
2782    pub fn x1(&self) -> FWord {
2783        let range = self.x1_byte_range();
2784        self.data.read_at(range.start).ok().unwrap()
2785    }
2786
2787    /// End circle center y coordinate. For variation, use varIndexBase
2788    /// + 4.
2789    pub fn y1(&self) -> FWord {
2790        let range = self.y1_byte_range();
2791        self.data.read_at(range.start).ok().unwrap()
2792    }
2793
2794    /// End circle radius. For variation, use varIndexBase + 5.
2795    pub fn radius1(&self) -> UfWord {
2796        let range = self.radius1_byte_range();
2797        self.data.read_at(range.start).ok().unwrap()
2798    }
2799
2800    /// Base index into DeltaSetIndexMap.
2801    pub fn var_index_base(&self) -> u32 {
2802        let range = self.var_index_base_byte_range();
2803        self.data.read_at(range.start).ok().unwrap()
2804    }
2805
2806    pub fn format_byte_range(&self) -> Range<usize> {
2807        let start = 0;
2808        start..start + u8::RAW_BYTE_LEN
2809    }
2810
2811    pub fn color_line_offset_byte_range(&self) -> Range<usize> {
2812        let start = self.format_byte_range().end;
2813        start..start + Offset24::RAW_BYTE_LEN
2814    }
2815
2816    pub fn x0_byte_range(&self) -> Range<usize> {
2817        let start = self.color_line_offset_byte_range().end;
2818        start..start + FWord::RAW_BYTE_LEN
2819    }
2820
2821    pub fn y0_byte_range(&self) -> Range<usize> {
2822        let start = self.x0_byte_range().end;
2823        start..start + FWord::RAW_BYTE_LEN
2824    }
2825
2826    pub fn radius0_byte_range(&self) -> Range<usize> {
2827        let start = self.y0_byte_range().end;
2828        start..start + UfWord::RAW_BYTE_LEN
2829    }
2830
2831    pub fn x1_byte_range(&self) -> Range<usize> {
2832        let start = self.radius0_byte_range().end;
2833        start..start + FWord::RAW_BYTE_LEN
2834    }
2835
2836    pub fn y1_byte_range(&self) -> Range<usize> {
2837        let start = self.x1_byte_range().end;
2838        start..start + FWord::RAW_BYTE_LEN
2839    }
2840
2841    pub fn radius1_byte_range(&self) -> Range<usize> {
2842        let start = self.y1_byte_range().end;
2843        start..start + UfWord::RAW_BYTE_LEN
2844    }
2845
2846    pub fn var_index_base_byte_range(&self) -> Range<usize> {
2847        let start = self.radius1_byte_range().end;
2848        start..start + u32::RAW_BYTE_LEN
2849    }
2850}
2851
2852#[cfg(feature = "experimental_traverse")]
2853impl<'a> SomeTable<'a> for PaintVarRadialGradient<'a> {
2854    fn type_name(&self) -> &str {
2855        "PaintVarRadialGradient"
2856    }
2857    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2858        match idx {
2859            0usize => Some(Field::new("format", self.format())),
2860            1usize => Some(Field::new(
2861                "color_line_offset",
2862                FieldType::offset(self.color_line_offset(), self.color_line()),
2863            )),
2864            2usize => Some(Field::new("x0", self.x0())),
2865            3usize => Some(Field::new("y0", self.y0())),
2866            4usize => Some(Field::new("radius0", self.radius0())),
2867            5usize => Some(Field::new("x1", self.x1())),
2868            6usize => Some(Field::new("y1", self.y1())),
2869            7usize => Some(Field::new("radius1", self.radius1())),
2870            8usize => Some(Field::new("var_index_base", self.var_index_base())),
2871            _ => None,
2872        }
2873    }
2874}
2875
2876#[cfg(feature = "experimental_traverse")]
2877#[allow(clippy::needless_lifetimes)]
2878impl<'a> std::fmt::Debug for PaintVarRadialGradient<'a> {
2879    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2880        (self as &dyn SomeTable<'a>).fmt(f)
2881    }
2882}
2883
2884impl Format<u8> for PaintSweepGradient<'_> {
2885    const FORMAT: u8 = 8;
2886}
2887
2888impl<'a> MinByteRange<'a> for PaintSweepGradient<'a> {
2889    fn min_byte_range(&self) -> Range<usize> {
2890        0..self.end_angle_byte_range().end
2891    }
2892    fn min_table_bytes(&self) -> &'a [u8] {
2893        let range = self.min_byte_range();
2894        self.data.as_bytes().get(range).unwrap_or_default()
2895    }
2896}
2897
2898impl<'a> FontRead<'a> for PaintSweepGradient<'a> {
2899    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2900        #[allow(clippy::absurd_extreme_comparisons)]
2901        if data.len() < Self::MIN_SIZE {
2902            return Err(ReadError::OutOfBounds);
2903        }
2904        Ok(Self { data })
2905    }
2906}
2907
2908/// [PaintSweepGradient](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-8-and-9-paintsweepgradient-paintvarsweepgradient) table
2909#[derive(Clone)]
2910pub struct PaintSweepGradient<'a> {
2911    data: FontData<'a>,
2912}
2913
2914#[allow(clippy::needless_lifetimes)]
2915impl<'a> PaintSweepGradient<'a> {
2916    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN
2917        + Offset24::RAW_BYTE_LEN
2918        + FWord::RAW_BYTE_LEN
2919        + FWord::RAW_BYTE_LEN
2920        + F2Dot14::RAW_BYTE_LEN
2921        + F2Dot14::RAW_BYTE_LEN);
2922    basic_table_impls!(impl_the_methods);
2923
2924    /// Set to 8.
2925    pub fn format(&self) -> u8 {
2926        let range = self.format_byte_range();
2927        self.data.read_at(range.start).ok().unwrap()
2928    }
2929
2930    /// Offset to ColorLine table.
2931    pub fn color_line_offset(&self) -> Offset24 {
2932        let range = self.color_line_offset_byte_range();
2933        self.data.read_at(range.start).ok().unwrap()
2934    }
2935
2936    /// Attempt to resolve [`color_line_offset`][Self::color_line_offset].
2937    pub fn color_line(&self) -> Result<ColorLine<'a>, ReadError> {
2938        let data = self.data;
2939        self.color_line_offset().resolve(data)
2940    }
2941
2942    /// Center x coordinate.
2943    pub fn center_x(&self) -> FWord {
2944        let range = self.center_x_byte_range();
2945        self.data.read_at(range.start).ok().unwrap()
2946    }
2947
2948    /// Center y coordinate.
2949    pub fn center_y(&self) -> FWord {
2950        let range = self.center_y_byte_range();
2951        self.data.read_at(range.start).ok().unwrap()
2952    }
2953
2954    /// Start of the angular range of the gradient, 180° in
2955    /// counter-clockwise degrees per 1.0 of value.
2956    pub fn start_angle(&self) -> F2Dot14 {
2957        let range = self.start_angle_byte_range();
2958        self.data.read_at(range.start).ok().unwrap()
2959    }
2960
2961    /// End of the angular range of the gradient, 180° in
2962    /// counter-clockwise degrees per 1.0 of value.
2963    pub fn end_angle(&self) -> F2Dot14 {
2964        let range = self.end_angle_byte_range();
2965        self.data.read_at(range.start).ok().unwrap()
2966    }
2967
2968    pub fn format_byte_range(&self) -> Range<usize> {
2969        let start = 0;
2970        start..start + u8::RAW_BYTE_LEN
2971    }
2972
2973    pub fn color_line_offset_byte_range(&self) -> Range<usize> {
2974        let start = self.format_byte_range().end;
2975        start..start + Offset24::RAW_BYTE_LEN
2976    }
2977
2978    pub fn center_x_byte_range(&self) -> Range<usize> {
2979        let start = self.color_line_offset_byte_range().end;
2980        start..start + FWord::RAW_BYTE_LEN
2981    }
2982
2983    pub fn center_y_byte_range(&self) -> Range<usize> {
2984        let start = self.center_x_byte_range().end;
2985        start..start + FWord::RAW_BYTE_LEN
2986    }
2987
2988    pub fn start_angle_byte_range(&self) -> Range<usize> {
2989        let start = self.center_y_byte_range().end;
2990        start..start + F2Dot14::RAW_BYTE_LEN
2991    }
2992
2993    pub fn end_angle_byte_range(&self) -> Range<usize> {
2994        let start = self.start_angle_byte_range().end;
2995        start..start + F2Dot14::RAW_BYTE_LEN
2996    }
2997}
2998
2999#[cfg(feature = "experimental_traverse")]
3000impl<'a> SomeTable<'a> for PaintSweepGradient<'a> {
3001    fn type_name(&self) -> &str {
3002        "PaintSweepGradient"
3003    }
3004    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3005        match idx {
3006            0usize => Some(Field::new("format", self.format())),
3007            1usize => Some(Field::new(
3008                "color_line_offset",
3009                FieldType::offset(self.color_line_offset(), self.color_line()),
3010            )),
3011            2usize => Some(Field::new("center_x", self.center_x())),
3012            3usize => Some(Field::new("center_y", self.center_y())),
3013            4usize => Some(Field::new("start_angle", self.start_angle())),
3014            5usize => Some(Field::new("end_angle", self.end_angle())),
3015            _ => None,
3016        }
3017    }
3018}
3019
3020#[cfg(feature = "experimental_traverse")]
3021#[allow(clippy::needless_lifetimes)]
3022impl<'a> std::fmt::Debug for PaintSweepGradient<'a> {
3023    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3024        (self as &dyn SomeTable<'a>).fmt(f)
3025    }
3026}
3027
3028impl Format<u8> for PaintVarSweepGradient<'_> {
3029    const FORMAT: u8 = 9;
3030}
3031
3032impl<'a> MinByteRange<'a> for PaintVarSweepGradient<'a> {
3033    fn min_byte_range(&self) -> Range<usize> {
3034        0..self.var_index_base_byte_range().end
3035    }
3036    fn min_table_bytes(&self) -> &'a [u8] {
3037        let range = self.min_byte_range();
3038        self.data.as_bytes().get(range).unwrap_or_default()
3039    }
3040}
3041
3042impl<'a> FontRead<'a> for PaintVarSweepGradient<'a> {
3043    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3044        #[allow(clippy::absurd_extreme_comparisons)]
3045        if data.len() < Self::MIN_SIZE {
3046            return Err(ReadError::OutOfBounds);
3047        }
3048        Ok(Self { data })
3049    }
3050}
3051
3052/// [PaintVarSweepGradient](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-8-and-9-paintsweepgradient-paintvarsweepgradient) table
3053#[derive(Clone)]
3054pub struct PaintVarSweepGradient<'a> {
3055    data: FontData<'a>,
3056}
3057
3058#[allow(clippy::needless_lifetimes)]
3059impl<'a> PaintVarSweepGradient<'a> {
3060    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN
3061        + Offset24::RAW_BYTE_LEN
3062        + FWord::RAW_BYTE_LEN
3063        + FWord::RAW_BYTE_LEN
3064        + F2Dot14::RAW_BYTE_LEN
3065        + F2Dot14::RAW_BYTE_LEN
3066        + u32::RAW_BYTE_LEN);
3067    basic_table_impls!(impl_the_methods);
3068
3069    /// Set to 9.
3070    pub fn format(&self) -> u8 {
3071        let range = self.format_byte_range();
3072        self.data.read_at(range.start).ok().unwrap()
3073    }
3074
3075    /// Offset to VarColorLine table.
3076    pub fn color_line_offset(&self) -> Offset24 {
3077        let range = self.color_line_offset_byte_range();
3078        self.data.read_at(range.start).ok().unwrap()
3079    }
3080
3081    /// Attempt to resolve [`color_line_offset`][Self::color_line_offset].
3082    pub fn color_line(&self) -> Result<VarColorLine<'a>, ReadError> {
3083        let data = self.data;
3084        self.color_line_offset().resolve(data)
3085    }
3086
3087    /// Center x coordinate. For variation, use varIndexBase + 0.
3088    pub fn center_x(&self) -> FWord {
3089        let range = self.center_x_byte_range();
3090        self.data.read_at(range.start).ok().unwrap()
3091    }
3092
3093    /// Center y coordinate. For variation, use varIndexBase + 1.
3094    pub fn center_y(&self) -> FWord {
3095        let range = self.center_y_byte_range();
3096        self.data.read_at(range.start).ok().unwrap()
3097    }
3098
3099    /// Start of the angular range of the gradient, 180° in
3100    /// counter-clockwise degrees per 1.0 of value. For variation, use
3101    /// varIndexBase + 2.
3102    pub fn start_angle(&self) -> F2Dot14 {
3103        let range = self.start_angle_byte_range();
3104        self.data.read_at(range.start).ok().unwrap()
3105    }
3106
3107    /// End of the angular range of the gradient, 180° in
3108    /// counter-clockwise degrees per 1.0 of value. For variation, use
3109    /// varIndexBase + 3.
3110    pub fn end_angle(&self) -> F2Dot14 {
3111        let range = self.end_angle_byte_range();
3112        self.data.read_at(range.start).ok().unwrap()
3113    }
3114
3115    /// Base index into DeltaSetIndexMap.
3116    pub fn var_index_base(&self) -> u32 {
3117        let range = self.var_index_base_byte_range();
3118        self.data.read_at(range.start).ok().unwrap()
3119    }
3120
3121    pub fn format_byte_range(&self) -> Range<usize> {
3122        let start = 0;
3123        start..start + u8::RAW_BYTE_LEN
3124    }
3125
3126    pub fn color_line_offset_byte_range(&self) -> Range<usize> {
3127        let start = self.format_byte_range().end;
3128        start..start + Offset24::RAW_BYTE_LEN
3129    }
3130
3131    pub fn center_x_byte_range(&self) -> Range<usize> {
3132        let start = self.color_line_offset_byte_range().end;
3133        start..start + FWord::RAW_BYTE_LEN
3134    }
3135
3136    pub fn center_y_byte_range(&self) -> Range<usize> {
3137        let start = self.center_x_byte_range().end;
3138        start..start + FWord::RAW_BYTE_LEN
3139    }
3140
3141    pub fn start_angle_byte_range(&self) -> Range<usize> {
3142        let start = self.center_y_byte_range().end;
3143        start..start + F2Dot14::RAW_BYTE_LEN
3144    }
3145
3146    pub fn end_angle_byte_range(&self) -> Range<usize> {
3147        let start = self.start_angle_byte_range().end;
3148        start..start + F2Dot14::RAW_BYTE_LEN
3149    }
3150
3151    pub fn var_index_base_byte_range(&self) -> Range<usize> {
3152        let start = self.end_angle_byte_range().end;
3153        start..start + u32::RAW_BYTE_LEN
3154    }
3155}
3156
3157#[cfg(feature = "experimental_traverse")]
3158impl<'a> SomeTable<'a> for PaintVarSweepGradient<'a> {
3159    fn type_name(&self) -> &str {
3160        "PaintVarSweepGradient"
3161    }
3162    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3163        match idx {
3164            0usize => Some(Field::new("format", self.format())),
3165            1usize => Some(Field::new(
3166                "color_line_offset",
3167                FieldType::offset(self.color_line_offset(), self.color_line()),
3168            )),
3169            2usize => Some(Field::new("center_x", self.center_x())),
3170            3usize => Some(Field::new("center_y", self.center_y())),
3171            4usize => Some(Field::new("start_angle", self.start_angle())),
3172            5usize => Some(Field::new("end_angle", self.end_angle())),
3173            6usize => Some(Field::new("var_index_base", self.var_index_base())),
3174            _ => None,
3175        }
3176    }
3177}
3178
3179#[cfg(feature = "experimental_traverse")]
3180#[allow(clippy::needless_lifetimes)]
3181impl<'a> std::fmt::Debug for PaintVarSweepGradient<'a> {
3182    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3183        (self as &dyn SomeTable<'a>).fmt(f)
3184    }
3185}
3186
3187impl Format<u8> for PaintGlyph<'_> {
3188    const FORMAT: u8 = 10;
3189}
3190
3191impl<'a> MinByteRange<'a> for PaintGlyph<'a> {
3192    fn min_byte_range(&self) -> Range<usize> {
3193        0..self.glyph_id_byte_range().end
3194    }
3195    fn min_table_bytes(&self) -> &'a [u8] {
3196        let range = self.min_byte_range();
3197        self.data.as_bytes().get(range).unwrap_or_default()
3198    }
3199}
3200
3201impl<'a> FontRead<'a> for PaintGlyph<'a> {
3202    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3203        #[allow(clippy::absurd_extreme_comparisons)]
3204        if data.len() < Self::MIN_SIZE {
3205            return Err(ReadError::OutOfBounds);
3206        }
3207        Ok(Self { data })
3208    }
3209}
3210
3211/// [PaintGlyph](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#format-10-paintglyph) table
3212#[derive(Clone)]
3213pub struct PaintGlyph<'a> {
3214    data: FontData<'a>,
3215}
3216
3217#[allow(clippy::needless_lifetimes)]
3218impl<'a> PaintGlyph<'a> {
3219    pub const MIN_SIZE: usize =
3220        (u8::RAW_BYTE_LEN + Offset24::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN);
3221    basic_table_impls!(impl_the_methods);
3222
3223    /// Set to 10.
3224    pub fn format(&self) -> u8 {
3225        let range = self.format_byte_range();
3226        self.data.read_at(range.start).ok().unwrap()
3227    }
3228
3229    /// Offset to a Paint table.
3230    pub fn paint_offset(&self) -> Offset24 {
3231        let range = self.paint_offset_byte_range();
3232        self.data.read_at(range.start).ok().unwrap()
3233    }
3234
3235    /// Attempt to resolve [`paint_offset`][Self::paint_offset].
3236    pub fn paint(&self) -> Result<Paint<'a>, ReadError> {
3237        let data = self.data;
3238        self.paint_offset().resolve(data)
3239    }
3240
3241    /// Glyph ID for the source outline.
3242    pub fn glyph_id(&self) -> GlyphId16 {
3243        let range = self.glyph_id_byte_range();
3244        self.data.read_at(range.start).ok().unwrap()
3245    }
3246
3247    pub fn format_byte_range(&self) -> Range<usize> {
3248        let start = 0;
3249        start..start + u8::RAW_BYTE_LEN
3250    }
3251
3252    pub fn paint_offset_byte_range(&self) -> Range<usize> {
3253        let start = self.format_byte_range().end;
3254        start..start + Offset24::RAW_BYTE_LEN
3255    }
3256
3257    pub fn glyph_id_byte_range(&self) -> Range<usize> {
3258        let start = self.paint_offset_byte_range().end;
3259        start..start + GlyphId16::RAW_BYTE_LEN
3260    }
3261}
3262
3263#[cfg(feature = "experimental_traverse")]
3264impl<'a> SomeTable<'a> for PaintGlyph<'a> {
3265    fn type_name(&self) -> &str {
3266        "PaintGlyph"
3267    }
3268    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3269        match idx {
3270            0usize => Some(Field::new("format", self.format())),
3271            1usize => Some(Field::new(
3272                "paint_offset",
3273                FieldType::offset(self.paint_offset(), self.paint()),
3274            )),
3275            2usize => Some(Field::new("glyph_id", self.glyph_id())),
3276            _ => None,
3277        }
3278    }
3279}
3280
3281#[cfg(feature = "experimental_traverse")]
3282#[allow(clippy::needless_lifetimes)]
3283impl<'a> std::fmt::Debug for PaintGlyph<'a> {
3284    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3285        (self as &dyn SomeTable<'a>).fmt(f)
3286    }
3287}
3288
3289impl Format<u8> for PaintColrGlyph<'_> {
3290    const FORMAT: u8 = 11;
3291}
3292
3293impl<'a> MinByteRange<'a> for PaintColrGlyph<'a> {
3294    fn min_byte_range(&self) -> Range<usize> {
3295        0..self.glyph_id_byte_range().end
3296    }
3297    fn min_table_bytes(&self) -> &'a [u8] {
3298        let range = self.min_byte_range();
3299        self.data.as_bytes().get(range).unwrap_or_default()
3300    }
3301}
3302
3303impl<'a> FontRead<'a> for PaintColrGlyph<'a> {
3304    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3305        #[allow(clippy::absurd_extreme_comparisons)]
3306        if data.len() < Self::MIN_SIZE {
3307            return Err(ReadError::OutOfBounds);
3308        }
3309        Ok(Self { data })
3310    }
3311}
3312
3313/// [PaintColrGlyph](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#format-11-paintcolrglyph) table
3314#[derive(Clone)]
3315pub struct PaintColrGlyph<'a> {
3316    data: FontData<'a>,
3317}
3318
3319#[allow(clippy::needless_lifetimes)]
3320impl<'a> PaintColrGlyph<'a> {
3321    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN);
3322    basic_table_impls!(impl_the_methods);
3323
3324    /// Set to 11.
3325    pub fn format(&self) -> u8 {
3326        let range = self.format_byte_range();
3327        self.data.read_at(range.start).ok().unwrap()
3328    }
3329
3330    /// Glyph ID for a BaseGlyphList base glyph.
3331    pub fn glyph_id(&self) -> GlyphId16 {
3332        let range = self.glyph_id_byte_range();
3333        self.data.read_at(range.start).ok().unwrap()
3334    }
3335
3336    pub fn format_byte_range(&self) -> Range<usize> {
3337        let start = 0;
3338        start..start + u8::RAW_BYTE_LEN
3339    }
3340
3341    pub fn glyph_id_byte_range(&self) -> Range<usize> {
3342        let start = self.format_byte_range().end;
3343        start..start + GlyphId16::RAW_BYTE_LEN
3344    }
3345}
3346
3347#[cfg(feature = "experimental_traverse")]
3348impl<'a> SomeTable<'a> for PaintColrGlyph<'a> {
3349    fn type_name(&self) -> &str {
3350        "PaintColrGlyph"
3351    }
3352    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3353        match idx {
3354            0usize => Some(Field::new("format", self.format())),
3355            1usize => Some(Field::new("glyph_id", self.glyph_id())),
3356            _ => None,
3357        }
3358    }
3359}
3360
3361#[cfg(feature = "experimental_traverse")]
3362#[allow(clippy::needless_lifetimes)]
3363impl<'a> std::fmt::Debug for PaintColrGlyph<'a> {
3364    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3365        (self as &dyn SomeTable<'a>).fmt(f)
3366    }
3367}
3368
3369impl Format<u8> for PaintTransform<'_> {
3370    const FORMAT: u8 = 12;
3371}
3372
3373impl<'a> MinByteRange<'a> for PaintTransform<'a> {
3374    fn min_byte_range(&self) -> Range<usize> {
3375        0..self.transform_offset_byte_range().end
3376    }
3377    fn min_table_bytes(&self) -> &'a [u8] {
3378        let range = self.min_byte_range();
3379        self.data.as_bytes().get(range).unwrap_or_default()
3380    }
3381}
3382
3383impl<'a> FontRead<'a> for PaintTransform<'a> {
3384    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3385        #[allow(clippy::absurd_extreme_comparisons)]
3386        if data.len() < Self::MIN_SIZE {
3387            return Err(ReadError::OutOfBounds);
3388        }
3389        Ok(Self { data })
3390    }
3391}
3392
3393/// [PaintTransform](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-12-and-13-painttransform-paintvartransform) table
3394#[derive(Clone)]
3395pub struct PaintTransform<'a> {
3396    data: FontData<'a>,
3397}
3398
3399#[allow(clippy::needless_lifetimes)]
3400impl<'a> PaintTransform<'a> {
3401    pub const MIN_SIZE: usize =
3402        (u8::RAW_BYTE_LEN + Offset24::RAW_BYTE_LEN + Offset24::RAW_BYTE_LEN);
3403    basic_table_impls!(impl_the_methods);
3404
3405    /// Set to 12.
3406    pub fn format(&self) -> u8 {
3407        let range = self.format_byte_range();
3408        self.data.read_at(range.start).ok().unwrap()
3409    }
3410
3411    /// Offset to a Paint subtable.
3412    pub fn paint_offset(&self) -> Offset24 {
3413        let range = self.paint_offset_byte_range();
3414        self.data.read_at(range.start).ok().unwrap()
3415    }
3416
3417    /// Attempt to resolve [`paint_offset`][Self::paint_offset].
3418    pub fn paint(&self) -> Result<Paint<'a>, ReadError> {
3419        let data = self.data;
3420        self.paint_offset().resolve(data)
3421    }
3422
3423    /// Offset to an Affine2x3 table.
3424    pub fn transform_offset(&self) -> Offset24 {
3425        let range = self.transform_offset_byte_range();
3426        self.data.read_at(range.start).ok().unwrap()
3427    }
3428
3429    /// Attempt to resolve [`transform_offset`][Self::transform_offset].
3430    pub fn transform(&self) -> Result<Affine2x3<'a>, ReadError> {
3431        let data = self.data;
3432        self.transform_offset().resolve(data)
3433    }
3434
3435    pub fn format_byte_range(&self) -> Range<usize> {
3436        let start = 0;
3437        start..start + u8::RAW_BYTE_LEN
3438    }
3439
3440    pub fn paint_offset_byte_range(&self) -> Range<usize> {
3441        let start = self.format_byte_range().end;
3442        start..start + Offset24::RAW_BYTE_LEN
3443    }
3444
3445    pub fn transform_offset_byte_range(&self) -> Range<usize> {
3446        let start = self.paint_offset_byte_range().end;
3447        start..start + Offset24::RAW_BYTE_LEN
3448    }
3449}
3450
3451#[cfg(feature = "experimental_traverse")]
3452impl<'a> SomeTable<'a> for PaintTransform<'a> {
3453    fn type_name(&self) -> &str {
3454        "PaintTransform"
3455    }
3456    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3457        match idx {
3458            0usize => Some(Field::new("format", self.format())),
3459            1usize => Some(Field::new(
3460                "paint_offset",
3461                FieldType::offset(self.paint_offset(), self.paint()),
3462            )),
3463            2usize => Some(Field::new(
3464                "transform_offset",
3465                FieldType::offset(self.transform_offset(), self.transform()),
3466            )),
3467            _ => None,
3468        }
3469    }
3470}
3471
3472#[cfg(feature = "experimental_traverse")]
3473#[allow(clippy::needless_lifetimes)]
3474impl<'a> std::fmt::Debug for PaintTransform<'a> {
3475    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3476        (self as &dyn SomeTable<'a>).fmt(f)
3477    }
3478}
3479
3480impl Format<u8> for PaintVarTransform<'_> {
3481    const FORMAT: u8 = 13;
3482}
3483
3484impl<'a> MinByteRange<'a> for PaintVarTransform<'a> {
3485    fn min_byte_range(&self) -> Range<usize> {
3486        0..self.transform_offset_byte_range().end
3487    }
3488    fn min_table_bytes(&self) -> &'a [u8] {
3489        let range = self.min_byte_range();
3490        self.data.as_bytes().get(range).unwrap_or_default()
3491    }
3492}
3493
3494impl<'a> FontRead<'a> for PaintVarTransform<'a> {
3495    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3496        #[allow(clippy::absurd_extreme_comparisons)]
3497        if data.len() < Self::MIN_SIZE {
3498            return Err(ReadError::OutOfBounds);
3499        }
3500        Ok(Self { data })
3501    }
3502}
3503
3504/// [PaintVarTransform](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-12-and-13-painttransform-paintvartransform) table
3505#[derive(Clone)]
3506pub struct PaintVarTransform<'a> {
3507    data: FontData<'a>,
3508}
3509
3510#[allow(clippy::needless_lifetimes)]
3511impl<'a> PaintVarTransform<'a> {
3512    pub const MIN_SIZE: usize =
3513        (u8::RAW_BYTE_LEN + Offset24::RAW_BYTE_LEN + Offset24::RAW_BYTE_LEN);
3514    basic_table_impls!(impl_the_methods);
3515
3516    /// Set to 13.
3517    pub fn format(&self) -> u8 {
3518        let range = self.format_byte_range();
3519        self.data.read_at(range.start).ok().unwrap()
3520    }
3521
3522    /// Offset to a Paint subtable.
3523    pub fn paint_offset(&self) -> Offset24 {
3524        let range = self.paint_offset_byte_range();
3525        self.data.read_at(range.start).ok().unwrap()
3526    }
3527
3528    /// Attempt to resolve [`paint_offset`][Self::paint_offset].
3529    pub fn paint(&self) -> Result<Paint<'a>, ReadError> {
3530        let data = self.data;
3531        self.paint_offset().resolve(data)
3532    }
3533
3534    /// Offset to a VarAffine2x3 table.
3535    pub fn transform_offset(&self) -> Offset24 {
3536        let range = self.transform_offset_byte_range();
3537        self.data.read_at(range.start).ok().unwrap()
3538    }
3539
3540    /// Attempt to resolve [`transform_offset`][Self::transform_offset].
3541    pub fn transform(&self) -> Result<VarAffine2x3<'a>, ReadError> {
3542        let data = self.data;
3543        self.transform_offset().resolve(data)
3544    }
3545
3546    pub fn format_byte_range(&self) -> Range<usize> {
3547        let start = 0;
3548        start..start + u8::RAW_BYTE_LEN
3549    }
3550
3551    pub fn paint_offset_byte_range(&self) -> Range<usize> {
3552        let start = self.format_byte_range().end;
3553        start..start + Offset24::RAW_BYTE_LEN
3554    }
3555
3556    pub fn transform_offset_byte_range(&self) -> Range<usize> {
3557        let start = self.paint_offset_byte_range().end;
3558        start..start + Offset24::RAW_BYTE_LEN
3559    }
3560}
3561
3562#[cfg(feature = "experimental_traverse")]
3563impl<'a> SomeTable<'a> for PaintVarTransform<'a> {
3564    fn type_name(&self) -> &str {
3565        "PaintVarTransform"
3566    }
3567    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3568        match idx {
3569            0usize => Some(Field::new("format", self.format())),
3570            1usize => Some(Field::new(
3571                "paint_offset",
3572                FieldType::offset(self.paint_offset(), self.paint()),
3573            )),
3574            2usize => Some(Field::new(
3575                "transform_offset",
3576                FieldType::offset(self.transform_offset(), self.transform()),
3577            )),
3578            _ => None,
3579        }
3580    }
3581}
3582
3583#[cfg(feature = "experimental_traverse")]
3584#[allow(clippy::needless_lifetimes)]
3585impl<'a> std::fmt::Debug for PaintVarTransform<'a> {
3586    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3587        (self as &dyn SomeTable<'a>).fmt(f)
3588    }
3589}
3590
3591impl<'a> MinByteRange<'a> for Affine2x3<'a> {
3592    fn min_byte_range(&self) -> Range<usize> {
3593        0..self.dy_byte_range().end
3594    }
3595    fn min_table_bytes(&self) -> &'a [u8] {
3596        let range = self.min_byte_range();
3597        self.data.as_bytes().get(range).unwrap_or_default()
3598    }
3599}
3600
3601impl<'a> FontRead<'a> for Affine2x3<'a> {
3602    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3603        #[allow(clippy::absurd_extreme_comparisons)]
3604        if data.len() < Self::MIN_SIZE {
3605            return Err(ReadError::OutOfBounds);
3606        }
3607        Ok(Self { data })
3608    }
3609}
3610
3611/// [Affine2x3](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-12-and-13-painttransform-paintvartransform) record
3612#[derive(Clone)]
3613pub struct Affine2x3<'a> {
3614    data: FontData<'a>,
3615}
3616
3617#[allow(clippy::needless_lifetimes)]
3618impl<'a> Affine2x3<'a> {
3619    pub const MIN_SIZE: usize = (Fixed::RAW_BYTE_LEN
3620        + Fixed::RAW_BYTE_LEN
3621        + Fixed::RAW_BYTE_LEN
3622        + Fixed::RAW_BYTE_LEN
3623        + Fixed::RAW_BYTE_LEN
3624        + Fixed::RAW_BYTE_LEN);
3625    basic_table_impls!(impl_the_methods);
3626
3627    /// x-component of transformed x-basis vector.
3628    pub fn xx(&self) -> Fixed {
3629        let range = self.xx_byte_range();
3630        self.data.read_at(range.start).ok().unwrap()
3631    }
3632
3633    /// y-component of transformed x-basis vector.
3634    pub fn yx(&self) -> Fixed {
3635        let range = self.yx_byte_range();
3636        self.data.read_at(range.start).ok().unwrap()
3637    }
3638
3639    /// x-component of transformed y-basis vector.
3640    pub fn xy(&self) -> Fixed {
3641        let range = self.xy_byte_range();
3642        self.data.read_at(range.start).ok().unwrap()
3643    }
3644
3645    /// y-component of transformed y-basis vector.
3646    pub fn yy(&self) -> Fixed {
3647        let range = self.yy_byte_range();
3648        self.data.read_at(range.start).ok().unwrap()
3649    }
3650
3651    /// Translation in x direction.
3652    pub fn dx(&self) -> Fixed {
3653        let range = self.dx_byte_range();
3654        self.data.read_at(range.start).ok().unwrap()
3655    }
3656
3657    /// Translation in y direction.
3658    pub fn dy(&self) -> Fixed {
3659        let range = self.dy_byte_range();
3660        self.data.read_at(range.start).ok().unwrap()
3661    }
3662
3663    pub fn xx_byte_range(&self) -> Range<usize> {
3664        let start = 0;
3665        start..start + Fixed::RAW_BYTE_LEN
3666    }
3667
3668    pub fn yx_byte_range(&self) -> Range<usize> {
3669        let start = self.xx_byte_range().end;
3670        start..start + Fixed::RAW_BYTE_LEN
3671    }
3672
3673    pub fn xy_byte_range(&self) -> Range<usize> {
3674        let start = self.yx_byte_range().end;
3675        start..start + Fixed::RAW_BYTE_LEN
3676    }
3677
3678    pub fn yy_byte_range(&self) -> Range<usize> {
3679        let start = self.xy_byte_range().end;
3680        start..start + Fixed::RAW_BYTE_LEN
3681    }
3682
3683    pub fn dx_byte_range(&self) -> Range<usize> {
3684        let start = self.yy_byte_range().end;
3685        start..start + Fixed::RAW_BYTE_LEN
3686    }
3687
3688    pub fn dy_byte_range(&self) -> Range<usize> {
3689        let start = self.dx_byte_range().end;
3690        start..start + Fixed::RAW_BYTE_LEN
3691    }
3692}
3693
3694#[cfg(feature = "experimental_traverse")]
3695impl<'a> SomeTable<'a> for Affine2x3<'a> {
3696    fn type_name(&self) -> &str {
3697        "Affine2x3"
3698    }
3699    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3700        match idx {
3701            0usize => Some(Field::new("xx", self.xx())),
3702            1usize => Some(Field::new("yx", self.yx())),
3703            2usize => Some(Field::new("xy", self.xy())),
3704            3usize => Some(Field::new("yy", self.yy())),
3705            4usize => Some(Field::new("dx", self.dx())),
3706            5usize => Some(Field::new("dy", self.dy())),
3707            _ => None,
3708        }
3709    }
3710}
3711
3712#[cfg(feature = "experimental_traverse")]
3713#[allow(clippy::needless_lifetimes)]
3714impl<'a> std::fmt::Debug for Affine2x3<'a> {
3715    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3716        (self as &dyn SomeTable<'a>).fmt(f)
3717    }
3718}
3719
3720impl<'a> MinByteRange<'a> for VarAffine2x3<'a> {
3721    fn min_byte_range(&self) -> Range<usize> {
3722        0..self.var_index_base_byte_range().end
3723    }
3724    fn min_table_bytes(&self) -> &'a [u8] {
3725        let range = self.min_byte_range();
3726        self.data.as_bytes().get(range).unwrap_or_default()
3727    }
3728}
3729
3730impl<'a> FontRead<'a> for VarAffine2x3<'a> {
3731    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3732        #[allow(clippy::absurd_extreme_comparisons)]
3733        if data.len() < Self::MIN_SIZE {
3734            return Err(ReadError::OutOfBounds);
3735        }
3736        Ok(Self { data })
3737    }
3738}
3739
3740/// [VarAffine2x3](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-12-and-13-painttransform-paintvartransform) record
3741#[derive(Clone)]
3742pub struct VarAffine2x3<'a> {
3743    data: FontData<'a>,
3744}
3745
3746#[allow(clippy::needless_lifetimes)]
3747impl<'a> VarAffine2x3<'a> {
3748    pub const MIN_SIZE: usize = (Fixed::RAW_BYTE_LEN
3749        + Fixed::RAW_BYTE_LEN
3750        + Fixed::RAW_BYTE_LEN
3751        + Fixed::RAW_BYTE_LEN
3752        + Fixed::RAW_BYTE_LEN
3753        + Fixed::RAW_BYTE_LEN
3754        + u32::RAW_BYTE_LEN);
3755    basic_table_impls!(impl_the_methods);
3756
3757    /// x-component of transformed x-basis vector. For variation, use
3758    /// varIndexBase + 0.
3759    pub fn xx(&self) -> Fixed {
3760        let range = self.xx_byte_range();
3761        self.data.read_at(range.start).ok().unwrap()
3762    }
3763
3764    /// y-component of transformed x-basis vector. For variation, use
3765    /// varIndexBase + 1.
3766    pub fn yx(&self) -> Fixed {
3767        let range = self.yx_byte_range();
3768        self.data.read_at(range.start).ok().unwrap()
3769    }
3770
3771    /// x-component of transformed y-basis vector. For variation, use
3772    /// varIndexBase + 2.
3773    pub fn xy(&self) -> Fixed {
3774        let range = self.xy_byte_range();
3775        self.data.read_at(range.start).ok().unwrap()
3776    }
3777
3778    /// y-component of transformed y-basis vector. For variation, use
3779    /// varIndexBase + 3.
3780    pub fn yy(&self) -> Fixed {
3781        let range = self.yy_byte_range();
3782        self.data.read_at(range.start).ok().unwrap()
3783    }
3784
3785    /// Translation in x direction. For variation, use varIndexBase + 4.
3786    pub fn dx(&self) -> Fixed {
3787        let range = self.dx_byte_range();
3788        self.data.read_at(range.start).ok().unwrap()
3789    }
3790
3791    /// Translation in y direction. For variation, use varIndexBase + 5.
3792    pub fn dy(&self) -> Fixed {
3793        let range = self.dy_byte_range();
3794        self.data.read_at(range.start).ok().unwrap()
3795    }
3796
3797    /// Base index into DeltaSetIndexMap.
3798    pub fn var_index_base(&self) -> u32 {
3799        let range = self.var_index_base_byte_range();
3800        self.data.read_at(range.start).ok().unwrap()
3801    }
3802
3803    pub fn xx_byte_range(&self) -> Range<usize> {
3804        let start = 0;
3805        start..start + Fixed::RAW_BYTE_LEN
3806    }
3807
3808    pub fn yx_byte_range(&self) -> Range<usize> {
3809        let start = self.xx_byte_range().end;
3810        start..start + Fixed::RAW_BYTE_LEN
3811    }
3812
3813    pub fn xy_byte_range(&self) -> Range<usize> {
3814        let start = self.yx_byte_range().end;
3815        start..start + Fixed::RAW_BYTE_LEN
3816    }
3817
3818    pub fn yy_byte_range(&self) -> Range<usize> {
3819        let start = self.xy_byte_range().end;
3820        start..start + Fixed::RAW_BYTE_LEN
3821    }
3822
3823    pub fn dx_byte_range(&self) -> Range<usize> {
3824        let start = self.yy_byte_range().end;
3825        start..start + Fixed::RAW_BYTE_LEN
3826    }
3827
3828    pub fn dy_byte_range(&self) -> Range<usize> {
3829        let start = self.dx_byte_range().end;
3830        start..start + Fixed::RAW_BYTE_LEN
3831    }
3832
3833    pub fn var_index_base_byte_range(&self) -> Range<usize> {
3834        let start = self.dy_byte_range().end;
3835        start..start + u32::RAW_BYTE_LEN
3836    }
3837}
3838
3839#[cfg(feature = "experimental_traverse")]
3840impl<'a> SomeTable<'a> for VarAffine2x3<'a> {
3841    fn type_name(&self) -> &str {
3842        "VarAffine2x3"
3843    }
3844    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3845        match idx {
3846            0usize => Some(Field::new("xx", self.xx())),
3847            1usize => Some(Field::new("yx", self.yx())),
3848            2usize => Some(Field::new("xy", self.xy())),
3849            3usize => Some(Field::new("yy", self.yy())),
3850            4usize => Some(Field::new("dx", self.dx())),
3851            5usize => Some(Field::new("dy", self.dy())),
3852            6usize => Some(Field::new("var_index_base", self.var_index_base())),
3853            _ => None,
3854        }
3855    }
3856}
3857
3858#[cfg(feature = "experimental_traverse")]
3859#[allow(clippy::needless_lifetimes)]
3860impl<'a> std::fmt::Debug for VarAffine2x3<'a> {
3861    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3862        (self as &dyn SomeTable<'a>).fmt(f)
3863    }
3864}
3865
3866impl Format<u8> for PaintTranslate<'_> {
3867    const FORMAT: u8 = 14;
3868}
3869
3870impl<'a> MinByteRange<'a> for PaintTranslate<'a> {
3871    fn min_byte_range(&self) -> Range<usize> {
3872        0..self.dy_byte_range().end
3873    }
3874    fn min_table_bytes(&self) -> &'a [u8] {
3875        let range = self.min_byte_range();
3876        self.data.as_bytes().get(range).unwrap_or_default()
3877    }
3878}
3879
3880impl<'a> FontRead<'a> for PaintTranslate<'a> {
3881    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3882        #[allow(clippy::absurd_extreme_comparisons)]
3883        if data.len() < Self::MIN_SIZE {
3884            return Err(ReadError::OutOfBounds);
3885        }
3886        Ok(Self { data })
3887    }
3888}
3889
3890/// [PaintTranslate](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-14-and-15-painttranslate-paintvartranslate) table
3891#[derive(Clone)]
3892pub struct PaintTranslate<'a> {
3893    data: FontData<'a>,
3894}
3895
3896#[allow(clippy::needless_lifetimes)]
3897impl<'a> PaintTranslate<'a> {
3898    pub const MIN_SIZE: usize =
3899        (u8::RAW_BYTE_LEN + Offset24::RAW_BYTE_LEN + FWord::RAW_BYTE_LEN + FWord::RAW_BYTE_LEN);
3900    basic_table_impls!(impl_the_methods);
3901
3902    /// Set to 14.
3903    pub fn format(&self) -> u8 {
3904        let range = self.format_byte_range();
3905        self.data.read_at(range.start).ok().unwrap()
3906    }
3907
3908    /// Offset to a Paint subtable.
3909    pub fn paint_offset(&self) -> Offset24 {
3910        let range = self.paint_offset_byte_range();
3911        self.data.read_at(range.start).ok().unwrap()
3912    }
3913
3914    /// Attempt to resolve [`paint_offset`][Self::paint_offset].
3915    pub fn paint(&self) -> Result<Paint<'a>, ReadError> {
3916        let data = self.data;
3917        self.paint_offset().resolve(data)
3918    }
3919
3920    /// Translation in x direction.
3921    pub fn dx(&self) -> FWord {
3922        let range = self.dx_byte_range();
3923        self.data.read_at(range.start).ok().unwrap()
3924    }
3925
3926    /// Translation in y direction.
3927    pub fn dy(&self) -> FWord {
3928        let range = self.dy_byte_range();
3929        self.data.read_at(range.start).ok().unwrap()
3930    }
3931
3932    pub fn format_byte_range(&self) -> Range<usize> {
3933        let start = 0;
3934        start..start + u8::RAW_BYTE_LEN
3935    }
3936
3937    pub fn paint_offset_byte_range(&self) -> Range<usize> {
3938        let start = self.format_byte_range().end;
3939        start..start + Offset24::RAW_BYTE_LEN
3940    }
3941
3942    pub fn dx_byte_range(&self) -> Range<usize> {
3943        let start = self.paint_offset_byte_range().end;
3944        start..start + FWord::RAW_BYTE_LEN
3945    }
3946
3947    pub fn dy_byte_range(&self) -> Range<usize> {
3948        let start = self.dx_byte_range().end;
3949        start..start + FWord::RAW_BYTE_LEN
3950    }
3951}
3952
3953#[cfg(feature = "experimental_traverse")]
3954impl<'a> SomeTable<'a> for PaintTranslate<'a> {
3955    fn type_name(&self) -> &str {
3956        "PaintTranslate"
3957    }
3958    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3959        match idx {
3960            0usize => Some(Field::new("format", self.format())),
3961            1usize => Some(Field::new(
3962                "paint_offset",
3963                FieldType::offset(self.paint_offset(), self.paint()),
3964            )),
3965            2usize => Some(Field::new("dx", self.dx())),
3966            3usize => Some(Field::new("dy", self.dy())),
3967            _ => None,
3968        }
3969    }
3970}
3971
3972#[cfg(feature = "experimental_traverse")]
3973#[allow(clippy::needless_lifetimes)]
3974impl<'a> std::fmt::Debug for PaintTranslate<'a> {
3975    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3976        (self as &dyn SomeTable<'a>).fmt(f)
3977    }
3978}
3979
3980impl Format<u8> for PaintVarTranslate<'_> {
3981    const FORMAT: u8 = 15;
3982}
3983
3984impl<'a> MinByteRange<'a> for PaintVarTranslate<'a> {
3985    fn min_byte_range(&self) -> Range<usize> {
3986        0..self.var_index_base_byte_range().end
3987    }
3988    fn min_table_bytes(&self) -> &'a [u8] {
3989        let range = self.min_byte_range();
3990        self.data.as_bytes().get(range).unwrap_or_default()
3991    }
3992}
3993
3994impl<'a> FontRead<'a> for PaintVarTranslate<'a> {
3995    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3996        #[allow(clippy::absurd_extreme_comparisons)]
3997        if data.len() < Self::MIN_SIZE {
3998            return Err(ReadError::OutOfBounds);
3999        }
4000        Ok(Self { data })
4001    }
4002}
4003
4004/// [PaintVarTranslate](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-14-and-15-painttranslate-paintvartranslate) table
4005#[derive(Clone)]
4006pub struct PaintVarTranslate<'a> {
4007    data: FontData<'a>,
4008}
4009
4010#[allow(clippy::needless_lifetimes)]
4011impl<'a> PaintVarTranslate<'a> {
4012    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN
4013        + Offset24::RAW_BYTE_LEN
4014        + FWord::RAW_BYTE_LEN
4015        + FWord::RAW_BYTE_LEN
4016        + u32::RAW_BYTE_LEN);
4017    basic_table_impls!(impl_the_methods);
4018
4019    /// Set to 15.
4020    pub fn format(&self) -> u8 {
4021        let range = self.format_byte_range();
4022        self.data.read_at(range.start).ok().unwrap()
4023    }
4024
4025    /// Offset to a Paint subtable.
4026    pub fn paint_offset(&self) -> Offset24 {
4027        let range = self.paint_offset_byte_range();
4028        self.data.read_at(range.start).ok().unwrap()
4029    }
4030
4031    /// Attempt to resolve [`paint_offset`][Self::paint_offset].
4032    pub fn paint(&self) -> Result<Paint<'a>, ReadError> {
4033        let data = self.data;
4034        self.paint_offset().resolve(data)
4035    }
4036
4037    /// Translation in x direction. For variation, use varIndexBase + 0.
4038    pub fn dx(&self) -> FWord {
4039        let range = self.dx_byte_range();
4040        self.data.read_at(range.start).ok().unwrap()
4041    }
4042
4043    /// Translation in y direction. For variation, use varIndexBase + 1.
4044    pub fn dy(&self) -> FWord {
4045        let range = self.dy_byte_range();
4046        self.data.read_at(range.start).ok().unwrap()
4047    }
4048
4049    /// Base index into DeltaSetIndexMap.
4050    pub fn var_index_base(&self) -> u32 {
4051        let range = self.var_index_base_byte_range();
4052        self.data.read_at(range.start).ok().unwrap()
4053    }
4054
4055    pub fn format_byte_range(&self) -> Range<usize> {
4056        let start = 0;
4057        start..start + u8::RAW_BYTE_LEN
4058    }
4059
4060    pub fn paint_offset_byte_range(&self) -> Range<usize> {
4061        let start = self.format_byte_range().end;
4062        start..start + Offset24::RAW_BYTE_LEN
4063    }
4064
4065    pub fn dx_byte_range(&self) -> Range<usize> {
4066        let start = self.paint_offset_byte_range().end;
4067        start..start + FWord::RAW_BYTE_LEN
4068    }
4069
4070    pub fn dy_byte_range(&self) -> Range<usize> {
4071        let start = self.dx_byte_range().end;
4072        start..start + FWord::RAW_BYTE_LEN
4073    }
4074
4075    pub fn var_index_base_byte_range(&self) -> Range<usize> {
4076        let start = self.dy_byte_range().end;
4077        start..start + u32::RAW_BYTE_LEN
4078    }
4079}
4080
4081#[cfg(feature = "experimental_traverse")]
4082impl<'a> SomeTable<'a> for PaintVarTranslate<'a> {
4083    fn type_name(&self) -> &str {
4084        "PaintVarTranslate"
4085    }
4086    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4087        match idx {
4088            0usize => Some(Field::new("format", self.format())),
4089            1usize => Some(Field::new(
4090                "paint_offset",
4091                FieldType::offset(self.paint_offset(), self.paint()),
4092            )),
4093            2usize => Some(Field::new("dx", self.dx())),
4094            3usize => Some(Field::new("dy", self.dy())),
4095            4usize => Some(Field::new("var_index_base", self.var_index_base())),
4096            _ => None,
4097        }
4098    }
4099}
4100
4101#[cfg(feature = "experimental_traverse")]
4102#[allow(clippy::needless_lifetimes)]
4103impl<'a> std::fmt::Debug for PaintVarTranslate<'a> {
4104    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4105        (self as &dyn SomeTable<'a>).fmt(f)
4106    }
4107}
4108
4109impl Format<u8> for PaintScale<'_> {
4110    const FORMAT: u8 = 16;
4111}
4112
4113impl<'a> MinByteRange<'a> for PaintScale<'a> {
4114    fn min_byte_range(&self) -> Range<usize> {
4115        0..self.scale_y_byte_range().end
4116    }
4117    fn min_table_bytes(&self) -> &'a [u8] {
4118        let range = self.min_byte_range();
4119        self.data.as_bytes().get(range).unwrap_or_default()
4120    }
4121}
4122
4123impl<'a> FontRead<'a> for PaintScale<'a> {
4124    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4125        #[allow(clippy::absurd_extreme_comparisons)]
4126        if data.len() < Self::MIN_SIZE {
4127            return Err(ReadError::OutOfBounds);
4128        }
4129        Ok(Self { data })
4130    }
4131}
4132
4133/// [PaintScale](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-16-to-23-paintscale-and-variant-scaling-formats) table
4134#[derive(Clone)]
4135pub struct PaintScale<'a> {
4136    data: FontData<'a>,
4137}
4138
4139#[allow(clippy::needless_lifetimes)]
4140impl<'a> PaintScale<'a> {
4141    pub const MIN_SIZE: usize =
4142        (u8::RAW_BYTE_LEN + Offset24::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN);
4143    basic_table_impls!(impl_the_methods);
4144
4145    /// Set to 16.
4146    pub fn format(&self) -> u8 {
4147        let range = self.format_byte_range();
4148        self.data.read_at(range.start).ok().unwrap()
4149    }
4150
4151    /// Offset to a Paint subtable.
4152    pub fn paint_offset(&self) -> Offset24 {
4153        let range = self.paint_offset_byte_range();
4154        self.data.read_at(range.start).ok().unwrap()
4155    }
4156
4157    /// Attempt to resolve [`paint_offset`][Self::paint_offset].
4158    pub fn paint(&self) -> Result<Paint<'a>, ReadError> {
4159        let data = self.data;
4160        self.paint_offset().resolve(data)
4161    }
4162
4163    /// Scale factor in x direction.
4164    pub fn scale_x(&self) -> F2Dot14 {
4165        let range = self.scale_x_byte_range();
4166        self.data.read_at(range.start).ok().unwrap()
4167    }
4168
4169    /// Scale factor in y direction.
4170    pub fn scale_y(&self) -> F2Dot14 {
4171        let range = self.scale_y_byte_range();
4172        self.data.read_at(range.start).ok().unwrap()
4173    }
4174
4175    pub fn format_byte_range(&self) -> Range<usize> {
4176        let start = 0;
4177        start..start + u8::RAW_BYTE_LEN
4178    }
4179
4180    pub fn paint_offset_byte_range(&self) -> Range<usize> {
4181        let start = self.format_byte_range().end;
4182        start..start + Offset24::RAW_BYTE_LEN
4183    }
4184
4185    pub fn scale_x_byte_range(&self) -> Range<usize> {
4186        let start = self.paint_offset_byte_range().end;
4187        start..start + F2Dot14::RAW_BYTE_LEN
4188    }
4189
4190    pub fn scale_y_byte_range(&self) -> Range<usize> {
4191        let start = self.scale_x_byte_range().end;
4192        start..start + F2Dot14::RAW_BYTE_LEN
4193    }
4194}
4195
4196#[cfg(feature = "experimental_traverse")]
4197impl<'a> SomeTable<'a> for PaintScale<'a> {
4198    fn type_name(&self) -> &str {
4199        "PaintScale"
4200    }
4201    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4202        match idx {
4203            0usize => Some(Field::new("format", self.format())),
4204            1usize => Some(Field::new(
4205                "paint_offset",
4206                FieldType::offset(self.paint_offset(), self.paint()),
4207            )),
4208            2usize => Some(Field::new("scale_x", self.scale_x())),
4209            3usize => Some(Field::new("scale_y", self.scale_y())),
4210            _ => None,
4211        }
4212    }
4213}
4214
4215#[cfg(feature = "experimental_traverse")]
4216#[allow(clippy::needless_lifetimes)]
4217impl<'a> std::fmt::Debug for PaintScale<'a> {
4218    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4219        (self as &dyn SomeTable<'a>).fmt(f)
4220    }
4221}
4222
4223impl Format<u8> for PaintVarScale<'_> {
4224    const FORMAT: u8 = 17;
4225}
4226
4227impl<'a> MinByteRange<'a> for PaintVarScale<'a> {
4228    fn min_byte_range(&self) -> Range<usize> {
4229        0..self.var_index_base_byte_range().end
4230    }
4231    fn min_table_bytes(&self) -> &'a [u8] {
4232        let range = self.min_byte_range();
4233        self.data.as_bytes().get(range).unwrap_or_default()
4234    }
4235}
4236
4237impl<'a> FontRead<'a> for PaintVarScale<'a> {
4238    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4239        #[allow(clippy::absurd_extreme_comparisons)]
4240        if data.len() < Self::MIN_SIZE {
4241            return Err(ReadError::OutOfBounds);
4242        }
4243        Ok(Self { data })
4244    }
4245}
4246
4247/// [PaintVarScale](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-16-to-23-paintscale-and-variant-scaling-formats) table
4248#[derive(Clone)]
4249pub struct PaintVarScale<'a> {
4250    data: FontData<'a>,
4251}
4252
4253#[allow(clippy::needless_lifetimes)]
4254impl<'a> PaintVarScale<'a> {
4255    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN
4256        + Offset24::RAW_BYTE_LEN
4257        + F2Dot14::RAW_BYTE_LEN
4258        + F2Dot14::RAW_BYTE_LEN
4259        + u32::RAW_BYTE_LEN);
4260    basic_table_impls!(impl_the_methods);
4261
4262    /// Set to 17.
4263    pub fn format(&self) -> u8 {
4264        let range = self.format_byte_range();
4265        self.data.read_at(range.start).ok().unwrap()
4266    }
4267
4268    /// Offset to a Paint subtable.
4269    pub fn paint_offset(&self) -> Offset24 {
4270        let range = self.paint_offset_byte_range();
4271        self.data.read_at(range.start).ok().unwrap()
4272    }
4273
4274    /// Attempt to resolve [`paint_offset`][Self::paint_offset].
4275    pub fn paint(&self) -> Result<Paint<'a>, ReadError> {
4276        let data = self.data;
4277        self.paint_offset().resolve(data)
4278    }
4279
4280    /// Scale factor in x direction. For variation, use varIndexBase +
4281    /// 0.
4282    pub fn scale_x(&self) -> F2Dot14 {
4283        let range = self.scale_x_byte_range();
4284        self.data.read_at(range.start).ok().unwrap()
4285    }
4286
4287    /// Scale factor in y direction. For variation, use varIndexBase +
4288    /// 1.
4289    pub fn scale_y(&self) -> F2Dot14 {
4290        let range = self.scale_y_byte_range();
4291        self.data.read_at(range.start).ok().unwrap()
4292    }
4293
4294    /// Base index into DeltaSetIndexMap.
4295    pub fn var_index_base(&self) -> u32 {
4296        let range = self.var_index_base_byte_range();
4297        self.data.read_at(range.start).ok().unwrap()
4298    }
4299
4300    pub fn format_byte_range(&self) -> Range<usize> {
4301        let start = 0;
4302        start..start + u8::RAW_BYTE_LEN
4303    }
4304
4305    pub fn paint_offset_byte_range(&self) -> Range<usize> {
4306        let start = self.format_byte_range().end;
4307        start..start + Offset24::RAW_BYTE_LEN
4308    }
4309
4310    pub fn scale_x_byte_range(&self) -> Range<usize> {
4311        let start = self.paint_offset_byte_range().end;
4312        start..start + F2Dot14::RAW_BYTE_LEN
4313    }
4314
4315    pub fn scale_y_byte_range(&self) -> Range<usize> {
4316        let start = self.scale_x_byte_range().end;
4317        start..start + F2Dot14::RAW_BYTE_LEN
4318    }
4319
4320    pub fn var_index_base_byte_range(&self) -> Range<usize> {
4321        let start = self.scale_y_byte_range().end;
4322        start..start + u32::RAW_BYTE_LEN
4323    }
4324}
4325
4326#[cfg(feature = "experimental_traverse")]
4327impl<'a> SomeTable<'a> for PaintVarScale<'a> {
4328    fn type_name(&self) -> &str {
4329        "PaintVarScale"
4330    }
4331    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4332        match idx {
4333            0usize => Some(Field::new("format", self.format())),
4334            1usize => Some(Field::new(
4335                "paint_offset",
4336                FieldType::offset(self.paint_offset(), self.paint()),
4337            )),
4338            2usize => Some(Field::new("scale_x", self.scale_x())),
4339            3usize => Some(Field::new("scale_y", self.scale_y())),
4340            4usize => Some(Field::new("var_index_base", self.var_index_base())),
4341            _ => None,
4342        }
4343    }
4344}
4345
4346#[cfg(feature = "experimental_traverse")]
4347#[allow(clippy::needless_lifetimes)]
4348impl<'a> std::fmt::Debug for PaintVarScale<'a> {
4349    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4350        (self as &dyn SomeTable<'a>).fmt(f)
4351    }
4352}
4353
4354impl Format<u8> for PaintScaleAroundCenter<'_> {
4355    const FORMAT: u8 = 18;
4356}
4357
4358impl<'a> MinByteRange<'a> for PaintScaleAroundCenter<'a> {
4359    fn min_byte_range(&self) -> Range<usize> {
4360        0..self.center_y_byte_range().end
4361    }
4362    fn min_table_bytes(&self) -> &'a [u8] {
4363        let range = self.min_byte_range();
4364        self.data.as_bytes().get(range).unwrap_or_default()
4365    }
4366}
4367
4368impl<'a> FontRead<'a> for PaintScaleAroundCenter<'a> {
4369    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4370        #[allow(clippy::absurd_extreme_comparisons)]
4371        if data.len() < Self::MIN_SIZE {
4372            return Err(ReadError::OutOfBounds);
4373        }
4374        Ok(Self { data })
4375    }
4376}
4377
4378/// [PaintScaleAroundCenter](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-16-to-23-paintscale-and-variant-scaling-formats) table
4379#[derive(Clone)]
4380pub struct PaintScaleAroundCenter<'a> {
4381    data: FontData<'a>,
4382}
4383
4384#[allow(clippy::needless_lifetimes)]
4385impl<'a> PaintScaleAroundCenter<'a> {
4386    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN
4387        + Offset24::RAW_BYTE_LEN
4388        + F2Dot14::RAW_BYTE_LEN
4389        + F2Dot14::RAW_BYTE_LEN
4390        + FWord::RAW_BYTE_LEN
4391        + FWord::RAW_BYTE_LEN);
4392    basic_table_impls!(impl_the_methods);
4393
4394    /// Set to 18.
4395    pub fn format(&self) -> u8 {
4396        let range = self.format_byte_range();
4397        self.data.read_at(range.start).ok().unwrap()
4398    }
4399
4400    /// Offset to a Paint subtable.
4401    pub fn paint_offset(&self) -> Offset24 {
4402        let range = self.paint_offset_byte_range();
4403        self.data.read_at(range.start).ok().unwrap()
4404    }
4405
4406    /// Attempt to resolve [`paint_offset`][Self::paint_offset].
4407    pub fn paint(&self) -> Result<Paint<'a>, ReadError> {
4408        let data = self.data;
4409        self.paint_offset().resolve(data)
4410    }
4411
4412    /// Scale factor in x direction.
4413    pub fn scale_x(&self) -> F2Dot14 {
4414        let range = self.scale_x_byte_range();
4415        self.data.read_at(range.start).ok().unwrap()
4416    }
4417
4418    /// Scale factor in y direction.
4419    pub fn scale_y(&self) -> F2Dot14 {
4420        let range = self.scale_y_byte_range();
4421        self.data.read_at(range.start).ok().unwrap()
4422    }
4423
4424    /// x coordinate for the center of scaling.
4425    pub fn center_x(&self) -> FWord {
4426        let range = self.center_x_byte_range();
4427        self.data.read_at(range.start).ok().unwrap()
4428    }
4429
4430    /// y coordinate for the center of scaling.
4431    pub fn center_y(&self) -> FWord {
4432        let range = self.center_y_byte_range();
4433        self.data.read_at(range.start).ok().unwrap()
4434    }
4435
4436    pub fn format_byte_range(&self) -> Range<usize> {
4437        let start = 0;
4438        start..start + u8::RAW_BYTE_LEN
4439    }
4440
4441    pub fn paint_offset_byte_range(&self) -> Range<usize> {
4442        let start = self.format_byte_range().end;
4443        start..start + Offset24::RAW_BYTE_LEN
4444    }
4445
4446    pub fn scale_x_byte_range(&self) -> Range<usize> {
4447        let start = self.paint_offset_byte_range().end;
4448        start..start + F2Dot14::RAW_BYTE_LEN
4449    }
4450
4451    pub fn scale_y_byte_range(&self) -> Range<usize> {
4452        let start = self.scale_x_byte_range().end;
4453        start..start + F2Dot14::RAW_BYTE_LEN
4454    }
4455
4456    pub fn center_x_byte_range(&self) -> Range<usize> {
4457        let start = self.scale_y_byte_range().end;
4458        start..start + FWord::RAW_BYTE_LEN
4459    }
4460
4461    pub fn center_y_byte_range(&self) -> Range<usize> {
4462        let start = self.center_x_byte_range().end;
4463        start..start + FWord::RAW_BYTE_LEN
4464    }
4465}
4466
4467#[cfg(feature = "experimental_traverse")]
4468impl<'a> SomeTable<'a> for PaintScaleAroundCenter<'a> {
4469    fn type_name(&self) -> &str {
4470        "PaintScaleAroundCenter"
4471    }
4472    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4473        match idx {
4474            0usize => Some(Field::new("format", self.format())),
4475            1usize => Some(Field::new(
4476                "paint_offset",
4477                FieldType::offset(self.paint_offset(), self.paint()),
4478            )),
4479            2usize => Some(Field::new("scale_x", self.scale_x())),
4480            3usize => Some(Field::new("scale_y", self.scale_y())),
4481            4usize => Some(Field::new("center_x", self.center_x())),
4482            5usize => Some(Field::new("center_y", self.center_y())),
4483            _ => None,
4484        }
4485    }
4486}
4487
4488#[cfg(feature = "experimental_traverse")]
4489#[allow(clippy::needless_lifetimes)]
4490impl<'a> std::fmt::Debug for PaintScaleAroundCenter<'a> {
4491    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4492        (self as &dyn SomeTable<'a>).fmt(f)
4493    }
4494}
4495
4496impl Format<u8> for PaintVarScaleAroundCenter<'_> {
4497    const FORMAT: u8 = 19;
4498}
4499
4500impl<'a> MinByteRange<'a> for PaintVarScaleAroundCenter<'a> {
4501    fn min_byte_range(&self) -> Range<usize> {
4502        0..self.var_index_base_byte_range().end
4503    }
4504    fn min_table_bytes(&self) -> &'a [u8] {
4505        let range = self.min_byte_range();
4506        self.data.as_bytes().get(range).unwrap_or_default()
4507    }
4508}
4509
4510impl<'a> FontRead<'a> for PaintVarScaleAroundCenter<'a> {
4511    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4512        #[allow(clippy::absurd_extreme_comparisons)]
4513        if data.len() < Self::MIN_SIZE {
4514            return Err(ReadError::OutOfBounds);
4515        }
4516        Ok(Self { data })
4517    }
4518}
4519
4520/// [PaintVarScaleAroundCenter](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-16-to-23-paintscale-and-variant-scaling-formats) table
4521#[derive(Clone)]
4522pub struct PaintVarScaleAroundCenter<'a> {
4523    data: FontData<'a>,
4524}
4525
4526#[allow(clippy::needless_lifetimes)]
4527impl<'a> PaintVarScaleAroundCenter<'a> {
4528    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN
4529        + Offset24::RAW_BYTE_LEN
4530        + F2Dot14::RAW_BYTE_LEN
4531        + F2Dot14::RAW_BYTE_LEN
4532        + FWord::RAW_BYTE_LEN
4533        + FWord::RAW_BYTE_LEN
4534        + u32::RAW_BYTE_LEN);
4535    basic_table_impls!(impl_the_methods);
4536
4537    /// Set to 19.
4538    pub fn format(&self) -> u8 {
4539        let range = self.format_byte_range();
4540        self.data.read_at(range.start).ok().unwrap()
4541    }
4542
4543    /// Offset to a Paint subtable.
4544    pub fn paint_offset(&self) -> Offset24 {
4545        let range = self.paint_offset_byte_range();
4546        self.data.read_at(range.start).ok().unwrap()
4547    }
4548
4549    /// Attempt to resolve [`paint_offset`][Self::paint_offset].
4550    pub fn paint(&self) -> Result<Paint<'a>, ReadError> {
4551        let data = self.data;
4552        self.paint_offset().resolve(data)
4553    }
4554
4555    /// Scale factor in x direction. For variation, use varIndexBase +
4556    /// 0.
4557    pub fn scale_x(&self) -> F2Dot14 {
4558        let range = self.scale_x_byte_range();
4559        self.data.read_at(range.start).ok().unwrap()
4560    }
4561
4562    /// Scale factor in y direction. For variation, use varIndexBase +
4563    /// 1.
4564    pub fn scale_y(&self) -> F2Dot14 {
4565        let range = self.scale_y_byte_range();
4566        self.data.read_at(range.start).ok().unwrap()
4567    }
4568
4569    /// x coordinate for the center of scaling. For variation, use
4570    /// varIndexBase + 2.
4571    pub fn center_x(&self) -> FWord {
4572        let range = self.center_x_byte_range();
4573        self.data.read_at(range.start).ok().unwrap()
4574    }
4575
4576    /// y coordinate for the center of scaling. For variation, use
4577    /// varIndexBase + 3.
4578    pub fn center_y(&self) -> FWord {
4579        let range = self.center_y_byte_range();
4580        self.data.read_at(range.start).ok().unwrap()
4581    }
4582
4583    /// Base index into DeltaSetIndexMap.
4584    pub fn var_index_base(&self) -> u32 {
4585        let range = self.var_index_base_byte_range();
4586        self.data.read_at(range.start).ok().unwrap()
4587    }
4588
4589    pub fn format_byte_range(&self) -> Range<usize> {
4590        let start = 0;
4591        start..start + u8::RAW_BYTE_LEN
4592    }
4593
4594    pub fn paint_offset_byte_range(&self) -> Range<usize> {
4595        let start = self.format_byte_range().end;
4596        start..start + Offset24::RAW_BYTE_LEN
4597    }
4598
4599    pub fn scale_x_byte_range(&self) -> Range<usize> {
4600        let start = self.paint_offset_byte_range().end;
4601        start..start + F2Dot14::RAW_BYTE_LEN
4602    }
4603
4604    pub fn scale_y_byte_range(&self) -> Range<usize> {
4605        let start = self.scale_x_byte_range().end;
4606        start..start + F2Dot14::RAW_BYTE_LEN
4607    }
4608
4609    pub fn center_x_byte_range(&self) -> Range<usize> {
4610        let start = self.scale_y_byte_range().end;
4611        start..start + FWord::RAW_BYTE_LEN
4612    }
4613
4614    pub fn center_y_byte_range(&self) -> Range<usize> {
4615        let start = self.center_x_byte_range().end;
4616        start..start + FWord::RAW_BYTE_LEN
4617    }
4618
4619    pub fn var_index_base_byte_range(&self) -> Range<usize> {
4620        let start = self.center_y_byte_range().end;
4621        start..start + u32::RAW_BYTE_LEN
4622    }
4623}
4624
4625#[cfg(feature = "experimental_traverse")]
4626impl<'a> SomeTable<'a> for PaintVarScaleAroundCenter<'a> {
4627    fn type_name(&self) -> &str {
4628        "PaintVarScaleAroundCenter"
4629    }
4630    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4631        match idx {
4632            0usize => Some(Field::new("format", self.format())),
4633            1usize => Some(Field::new(
4634                "paint_offset",
4635                FieldType::offset(self.paint_offset(), self.paint()),
4636            )),
4637            2usize => Some(Field::new("scale_x", self.scale_x())),
4638            3usize => Some(Field::new("scale_y", self.scale_y())),
4639            4usize => Some(Field::new("center_x", self.center_x())),
4640            5usize => Some(Field::new("center_y", self.center_y())),
4641            6usize => Some(Field::new("var_index_base", self.var_index_base())),
4642            _ => None,
4643        }
4644    }
4645}
4646
4647#[cfg(feature = "experimental_traverse")]
4648#[allow(clippy::needless_lifetimes)]
4649impl<'a> std::fmt::Debug for PaintVarScaleAroundCenter<'a> {
4650    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4651        (self as &dyn SomeTable<'a>).fmt(f)
4652    }
4653}
4654
4655impl Format<u8> for PaintScaleUniform<'_> {
4656    const FORMAT: u8 = 20;
4657}
4658
4659impl<'a> MinByteRange<'a> for PaintScaleUniform<'a> {
4660    fn min_byte_range(&self) -> Range<usize> {
4661        0..self.scale_byte_range().end
4662    }
4663    fn min_table_bytes(&self) -> &'a [u8] {
4664        let range = self.min_byte_range();
4665        self.data.as_bytes().get(range).unwrap_or_default()
4666    }
4667}
4668
4669impl<'a> FontRead<'a> for PaintScaleUniform<'a> {
4670    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4671        #[allow(clippy::absurd_extreme_comparisons)]
4672        if data.len() < Self::MIN_SIZE {
4673            return Err(ReadError::OutOfBounds);
4674        }
4675        Ok(Self { data })
4676    }
4677}
4678
4679/// [PaintScaleUniform](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-16-to-23-paintscale-and-variant-scaling-formats) table
4680#[derive(Clone)]
4681pub struct PaintScaleUniform<'a> {
4682    data: FontData<'a>,
4683}
4684
4685#[allow(clippy::needless_lifetimes)]
4686impl<'a> PaintScaleUniform<'a> {
4687    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN + Offset24::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN);
4688    basic_table_impls!(impl_the_methods);
4689
4690    /// Set to 20.
4691    pub fn format(&self) -> u8 {
4692        let range = self.format_byte_range();
4693        self.data.read_at(range.start).ok().unwrap()
4694    }
4695
4696    /// Offset to a Paint subtable.
4697    pub fn paint_offset(&self) -> Offset24 {
4698        let range = self.paint_offset_byte_range();
4699        self.data.read_at(range.start).ok().unwrap()
4700    }
4701
4702    /// Attempt to resolve [`paint_offset`][Self::paint_offset].
4703    pub fn paint(&self) -> Result<Paint<'a>, ReadError> {
4704        let data = self.data;
4705        self.paint_offset().resolve(data)
4706    }
4707
4708    /// Scale factor in x and y directions.
4709    pub fn scale(&self) -> F2Dot14 {
4710        let range = self.scale_byte_range();
4711        self.data.read_at(range.start).ok().unwrap()
4712    }
4713
4714    pub fn format_byte_range(&self) -> Range<usize> {
4715        let start = 0;
4716        start..start + u8::RAW_BYTE_LEN
4717    }
4718
4719    pub fn paint_offset_byte_range(&self) -> Range<usize> {
4720        let start = self.format_byte_range().end;
4721        start..start + Offset24::RAW_BYTE_LEN
4722    }
4723
4724    pub fn scale_byte_range(&self) -> Range<usize> {
4725        let start = self.paint_offset_byte_range().end;
4726        start..start + F2Dot14::RAW_BYTE_LEN
4727    }
4728}
4729
4730#[cfg(feature = "experimental_traverse")]
4731impl<'a> SomeTable<'a> for PaintScaleUniform<'a> {
4732    fn type_name(&self) -> &str {
4733        "PaintScaleUniform"
4734    }
4735    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4736        match idx {
4737            0usize => Some(Field::new("format", self.format())),
4738            1usize => Some(Field::new(
4739                "paint_offset",
4740                FieldType::offset(self.paint_offset(), self.paint()),
4741            )),
4742            2usize => Some(Field::new("scale", self.scale())),
4743            _ => None,
4744        }
4745    }
4746}
4747
4748#[cfg(feature = "experimental_traverse")]
4749#[allow(clippy::needless_lifetimes)]
4750impl<'a> std::fmt::Debug for PaintScaleUniform<'a> {
4751    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4752        (self as &dyn SomeTable<'a>).fmt(f)
4753    }
4754}
4755
4756impl Format<u8> for PaintVarScaleUniform<'_> {
4757    const FORMAT: u8 = 21;
4758}
4759
4760impl<'a> MinByteRange<'a> for PaintVarScaleUniform<'a> {
4761    fn min_byte_range(&self) -> Range<usize> {
4762        0..self.var_index_base_byte_range().end
4763    }
4764    fn min_table_bytes(&self) -> &'a [u8] {
4765        let range = self.min_byte_range();
4766        self.data.as_bytes().get(range).unwrap_or_default()
4767    }
4768}
4769
4770impl<'a> FontRead<'a> for PaintVarScaleUniform<'a> {
4771    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4772        #[allow(clippy::absurd_extreme_comparisons)]
4773        if data.len() < Self::MIN_SIZE {
4774            return Err(ReadError::OutOfBounds);
4775        }
4776        Ok(Self { data })
4777    }
4778}
4779
4780/// [PaintVarScaleUniform](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-16-to-23-paintscale-and-variant-scaling-formats) table
4781#[derive(Clone)]
4782pub struct PaintVarScaleUniform<'a> {
4783    data: FontData<'a>,
4784}
4785
4786#[allow(clippy::needless_lifetimes)]
4787impl<'a> PaintVarScaleUniform<'a> {
4788    pub const MIN_SIZE: usize =
4789        (u8::RAW_BYTE_LEN + Offset24::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
4790    basic_table_impls!(impl_the_methods);
4791
4792    /// Set to 21.
4793    pub fn format(&self) -> u8 {
4794        let range = self.format_byte_range();
4795        self.data.read_at(range.start).ok().unwrap()
4796    }
4797
4798    /// Offset to a Paint subtable.
4799    pub fn paint_offset(&self) -> Offset24 {
4800        let range = self.paint_offset_byte_range();
4801        self.data.read_at(range.start).ok().unwrap()
4802    }
4803
4804    /// Attempt to resolve [`paint_offset`][Self::paint_offset].
4805    pub fn paint(&self) -> Result<Paint<'a>, ReadError> {
4806        let data = self.data;
4807        self.paint_offset().resolve(data)
4808    }
4809
4810    /// Scale factor in x and y directions. For variation, use
4811    /// varIndexBase + 0.
4812    pub fn scale(&self) -> F2Dot14 {
4813        let range = self.scale_byte_range();
4814        self.data.read_at(range.start).ok().unwrap()
4815    }
4816
4817    /// Base index into DeltaSetIndexMap.
4818    pub fn var_index_base(&self) -> u32 {
4819        let range = self.var_index_base_byte_range();
4820        self.data.read_at(range.start).ok().unwrap()
4821    }
4822
4823    pub fn format_byte_range(&self) -> Range<usize> {
4824        let start = 0;
4825        start..start + u8::RAW_BYTE_LEN
4826    }
4827
4828    pub fn paint_offset_byte_range(&self) -> Range<usize> {
4829        let start = self.format_byte_range().end;
4830        start..start + Offset24::RAW_BYTE_LEN
4831    }
4832
4833    pub fn scale_byte_range(&self) -> Range<usize> {
4834        let start = self.paint_offset_byte_range().end;
4835        start..start + F2Dot14::RAW_BYTE_LEN
4836    }
4837
4838    pub fn var_index_base_byte_range(&self) -> Range<usize> {
4839        let start = self.scale_byte_range().end;
4840        start..start + u32::RAW_BYTE_LEN
4841    }
4842}
4843
4844#[cfg(feature = "experimental_traverse")]
4845impl<'a> SomeTable<'a> for PaintVarScaleUniform<'a> {
4846    fn type_name(&self) -> &str {
4847        "PaintVarScaleUniform"
4848    }
4849    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4850        match idx {
4851            0usize => Some(Field::new("format", self.format())),
4852            1usize => Some(Field::new(
4853                "paint_offset",
4854                FieldType::offset(self.paint_offset(), self.paint()),
4855            )),
4856            2usize => Some(Field::new("scale", self.scale())),
4857            3usize => Some(Field::new("var_index_base", self.var_index_base())),
4858            _ => None,
4859        }
4860    }
4861}
4862
4863#[cfg(feature = "experimental_traverse")]
4864#[allow(clippy::needless_lifetimes)]
4865impl<'a> std::fmt::Debug for PaintVarScaleUniform<'a> {
4866    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4867        (self as &dyn SomeTable<'a>).fmt(f)
4868    }
4869}
4870
4871impl Format<u8> for PaintScaleUniformAroundCenter<'_> {
4872    const FORMAT: u8 = 22;
4873}
4874
4875impl<'a> MinByteRange<'a> for PaintScaleUniformAroundCenter<'a> {
4876    fn min_byte_range(&self) -> Range<usize> {
4877        0..self.center_y_byte_range().end
4878    }
4879    fn min_table_bytes(&self) -> &'a [u8] {
4880        let range = self.min_byte_range();
4881        self.data.as_bytes().get(range).unwrap_or_default()
4882    }
4883}
4884
4885impl<'a> FontRead<'a> for PaintScaleUniformAroundCenter<'a> {
4886    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4887        #[allow(clippy::absurd_extreme_comparisons)]
4888        if data.len() < Self::MIN_SIZE {
4889            return Err(ReadError::OutOfBounds);
4890        }
4891        Ok(Self { data })
4892    }
4893}
4894
4895/// [PaintScaleUniformAroundCenter](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-16-to-23-paintscale-and-variant-scaling-formats) table
4896#[derive(Clone)]
4897pub struct PaintScaleUniformAroundCenter<'a> {
4898    data: FontData<'a>,
4899}
4900
4901#[allow(clippy::needless_lifetimes)]
4902impl<'a> PaintScaleUniformAroundCenter<'a> {
4903    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN
4904        + Offset24::RAW_BYTE_LEN
4905        + F2Dot14::RAW_BYTE_LEN
4906        + FWord::RAW_BYTE_LEN
4907        + FWord::RAW_BYTE_LEN);
4908    basic_table_impls!(impl_the_methods);
4909
4910    /// Set to 22.
4911    pub fn format(&self) -> u8 {
4912        let range = self.format_byte_range();
4913        self.data.read_at(range.start).ok().unwrap()
4914    }
4915
4916    /// Offset to a Paint subtable.
4917    pub fn paint_offset(&self) -> Offset24 {
4918        let range = self.paint_offset_byte_range();
4919        self.data.read_at(range.start).ok().unwrap()
4920    }
4921
4922    /// Attempt to resolve [`paint_offset`][Self::paint_offset].
4923    pub fn paint(&self) -> Result<Paint<'a>, ReadError> {
4924        let data = self.data;
4925        self.paint_offset().resolve(data)
4926    }
4927
4928    /// Scale factor in x and y directions.
4929    pub fn scale(&self) -> F2Dot14 {
4930        let range = self.scale_byte_range();
4931        self.data.read_at(range.start).ok().unwrap()
4932    }
4933
4934    /// x coordinate for the center of scaling.
4935    pub fn center_x(&self) -> FWord {
4936        let range = self.center_x_byte_range();
4937        self.data.read_at(range.start).ok().unwrap()
4938    }
4939
4940    /// y coordinate for the center of scaling.
4941    pub fn center_y(&self) -> FWord {
4942        let range = self.center_y_byte_range();
4943        self.data.read_at(range.start).ok().unwrap()
4944    }
4945
4946    pub fn format_byte_range(&self) -> Range<usize> {
4947        let start = 0;
4948        start..start + u8::RAW_BYTE_LEN
4949    }
4950
4951    pub fn paint_offset_byte_range(&self) -> Range<usize> {
4952        let start = self.format_byte_range().end;
4953        start..start + Offset24::RAW_BYTE_LEN
4954    }
4955
4956    pub fn scale_byte_range(&self) -> Range<usize> {
4957        let start = self.paint_offset_byte_range().end;
4958        start..start + F2Dot14::RAW_BYTE_LEN
4959    }
4960
4961    pub fn center_x_byte_range(&self) -> Range<usize> {
4962        let start = self.scale_byte_range().end;
4963        start..start + FWord::RAW_BYTE_LEN
4964    }
4965
4966    pub fn center_y_byte_range(&self) -> Range<usize> {
4967        let start = self.center_x_byte_range().end;
4968        start..start + FWord::RAW_BYTE_LEN
4969    }
4970}
4971
4972#[cfg(feature = "experimental_traverse")]
4973impl<'a> SomeTable<'a> for PaintScaleUniformAroundCenter<'a> {
4974    fn type_name(&self) -> &str {
4975        "PaintScaleUniformAroundCenter"
4976    }
4977    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4978        match idx {
4979            0usize => Some(Field::new("format", self.format())),
4980            1usize => Some(Field::new(
4981                "paint_offset",
4982                FieldType::offset(self.paint_offset(), self.paint()),
4983            )),
4984            2usize => Some(Field::new("scale", self.scale())),
4985            3usize => Some(Field::new("center_x", self.center_x())),
4986            4usize => Some(Field::new("center_y", self.center_y())),
4987            _ => None,
4988        }
4989    }
4990}
4991
4992#[cfg(feature = "experimental_traverse")]
4993#[allow(clippy::needless_lifetimes)]
4994impl<'a> std::fmt::Debug for PaintScaleUniformAroundCenter<'a> {
4995    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4996        (self as &dyn SomeTable<'a>).fmt(f)
4997    }
4998}
4999
5000impl Format<u8> for PaintVarScaleUniformAroundCenter<'_> {
5001    const FORMAT: u8 = 23;
5002}
5003
5004impl<'a> MinByteRange<'a> for PaintVarScaleUniformAroundCenter<'a> {
5005    fn min_byte_range(&self) -> Range<usize> {
5006        0..self.var_index_base_byte_range().end
5007    }
5008    fn min_table_bytes(&self) -> &'a [u8] {
5009        let range = self.min_byte_range();
5010        self.data.as_bytes().get(range).unwrap_or_default()
5011    }
5012}
5013
5014impl<'a> FontRead<'a> for PaintVarScaleUniformAroundCenter<'a> {
5015    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
5016        #[allow(clippy::absurd_extreme_comparisons)]
5017        if data.len() < Self::MIN_SIZE {
5018            return Err(ReadError::OutOfBounds);
5019        }
5020        Ok(Self { data })
5021    }
5022}
5023
5024/// [PaintVarScaleUniformAroundCenter](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-16-to-23-paintscale-and-variant-scaling-formats) table
5025#[derive(Clone)]
5026pub struct PaintVarScaleUniformAroundCenter<'a> {
5027    data: FontData<'a>,
5028}
5029
5030#[allow(clippy::needless_lifetimes)]
5031impl<'a> PaintVarScaleUniformAroundCenter<'a> {
5032    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN
5033        + Offset24::RAW_BYTE_LEN
5034        + F2Dot14::RAW_BYTE_LEN
5035        + FWord::RAW_BYTE_LEN
5036        + FWord::RAW_BYTE_LEN
5037        + u32::RAW_BYTE_LEN);
5038    basic_table_impls!(impl_the_methods);
5039
5040    /// Set to 23.
5041    pub fn format(&self) -> u8 {
5042        let range = self.format_byte_range();
5043        self.data.read_at(range.start).ok().unwrap()
5044    }
5045
5046    /// Offset to a Paint subtable.
5047    pub fn paint_offset(&self) -> Offset24 {
5048        let range = self.paint_offset_byte_range();
5049        self.data.read_at(range.start).ok().unwrap()
5050    }
5051
5052    /// Attempt to resolve [`paint_offset`][Self::paint_offset].
5053    pub fn paint(&self) -> Result<Paint<'a>, ReadError> {
5054        let data = self.data;
5055        self.paint_offset().resolve(data)
5056    }
5057
5058    /// Scale factor in x and y directions. For variation, use
5059    /// varIndexBase + 0.
5060    pub fn scale(&self) -> F2Dot14 {
5061        let range = self.scale_byte_range();
5062        self.data.read_at(range.start).ok().unwrap()
5063    }
5064
5065    /// x coordinate for the center of scaling. For variation, use
5066    /// varIndexBase + 1.
5067    pub fn center_x(&self) -> FWord {
5068        let range = self.center_x_byte_range();
5069        self.data.read_at(range.start).ok().unwrap()
5070    }
5071
5072    /// y coordinate for the center of scaling. For variation, use
5073    /// varIndexBase + 2.
5074    pub fn center_y(&self) -> FWord {
5075        let range = self.center_y_byte_range();
5076        self.data.read_at(range.start).ok().unwrap()
5077    }
5078
5079    /// Base index into DeltaSetIndexMap.
5080    pub fn var_index_base(&self) -> u32 {
5081        let range = self.var_index_base_byte_range();
5082        self.data.read_at(range.start).ok().unwrap()
5083    }
5084
5085    pub fn format_byte_range(&self) -> Range<usize> {
5086        let start = 0;
5087        start..start + u8::RAW_BYTE_LEN
5088    }
5089
5090    pub fn paint_offset_byte_range(&self) -> Range<usize> {
5091        let start = self.format_byte_range().end;
5092        start..start + Offset24::RAW_BYTE_LEN
5093    }
5094
5095    pub fn scale_byte_range(&self) -> Range<usize> {
5096        let start = self.paint_offset_byte_range().end;
5097        start..start + F2Dot14::RAW_BYTE_LEN
5098    }
5099
5100    pub fn center_x_byte_range(&self) -> Range<usize> {
5101        let start = self.scale_byte_range().end;
5102        start..start + FWord::RAW_BYTE_LEN
5103    }
5104
5105    pub fn center_y_byte_range(&self) -> Range<usize> {
5106        let start = self.center_x_byte_range().end;
5107        start..start + FWord::RAW_BYTE_LEN
5108    }
5109
5110    pub fn var_index_base_byte_range(&self) -> Range<usize> {
5111        let start = self.center_y_byte_range().end;
5112        start..start + u32::RAW_BYTE_LEN
5113    }
5114}
5115
5116#[cfg(feature = "experimental_traverse")]
5117impl<'a> SomeTable<'a> for PaintVarScaleUniformAroundCenter<'a> {
5118    fn type_name(&self) -> &str {
5119        "PaintVarScaleUniformAroundCenter"
5120    }
5121    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
5122        match idx {
5123            0usize => Some(Field::new("format", self.format())),
5124            1usize => Some(Field::new(
5125                "paint_offset",
5126                FieldType::offset(self.paint_offset(), self.paint()),
5127            )),
5128            2usize => Some(Field::new("scale", self.scale())),
5129            3usize => Some(Field::new("center_x", self.center_x())),
5130            4usize => Some(Field::new("center_y", self.center_y())),
5131            5usize => Some(Field::new("var_index_base", self.var_index_base())),
5132            _ => None,
5133        }
5134    }
5135}
5136
5137#[cfg(feature = "experimental_traverse")]
5138#[allow(clippy::needless_lifetimes)]
5139impl<'a> std::fmt::Debug for PaintVarScaleUniformAroundCenter<'a> {
5140    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5141        (self as &dyn SomeTable<'a>).fmt(f)
5142    }
5143}
5144
5145impl Format<u8> for PaintRotate<'_> {
5146    const FORMAT: u8 = 24;
5147}
5148
5149impl<'a> MinByteRange<'a> for PaintRotate<'a> {
5150    fn min_byte_range(&self) -> Range<usize> {
5151        0..self.angle_byte_range().end
5152    }
5153    fn min_table_bytes(&self) -> &'a [u8] {
5154        let range = self.min_byte_range();
5155        self.data.as_bytes().get(range).unwrap_or_default()
5156    }
5157}
5158
5159impl<'a> FontRead<'a> for PaintRotate<'a> {
5160    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
5161        #[allow(clippy::absurd_extreme_comparisons)]
5162        if data.len() < Self::MIN_SIZE {
5163            return Err(ReadError::OutOfBounds);
5164        }
5165        Ok(Self { data })
5166    }
5167}
5168
5169/// [PaintRotate](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-24-to-27-paintrotate-paintvarrotate-paintrotatearoundcenter-paintvarrotatearoundcenter) table
5170#[derive(Clone)]
5171pub struct PaintRotate<'a> {
5172    data: FontData<'a>,
5173}
5174
5175#[allow(clippy::needless_lifetimes)]
5176impl<'a> PaintRotate<'a> {
5177    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN + Offset24::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN);
5178    basic_table_impls!(impl_the_methods);
5179
5180    /// Set to 24.
5181    pub fn format(&self) -> u8 {
5182        let range = self.format_byte_range();
5183        self.data.read_at(range.start).ok().unwrap()
5184    }
5185
5186    /// Offset to a Paint subtable.
5187    pub fn paint_offset(&self) -> Offset24 {
5188        let range = self.paint_offset_byte_range();
5189        self.data.read_at(range.start).ok().unwrap()
5190    }
5191
5192    /// Attempt to resolve [`paint_offset`][Self::paint_offset].
5193    pub fn paint(&self) -> Result<Paint<'a>, ReadError> {
5194        let data = self.data;
5195        self.paint_offset().resolve(data)
5196    }
5197
5198    /// Rotation angle, 180° in counter-clockwise degrees per 1.0 of
5199    /// value.
5200    pub fn angle(&self) -> F2Dot14 {
5201        let range = self.angle_byte_range();
5202        self.data.read_at(range.start).ok().unwrap()
5203    }
5204
5205    pub fn format_byte_range(&self) -> Range<usize> {
5206        let start = 0;
5207        start..start + u8::RAW_BYTE_LEN
5208    }
5209
5210    pub fn paint_offset_byte_range(&self) -> Range<usize> {
5211        let start = self.format_byte_range().end;
5212        start..start + Offset24::RAW_BYTE_LEN
5213    }
5214
5215    pub fn angle_byte_range(&self) -> Range<usize> {
5216        let start = self.paint_offset_byte_range().end;
5217        start..start + F2Dot14::RAW_BYTE_LEN
5218    }
5219}
5220
5221#[cfg(feature = "experimental_traverse")]
5222impl<'a> SomeTable<'a> for PaintRotate<'a> {
5223    fn type_name(&self) -> &str {
5224        "PaintRotate"
5225    }
5226    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
5227        match idx {
5228            0usize => Some(Field::new("format", self.format())),
5229            1usize => Some(Field::new(
5230                "paint_offset",
5231                FieldType::offset(self.paint_offset(), self.paint()),
5232            )),
5233            2usize => Some(Field::new("angle", self.angle())),
5234            _ => None,
5235        }
5236    }
5237}
5238
5239#[cfg(feature = "experimental_traverse")]
5240#[allow(clippy::needless_lifetimes)]
5241impl<'a> std::fmt::Debug for PaintRotate<'a> {
5242    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5243        (self as &dyn SomeTable<'a>).fmt(f)
5244    }
5245}
5246
5247impl Format<u8> for PaintVarRotate<'_> {
5248    const FORMAT: u8 = 25;
5249}
5250
5251impl<'a> MinByteRange<'a> for PaintVarRotate<'a> {
5252    fn min_byte_range(&self) -> Range<usize> {
5253        0..self.var_index_base_byte_range().end
5254    }
5255    fn min_table_bytes(&self) -> &'a [u8] {
5256        let range = self.min_byte_range();
5257        self.data.as_bytes().get(range).unwrap_or_default()
5258    }
5259}
5260
5261impl<'a> FontRead<'a> for PaintVarRotate<'a> {
5262    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
5263        #[allow(clippy::absurd_extreme_comparisons)]
5264        if data.len() < Self::MIN_SIZE {
5265            return Err(ReadError::OutOfBounds);
5266        }
5267        Ok(Self { data })
5268    }
5269}
5270
5271/// [PaintVarRotate](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-24-to-27-paintrotate-paintvarrotate-paintrotatearoundcenter-paintvarrotatearoundcenter) table
5272#[derive(Clone)]
5273pub struct PaintVarRotate<'a> {
5274    data: FontData<'a>,
5275}
5276
5277#[allow(clippy::needless_lifetimes)]
5278impl<'a> PaintVarRotate<'a> {
5279    pub const MIN_SIZE: usize =
5280        (u8::RAW_BYTE_LEN + Offset24::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
5281    basic_table_impls!(impl_the_methods);
5282
5283    /// Set to 25.
5284    pub fn format(&self) -> u8 {
5285        let range = self.format_byte_range();
5286        self.data.read_at(range.start).ok().unwrap()
5287    }
5288
5289    /// Offset to a Paint subtable.
5290    pub fn paint_offset(&self) -> Offset24 {
5291        let range = self.paint_offset_byte_range();
5292        self.data.read_at(range.start).ok().unwrap()
5293    }
5294
5295    /// Attempt to resolve [`paint_offset`][Self::paint_offset].
5296    pub fn paint(&self) -> Result<Paint<'a>, ReadError> {
5297        let data = self.data;
5298        self.paint_offset().resolve(data)
5299    }
5300
5301    /// Rotation angle, 180° in counter-clockwise degrees per 1.0 of
5302    /// value. For variation, use varIndexBase + 0.
5303    pub fn angle(&self) -> F2Dot14 {
5304        let range = self.angle_byte_range();
5305        self.data.read_at(range.start).ok().unwrap()
5306    }
5307
5308    /// Base index into DeltaSetIndexMap.
5309    pub fn var_index_base(&self) -> u32 {
5310        let range = self.var_index_base_byte_range();
5311        self.data.read_at(range.start).ok().unwrap()
5312    }
5313
5314    pub fn format_byte_range(&self) -> Range<usize> {
5315        let start = 0;
5316        start..start + u8::RAW_BYTE_LEN
5317    }
5318
5319    pub fn paint_offset_byte_range(&self) -> Range<usize> {
5320        let start = self.format_byte_range().end;
5321        start..start + Offset24::RAW_BYTE_LEN
5322    }
5323
5324    pub fn angle_byte_range(&self) -> Range<usize> {
5325        let start = self.paint_offset_byte_range().end;
5326        start..start + F2Dot14::RAW_BYTE_LEN
5327    }
5328
5329    pub fn var_index_base_byte_range(&self) -> Range<usize> {
5330        let start = self.angle_byte_range().end;
5331        start..start + u32::RAW_BYTE_LEN
5332    }
5333}
5334
5335#[cfg(feature = "experimental_traverse")]
5336impl<'a> SomeTable<'a> for PaintVarRotate<'a> {
5337    fn type_name(&self) -> &str {
5338        "PaintVarRotate"
5339    }
5340    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
5341        match idx {
5342            0usize => Some(Field::new("format", self.format())),
5343            1usize => Some(Field::new(
5344                "paint_offset",
5345                FieldType::offset(self.paint_offset(), self.paint()),
5346            )),
5347            2usize => Some(Field::new("angle", self.angle())),
5348            3usize => Some(Field::new("var_index_base", self.var_index_base())),
5349            _ => None,
5350        }
5351    }
5352}
5353
5354#[cfg(feature = "experimental_traverse")]
5355#[allow(clippy::needless_lifetimes)]
5356impl<'a> std::fmt::Debug for PaintVarRotate<'a> {
5357    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5358        (self as &dyn SomeTable<'a>).fmt(f)
5359    }
5360}
5361
5362impl Format<u8> for PaintRotateAroundCenter<'_> {
5363    const FORMAT: u8 = 26;
5364}
5365
5366impl<'a> MinByteRange<'a> for PaintRotateAroundCenter<'a> {
5367    fn min_byte_range(&self) -> Range<usize> {
5368        0..self.center_y_byte_range().end
5369    }
5370    fn min_table_bytes(&self) -> &'a [u8] {
5371        let range = self.min_byte_range();
5372        self.data.as_bytes().get(range).unwrap_or_default()
5373    }
5374}
5375
5376impl<'a> FontRead<'a> for PaintRotateAroundCenter<'a> {
5377    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
5378        #[allow(clippy::absurd_extreme_comparisons)]
5379        if data.len() < Self::MIN_SIZE {
5380            return Err(ReadError::OutOfBounds);
5381        }
5382        Ok(Self { data })
5383    }
5384}
5385
5386/// [PaintRotateAroundCenter](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-24-to-27-paintrotate-paintvarrotate-paintrotatearoundcenter-paintvarrotatearoundcenter) table
5387#[derive(Clone)]
5388pub struct PaintRotateAroundCenter<'a> {
5389    data: FontData<'a>,
5390}
5391
5392#[allow(clippy::needless_lifetimes)]
5393impl<'a> PaintRotateAroundCenter<'a> {
5394    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN
5395        + Offset24::RAW_BYTE_LEN
5396        + F2Dot14::RAW_BYTE_LEN
5397        + FWord::RAW_BYTE_LEN
5398        + FWord::RAW_BYTE_LEN);
5399    basic_table_impls!(impl_the_methods);
5400
5401    /// Set to 26.
5402    pub fn format(&self) -> u8 {
5403        let range = self.format_byte_range();
5404        self.data.read_at(range.start).ok().unwrap()
5405    }
5406
5407    /// Offset to a Paint subtable.
5408    pub fn paint_offset(&self) -> Offset24 {
5409        let range = self.paint_offset_byte_range();
5410        self.data.read_at(range.start).ok().unwrap()
5411    }
5412
5413    /// Attempt to resolve [`paint_offset`][Self::paint_offset].
5414    pub fn paint(&self) -> Result<Paint<'a>, ReadError> {
5415        let data = self.data;
5416        self.paint_offset().resolve(data)
5417    }
5418
5419    /// Rotation angle, 180° in counter-clockwise degrees per 1.0 of
5420    /// value.
5421    pub fn angle(&self) -> F2Dot14 {
5422        let range = self.angle_byte_range();
5423        self.data.read_at(range.start).ok().unwrap()
5424    }
5425
5426    /// x coordinate for the center of rotation.
5427    pub fn center_x(&self) -> FWord {
5428        let range = self.center_x_byte_range();
5429        self.data.read_at(range.start).ok().unwrap()
5430    }
5431
5432    /// y coordinate for the center of rotation.
5433    pub fn center_y(&self) -> FWord {
5434        let range = self.center_y_byte_range();
5435        self.data.read_at(range.start).ok().unwrap()
5436    }
5437
5438    pub fn format_byte_range(&self) -> Range<usize> {
5439        let start = 0;
5440        start..start + u8::RAW_BYTE_LEN
5441    }
5442
5443    pub fn paint_offset_byte_range(&self) -> Range<usize> {
5444        let start = self.format_byte_range().end;
5445        start..start + Offset24::RAW_BYTE_LEN
5446    }
5447
5448    pub fn angle_byte_range(&self) -> Range<usize> {
5449        let start = self.paint_offset_byte_range().end;
5450        start..start + F2Dot14::RAW_BYTE_LEN
5451    }
5452
5453    pub fn center_x_byte_range(&self) -> Range<usize> {
5454        let start = self.angle_byte_range().end;
5455        start..start + FWord::RAW_BYTE_LEN
5456    }
5457
5458    pub fn center_y_byte_range(&self) -> Range<usize> {
5459        let start = self.center_x_byte_range().end;
5460        start..start + FWord::RAW_BYTE_LEN
5461    }
5462}
5463
5464#[cfg(feature = "experimental_traverse")]
5465impl<'a> SomeTable<'a> for PaintRotateAroundCenter<'a> {
5466    fn type_name(&self) -> &str {
5467        "PaintRotateAroundCenter"
5468    }
5469    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
5470        match idx {
5471            0usize => Some(Field::new("format", self.format())),
5472            1usize => Some(Field::new(
5473                "paint_offset",
5474                FieldType::offset(self.paint_offset(), self.paint()),
5475            )),
5476            2usize => Some(Field::new("angle", self.angle())),
5477            3usize => Some(Field::new("center_x", self.center_x())),
5478            4usize => Some(Field::new("center_y", self.center_y())),
5479            _ => None,
5480        }
5481    }
5482}
5483
5484#[cfg(feature = "experimental_traverse")]
5485#[allow(clippy::needless_lifetimes)]
5486impl<'a> std::fmt::Debug for PaintRotateAroundCenter<'a> {
5487    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5488        (self as &dyn SomeTable<'a>).fmt(f)
5489    }
5490}
5491
5492impl Format<u8> for PaintVarRotateAroundCenter<'_> {
5493    const FORMAT: u8 = 27;
5494}
5495
5496impl<'a> MinByteRange<'a> for PaintVarRotateAroundCenter<'a> {
5497    fn min_byte_range(&self) -> Range<usize> {
5498        0..self.var_index_base_byte_range().end
5499    }
5500    fn min_table_bytes(&self) -> &'a [u8] {
5501        let range = self.min_byte_range();
5502        self.data.as_bytes().get(range).unwrap_or_default()
5503    }
5504}
5505
5506impl<'a> FontRead<'a> for PaintVarRotateAroundCenter<'a> {
5507    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
5508        #[allow(clippy::absurd_extreme_comparisons)]
5509        if data.len() < Self::MIN_SIZE {
5510            return Err(ReadError::OutOfBounds);
5511        }
5512        Ok(Self { data })
5513    }
5514}
5515
5516/// [PaintVarRotateAroundCenter](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-24-to-27-paintrotate-paintvarrotate-paintrotatearoundcenter-paintvarrotatearoundcenter) table
5517#[derive(Clone)]
5518pub struct PaintVarRotateAroundCenter<'a> {
5519    data: FontData<'a>,
5520}
5521
5522#[allow(clippy::needless_lifetimes)]
5523impl<'a> PaintVarRotateAroundCenter<'a> {
5524    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN
5525        + Offset24::RAW_BYTE_LEN
5526        + F2Dot14::RAW_BYTE_LEN
5527        + FWord::RAW_BYTE_LEN
5528        + FWord::RAW_BYTE_LEN
5529        + u32::RAW_BYTE_LEN);
5530    basic_table_impls!(impl_the_methods);
5531
5532    /// Set to 27.
5533    pub fn format(&self) -> u8 {
5534        let range = self.format_byte_range();
5535        self.data.read_at(range.start).ok().unwrap()
5536    }
5537
5538    /// Offset to a Paint subtable.
5539    pub fn paint_offset(&self) -> Offset24 {
5540        let range = self.paint_offset_byte_range();
5541        self.data.read_at(range.start).ok().unwrap()
5542    }
5543
5544    /// Attempt to resolve [`paint_offset`][Self::paint_offset].
5545    pub fn paint(&self) -> Result<Paint<'a>, ReadError> {
5546        let data = self.data;
5547        self.paint_offset().resolve(data)
5548    }
5549
5550    /// Rotation angle, 180° in counter-clockwise degrees per 1.0 of
5551    /// value. For variation, use varIndexBase + 0.
5552    pub fn angle(&self) -> F2Dot14 {
5553        let range = self.angle_byte_range();
5554        self.data.read_at(range.start).ok().unwrap()
5555    }
5556
5557    /// x coordinate for the center of rotation. For variation, use
5558    /// varIndexBase + 1.
5559    pub fn center_x(&self) -> FWord {
5560        let range = self.center_x_byte_range();
5561        self.data.read_at(range.start).ok().unwrap()
5562    }
5563
5564    /// y coordinate for the center of rotation. For variation, use
5565    /// varIndexBase + 2.
5566    pub fn center_y(&self) -> FWord {
5567        let range = self.center_y_byte_range();
5568        self.data.read_at(range.start).ok().unwrap()
5569    }
5570
5571    /// Base index into DeltaSetIndexMap.
5572    pub fn var_index_base(&self) -> u32 {
5573        let range = self.var_index_base_byte_range();
5574        self.data.read_at(range.start).ok().unwrap()
5575    }
5576
5577    pub fn format_byte_range(&self) -> Range<usize> {
5578        let start = 0;
5579        start..start + u8::RAW_BYTE_LEN
5580    }
5581
5582    pub fn paint_offset_byte_range(&self) -> Range<usize> {
5583        let start = self.format_byte_range().end;
5584        start..start + Offset24::RAW_BYTE_LEN
5585    }
5586
5587    pub fn angle_byte_range(&self) -> Range<usize> {
5588        let start = self.paint_offset_byte_range().end;
5589        start..start + F2Dot14::RAW_BYTE_LEN
5590    }
5591
5592    pub fn center_x_byte_range(&self) -> Range<usize> {
5593        let start = self.angle_byte_range().end;
5594        start..start + FWord::RAW_BYTE_LEN
5595    }
5596
5597    pub fn center_y_byte_range(&self) -> Range<usize> {
5598        let start = self.center_x_byte_range().end;
5599        start..start + FWord::RAW_BYTE_LEN
5600    }
5601
5602    pub fn var_index_base_byte_range(&self) -> Range<usize> {
5603        let start = self.center_y_byte_range().end;
5604        start..start + u32::RAW_BYTE_LEN
5605    }
5606}
5607
5608#[cfg(feature = "experimental_traverse")]
5609impl<'a> SomeTable<'a> for PaintVarRotateAroundCenter<'a> {
5610    fn type_name(&self) -> &str {
5611        "PaintVarRotateAroundCenter"
5612    }
5613    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
5614        match idx {
5615            0usize => Some(Field::new("format", self.format())),
5616            1usize => Some(Field::new(
5617                "paint_offset",
5618                FieldType::offset(self.paint_offset(), self.paint()),
5619            )),
5620            2usize => Some(Field::new("angle", self.angle())),
5621            3usize => Some(Field::new("center_x", self.center_x())),
5622            4usize => Some(Field::new("center_y", self.center_y())),
5623            5usize => Some(Field::new("var_index_base", self.var_index_base())),
5624            _ => None,
5625        }
5626    }
5627}
5628
5629#[cfg(feature = "experimental_traverse")]
5630#[allow(clippy::needless_lifetimes)]
5631impl<'a> std::fmt::Debug for PaintVarRotateAroundCenter<'a> {
5632    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5633        (self as &dyn SomeTable<'a>).fmt(f)
5634    }
5635}
5636
5637impl Format<u8> for PaintSkew<'_> {
5638    const FORMAT: u8 = 28;
5639}
5640
5641impl<'a> MinByteRange<'a> for PaintSkew<'a> {
5642    fn min_byte_range(&self) -> Range<usize> {
5643        0..self.y_skew_angle_byte_range().end
5644    }
5645    fn min_table_bytes(&self) -> &'a [u8] {
5646        let range = self.min_byte_range();
5647        self.data.as_bytes().get(range).unwrap_or_default()
5648    }
5649}
5650
5651impl<'a> FontRead<'a> for PaintSkew<'a> {
5652    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
5653        #[allow(clippy::absurd_extreme_comparisons)]
5654        if data.len() < Self::MIN_SIZE {
5655            return Err(ReadError::OutOfBounds);
5656        }
5657        Ok(Self { data })
5658    }
5659}
5660
5661/// [PaintSkew](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-28-to-31-paintskew-paintvarskew-paintskewaroundcenter-paintvarskewaroundcenter) table
5662#[derive(Clone)]
5663pub struct PaintSkew<'a> {
5664    data: FontData<'a>,
5665}
5666
5667#[allow(clippy::needless_lifetimes)]
5668impl<'a> PaintSkew<'a> {
5669    pub const MIN_SIZE: usize =
5670        (u8::RAW_BYTE_LEN + Offset24::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN);
5671    basic_table_impls!(impl_the_methods);
5672
5673    /// Set to 28.
5674    pub fn format(&self) -> u8 {
5675        let range = self.format_byte_range();
5676        self.data.read_at(range.start).ok().unwrap()
5677    }
5678
5679    /// Offset to a Paint subtable.
5680    pub fn paint_offset(&self) -> Offset24 {
5681        let range = self.paint_offset_byte_range();
5682        self.data.read_at(range.start).ok().unwrap()
5683    }
5684
5685    /// Attempt to resolve [`paint_offset`][Self::paint_offset].
5686    pub fn paint(&self) -> Result<Paint<'a>, ReadError> {
5687        let data = self.data;
5688        self.paint_offset().resolve(data)
5689    }
5690
5691    /// Angle of skew in the direction of the x-axis, 180° in
5692    /// counter-clockwise degrees per 1.0 of value.
5693    pub fn x_skew_angle(&self) -> F2Dot14 {
5694        let range = self.x_skew_angle_byte_range();
5695        self.data.read_at(range.start).ok().unwrap()
5696    }
5697
5698    /// Angle of skew in the direction of the y-axis, 180° in
5699    /// counter-clockwise degrees per 1.0 of value.
5700    pub fn y_skew_angle(&self) -> F2Dot14 {
5701        let range = self.y_skew_angle_byte_range();
5702        self.data.read_at(range.start).ok().unwrap()
5703    }
5704
5705    pub fn format_byte_range(&self) -> Range<usize> {
5706        let start = 0;
5707        start..start + u8::RAW_BYTE_LEN
5708    }
5709
5710    pub fn paint_offset_byte_range(&self) -> Range<usize> {
5711        let start = self.format_byte_range().end;
5712        start..start + Offset24::RAW_BYTE_LEN
5713    }
5714
5715    pub fn x_skew_angle_byte_range(&self) -> Range<usize> {
5716        let start = self.paint_offset_byte_range().end;
5717        start..start + F2Dot14::RAW_BYTE_LEN
5718    }
5719
5720    pub fn y_skew_angle_byte_range(&self) -> Range<usize> {
5721        let start = self.x_skew_angle_byte_range().end;
5722        start..start + F2Dot14::RAW_BYTE_LEN
5723    }
5724}
5725
5726#[cfg(feature = "experimental_traverse")]
5727impl<'a> SomeTable<'a> for PaintSkew<'a> {
5728    fn type_name(&self) -> &str {
5729        "PaintSkew"
5730    }
5731    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
5732        match idx {
5733            0usize => Some(Field::new("format", self.format())),
5734            1usize => Some(Field::new(
5735                "paint_offset",
5736                FieldType::offset(self.paint_offset(), self.paint()),
5737            )),
5738            2usize => Some(Field::new("x_skew_angle", self.x_skew_angle())),
5739            3usize => Some(Field::new("y_skew_angle", self.y_skew_angle())),
5740            _ => None,
5741        }
5742    }
5743}
5744
5745#[cfg(feature = "experimental_traverse")]
5746#[allow(clippy::needless_lifetimes)]
5747impl<'a> std::fmt::Debug for PaintSkew<'a> {
5748    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5749        (self as &dyn SomeTable<'a>).fmt(f)
5750    }
5751}
5752
5753impl Format<u8> for PaintVarSkew<'_> {
5754    const FORMAT: u8 = 29;
5755}
5756
5757impl<'a> MinByteRange<'a> for PaintVarSkew<'a> {
5758    fn min_byte_range(&self) -> Range<usize> {
5759        0..self.var_index_base_byte_range().end
5760    }
5761    fn min_table_bytes(&self) -> &'a [u8] {
5762        let range = self.min_byte_range();
5763        self.data.as_bytes().get(range).unwrap_or_default()
5764    }
5765}
5766
5767impl<'a> FontRead<'a> for PaintVarSkew<'a> {
5768    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
5769        #[allow(clippy::absurd_extreme_comparisons)]
5770        if data.len() < Self::MIN_SIZE {
5771            return Err(ReadError::OutOfBounds);
5772        }
5773        Ok(Self { data })
5774    }
5775}
5776
5777/// [PaintVarSkew](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-28-to-31-paintskew-paintvarskew-paintskewaroundcenter-paintvarskewaroundcenter) table
5778#[derive(Clone)]
5779pub struct PaintVarSkew<'a> {
5780    data: FontData<'a>,
5781}
5782
5783#[allow(clippy::needless_lifetimes)]
5784impl<'a> PaintVarSkew<'a> {
5785    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN
5786        + Offset24::RAW_BYTE_LEN
5787        + F2Dot14::RAW_BYTE_LEN
5788        + F2Dot14::RAW_BYTE_LEN
5789        + u32::RAW_BYTE_LEN);
5790    basic_table_impls!(impl_the_methods);
5791
5792    /// Set to 29.
5793    pub fn format(&self) -> u8 {
5794        let range = self.format_byte_range();
5795        self.data.read_at(range.start).ok().unwrap()
5796    }
5797
5798    /// Offset to a Paint subtable.
5799    pub fn paint_offset(&self) -> Offset24 {
5800        let range = self.paint_offset_byte_range();
5801        self.data.read_at(range.start).ok().unwrap()
5802    }
5803
5804    /// Attempt to resolve [`paint_offset`][Self::paint_offset].
5805    pub fn paint(&self) -> Result<Paint<'a>, ReadError> {
5806        let data = self.data;
5807        self.paint_offset().resolve(data)
5808    }
5809
5810    /// Angle of skew in the direction of the x-axis, 180° ┬░ in
5811    /// counter-clockwise degrees per 1.0 of value. For variation, use
5812    /// varIndexBase + 0.
5813    pub fn x_skew_angle(&self) -> F2Dot14 {
5814        let range = self.x_skew_angle_byte_range();
5815        self.data.read_at(range.start).ok().unwrap()
5816    }
5817
5818    /// Angle of skew in the direction of the y-axis, 180° in
5819    /// counter-clockwise degrees per 1.0 of value. For variation, use
5820    /// varIndexBase + 1.
5821    pub fn y_skew_angle(&self) -> F2Dot14 {
5822        let range = self.y_skew_angle_byte_range();
5823        self.data.read_at(range.start).ok().unwrap()
5824    }
5825
5826    /// Base index into DeltaSetIndexMap.
5827    pub fn var_index_base(&self) -> u32 {
5828        let range = self.var_index_base_byte_range();
5829        self.data.read_at(range.start).ok().unwrap()
5830    }
5831
5832    pub fn format_byte_range(&self) -> Range<usize> {
5833        let start = 0;
5834        start..start + u8::RAW_BYTE_LEN
5835    }
5836
5837    pub fn paint_offset_byte_range(&self) -> Range<usize> {
5838        let start = self.format_byte_range().end;
5839        start..start + Offset24::RAW_BYTE_LEN
5840    }
5841
5842    pub fn x_skew_angle_byte_range(&self) -> Range<usize> {
5843        let start = self.paint_offset_byte_range().end;
5844        start..start + F2Dot14::RAW_BYTE_LEN
5845    }
5846
5847    pub fn y_skew_angle_byte_range(&self) -> Range<usize> {
5848        let start = self.x_skew_angle_byte_range().end;
5849        start..start + F2Dot14::RAW_BYTE_LEN
5850    }
5851
5852    pub fn var_index_base_byte_range(&self) -> Range<usize> {
5853        let start = self.y_skew_angle_byte_range().end;
5854        start..start + u32::RAW_BYTE_LEN
5855    }
5856}
5857
5858#[cfg(feature = "experimental_traverse")]
5859impl<'a> SomeTable<'a> for PaintVarSkew<'a> {
5860    fn type_name(&self) -> &str {
5861        "PaintVarSkew"
5862    }
5863    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
5864        match idx {
5865            0usize => Some(Field::new("format", self.format())),
5866            1usize => Some(Field::new(
5867                "paint_offset",
5868                FieldType::offset(self.paint_offset(), self.paint()),
5869            )),
5870            2usize => Some(Field::new("x_skew_angle", self.x_skew_angle())),
5871            3usize => Some(Field::new("y_skew_angle", self.y_skew_angle())),
5872            4usize => Some(Field::new("var_index_base", self.var_index_base())),
5873            _ => None,
5874        }
5875    }
5876}
5877
5878#[cfg(feature = "experimental_traverse")]
5879#[allow(clippy::needless_lifetimes)]
5880impl<'a> std::fmt::Debug for PaintVarSkew<'a> {
5881    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5882        (self as &dyn SomeTable<'a>).fmt(f)
5883    }
5884}
5885
5886impl Format<u8> for PaintSkewAroundCenter<'_> {
5887    const FORMAT: u8 = 30;
5888}
5889
5890impl<'a> MinByteRange<'a> for PaintSkewAroundCenter<'a> {
5891    fn min_byte_range(&self) -> Range<usize> {
5892        0..self.center_y_byte_range().end
5893    }
5894    fn min_table_bytes(&self) -> &'a [u8] {
5895        let range = self.min_byte_range();
5896        self.data.as_bytes().get(range).unwrap_or_default()
5897    }
5898}
5899
5900impl<'a> FontRead<'a> for PaintSkewAroundCenter<'a> {
5901    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
5902        #[allow(clippy::absurd_extreme_comparisons)]
5903        if data.len() < Self::MIN_SIZE {
5904            return Err(ReadError::OutOfBounds);
5905        }
5906        Ok(Self { data })
5907    }
5908}
5909
5910/// [PaintSkewAroundCenter](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-28-to-31-paintskew-paintvarskew-paintskewaroundcenter-paintvarskewaroundcenter) table
5911#[derive(Clone)]
5912pub struct PaintSkewAroundCenter<'a> {
5913    data: FontData<'a>,
5914}
5915
5916#[allow(clippy::needless_lifetimes)]
5917impl<'a> PaintSkewAroundCenter<'a> {
5918    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN
5919        + Offset24::RAW_BYTE_LEN
5920        + F2Dot14::RAW_BYTE_LEN
5921        + F2Dot14::RAW_BYTE_LEN
5922        + FWord::RAW_BYTE_LEN
5923        + FWord::RAW_BYTE_LEN);
5924    basic_table_impls!(impl_the_methods);
5925
5926    /// Set to 30.
5927    pub fn format(&self) -> u8 {
5928        let range = self.format_byte_range();
5929        self.data.read_at(range.start).ok().unwrap()
5930    }
5931
5932    /// Offset to a Paint subtable.
5933    pub fn paint_offset(&self) -> Offset24 {
5934        let range = self.paint_offset_byte_range();
5935        self.data.read_at(range.start).ok().unwrap()
5936    }
5937
5938    /// Attempt to resolve [`paint_offset`][Self::paint_offset].
5939    pub fn paint(&self) -> Result<Paint<'a>, ReadError> {
5940        let data = self.data;
5941        self.paint_offset().resolve(data)
5942    }
5943
5944    /// Angle of skew in the direction of the x-axis, 180° in
5945    /// counter-clockwise degrees per 1.0 of value.
5946    pub fn x_skew_angle(&self) -> F2Dot14 {
5947        let range = self.x_skew_angle_byte_range();
5948        self.data.read_at(range.start).ok().unwrap()
5949    }
5950
5951    /// Angle of skew in the direction of the y-axis, 180° in
5952    /// counter-clockwise degrees per 1.0 of value.
5953    pub fn y_skew_angle(&self) -> F2Dot14 {
5954        let range = self.y_skew_angle_byte_range();
5955        self.data.read_at(range.start).ok().unwrap()
5956    }
5957
5958    /// x coordinate for the center of rotation.
5959    pub fn center_x(&self) -> FWord {
5960        let range = self.center_x_byte_range();
5961        self.data.read_at(range.start).ok().unwrap()
5962    }
5963
5964    /// y coordinate for the center of rotation.
5965    pub fn center_y(&self) -> FWord {
5966        let range = self.center_y_byte_range();
5967        self.data.read_at(range.start).ok().unwrap()
5968    }
5969
5970    pub fn format_byte_range(&self) -> Range<usize> {
5971        let start = 0;
5972        start..start + u8::RAW_BYTE_LEN
5973    }
5974
5975    pub fn paint_offset_byte_range(&self) -> Range<usize> {
5976        let start = self.format_byte_range().end;
5977        start..start + Offset24::RAW_BYTE_LEN
5978    }
5979
5980    pub fn x_skew_angle_byte_range(&self) -> Range<usize> {
5981        let start = self.paint_offset_byte_range().end;
5982        start..start + F2Dot14::RAW_BYTE_LEN
5983    }
5984
5985    pub fn y_skew_angle_byte_range(&self) -> Range<usize> {
5986        let start = self.x_skew_angle_byte_range().end;
5987        start..start + F2Dot14::RAW_BYTE_LEN
5988    }
5989
5990    pub fn center_x_byte_range(&self) -> Range<usize> {
5991        let start = self.y_skew_angle_byte_range().end;
5992        start..start + FWord::RAW_BYTE_LEN
5993    }
5994
5995    pub fn center_y_byte_range(&self) -> Range<usize> {
5996        let start = self.center_x_byte_range().end;
5997        start..start + FWord::RAW_BYTE_LEN
5998    }
5999}
6000
6001#[cfg(feature = "experimental_traverse")]
6002impl<'a> SomeTable<'a> for PaintSkewAroundCenter<'a> {
6003    fn type_name(&self) -> &str {
6004        "PaintSkewAroundCenter"
6005    }
6006    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
6007        match idx {
6008            0usize => Some(Field::new("format", self.format())),
6009            1usize => Some(Field::new(
6010                "paint_offset",
6011                FieldType::offset(self.paint_offset(), self.paint()),
6012            )),
6013            2usize => Some(Field::new("x_skew_angle", self.x_skew_angle())),
6014            3usize => Some(Field::new("y_skew_angle", self.y_skew_angle())),
6015            4usize => Some(Field::new("center_x", self.center_x())),
6016            5usize => Some(Field::new("center_y", self.center_y())),
6017            _ => None,
6018        }
6019    }
6020}
6021
6022#[cfg(feature = "experimental_traverse")]
6023#[allow(clippy::needless_lifetimes)]
6024impl<'a> std::fmt::Debug for PaintSkewAroundCenter<'a> {
6025    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6026        (self as &dyn SomeTable<'a>).fmt(f)
6027    }
6028}
6029
6030impl Format<u8> for PaintVarSkewAroundCenter<'_> {
6031    const FORMAT: u8 = 31;
6032}
6033
6034impl<'a> MinByteRange<'a> for PaintVarSkewAroundCenter<'a> {
6035    fn min_byte_range(&self) -> Range<usize> {
6036        0..self.var_index_base_byte_range().end
6037    }
6038    fn min_table_bytes(&self) -> &'a [u8] {
6039        let range = self.min_byte_range();
6040        self.data.as_bytes().get(range).unwrap_or_default()
6041    }
6042}
6043
6044impl<'a> FontRead<'a> for PaintVarSkewAroundCenter<'a> {
6045    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
6046        #[allow(clippy::absurd_extreme_comparisons)]
6047        if data.len() < Self::MIN_SIZE {
6048            return Err(ReadError::OutOfBounds);
6049        }
6050        Ok(Self { data })
6051    }
6052}
6053
6054/// [PaintVarSkewAroundCenter](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#formats-28-to-31-paintskew-paintvarskew-paintskewaroundcenter-paintvarskewaroundcenter) table
6055#[derive(Clone)]
6056pub struct PaintVarSkewAroundCenter<'a> {
6057    data: FontData<'a>,
6058}
6059
6060#[allow(clippy::needless_lifetimes)]
6061impl<'a> PaintVarSkewAroundCenter<'a> {
6062    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN
6063        + Offset24::RAW_BYTE_LEN
6064        + F2Dot14::RAW_BYTE_LEN
6065        + F2Dot14::RAW_BYTE_LEN
6066        + FWord::RAW_BYTE_LEN
6067        + FWord::RAW_BYTE_LEN
6068        + u32::RAW_BYTE_LEN);
6069    basic_table_impls!(impl_the_methods);
6070
6071    /// Set to 31.
6072    pub fn format(&self) -> u8 {
6073        let range = self.format_byte_range();
6074        self.data.read_at(range.start).ok().unwrap()
6075    }
6076
6077    /// Offset to a Paint subtable.
6078    pub fn paint_offset(&self) -> Offset24 {
6079        let range = self.paint_offset_byte_range();
6080        self.data.read_at(range.start).ok().unwrap()
6081    }
6082
6083    /// Attempt to resolve [`paint_offset`][Self::paint_offset].
6084    pub fn paint(&self) -> Result<Paint<'a>, ReadError> {
6085        let data = self.data;
6086        self.paint_offset().resolve(data)
6087    }
6088
6089    /// Angle of skew in the direction of the x-axis, 180° in
6090    /// counter-clockwise degrees per 1.0 of value. For variation, use
6091    /// varIndexBase + 0.
6092    pub fn x_skew_angle(&self) -> F2Dot14 {
6093        let range = self.x_skew_angle_byte_range();
6094        self.data.read_at(range.start).ok().unwrap()
6095    }
6096
6097    /// Angle of skew in the direction of the y-axis, 180° in
6098    /// counter-clockwise degrees per 1.0 of value. For variation, use
6099    /// varIndexBase + 1.
6100    pub fn y_skew_angle(&self) -> F2Dot14 {
6101        let range = self.y_skew_angle_byte_range();
6102        self.data.read_at(range.start).ok().unwrap()
6103    }
6104
6105    /// x coordinate for the center of rotation. For variation, use
6106    /// varIndexBase + 2.
6107    pub fn center_x(&self) -> FWord {
6108        let range = self.center_x_byte_range();
6109        self.data.read_at(range.start).ok().unwrap()
6110    }
6111
6112    /// y coordinate for the center of rotation. For variation, use
6113    /// varIndexBase + 3.
6114    pub fn center_y(&self) -> FWord {
6115        let range = self.center_y_byte_range();
6116        self.data.read_at(range.start).ok().unwrap()
6117    }
6118
6119    /// Base index into DeltaSetIndexMap.
6120    pub fn var_index_base(&self) -> u32 {
6121        let range = self.var_index_base_byte_range();
6122        self.data.read_at(range.start).ok().unwrap()
6123    }
6124
6125    pub fn format_byte_range(&self) -> Range<usize> {
6126        let start = 0;
6127        start..start + u8::RAW_BYTE_LEN
6128    }
6129
6130    pub fn paint_offset_byte_range(&self) -> Range<usize> {
6131        let start = self.format_byte_range().end;
6132        start..start + Offset24::RAW_BYTE_LEN
6133    }
6134
6135    pub fn x_skew_angle_byte_range(&self) -> Range<usize> {
6136        let start = self.paint_offset_byte_range().end;
6137        start..start + F2Dot14::RAW_BYTE_LEN
6138    }
6139
6140    pub fn y_skew_angle_byte_range(&self) -> Range<usize> {
6141        let start = self.x_skew_angle_byte_range().end;
6142        start..start + F2Dot14::RAW_BYTE_LEN
6143    }
6144
6145    pub fn center_x_byte_range(&self) -> Range<usize> {
6146        let start = self.y_skew_angle_byte_range().end;
6147        start..start + FWord::RAW_BYTE_LEN
6148    }
6149
6150    pub fn center_y_byte_range(&self) -> Range<usize> {
6151        let start = self.center_x_byte_range().end;
6152        start..start + FWord::RAW_BYTE_LEN
6153    }
6154
6155    pub fn var_index_base_byte_range(&self) -> Range<usize> {
6156        let start = self.center_y_byte_range().end;
6157        start..start + u32::RAW_BYTE_LEN
6158    }
6159}
6160
6161#[cfg(feature = "experimental_traverse")]
6162impl<'a> SomeTable<'a> for PaintVarSkewAroundCenter<'a> {
6163    fn type_name(&self) -> &str {
6164        "PaintVarSkewAroundCenter"
6165    }
6166    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
6167        match idx {
6168            0usize => Some(Field::new("format", self.format())),
6169            1usize => Some(Field::new(
6170                "paint_offset",
6171                FieldType::offset(self.paint_offset(), self.paint()),
6172            )),
6173            2usize => Some(Field::new("x_skew_angle", self.x_skew_angle())),
6174            3usize => Some(Field::new("y_skew_angle", self.y_skew_angle())),
6175            4usize => Some(Field::new("center_x", self.center_x())),
6176            5usize => Some(Field::new("center_y", self.center_y())),
6177            6usize => Some(Field::new("var_index_base", self.var_index_base())),
6178            _ => None,
6179        }
6180    }
6181}
6182
6183#[cfg(feature = "experimental_traverse")]
6184#[allow(clippy::needless_lifetimes)]
6185impl<'a> std::fmt::Debug for PaintVarSkewAroundCenter<'a> {
6186    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6187        (self as &dyn SomeTable<'a>).fmt(f)
6188    }
6189}
6190
6191impl Format<u8> for PaintComposite<'_> {
6192    const FORMAT: u8 = 32;
6193}
6194
6195impl<'a> MinByteRange<'a> for PaintComposite<'a> {
6196    fn min_byte_range(&self) -> Range<usize> {
6197        0..self.backdrop_paint_offset_byte_range().end
6198    }
6199    fn min_table_bytes(&self) -> &'a [u8] {
6200        let range = self.min_byte_range();
6201        self.data.as_bytes().get(range).unwrap_or_default()
6202    }
6203}
6204
6205impl<'a> FontRead<'a> for PaintComposite<'a> {
6206    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
6207        #[allow(clippy::absurd_extreme_comparisons)]
6208        if data.len() < Self::MIN_SIZE {
6209            return Err(ReadError::OutOfBounds);
6210        }
6211        Ok(Self { data })
6212    }
6213}
6214
6215/// [PaintComposite](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#format-32-paintcomposite) table
6216#[derive(Clone)]
6217pub struct PaintComposite<'a> {
6218    data: FontData<'a>,
6219}
6220
6221#[allow(clippy::needless_lifetimes)]
6222impl<'a> PaintComposite<'a> {
6223    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN
6224        + Offset24::RAW_BYTE_LEN
6225        + CompositeMode::RAW_BYTE_LEN
6226        + Offset24::RAW_BYTE_LEN);
6227    basic_table_impls!(impl_the_methods);
6228
6229    /// Set to 32.
6230    pub fn format(&self) -> u8 {
6231        let range = self.format_byte_range();
6232        self.data.read_at(range.start).ok().unwrap()
6233    }
6234
6235    /// Offset to a source Paint table.
6236    pub fn source_paint_offset(&self) -> Offset24 {
6237        let range = self.source_paint_offset_byte_range();
6238        self.data.read_at(range.start).ok().unwrap()
6239    }
6240
6241    /// Attempt to resolve [`source_paint_offset`][Self::source_paint_offset].
6242    pub fn source_paint(&self) -> Result<Paint<'a>, ReadError> {
6243        let data = self.data;
6244        self.source_paint_offset().resolve(data)
6245    }
6246
6247    /// A CompositeMode enumeration value.
6248    pub fn composite_mode(&self) -> CompositeMode {
6249        let range = self.composite_mode_byte_range();
6250        self.data.read_at(range.start).ok().unwrap()
6251    }
6252
6253    /// Offset to a backdrop Paint table.
6254    pub fn backdrop_paint_offset(&self) -> Offset24 {
6255        let range = self.backdrop_paint_offset_byte_range();
6256        self.data.read_at(range.start).ok().unwrap()
6257    }
6258
6259    /// Attempt to resolve [`backdrop_paint_offset`][Self::backdrop_paint_offset].
6260    pub fn backdrop_paint(&self) -> Result<Paint<'a>, ReadError> {
6261        let data = self.data;
6262        self.backdrop_paint_offset().resolve(data)
6263    }
6264
6265    pub fn format_byte_range(&self) -> Range<usize> {
6266        let start = 0;
6267        start..start + u8::RAW_BYTE_LEN
6268    }
6269
6270    pub fn source_paint_offset_byte_range(&self) -> Range<usize> {
6271        let start = self.format_byte_range().end;
6272        start..start + Offset24::RAW_BYTE_LEN
6273    }
6274
6275    pub fn composite_mode_byte_range(&self) -> Range<usize> {
6276        let start = self.source_paint_offset_byte_range().end;
6277        start..start + CompositeMode::RAW_BYTE_LEN
6278    }
6279
6280    pub fn backdrop_paint_offset_byte_range(&self) -> Range<usize> {
6281        let start = self.composite_mode_byte_range().end;
6282        start..start + Offset24::RAW_BYTE_LEN
6283    }
6284}
6285
6286#[cfg(feature = "experimental_traverse")]
6287impl<'a> SomeTable<'a> for PaintComposite<'a> {
6288    fn type_name(&self) -> &str {
6289        "PaintComposite"
6290    }
6291    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
6292        match idx {
6293            0usize => Some(Field::new("format", self.format())),
6294            1usize => Some(Field::new(
6295                "source_paint_offset",
6296                FieldType::offset(self.source_paint_offset(), self.source_paint()),
6297            )),
6298            2usize => Some(Field::new("composite_mode", self.composite_mode())),
6299            3usize => Some(Field::new(
6300                "backdrop_paint_offset",
6301                FieldType::offset(self.backdrop_paint_offset(), self.backdrop_paint()),
6302            )),
6303            _ => None,
6304        }
6305    }
6306}
6307
6308#[cfg(feature = "experimental_traverse")]
6309#[allow(clippy::needless_lifetimes)]
6310impl<'a> std::fmt::Debug for PaintComposite<'a> {
6311    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6312        (self as &dyn SomeTable<'a>).fmt(f)
6313    }
6314}
6315
6316/// [CompositeMode](https://learn.microsoft.com/en-us/typography/opentype/spec/colr#format-32-paintcomposite) enumeration
6317#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
6318#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6319#[repr(u8)]
6320#[allow(clippy::manual_non_exhaustive)]
6321pub enum CompositeMode {
6322    Clear = 0,
6323    Src = 1,
6324    Dest = 2,
6325    #[default]
6326    SrcOver = 3,
6327    DestOver = 4,
6328    SrcIn = 5,
6329    DestIn = 6,
6330    SrcOut = 7,
6331    DestOut = 8,
6332    SrcAtop = 9,
6333    DestAtop = 10,
6334    Xor = 11,
6335    Plus = 12,
6336    Screen = 13,
6337    Overlay = 14,
6338    Darken = 15,
6339    Lighten = 16,
6340    ColorDodge = 17,
6341    ColorBurn = 18,
6342    HardLight = 19,
6343    SoftLight = 20,
6344    Difference = 21,
6345    Exclusion = 22,
6346    Multiply = 23,
6347    HslHue = 24,
6348    HslSaturation = 25,
6349    HslColor = 26,
6350    HslLuminosity = 27,
6351    #[doc(hidden)]
6352    /// If font data is malformed we will map unknown values to this variant
6353    Unknown,
6354}
6355
6356impl CompositeMode {
6357    /// Create from a raw scalar.
6358    ///
6359    /// This will never fail; unknown values will be mapped to the `Unknown` variant
6360    pub fn new(raw: u8) -> Self {
6361        match raw {
6362            0 => Self::Clear,
6363            1 => Self::Src,
6364            2 => Self::Dest,
6365            3 => Self::SrcOver,
6366            4 => Self::DestOver,
6367            5 => Self::SrcIn,
6368            6 => Self::DestIn,
6369            7 => Self::SrcOut,
6370            8 => Self::DestOut,
6371            9 => Self::SrcAtop,
6372            10 => Self::DestAtop,
6373            11 => Self::Xor,
6374            12 => Self::Plus,
6375            13 => Self::Screen,
6376            14 => Self::Overlay,
6377            15 => Self::Darken,
6378            16 => Self::Lighten,
6379            17 => Self::ColorDodge,
6380            18 => Self::ColorBurn,
6381            19 => Self::HardLight,
6382            20 => Self::SoftLight,
6383            21 => Self::Difference,
6384            22 => Self::Exclusion,
6385            23 => Self::Multiply,
6386            24 => Self::HslHue,
6387            25 => Self::HslSaturation,
6388            26 => Self::HslColor,
6389            27 => Self::HslLuminosity,
6390            _ => Self::Unknown,
6391        }
6392    }
6393}
6394
6395impl font_types::Scalar for CompositeMode {
6396    type Raw = <u8 as font_types::Scalar>::Raw;
6397    fn to_raw(self) -> Self::Raw {
6398        (self as u8).to_raw()
6399    }
6400    fn from_raw(raw: Self::Raw) -> Self {
6401        let t = <u8>::from_raw(raw);
6402        Self::new(t)
6403    }
6404}
6405
6406#[cfg(feature = "experimental_traverse")]
6407impl<'a> From<CompositeMode> for FieldType<'a> {
6408    fn from(src: CompositeMode) -> FieldType<'a> {
6409        (src as u8).into()
6410    }
6411}