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