Coverage Report

Created: 2026-05-24 07:46

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