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