Coverage Report

Created: 2026-10-24 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/read-fonts-0.46.0/generated/generated_variations.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 TupleVariationHeader<'a> {
9
0
    fn min_byte_range(&self) -> Range<usize> {
10
0
        0..self.intermediate_end_tuple_byte_range().end
11
0
    }
12
0
    fn min_table_bytes(&self) -> &'a [u8] {
13
0
        let range = self.min_byte_range();
14
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
15
0
    }
16
}
17
18
impl ReadArgs for TupleVariationHeader<'_> {
19
    type Args = u16;
20
}
21
22
impl<'a> FontRead<'a> for TupleVariationHeader<'a> {
23
27.3k
    fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
24
27.3k
        let axis_count = args;
25
26
        #[allow(clippy::absurd_extreme_comparisons)]
27
27.3k
        if data.len() < Self::MIN_SIZE {
28
180
            return Err(ReadError::OutOfBounds);
29
27.1k
        }
30
27.1k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
31
0
            return Err(ReadError::OutOfBounds);
32
        };
33
27.1k
        Ok(Self { data, axis_count })
34
27.3k
    }
35
}
36
37
impl<'a> TupleVariationHeader<'a> {
38
    /// A constructor that requires additional arguments.
39
    ///
40
    /// This type requires some external state in order to be
41
    /// parsed.
42
27.3k
    pub fn read(data: FontData<'a>, axis_count: u16) -> Result<Self, ReadError> {
43
27.3k
        let args = axis_count;
44
27.3k
        Self::read_with_args(data, args)
45
27.3k
    }
46
}
47
48
/// The fields at the start of the table, which are read directly.
49
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
50
#[repr(C, packed)]
51
#[doc(hidden)]
52
pub struct TupleVariationHeaderFixedHeader {
53
    pub variation_data_size: BigEndian<u16>,
54
    pub tuple_index: BigEndian<TupleIndex>,
55
}
56
57
#[allow(clippy::absurd_extreme_comparisons)]
58
const _: () = assert!(
59
    std::mem::size_of::<TupleVariationHeaderFixedHeader>() <= TupleVariationHeader::MIN_SIZE
60
);
61
62
/// [TupleVariationHeader](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuplevariationheader)
63
#[derive(Clone)]
64
pub struct TupleVariationHeader<'a> {
65
    data: TableDataRef<'a, TupleVariationHeaderFixedHeader>,
66
    axis_count: u16,
67
}
68
69
#[allow(clippy::needless_lifetimes)]
70
impl<'a> TupleVariationHeader<'a> {
71
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + TupleIndex::RAW_BYTE_LEN);
72
    basic_table_impls!(impl_the_methods);
73
74
    /// The size in bytes of the serialized data for this tuple
75
    /// variation table.
76
26.7k
    pub fn variation_data_size(&self) -> u16 {
77
26.7k
        self.data.header().variation_data_size.get()
78
26.7k
    }
79
80
    /// A packed field. The high 4 bits are flags (see below). The low
81
    /// 12 bits are an index into a shared tuple records array.
82
135k
    pub fn tuple_index(&self) -> TupleIndex {
83
135k
        self.data.header().tuple_index.get()
84
135k
    }
85
86
45.2k
    pub(crate) fn axis_count(&self) -> u16 {
87
45.2k
        self.axis_count
88
45.2k
    }
89
90
21.7k
    pub fn variation_data_size_byte_range(&self) -> Range<usize> {
91
21.7k
        let start = 0;
92
21.7k
        let end = start + u16::RAW_BYTE_LEN;
93
21.7k
        start..end
94
21.7k
    }
95
96
21.7k
    pub fn tuple_index_byte_range(&self) -> Range<usize> {
97
21.7k
        let start = self.variation_data_size_byte_range().end;
98
21.7k
        let end = start + TupleIndex::RAW_BYTE_LEN;
99
21.7k
        start..end
100
21.7k
    }
101
102
21.7k
    pub fn peak_tuple_byte_range(&self) -> Range<usize> {
103
21.7k
        let tuple_index = self.tuple_index();
104
21.7k
        let axis_count = self.axis_count();
105
21.7k
        let start = self.tuple_index_byte_range().end;
106
21.7k
        let end = start
107
21.7k
            + (TupleIndex::tuple_len(tuple_index, axis_count, 0_usize))
108
21.7k
                .saturating_mul(F2Dot14::RAW_BYTE_LEN);
109
21.7k
        start..end
110
21.7k
    }
111
112
15.6k
    pub fn intermediate_start_tuple_byte_range(&self) -> Range<usize> {
113
15.6k
        let tuple_index = self.tuple_index();
114
15.6k
        let axis_count = self.axis_count();
115
15.6k
        let start = self.peak_tuple_byte_range().end;
116
15.6k
        let end = start
117
15.6k
            + (TupleIndex::tuple_len(tuple_index, axis_count, 1_usize))
118
15.6k
                .saturating_mul(F2Dot14::RAW_BYTE_LEN);
119
15.6k
        start..end
120
15.6k
    }
121
122
7.82k
    pub fn intermediate_end_tuple_byte_range(&self) -> Range<usize> {
123
7.82k
        let tuple_index = self.tuple_index();
124
7.82k
        let axis_count = self.axis_count();
125
7.82k
        let start = self.intermediate_start_tuple_byte_range().end;
126
7.82k
        let end = start
127
7.82k
            + (TupleIndex::tuple_len(tuple_index, axis_count, 1_usize))
128
7.82k
                .saturating_mul(F2Dot14::RAW_BYTE_LEN);
129
7.82k
        start..end
130
7.82k
    }
131
}
132
133
const _: () = assert!(FontData::default_data_long_enough(
134
    TupleVariationHeader::MIN_SIZE
135
));
136
137
impl Default for TupleVariationHeader<'_> {
138
0
    fn default() -> Self {
139
        Self {
140
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
141
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
142
0
            axis_count: Default::default(),
143
        }
144
0
    }
145
}
146
147
/// A [Tuple Record](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuple-records)
148
///
149
/// The tuple variation store formats reference regions within the font’s
150
/// variation space using tuple records. A tuple record identifies a position
151
/// in terms of normalized coordinates, which use F2DOT14 values.
152
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
153
pub struct Tuple<'a> {
154
    /// Coordinate array specifying a position within the font’s variation space.
