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