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