155
    ///
156
    /// The number of elements must match the axisCount specified in the
157
    /// 'fvar' table.
158
    pub values: &'a [BigEndian<F2Dot14>],
159
}
160
161
impl<'a> Tuple<'a> {
162
    /// Coordinate array specifying a position within the font’s variation space.
163
    ///
164
    /// The number of elements must match the axisCount specified in the
165
    /// 'fvar' table.
166
10.0k
    pub fn values(&self) -> &'a [BigEndian<F2Dot14>] {
167
10.0k
        self.values
168
10.0k
    }
169
}
170
171
impl ReadArgs for Tuple<'_> {
172
    type Args = u16;
173
}
174
175
impl ComputeSize for Tuple<'_> {
176
    #[allow(clippy::needless_question_mark)]
177
10.7k
    fn compute_size(args: u16) -> Result<usize, ReadError> {
178
10.7k
        let axis_count = args;
179
10.7k
        Ok((transforms::to_usize(axis_count)).saturating_mul(F2Dot14::RAW_BYTE_LEN))
180
10.7k
    }
181
}
182
183
impl<'a> FontRead<'a> for Tuple<'a> {
184
3.87k
    fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
185
3.87k
        let mut cursor = data.cursor();
186
3.87k
        let axis_count = args;
187
        Ok(Self {
188
3.87k
            values: cursor.read_array(transforms::to_usize(axis_count))?,
189
        })
190
3.87k
    }
191
}
192
193
crate::impl_font_read_at!(Tuple<'a>);
194
195
#[allow(clippy::needless_lifetimes)]
196
impl<'a> Tuple<'a> {
197
    /// A constructor that requires additional arguments.
198
    ///
199
    /// This type requires some external state in order to be
200
    /// parsed.
201
0
    pub fn read(data: FontData<'a>, axis_count: u16) -> Result<Self, ReadError> {
202
0
        let args = axis_count;
203
0
        Self::read_with_args(data, args)
204
0
    }
205
}
206
207
impl Format<u8> for DeltaSetIndexMapFormat0<'_> {
208
    const FORMAT: u8 = 0;
209
}
210
211
impl<'a> MinByteRange<'a> for DeltaSetIndexMapFormat0<'a> {
212
0
    fn min_byte_range(&self) -> Range<usize> {
213
0
        0..self.map_data_byte_range().end
214
0
    }
215
0
    fn min_table_bytes(&self) -> &'a [u8] {
216
0
        let range = self.min_byte_range();
217
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
218
0
    }
219
}
220
221
impl ReadArgs for DeltaSetIndexMapFormat0<'_> {
222
    type Args = ();
223
}
224
225
impl<'a> FontRead<'a> for DeltaSetIndexMapFormat0<'a> {
226
744
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
227
        #[allow(clippy::absurd_extreme_comparisons)]
228
744
        if data.len() < Self::MIN_SIZE {
229
64
            return Err(ReadError::OutOfBounds);
230
680
        }
231
680
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
232
0
            return Err(ReadError::OutOfBounds);
233
        };
234
680
        Ok(Self { data })
235
744
    }
236
}
237
238
/// The fields at the start of the table, which are read directly.
239
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
240
#[repr(C, packed)]
241
#[doc(hidden)]
242
pub struct DeltaSetIndexMapFormat0FixedHeader {
243
    pub format: u8,
244
    pub entry_format: BigEndian<EntryFormat>,
245
    pub map_count: BigEndian<u16>,
246
}
247
248
#[allow(clippy::absurd_extreme_comparisons)]
249
const _: () = assert!(
250
    std::mem::size_of::<DeltaSetIndexMapFormat0FixedHeader>() <= DeltaSetIndexMapFormat0::MIN_SIZE
251
);
252
253
/// The [DeltaSetIndexMap](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#associating-target-items-to-variation-data) table format 0
254
#[derive(Clone)]
255
pub struct DeltaSetIndexMapFormat0<'a> {
256
    data: TableDataRef<'a, DeltaSetIndexMapFormat0FixedHeader>,
257
}
258
259
#[allow(clippy::needless_lifetimes)]
260
impl<'a> DeltaSetIndexMapFormat0<'a> {
261
    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN + EntryFormat::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
262
    basic_table_impls!(impl_the_methods);
263
264
    /// DeltaSetIndexMap format: set to 0.
265
0
    pub fn format(&self) -> u8 {
266
0
        self.data.header().format
267
0
    }
268
269
    /// A packed field that describes the compressed representation of
270
    /// delta-set indices. See details below.
271
1.34k
    pub fn entry_format(&self) -> EntryFormat {
272
1.34k
        self.data.header().entry_format.get()
273
1.34k
    }
274
275
    /// The number of mapping entries.
276
1.34k
    pub fn map_count(&self) -> u16 {
277
1.34k
        self.data.header().map_count.get()
278
1.34k
    }
279
280
    /// The delta-set index mapping data. See details below.
281
673
    pub fn map_data(&self) -> &'a [u8] {
282
673
        let range = self.map_data_byte_range();
283
673
        self.offset_data()
284
673
            .read_array(range)
285
673
            .ok()
286
673
            .unwrap_or_default()
287
673
    }
288
289
673
    pub fn format_byte_range(&self) -> Range<usize> {
290
673
        let start = 0;
291
673
        let end = start + u8::RAW_BYTE_LEN;
292
673
        start..end
293
673
    }
294
295
673
    pub fn entry_format_byte_range(&self) -> Range<usize> {
296
673
        let start = self.format_byte_range().end;
297
673
        let end = start + EntryFormat::RAW_BYTE_LEN;
298
673
        start..end
299
673
    }
300
301
673
    pub fn map_count_byte_range(&self) -> Range<usize> {
302
673
        let start = self.entry_format_byte_range().end;
303
673
        let end = start + u16::RAW_BYTE_LEN;
304
673
        start..end
305
673
    }
306
307
673
    pub fn map_data_byte_range(&self) -> Range<usize> {
308
673
        let entry_format = self.entry_format();
309
673
        let map_count = self.map_count();
310
673
        let start = self.map_count_byte_range().end;
311
673
        let end = start
312
673
            + (EntryFormat::map_size(entry_format, map_count)).saturating_mul(u8::RAW_BYTE_LEN);
313
673
        start..end
314
673
    }
