Coverage Report

Created: 2026-10-24 07:19

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