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