315
}
316
317
const _: () = assert!(FontData::default_data_long_enough(
318
    DeltaSetIndexMapFormat0::MIN_SIZE
319
));
320
321
impl Default for DeltaSetIndexMapFormat0<'_> {
322
0
    fn default() -> Self {
323
        Self {
324
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
325
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
326
        }
327
0
    }
328
}
329
330
impl Format<u8> for DeltaSetIndexMapFormat1<'_> {
331
    const FORMAT: u8 = 1;
332
}
333
334
impl<'a> MinByteRange<'a> for DeltaSetIndexMapFormat1<'a> {
335
0
    fn min_byte_range(&self) -> Range<usize> {
336
0
        0..self.map_data_byte_range().end
337
0
    }
338
0
    fn min_table_bytes(&self) -> &'a [u8] {
339
0
        let range = self.min_byte_range();
340
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
341
0
    }
342
}
343
344
impl ReadArgs for DeltaSetIndexMapFormat1<'_> {
345
    type Args = ();
346
}
347
348
impl<'a> FontRead<'a> for DeltaSetIndexMapFormat1<'a> {
349
404
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
350
        #[allow(clippy::absurd_extreme_comparisons)]
351
404
        if data.len() < Self::MIN_SIZE {
352
63
            return Err(ReadError::OutOfBounds);
353
341
        }
354
341
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
355
0
            return Err(ReadError::OutOfBounds);
356
        };
357
341
        Ok(Self { data })
358
404
    }
359
}
360
361
/// The fields at the start of the table, which are read directly.
362
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
363
#[repr(C, packed)]
364
#[doc(hidden)]
365
pub struct DeltaSetIndexMapFormat1FixedHeader {
366
    pub format: u8,
367
    pub entry_format: BigEndian<EntryFormat>,
368
    pub map_count: BigEndian<u32>,
369
}
370
371
#[allow(clippy::absurd_extreme_comparisons)]
372
const _: () = assert!(
373
    std::mem::size_of::<DeltaSetIndexMapFormat1FixedHeader>() <= DeltaSetIndexMapFormat1::MIN_SIZE
374
);
375
376
/// The [DeltaSetIndexMap](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#associating-target-items-to-variation-data) table format 1
377
#[derive(Clone)]
378
pub struct DeltaSetIndexMapFormat1<'a> {
379
    data: TableDataRef<'a, DeltaSetIndexMapFormat1FixedHeader>,
380
}
381
382
#[allow(clippy::needless_lifetimes)]
383
impl<'a> DeltaSetIndexMapFormat1<'a> {
384
    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN + EntryFormat::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
385
    basic_table_impls!(impl_the_methods);
386
387
    /// DeltaSetIndexMap format: set to 1.
388
0
    pub fn format(&self) -> u8 {
389
0
        self.data.header().format
390
0
    }
391
392
    /// A packed field that describes the compressed representation of
393
    /// delta-set indices. See details below.
394
680
    pub fn entry_format(&self) -> EntryFormat {
395
680
        self.data.header().entry_format.get()
396
680
    }
397
398
    /// The number of mapping entries.
399
680
    pub fn map_count(&self) -> u32 {
400
680
        self.data.header().map_count.get()
401
680
    }
402
403
    /// The delta-set index mapping data. See details below.
404
340
    pub fn map_data(&self) -> &'a [u8] {
405
340
        let range = self.map_data_byte_range();
406
340
        self.offset_data()
407
340
            .read_array(range)
408
340
            .ok()
409
340
            .unwrap_or_default()
410
340
    }
411
412
340
    pub fn format_byte_range(&self) -> Range<usize> {
413
340
        let start = 0;
414
340
        let end = start + u8::RAW_BYTE_LEN;
415
340
        start..end
416
340
    }
417
418
340
    pub fn entry_format_byte_range(&self) -> Range<usize> {
419
340
        let start = self.format_byte_range().end;
420
340
        let end = start + EntryFormat::RAW_BYTE_LEN;
421
340
        start..end
422
340
    }
423
424
340
    pub fn map_count_byte_range(&self) -> Range<usize> {
425
340
        let start = self.entry_format_byte_range().end;
426
340
        let end = start + u32::RAW_BYTE_LEN;
427
340
        start..end
428
340
    }
429
430
340
    pub fn map_data_byte_range(&self) -> Range<usize> {
431
340
        let entry_format = self.entry_format();
432
340
        let map_count = self.map_count();
433
340
        let start = self.map_count_byte_range().end;
434
340
        let end = start
435
340
            + (EntryFormat::map_size(entry_format, map_count)).saturating_mul(u8::RAW_BYTE_LEN);
436
340
        start..end
437
340
    }
438
}
439
440
const _: () = assert!(FontData::default_data_long_enough(
441
    DeltaSetIndexMapFormat1::MIN_SIZE
442
));
443
444
impl Default for DeltaSetIndexMapFormat1<'_> {
445
0
    fn default() -> Self {
446
        Self {
447
0
            data: TableDataRef::new(FontData::default_format_1_u8_table_data().as_bytes())
448
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
449
        }
450
0
    }
451
}
452
453
/// The [DeltaSetIndexMap](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#associating-target-items-to-variation-data) table
454
#[derive(Clone)]
455
pub enum DeltaSetIndexMap<'a> {
456
    Format0(DeltaSetIndexMapFormat0<'a>),
457
    Format1(DeltaSetIndexMapFormat1<'a>),
458
}
459
460
impl Default for DeltaSetIndexMap<'_> {
461
0
    fn default() -> Self {
462
0
        Self::Format0(Default::default())
463
0
    }
464
}
465
466
impl<'a> DeltaSetIndexMap<'a> {
467
    ///Return the `FontData` used to resolve offsets for this table.
468
0
    pub fn offset_data(&self) -> FontData<'a> {
469
0
        match self {
470
0
            Self::Format0(item) => item.offset_data(),
471
0
            Self::Format1(item) => item.offset_data(),
472
        }
473
0
    }
474
475
    /// DeltaSetIndexMap format: set to 0.
