Skip to main content

read_fonts/generated/
generated_colr.rs

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