Coverage Report

Created: 2026-10-28 07:26

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