476
0
    pub fn format(&self) -> u8 {
477
0
        match self {
478
0
            Self::Format0(item) => item.format(),
479
0
            Self::Format1(item) => item.format(),
480
        }
481
0
    }
482
483
    /// A packed field that describes the compressed representation of
484
    /// delta-set indices. See details below.
485
0
    pub fn entry_format(&self) -> EntryFormat {
486
0
        match self {
487
0
            Self::Format0(item) => item.entry_format(),
488
0
            Self::Format1(item) => item.entry_format(),
489
        }
490
0
    }
491
492
    /// The delta-set index mapping data. See details below.
493
0
    pub fn map_data(&self) -> &'a [u8] {
494
0
        match self {
495
0
            Self::Format0(item) => item.map_data(),
496
0
            Self::Format1(item) => item.map_data(),
497
        }
498
0
    }
499
}
500
501
impl ReadArgs for DeltaSetIndexMap<'_> {
502
    type Args = ();
503
}
504
505
impl<'a> FontRead<'a> for DeltaSetIndexMap<'a> {
506
    #[inline]
507
1.33k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
508
1.33k
        let format: u8 = data.read_at(0usize)?;
509
1.27k
        match format {
510
744
            DeltaSetIndexMapFormat0::FORMAT => Ok(Self::Format0(FontRead::read(data)?)),
511
404
            DeltaSetIndexMapFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
512
127
            other => Err(ReadError::InvalidFormat(other.into())),
513
        }
514
1.33k
    }
515
}
516
517
impl<'a> MinByteRange<'a> for DeltaSetIndexMap<'a> {
518
0
    fn min_byte_range(&self) -> Range<usize> {
519
0
        match self {
520
0
            Self::Format0(item) => item.min_byte_range(),
521
0
            Self::Format1(item) => item.min_byte_range(),
522
        }
523
0
    }
524
0
    fn min_table_bytes(&self) -> &'a [u8] {
525
0
        match self {
526
0
            Self::Format0(item) => item.min_table_bytes(),
527
0
            Self::Format1(item) => item.min_table_bytes(),
528
        }
529
0
    }
