Skip to main content

read_fonts/generated/
generated_colr.rs

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