530
}
531
532
/// Entry format for a [DeltaSetIndexMap].
533
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, bytemuck :: AnyBitPattern)]
534
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
535
#[repr(transparent)]
536
pub struct EntryFormat {
537
    bits: u8,
538
}
539
540
impl EntryFormat {
541
    /// Mask for the low 4 bits, which give the count of bits minus one that are used in each entry for the inner-level index.
542
    pub const INNER_INDEX_BIT_COUNT_MASK: Self = Self { bits: 0x0F };
543
544
    /// Mask for bits that indicate the size in bytes minus one of each entry.
545
    pub const MAP_ENTRY_SIZE_MASK: Self = Self { bits: 0x30 };
546
}
547
548
impl EntryFormat {
549
    ///  Returns an empty set of flags.
550
    #[inline]
551
0
    pub const fn empty() -> Self {
552
0
        Self { bits: 0 }
553
0
    }
554
555
    /// Returns the set containing all flags.
556
    #[inline]
557
2.02k
    pub const fn all() -> Self {
558
2.02k
        Self {
559
2.02k
            bits: Self::INNER_INDEX_BIT_COUNT_MASK.bits | Self::MAP_ENTRY_SIZE_MASK.bits,
560
2.02k
        }
561
2.02k
    }
562
563
    /// Returns the raw value of the flags currently stored.
564
    #[inline]
565
4.21k
    pub const fn bits(&self) -> u8 {
566
4.21k
        self.bits
567
4.21k
    }
568
569
    /// Convert from underlying bit representation, unless that
570
    /// representation contains bits that do not correspond to a flag.
571
    #[inline]
572
0
    pub const fn from_bits(bits: u8) -> Option<Self> {
573
0
        if (bits & !Self::all().bits()) == 0 {
574
0
            Some(Self { bits })
575
        } else {
576
0
            None
577
        }
578
0
    }
579
580
    /// Convert from underlying bit representation, dropping any bits
581
    /// that do not correspond to flags.
582
    #[inline]
583
2.02k
    pub const fn from_bits_truncate(bits: u8) -> Self {
584
2.02k
        Self {
585
2.02k
            bits: bits & Self::all().bits,
586
2.02k
        }
587
2.02k
    }
588
589
    /// Returns `true` if no flags are currently stored.
590
    #[inline]
591
0
    pub const fn is_empty(&self) -> bool {
592
0
        self.bits() == Self::empty().bits()
593
0
    }
594
595
    /// Returns `true` if there are flags common to both `self` and `other`.
596
    #[inline]
597
0
    pub const fn intersects(&self, other: Self) -> bool {
598
0
        !(Self {
599
0
            bits: self.bits & other.bits,
600
0
        })
601
0
        .is_empty()
602
0
    }
603
604
    /// Returns `true` if all of the flags in `other` are contained within `self`.
605
    #[inline]
606
0
    pub const fn contains(&self, other: Self) -> bool {
607
0
        (self.bits & other.bits) == other.bits
608
0
    }
609
610
    /// Inserts the specified flags in-place.
611
    #[inline]
612
0
    pub fn insert(&mut self, other: Self) {
613
0
        self.bits |= other.bits;
614
0
    }
615
616
    /// Removes the specified flags in-place.
617
    #[inline]
618
0
    pub fn remove(&mut self, other: Self) {
619
0
        self.bits &= !other.bits;
620
0
    }
621
622
    /// Toggles the specified flags in-place.
623
    #[inline]
624
0
    pub fn toggle(&mut self, other: Self) {
625
0
        self.bits ^= other.bits;
626
0
    }
627
628
    /// Returns the intersection between the flags in `self` and
629
    /// `other`.
630
    ///
631
    /// Specifically, the returned set contains only the flags which are
632
    /// present in *both* `self` *and* `other`.
633
    ///
634
    /// This is equivalent to using the `&` operator (e.g.
635
    /// [`ops::BitAnd`]), as in `flags & other`.
636
    ///
637
    /// [`ops::BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html
638
    #[inline]
639
    #[must_use]
640
0
    pub const fn intersection(self, other: Self) -> Self {
641
0
        Self {
642
0
            bits: self.bits & other.bits,
643
0
        }
644
0
    }
645
646
    /// Returns the union of between the flags in `self` and `other`.
647
    ///
648
    /// Specifically, the returned set contains all flags which are
649
    /// present in *either* `self` *or* `other`, including any which are
650
    /// present in both.
651
    ///
652
    /// This is equivalent to using the `|` operator (e.g.
653
    /// [`ops::BitOr`]), as in `flags | other`.
654
    ///
655
    /// [`ops::BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html
656
    #[inline]
657
    #[must_use]
658
0
    pub const fn union(self, other: Self) -> Self {
659
0
        Self {
660
0
            bits: self.bits | other.bits,
661
0
        }
662
0
    }
663
664
    /// Returns the difference between the flags in `self` and `other`.
665
    ///
666
    /// Specifically, the returned set contains all flags present in
667
    /// `self`, except for the ones present in `other`.
668
    ///
669
    /// It is also conceptually equivalent to the "bit-clear" operation:
670
    /// `flags & !other` (and this syntax is also supported).
671
    ///
672
    /// This is equivalent to using the `-` operator (e.g.
673
    /// [`ops::Sub`]), as in `flags - other`.
674
    ///
675
    /// [`ops::Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html
676
    #[inline]
677
    #[must_use]
678
0
    pub const fn difference(self, other: Self) -> Self {
679
0
        Self {
680
0
            bits: self.bits & !other.bits,
681
0
        }
682
0
    }
683
}
684
685
impl std::ops::BitOr for EntryFormat {
686
    type Output = Self;
687
688
    /// Returns the union of the two sets of flags.
689
    #[inline]
690
0
    fn bitor(self, other: EntryFormat) -> Self {
691
0
        Self {
692
0
            bits: self.bits | other.bits,
693
0
        }
694
0
    }
695
}
696
697
impl std::ops::BitOrAssign for EntryFormat {
698
    /// Adds the set of flags.
699
    #[inline]
700
0
    fn bitor_assign(&mut self, other: Self) {
701
0
        self.bits |= other.bits;
702
0
    }
703
}
704
705
impl std::ops::BitXor for EntryFormat {
706
    type Output = Self;
707
708
    /// Returns the left flags, but with all the right flags toggled.
709
    #[inline]
710
0
    fn bitxor(self, other: Self) -> Self {
711
0
        Self {
712
0
            bits: self.bits ^ other.bits,
713
0
        }
714
0
    }
715
}
716
717
impl std::ops::BitXorAssign for EntryFormat {
718
    /// Toggles the set of flags.
719
    #[inline]
720
0
    fn bitxor_assign(&mut self, other: Self) {
721
0
        self.bits ^= other.bits;
722
0
    }
723
}
724
725
impl std::ops::BitAnd for EntryFormat {
726
    type Output = Self;
727
728
    /// Returns the intersection between the two sets of flags.
729
    #[inline]
730
0
    fn bitand(self, other: Self) -> Self {
731
0
        Self {
732
0
            bits: self.bits & other.bits,
733
0
        }
734
0
    }
735
}
736
737
impl std::ops::BitAndAssign for EntryFormat {
738
    /// Disables all flags disabled in the set.
739
    #[inline]
740
0
    fn bitand_assign(&mut self, other: Self) {
741
0
        self.bits &= other.bits;
742
0
    }
743
}
744
745
impl std::ops::Sub for EntryFormat {
746
    type Output = Self;
747
748
    /// Returns the set difference of the two sets of flags.
749
    #[inline]
750
0
    fn sub(self, other: Self) -> Self {
751
0
        Self {
752
0
            bits: self.bits & !other.bits,
753
0
        }
754
0
    }
755
}
756
757
impl std::ops::SubAssign for EntryFormat {
758
    /// Disables all flags enabled in the set.
759
    #[inline]
760
0
    fn sub_assign(&mut self, other: Self) {
761
0
        self.bits &= !other.bits;
762
0
    }
763
}
764
765
impl std::ops::Not for EntryFormat {
766
    type Output = Self;
767
768
    /// Returns the complement of this set of flags.
769
    #[inline]
770
0
    fn not(self) -> Self {
771
0
        Self { bits: !self.bits } & Self::all()
772
0
    }
773
}
774
775
impl std::fmt::Debug for EntryFormat {
776
0
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
777
0
        let members: &[(&str, Self)] = &[
778
0
            (
779
0
                "INNER_INDEX_BIT_COUNT_MASK",
780
0
                Self::INNER_INDEX_BIT_COUNT_MASK,
781
0
            ),
782
0
            ("MAP_ENTRY_SIZE_MASK", Self::MAP_ENTRY_SIZE_MASK),
783
0
        ];
784
0
        let mut first = true;
785
0
        for (name, value) in members {
786
0
            if self.contains(*value) {
787
0
                if !first {
788
0
                    f.write_str(" | ")?;
789
0
                }
790
0
                first = false;
791
0
                f.write_str(name)?;
792
0
            }
793
        }
794
0
        if first {
795
0
            f.write_str("(empty)")?;
796
0
        }
797
0
        Ok(())
798
0
    }
799
}
800
801
impl std::fmt::Binary for EntryFormat {
802
0
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
803
0
        std::fmt::Binary::fmt(&self.bits, f)
804
0
    }
805
}
806
807
impl std::fmt::Octal for EntryFormat {
808
0
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
809
0
        std::fmt::Octal::fmt(&self.bits, f)
810
0
    }
811
}
812
813
impl std::fmt::LowerHex for EntryFormat {
814
0
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
815
0
        std::fmt::LowerHex::fmt(&self.bits, f)
816
0
    }
817
}
818
819
impl std::fmt::UpperHex for EntryFormat {
820
0
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
821
0
        std::fmt::UpperHex::fmt(&self.bits, f)
822
0
    }
823
}
824
825
impl font_types::Scalar for EntryFormat {
826
    type Raw = <u8 as font_types::Scalar>::Raw;
827
0
    fn to_raw(self) -> Self::Raw {
828
0
        self.bits().to_raw()
829
0
    }
830
2.02k
    fn from_raw(raw: Self::Raw) -> Self {
831
2.02k
        let t = <u8>::from_raw(raw);
832
2.02k
        Self::from_bits_truncate(t)
833
2.02k
    }
834
}
835
836
impl<'a> MinByteRange<'a> for VariationRegionList<'a> {
837
0
    fn min_byte_range(&self) -> Range<usize> {
838
0
        0..self.variation_regions_byte_range().end
839
0
    }
840
0
    fn min_table_bytes(&self) -> &'a [u8] {
841
0
        let range = self.min_byte_range();
842
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
843
0
    }
844
}
845
846
impl ReadArgs for VariationRegionList<'_> {
847
    type Args = ();
848
}
849
850
impl<'a> FontRead<'a> for VariationRegionList<'a> {
851
70
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
852
        #[allow(clippy::absurd_extreme_comparisons)]
853
70
        if data.len() < Self::MIN_SIZE {
854
2
            return Err(ReadError::OutOfBounds);
855
68
        }
856
68
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
857
0
            return Err(ReadError::OutOfBounds);
858
        };
859
68
        Ok(Self { data })
860
70
    }
861
}
862
863
/// The fields at the start of the table, which are read directly.
864
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
865
#[repr(C, packed)]
866
#[doc(hidden)]
867
pub struct VariationRegionListFixedHeader {
868
    pub axis_count: BigEndian<u16>,
869
    pub region_count: BigEndian<u16>,
870
}
871
872
#[allow(clippy::absurd_extreme_comparisons)]
873
const _: () =
874
    assert!(std::mem::size_of::<VariationRegionListFixedHeader>() <= VariationRegionList::MIN_SIZE);
875
876
/// The [VariationRegionList](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#variation-regions) table
877
#[derive(Clone)]
878
pub struct VariationRegionList<'a> {
879
    data: TableDataRef<'a, VariationRegionListFixedHeader>,
880
}
881
882
#[allow(clippy::needless_lifetimes)]
883
impl<'a> VariationRegionList<'a> {
884
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
885
    basic_table_impls!(impl_the_methods);
886
887
    /// The number of variation axes for this font. This must be the
888
    /// same number as axisCount in the 'fvar' table.
889
136
    pub fn axis_count(&self) -> u16 {
890
136
        self.data.header().axis_count.get()
891
136
    }
892
893
    /// The number of variation region tables in the variation region
894
    /// list. Must be less than 32,768.
895
68
    pub fn region_count(&self) -> u16 {
896
68
        self.data.header().region_count.get()
897
68
    }
898
899
    /// Array of variation regions.
900
68
    pub fn variation_regions(&self) -> ComputedArray<'a, VariationRegion<'a>> {
901
68
        let range = self.variation_regions_byte_range();
902
68
        ComputedArray::new(self.offset_data(), range, self.axis_count()).unwrap_or_default()
903
68
    }
904
905
68
    pub fn axis_count_byte_range(&self) -> Range<usize> {
906
68
        let start = 0;
907
68
        let end = start + u16::RAW_BYTE_LEN;
908
68
        start..end
909
68
    }
910
911
68
    pub fn region_count_byte_range(&self) -> Range<usize> {
912
68
        let start = self.axis_count_byte_range().end;
913
68
        let end = start + u16::RAW_BYTE_LEN;
914
68
        start..end
915
68
    }
916
917
68
    pub fn variation_regions_byte_range(&self) -> Range<usize> {
918
68
        let region_count = self.region_count();
919
68
        let start = self.region_count_byte_range().end;
920
68
        let end = start
921
68
            + (transforms::to_usize(region_count)).saturating_mul(
922
68
                <VariationRegion as ComputeSize>::compute_size(self.axis_count()).unwrap_or(0),
923
68
            );
924
68
        start..end
925
68
    }
926
}
927
928
const _: () = assert!(FontData::default_data_long_enough(
929
    VariationRegionList::MIN_SIZE
930
));
931
932
impl Default for VariationRegionList<'_> {
933
0
    fn default() -> Self {
934
        Self {
935
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
936
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
937
        }
938
0
    }
939
}
940
941
/// The [VariationRegion](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#variation-regions) record
942
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
943
pub struct VariationRegion<'a> {
944
    /// Array of region axis coordinates records, in the order of axes
945
    /// given in the 'fvar' table.
946
    pub region_axes: &'a [RegionAxisCoordinates],
947
}
948
949
impl<'a> VariationRegion<'a> {
950
    /// Array of region axis coordinates records, in the order of axes
951
    /// given in the 'fvar' table.
952
12
    pub fn region_axes(&self) -> &'a [RegionAxisCoordinates] {
953
12
        self.region_axes
954
12
    }
955
}
956
957
impl ReadArgs for VariationRegion<'_> {
958
    type Args = u16;
959
}
960
961
impl ComputeSize for VariationRegion<'_> {
962
    #[allow(clippy::needless_question_mark)]
963
148
    fn compute_size(args: u16) -> Result<usize, ReadError> {
964
148
        let axis_count = args;
965
148
        Ok((transforms::to_usize(axis_count)).saturating_mul(RegionAxisCoordinates::RAW_BYTE_LEN))
966
148
    }
967
}
968
969
impl<'a> FontRead<'a> for VariationRegion<'a> {
970
12
    fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
971
12
        let mut cursor = data.cursor();
972
12
        let axis_count = args;
973
        Ok(Self {
974
12
            region_axes: cursor.read_array(transforms::to_usize(axis_count))?,
975
        })
976
12
    }
977
}
978
979
crate::impl_font_read_at!(VariationRegion<'a>);
980
981
#[allow(clippy::needless_lifetimes)]
982
impl<'a> VariationRegion<'a> {
983
    /// A constructor that requires additional arguments.
984
    ///
985
    /// This type requires some external state in order to be
986
    /// parsed.
987
0
    pub fn read(data: FontData<'a>, axis_count: u16) -> Result<Self, ReadError> {
988
0
        let args = axis_count;
989
0
        Self::read_with_args(data, args)
990
0
    }
991
}
992
993
/// The [RegionAxisCoordinates](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#variation-regions) record
994
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
995
#[repr(C)]
996
#[repr(packed)]
997
pub struct RegionAxisCoordinates {
998
    /// The region start coordinate value for the current axis.
999
    pub start_coord: BigEndian<F2Dot14>,
1000
    /// The region peak coordinate value for the current axis.
1001
    pub peak_coord: BigEndian<F2Dot14>,
1002
    /// The region end coordinate value for the current axis.
1003
    pub end_coord: BigEndian<F2Dot14>,
1004
}
1005
1006
impl RegionAxisCoordinates {
1007
    /// The region start coordinate value for the current axis.
1008
0
    pub fn start_coord(&self) -> F2Dot14 {
1009
0
        self.start_coord.get()
1010
0
    }
1011
1012
    /// The region peak coordinate value for the current axis.
1013
22
    pub fn peak_coord(&self) -> F2Dot14 {
1014
22
        self.peak_coord.get()
1015
22
    }
1016
1017
    /// The region end coordinate value for the current axis.
1018
0
    pub fn end_coord(&self) -> F2Dot14 {
1019
0
        self.end_coord.get()
1020
0
    }
1021
}
1022
1023
impl FixedSize for RegionAxisCoordinates {
1024
    const RAW_BYTE_LEN: usize =
1025
        F2Dot14::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN;
1026
}
1027
1028
impl<'a> MinByteRange<'a> for ItemVariationStore<'a> {
1029
0
    fn min_byte_range(&self) -> Range<usize> {
1030
0
        0..self.item_variation_data_offsets_byte_range().end
1031
0
    }
1032
0
    fn min_table_bytes(&self) -> &'a [u8] {
1033
0
        let range = self.min_byte_range();
1034
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
1035
0
    }
1036
}
1037
1038
impl ReadArgs for ItemVariationStore<'_> {
1039
    type Args = ();
1040
}
1041
1042
impl<'a> FontRead<'a> for ItemVariationStore<'a> {
1043
1.75k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1044
        #[allow(clippy::absurd_extreme_comparisons)]
1045
1.75k
        if data.len() < Self::MIN_SIZE {
1046
88
            return Err(ReadError::OutOfBounds);
1047
1.66k
        }
1048
1.66k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1049
0
            return Err(ReadError::OutOfBounds);
1050
        };
1051
1.66k
        Ok(Self { data })
1052
1.75k
    }
1053
}
1054
1055
/// The fields at the start of the table, which are read directly.
1056
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1057
#[repr(C, packed)]
1058
#[doc(hidden)]
1059
pub struct ItemVariationStoreFixedHeader {
1060
    pub format: BigEndian<u16>,
1061
    pub variation_region_list_offset: BigEndian<Offset32>,
1062
    pub item_variation_data_count: BigEndian<u16>,
1063
}
1064
1065
#[allow(clippy::absurd_extreme_comparisons)]
1066
const _: () =
1067
    assert!(std::mem::size_of::<ItemVariationStoreFixedHeader>() <= ItemVariationStore::MIN_SIZE);
1068
1069
/// The [ItemVariationStore](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#item-variation-store-header-and-item-variation-data-subtables) table
1070
#[derive(Clone)]
1071
pub struct ItemVariationStore<'a> {
1072
    data: TableDataRef<'a, ItemVariationStoreFixedHeader>,
1073
}
1074
1075
#[allow(clippy::needless_lifetimes)]
1076
impl<'a> ItemVariationStore<'a> {
1077
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1078
    basic_table_impls!(impl_the_methods);
1079
1080
    /// Format— set to 1
1081
0
    pub fn format(&self) -> u16 {
1082
0
        self.data.header().format.get()
1083
0
    }
1084
1085
    /// Offset in bytes from the start of the item variation store to
1086
    /// the variation region list.
1087
130
    pub fn variation_region_list_offset(&self) -> Offset32 {
1088
130
        self.data.header().variation_region_list_offset.get()
1089
130
    }
1090
1091
    /// Attempt to resolve [`variation_region_list_offset`][Self::variation_region_list_offset].
1092
130
    pub fn variation_region_list(&self) -> Result<VariationRegionList<'a>, ReadError> {
1093
130
        let data = self.offset_data();
1094
130
        self.variation_region_list_offset().resolve(data)
1095
130
    }
1096
1097
    /// The number of item variation data subtables.
1098
1.15k
    pub fn item_variation_data_count(&self) -> u16 {
1099
1.15k
        self.data.header().item_variation_data_count.get()
1100
1.15k
    }
1101
1102
    /// Offsets in bytes from the start of the item variation store to
1103
    /// each item variation data subtable.
1104
1.15k
    pub fn item_variation_data_offsets(&self) -> &'a [BigEndian<Nullable<Offset32>>] {
1105
1.15k
        let range = self.item_variation_data_offsets_byte_range();
1106
1.15k
        self.offset_data()
1107
1.15k
            .read_array(range)
1108
1.15k
            .ok()
1109
1.15k
            .unwrap_or_default()
1110
1.15k
    }
1111
1112
    /// A dynamically resolving wrapper for [`item_variation_data_offsets`][Self::item_variation_data_offsets].
1113
1.15k
    pub fn item_variation_data(
1114
1.15k
        &self,
1115
1.15k
    ) -> ArrayOfNullableOffsets<'a, ItemVariationData<'a>, Offset32> {
1116
1.15k
        let data = self.offset_data();
1117
1.15k
        let offsets = self.item_variation_data_offsets();
1118
1.15k
        ArrayOfNullableOffsets::new(offsets, data, ())
1119
1.15k
    }
1120
1121
1.15k
    pub fn format_byte_range(&self) -> Range<usize> {
1122
1.15k
        let start = 0;
1123
1.15k
        let end = start + u16::RAW_BYTE_LEN;
1124
1.15k
        start..end
1125
1.15k
    }
1126
1127
1.15k
    pub fn variation_region_list_offset_byte_range(&self) -> Range<usize> {
1128
1.15k
        let start = self.format_byte_range().end;
1129
1.15k
        let end = start + Offset32::RAW_BYTE_LEN;
1130
1.15k
        start..end
1131
1.15k
    }
1132
1133
1.15k
    pub fn item_variation_data_count_byte_range(&self) -> Range<usize> {
1134
1.15k
        let start = self.variation_region_list_offset_byte_range().end;
1135
1.15k
        let end = start + u16::RAW_BYTE_LEN;
1136
1.15k
        start..end
1137
1.15k
    }
1138
1139
1.15k
    pub fn item_variation_data_offsets_byte_range(&self) -> Range<usize> {
1140
1.15k
        let item_variation_data_count = self.item_variation_data_count();
1141
1.15k
        let start = self.item_variation_data_count_byte_range().end;
1142
1.15k
        let end = start
1143
1.15k
            + (transforms::to_usize(item_variation_data_count))
1144
1.15k
                .saturating_mul(Offset32::RAW_BYTE_LEN);
1145
1.15k
        start..end
1146
1.15k
    }
1147
}
1148
1149
const _: () = assert!(FontData::default_data_long_enough(
1150
    ItemVariationStore::MIN_SIZE
1151
));
1152
1153
impl Default for ItemVariationStore<'_> {
1154
0
    fn default() -> Self {
1155
        Self {
1156
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
1157
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1158
        }
1159
0
    }
1160
}
1161
1162
impl<'a> MinByteRange<'a> for ItemVariationData<'a> {
1163
0
    fn min_byte_range(&self) -> Range<usize> {
1164
0
        0..self.delta_sets_byte_range().end
1165
0
    }
1166
0
    fn min_table_bytes(&self) -> &'a [u8] {
1167
0
        let range = self.min_byte_range();
1168
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
1169
0
    }
1170
}
1171
1172
impl ReadArgs for ItemVariationData<'_> {
1173
    type Args = ();
1174
}
1175
1176
impl<'a> FontRead<'a> for ItemVariationData<'a> {
1177
97
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1178
        #[allow(clippy::absurd_extreme_comparisons)]
1179
97
        if data.len() < Self::MIN_SIZE {
1180
0
            return Err(ReadError::OutOfBounds);
1181
97
        }
1182
97
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1183
0
            return Err(ReadError::OutOfBounds);
1184
        };
1185
97
        Ok(Self { data })
1186
97
    }
1187
}
1188
1189
/// The fields at the start of the table, which are read directly.
1190
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1191
#[repr(C, packed)]
1192
#[doc(hidden)]
1193
pub struct ItemVariationDataFixedHeader {
1194
    pub item_count: BigEndian<u16>,
1195
    pub word_delta_count: BigEndian<u16>,
1196
    pub region_index_count: BigEndian<u16>,
1197
}
1198
1199
#[allow(clippy::absurd_extreme_comparisons)]
1200
const _: () =
1201
    assert!(std::mem::size_of::<ItemVariationDataFixedHeader>() <= ItemVariationData::MIN_SIZE);
1202
1203
/// The [ItemVariationData](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#item-variation-store-header-and-item-variation-data-subtables) subtable
1204
#[derive(Clone)]
1205
pub struct ItemVariationData<'a> {
1206
    data: TableDataRef<'a, ItemVariationDataFixedHeader>,
1207
}
1208
1209
#[allow(clippy::needless_lifetimes)]
1210
impl<'a> ItemVariationData<'a> {
1211
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1212
    basic_table_impls!(impl_the_methods);
1213
1214
    /// The number of delta sets for distinct items.
1215
97
    pub fn item_count(&self) -> u16 {
1216
97
        self.data.header().item_count.get()
1217
97
    }
1218
1219
    /// A packed field: the high bit is a flag—see details below.
1220
194
    pub fn word_delta_count(&self) -> u16 {
1221
194
        self.data.header().word_delta_count.get()
1222
194
    }
1223
1224
    /// The number of variation regions referenced.
1225
388
    pub fn region_index_count(&self) -> u16 {
1226
388
        self.data.header().region_index_count.get()
1227
388
    }
1228
1229
    /// Array of indices into the variation region list for the regions
1230
    /// referenced by this item variation data table.
1231
97
    pub fn region_indexes(&self) -> &'a [BigEndian<u16>] {
1232
97
        let range = self.region_indexes_byte_range();
1233
97
        self.offset_data()
1234
97
            .read_array(range)
1235
97
            .ok()
1236
97
            .unwrap_or_default()
1237
97
    }
1238
1239
    /// Delta-set rows.
1240
97
    pub fn delta_sets(&self) -> &'a [u8] {
1241
97
        let range = self.delta_sets_byte_range();
1242
97
        self.offset_data()
1243
97
            .read_array(range)
1244
97
            .ok()
1245
97
            .unwrap_or_default()
1246
97
    }
1247
1248
194
    pub fn item_count_byte_range(&self) -> Range<usize> {
1249
194
        let start = 0;
1250
194
        let end = start + u16::RAW_BYTE_LEN;
1251
194
        start..end
1252
194
    }
1253
1254
194
    pub fn word_delta_count_byte_range(&self) -> Range<usize> {
1255
194
        let start = self.item_count_byte_range().end;
1256
194
        let end = start + u16::RAW_BYTE_LEN;
1257
194
        start..end
1258
194
    }
1259
1260
194
    pub fn region_index_count_byte_range(&self) -> Range<usize> {
1261
194
        let start = self.word_delta_count_byte_range().end;
1262
194
        let end = start + u16::RAW_BYTE_LEN;
1263
194
        start..end
1264
194
    }
1265
1266
194
    pub fn region_indexes_byte_range(&self) -> Range<usize> {
1267
194
        let region_index_count = self.region_index_count();
1268
194
        let start = self.region_index_count_byte_range().end;
1269
194
        let end =
1270
194
            start + (transforms::to_usize(region_index_count)).saturating_mul(u16::RAW_BYTE_LEN);
1271
194
        start..end
1272
194
    }
1273
1274
97
    pub fn delta_sets_byte_range(&self) -> Range<usize> {
1275
97
        let item_count = self.item_count();
1276
97
        let word_delta_count = self.word_delta_count();
1277
97
        let region_index_count = self.region_index_count();
1278
97
        let start = self.region_indexes_byte_range().end;
1279
97
        let end = start
1280
97
            + (ItemVariationData::delta_sets_len(item_count, word_delta_count, region_index_count))
1281
97
                .saturating_mul(u8::RAW_BYTE_LEN);
1282
97
        start..end
1283
97
    }
1284
}
1285
1286
const _: () = assert!(FontData::default_data_long_enough(
1287
    ItemVariationData::MIN_SIZE
1288
));
1289
1290
impl Default for ItemVariationData<'_> {
1291
0
    fn default() -> Self {
1292
        Self {
1293
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
1294
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1295
        }
1296
0
    }
1297
}