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_base.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 Base<'a> {
9
0
    fn min_byte_range(&self) -> Range<usize> {
10
0
        0..self.vert_axis_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 Base<'_> {
19
    /// `BASE`
20
    const TAG: Tag = Tag::new(b"BASE");
21
}
22
23
impl ReadArgs for Base<'_> {
24
    type Args = ();
25
}
26
27
impl<'a> FontRead<'a> for Base<'a> {
28
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
29
        #[allow(clippy::absurd_extreme_comparisons)]
30
0
        if data.len() < Self::MIN_SIZE {
31
0
            return Err(ReadError::OutOfBounds);
32
0
        }
33
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
34
0
            return Err(ReadError::OutOfBounds);
35
        };
36
0
        Ok(Self { data })
37
0
    }
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 BaseFixedHeader {
45
    pub version: BigEndian<MajorMinor>,
46
    pub horiz_axis_offset: BigEndian<Nullable<Offset16>>,
47
    pub vert_axis_offset: BigEndian<Nullable<Offset16>>,
48
}
49
50
#[allow(clippy::absurd_extreme_comparisons)]
51
const _: () = assert!(std::mem::size_of::<BaseFixedHeader>() <= Base::MIN_SIZE);
52
53
/// The [BASE](https://learn.microsoft.com/en-us/typography/opentype/spec/base) (Baseline) table
54
#[derive(Clone)]
55
pub struct Base<'a> {
56
    data: TableDataRef<'a, BaseFixedHeader>,
57
}
58
59
#[allow(clippy::needless_lifetimes)]
60
impl<'a> Base<'a> {
61
    pub const MIN_SIZE: usize =
62
        (MajorMinor::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN);
63
    basic_table_impls!(impl_the_methods);
64
65
    /// (major, minor) Version for the BASE table (1,0) or (1,1)
66
0
    pub fn version(&self) -> MajorMinor {
67
0
        self.data.header().version.get()
68
0
    }
69
70
    /// Offset to horizontal Axis table, from beginning of BASE table (may be NULL)
71
0
    pub fn horiz_axis_offset(&self) -> Nullable<Offset16> {
72
0
        self.data.header().horiz_axis_offset.get()
73
0
    }
74
75
    /// Attempt to resolve [`horiz_axis_offset`][Self::horiz_axis_offset].
76
0
    pub fn horiz_axis(&self) -> Option<Result<Axis<'a>, ReadError>> {
77
0
        let data = self.offset_data();
78
0
        self.horiz_axis_offset().resolve(data)
79
0
    }
80
81
    /// Offset to vertical Axis table, from beginning of BASE table (may be NULL)
82
0
    pub fn vert_axis_offset(&self) -> Nullable<Offset16> {
83
0
        self.data.header().vert_axis_offset.get()
84
0
    }
85
86
    /// Attempt to resolve [`vert_axis_offset`][Self::vert_axis_offset].
87
0
    pub fn vert_axis(&self) -> Option<Result<Axis<'a>, ReadError>> {
88
0
        let data = self.offset_data();
89
0
        self.vert_axis_offset().resolve(data)
90
0
    }
91
92
    /// Offset to Item Variation Store table, from beginning of BASE table (may be null)
93
0
    pub fn item_var_store_offset(&self) -> Option<Nullable<Offset32>> {
94
0
        let range = self.item_var_store_offset_byte_range();
95
0
        (!range.is_empty())
96
0
            .then(|| self.offset_data().read_at(range.start).ok())
97
0
            .flatten()
98
0
    }
99
100
    /// Attempt to resolve [`item_var_store_offset`][Self::item_var_store_offset].
101
0
    pub fn item_var_store(&self) -> Option<Result<ItemVariationStore<'a>, ReadError>> {
102
0
        let data = self.offset_data();
103
0
        self.item_var_store_offset().map(|x| x.resolve(data))?
104
0
    }
105
106
0
    pub fn version_byte_range(&self) -> Range<usize> {
107
0
        let start = 0;
108
0
        let end = start + MajorMinor::RAW_BYTE_LEN;
109
0
        start..end
110
0
    }
111
112
0
    pub fn horiz_axis_offset_byte_range(&self) -> Range<usize> {
113
0
        let start = self.version_byte_range().end;
114
0
        let end = start + Offset16::RAW_BYTE_LEN;
115
0
        start..end
116
0
    }
117
118
0
    pub fn vert_axis_offset_byte_range(&self) -> Range<usize> {
119
0
        let start = self.horiz_axis_offset_byte_range().end;
120
0
        let end = start + Offset16::RAW_BYTE_LEN;
121
0
        start..end
122
0
    }
123
124
0
    pub fn item_var_store_offset_byte_range(&self) -> Range<usize> {
125
0
        let start = self.vert_axis_offset_byte_range().end;
126
0
        let end = if self.version().compatible((1u16, 1u16)) {
127
0
            start + Offset32::RAW_BYTE_LEN
128
        } else {
129
0
            start
130
        };
131
0
        start..end
132
0
    }
133
}
134
135
const _: () = assert!(FontData::default_data_long_enough(Base::MIN_SIZE));
136
137
impl Default for Base<'_> {
138
0
    fn default() -> Self {
139
        Self {
140
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
141
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
142
        }
143
0
    }
144
}
145
146
impl<'a> MinByteRange<'a> for Axis<'a> {
147
0
    fn min_byte_range(&self) -> Range<usize> {
148
0
        0..self.base_script_list_offset_byte_range().end
149
0
    }
150
0
    fn min_table_bytes(&self) -> &'a [u8] {
151
0
        let range = self.min_byte_range();
152
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
153
0
    }
154
}
155
156
impl ReadArgs for Axis<'_> {
157
    type Args = ();
158
}
159
160
impl<'a> FontRead<'a> for Axis<'a> {
161
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
162
        #[allow(clippy::absurd_extreme_comparisons)]
163
0
        if data.len() < Self::MIN_SIZE {
164
0
            return Err(ReadError::OutOfBounds);
165
0
        }
166
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
167
0
            return Err(ReadError::OutOfBounds);
168
        };
169
0
        Ok(Self { data })
170
0
    }
171
}
172
173
/// The fields at the start of the table, which are read directly.
174
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
175
#[repr(C, packed)]
176
#[doc(hidden)]
177
pub struct AxisFixedHeader {
178
    pub base_tag_list_offset: BigEndian<Nullable<Offset16>>,
179
    pub base_script_list_offset: BigEndian<Offset16>,
180
}
181
182
#[allow(clippy::absurd_extreme_comparisons)]
183
const _: () = assert!(std::mem::size_of::<AxisFixedHeader>() <= Axis::MIN_SIZE);
184
185
/// [Axis Table](https://learn.microsoft.com/en-us/typography/opentype/spec/base#axis-tables-horizaxis-and-vertaxis)
186
#[derive(Clone)]
187
pub struct Axis<'a> {
188
    data: TableDataRef<'a, AxisFixedHeader>,
189
}
190
191
#[allow(clippy::needless_lifetimes)]
192
impl<'a> Axis<'a> {
193
    pub const MIN_SIZE: usize = (Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN);
194
    basic_table_impls!(impl_the_methods);
195
196
    /// Offset to BaseTagList table, from beginning of Axis table (may
197
    /// be NULL)
198
0
    pub fn base_tag_list_offset(&self) -> Nullable<Offset16> {
199
0
        self.data.header().base_tag_list_offset.get()
200
0
    }
201
202
    /// Attempt to resolve [`base_tag_list_offset`][Self::base_tag_list_offset].
203
0
    pub fn base_tag_list(&self) -> Option<Result<BaseTagList<'a>, ReadError>> {
204
0
        let data = self.offset_data();
205
0
        self.base_tag_list_offset().resolve(data)
206
0
    }
207
208
    /// Offset to BaseScriptList table, from beginning of Axis table
209
0
    pub fn base_script_list_offset(&self) -> Offset16 {
210
0
        self.data.header().base_script_list_offset.get()
211
0
    }
212
213
    /// Attempt to resolve [`base_script_list_offset`][Self::base_script_list_offset].
214
0
    pub fn base_script_list(&self) -> Result<BaseScriptList<'a>, ReadError> {
215
0
        let data = self.offset_data();
216
0
        self.base_script_list_offset().resolve(data)
217
0
    }
218
219
0
    pub fn base_tag_list_offset_byte_range(&self) -> Range<usize> {
220
0
        let start = 0;
221
0
        let end = start + Offset16::RAW_BYTE_LEN;
222
0
        start..end
223
0
    }
224
225
0
    pub fn base_script_list_offset_byte_range(&self) -> Range<usize> {
226
0
        let start = self.base_tag_list_offset_byte_range().end;
227
0
        let end = start + Offset16::RAW_BYTE_LEN;
228
0
        start..end
229
0
    }
230
}
231
232
const _: () = assert!(FontData::default_data_long_enough(Axis::MIN_SIZE));
233
234
impl Default for Axis<'_> {
235
0
    fn default() -> Self {
236
        Self {
237
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
238
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
239
        }
240
0
    }
241
}
242
243
impl<'a> MinByteRange<'a> for BaseTagList<'a> {
244
0
    fn min_byte_range(&self) -> Range<usize> {
245
0
        0..self.baseline_tags_byte_range().end
246
0
    }
247
0
    fn min_table_bytes(&self) -> &'a [u8] {
248
0
        let range = self.min_byte_range();
249
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
250
0
    }
251
}
252
253
impl ReadArgs for BaseTagList<'_> {
254
    type Args = ();
255
}
256
257
impl<'a> FontRead<'a> for BaseTagList<'a> {
258
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
259
        #[allow(clippy::absurd_extreme_comparisons)]
260
0
        if data.len() < Self::MIN_SIZE {
261
0
            return Err(ReadError::OutOfBounds);
262
0
        }
263
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
264
0
            return Err(ReadError::OutOfBounds);
265
        };
266
0
        Ok(Self { data })
267
0
    }
268
}
269
270
/// The fields at the start of the table, which are read directly.
271
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
272
#[repr(C, packed)]
273
#[doc(hidden)]
274
pub struct BaseTagListFixedHeader {
275
    pub base_tag_count: BigEndian<u16>,
276
}
277
278
#[allow(clippy::absurd_extreme_comparisons)]
279
const _: () = assert!(std::mem::size_of::<BaseTagListFixedHeader>() <= BaseTagList::MIN_SIZE);
280
281
/// [BaseTagList Table](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basetaglist-table)
282
#[derive(Clone)]
283
pub struct BaseTagList<'a> {
284
    data: TableDataRef<'a, BaseTagListFixedHeader>,
285
}
286
287
#[allow(clippy::needless_lifetimes)]
288
impl<'a> BaseTagList<'a> {
289
    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
290
    basic_table_impls!(impl_the_methods);
291
292
    /// Number of baseline identification tags in this text direction
293
    /// — may be zero (0)
294
0
    pub fn base_tag_count(&self) -> u16 {
295
0
        self.data.header().base_tag_count.get()
296
0
    }
297
298
    /// Array of 4-byte baseline identification tags — must be in
299
    /// alphabetical order
300
0
    pub fn baseline_tags(&self) -> &'a [BigEndian<Tag>] {
301
0
        let range = self.baseline_tags_byte_range();
302
0
        self.offset_data()
303
0
            .read_array(range)
304
0
            .ok()
305
0
            .unwrap_or_default()
306
0
    }
307
308
0
    pub fn base_tag_count_byte_range(&self) -> Range<usize> {
309
0
        let start = 0;
310
0
        let end = start + u16::RAW_BYTE_LEN;
311
0
        start..end
312
0
    }
313
314
0
    pub fn baseline_tags_byte_range(&self) -> Range<usize> {
315
0
        let base_tag_count = self.base_tag_count();
316
0
        let start = self.base_tag_count_byte_range().end;
317
0
        let end = start + (transforms::to_usize(base_tag_count)).saturating_mul(Tag::RAW_BYTE_LEN);
318
0
        start..end
319
0
    }
320
}
321
322
const _: () = assert!(FontData::default_data_long_enough(BaseTagList::MIN_SIZE));
323
324
impl Default for BaseTagList<'_> {
325
0
    fn default() -> Self {
326
        Self {
327
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
328
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
329
        }
330
0
    }
331
}
332
333
impl<'a> MinByteRange<'a> for BaseScriptList<'a> {
334
0
    fn min_byte_range(&self) -> Range<usize> {
335
0
        0..self.base_script_records_byte_range().end
336
0
    }
337
0
    fn min_table_bytes(&self) -> &'a [u8] {
338
0
        let range = self.min_byte_range();
339
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
340
0
    }
341
}
342
343
impl ReadArgs for BaseScriptList<'_> {
344
    type Args = ();
345
}
346
347
impl<'a> FontRead<'a> for BaseScriptList<'a> {
348
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
349
        #[allow(clippy::absurd_extreme_comparisons)]
350
0
        if data.len() < Self::MIN_SIZE {
351
0
            return Err(ReadError::OutOfBounds);
352
0
        }
353
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
354
0
            return Err(ReadError::OutOfBounds);
355
        };
356
0
        Ok(Self { data })
357
0
    }
358
}
359
360
/// The fields at the start of the table, which are read directly.
361
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
362
#[repr(C, packed)]
363
#[doc(hidden)]
364
pub struct BaseScriptListFixedHeader {
365
    pub base_script_count: BigEndian<u16>,
366
}
367
368
#[allow(clippy::absurd_extreme_comparisons)]
369
const _: () = assert!(std::mem::size_of::<BaseScriptListFixedHeader>() <= BaseScriptList::MIN_SIZE);
370
371
/// [BaseScriptList Table](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basescriptlist-table)
372
#[derive(Clone)]
373
pub struct BaseScriptList<'a> {
374
    data: TableDataRef<'a, BaseScriptListFixedHeader>,
375
}
376
377
#[allow(clippy::needless_lifetimes)]
378
impl<'a> BaseScriptList<'a> {
379
    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
380
    basic_table_impls!(impl_the_methods);
381
382
    /// Number of BaseScriptRecords defined
383
0
    pub fn base_script_count(&self) -> u16 {
384
0
        self.data.header().base_script_count.get()
385
0
    }
386
387
    /// Array of BaseScriptRecords, in alphabetical order by
388
    /// baseScriptTag
389
0
    pub fn base_script_records(&self) -> &'a [BaseScriptRecord] {
390
0
        let range = self.base_script_records_byte_range();
391
0
        self.offset_data()
392
0
            .read_array(range)
393
0
            .ok()
394
0
            .unwrap_or_default()
395
0
    }
396
397
0
    pub fn base_script_count_byte_range(&self) -> Range<usize> {
398
0
        let start = 0;
399
0
        let end = start + u16::RAW_BYTE_LEN;
400
0
        start..end
401
0
    }
402
403
0
    pub fn base_script_records_byte_range(&self) -> Range<usize> {
404
0
        let base_script_count = self.base_script_count();
405
0
        let start = self.base_script_count_byte_range().end;
406
0
        let end = start
407
0
            + (transforms::to_usize(base_script_count))
408
0
                .saturating_mul(BaseScriptRecord::RAW_BYTE_LEN);
409
0
        start..end
410
0
    }
411
}
412
413
const _: () = assert!(FontData::default_data_long_enough(BaseScriptList::MIN_SIZE));
414
415
impl Default for BaseScriptList<'_> {
416
0
    fn default() -> Self {
417
        Self {
418
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
419
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
420
        }
421
0
    }
422
}
423
424
/// [BaseScriptRecord](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basescriptrecord)
425
#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
426
#[repr(C)]
427
#[repr(packed)]
428
pub struct BaseScriptRecord {
429
    /// 4-byte script identification tag
430
    pub base_script_tag: BigEndian<Tag>,
431
    /// Offset to BaseScript table, from beginning of BaseScriptList
432
    pub base_script_offset: BigEndian<Offset16>,
433
}
434
435
impl BaseScriptRecord {
436
    /// 4-byte script identification tag
437
0
    pub fn base_script_tag(&self) -> Tag {
438
0
        self.base_script_tag.get()
439
0
    }
440
441
    /// Offset to BaseScript table, from beginning of BaseScriptList
442
0
    pub fn base_script_offset(&self) -> Offset16 {
443
0
        self.base_script_offset.get()
444
0
    }
445
446
    /// Offset to BaseScript table, from beginning of BaseScriptList
447
    ///
448
    /// The `data` argument should be retrieved from the parent table
449
    /// By calling its `offset_data` method.
450
0
    pub fn base_script<'a>(&self, data: FontData<'a>) -> Result<BaseScript<'a>, ReadError> {
451
0
        self.base_script_offset().resolve(data)
452
0
    }
453
}
454
455
impl FixedSize for BaseScriptRecord {
456
    const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
457
}
458
459
impl<'a> MinByteRange<'a> for BaseScript<'a> {
460
0
    fn min_byte_range(&self) -> Range<usize> {
461
0
        0..self.base_lang_sys_records_byte_range().end
462
0
    }
463
0
    fn min_table_bytes(&self) -> &'a [u8] {
464
0
        let range = self.min_byte_range();
465
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
466
0
    }
467
}
468
469
impl ReadArgs for BaseScript<'_> {
470
    type Args = ();
471
}
472
473
impl<'a> FontRead<'a> for BaseScript<'a> {
474
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
475
        #[allow(clippy::absurd_extreme_comparisons)]
476
0
        if data.len() < Self::MIN_SIZE {
477
0
            return Err(ReadError::OutOfBounds);
478
0
        }
479
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
480
0
            return Err(ReadError::OutOfBounds);
481
        };
482
0
        Ok(Self { data })
483
0
    }
484
}
485
486
/// The fields at the start of the table, which are read directly.
487
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
488
#[repr(C, packed)]
489
#[doc(hidden)]
490
pub struct BaseScriptFixedHeader {
491
    pub base_values_offset: BigEndian<Nullable<Offset16>>,
492
    pub default_min_max_offset: BigEndian<Nullable<Offset16>>,
493
    pub base_lang_sys_count: BigEndian<u16>,
494
}
495
496
#[allow(clippy::absurd_extreme_comparisons)]
497
const _: () = assert!(std::mem::size_of::<BaseScriptFixedHeader>() <= BaseScript::MIN_SIZE);
498
499
/// [BaseScript Table](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basescript-table)
500
#[derive(Clone)]
501
pub struct BaseScript<'a> {
502
    data: TableDataRef<'a, BaseScriptFixedHeader>,
503
}
504
505
#[allow(clippy::needless_lifetimes)]
506
impl<'a> BaseScript<'a> {
507
    pub const MIN_SIZE: usize =
508
        (Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
509
    basic_table_impls!(impl_the_methods);
510
511
    /// Offset to BaseValues table, from beginning of BaseScript table (may be NULL)
512
0
    pub fn base_values_offset(&self) -> Nullable<Offset16> {
513
0
        self.data.header().base_values_offset.get()
514
0
    }
515
516
    /// Attempt to resolve [`base_values_offset`][Self::base_values_offset].
517
0
    pub fn base_values(&self) -> Option<Result<BaseValues<'a>, ReadError>> {
518
0
        let data = self.offset_data();
519
0
        self.base_values_offset().resolve(data)
520
0
    }
521
522
    /// Offset to MinMax table, from beginning of BaseScript table (may be NULL)
523
0
    pub fn default_min_max_offset(&self) -> Nullable<Offset16> {
524
0
        self.data.header().default_min_max_offset.get()
525
0
    }
526
527
    /// Attempt to resolve [`default_min_max_offset`][Self::default_min_max_offset].
528
0
    pub fn default_min_max(&self) -> Option<Result<MinMax<'a>, ReadError>> {
529
0
        let data = self.offset_data();
530
0
        self.default_min_max_offset().resolve(data)
531
0
    }
532
533
    /// Number of BaseLangSysRecords defined — may be zero (0)
534
0
    pub fn base_lang_sys_count(&self) -> u16 {
535
0
        self.data.header().base_lang_sys_count.get()
536
0
    }
537
538
    /// Array of BaseLangSysRecords, in alphabetical order by
539
    /// BaseLangSysTag
540
0
    pub fn base_lang_sys_records(&self) -> &'a [BaseLangSysRecord] {
541
0
        let range = self.base_lang_sys_records_byte_range();
542
0
        self.offset_data()
543
0
            .read_array(range)
544
0
            .ok()
545
0
            .unwrap_or_default()
546
0
    }
547
548
0
    pub fn base_values_offset_byte_range(&self) -> Range<usize> {
549
0
        let start = 0;
550
0
        let end = start + Offset16::RAW_BYTE_LEN;
551
0
        start..end
552
0
    }
553
554
0
    pub fn default_min_max_offset_byte_range(&self) -> Range<usize> {
555
0
        let start = self.base_values_offset_byte_range().end;
556
0
        let end = start + Offset16::RAW_BYTE_LEN;
557
0
        start..end
558
0
    }
559
560
0
    pub fn base_lang_sys_count_byte_range(&self) -> Range<usize> {
561
0
        let start = self.default_min_max_offset_byte_range().end;
562
0
        let end = start + u16::RAW_BYTE_LEN;
563
0
        start..end
564
0
    }
565
566
0
    pub fn base_lang_sys_records_byte_range(&self) -> Range<usize> {
567
0
        let base_lang_sys_count = self.base_lang_sys_count();
568
0
        let start = self.base_lang_sys_count_byte_range().end;
569
0
        let end = start
570
0
            + (transforms::to_usize(base_lang_sys_count))
571
0
                .saturating_mul(BaseLangSysRecord::RAW_BYTE_LEN);
572
0
        start..end
573
0
    }
574
}
575
576
const _: () = assert!(FontData::default_data_long_enough(BaseScript::MIN_SIZE));
577
578
impl Default for BaseScript<'_> {
579
0
    fn default() -> Self {
580
        Self {
581
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
582
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
583
        }
584
0
    }
585
}
586
587
/// [BaseLangSysRecord](https://learn.microsoft.com/en-us/typography/opentype/spec/base#baselangsysrecord)
588
#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
589
#[repr(C)]
590
#[repr(packed)]
591
pub struct BaseLangSysRecord {
592
    /// 4-byte language system identification tag
593
    pub base_lang_sys_tag: BigEndian<Tag>,
594
    /// Offset to MinMax table, from beginning of BaseScript table
595
    pub min_max_offset: BigEndian<Offset16>,
596
}
597
598
impl BaseLangSysRecord {
599
    /// 4-byte language system identification tag
600
0
    pub fn base_lang_sys_tag(&self) -> Tag {
601
0
        self.base_lang_sys_tag.get()
602
0
    }
603
604
    /// Offset to MinMax table, from beginning of BaseScript table
605
0
    pub fn min_max_offset(&self) -> Offset16 {
606
0
        self.min_max_offset.get()
607
0
    }
608
609
    /// Offset to MinMax table, from beginning of BaseScript table
610
    ///
611
    /// The `data` argument should be retrieved from the parent table
612
    /// By calling its `offset_data` method.
613
0
    pub fn min_max<'a>(&self, data: FontData<'a>) -> Result<MinMax<'a>, ReadError> {
614
0
        self.min_max_offset().resolve(data)
615
0
    }
616
}
617
618
impl FixedSize for BaseLangSysRecord {
619
    const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
620
}
621
622
impl<'a> MinByteRange<'a> for BaseValues<'a> {
623
0
    fn min_byte_range(&self) -> Range<usize> {
624
0
        0..self.base_coord_offsets_byte_range().end
625
0
    }
626
0
    fn min_table_bytes(&self) -> &'a [u8] {
627
0
        let range = self.min_byte_range();
628
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
629
0
    }
630
}
631
632
impl ReadArgs for BaseValues<'_> {
633
    type Args = ();
634
}
635
636
impl<'a> FontRead<'a> for BaseValues<'a> {
637
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
638
        #[allow(clippy::absurd_extreme_comparisons)]
639
0
        if data.len() < Self::MIN_SIZE {
640
0
            return Err(ReadError::OutOfBounds);
641
0
        }
642
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
643
0
            return Err(ReadError::OutOfBounds);
644
        };
645
0
        Ok(Self { data })
646
0
    }
647
}
648
649
/// The fields at the start of the table, which are read directly.
650
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
651
#[repr(C, packed)]
652
#[doc(hidden)]
653
pub struct BaseValuesFixedHeader {
654
    pub default_baseline_index: BigEndian<u16>,
655
    pub base_coord_count: BigEndian<u16>,
656
}
657
658
#[allow(clippy::absurd_extreme_comparisons)]
659
const _: () = assert!(std::mem::size_of::<BaseValuesFixedHeader>() <= BaseValues::MIN_SIZE);
660
661
/// [BaseValues](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basevalues-table) table
662
#[derive(Clone)]
663
pub struct BaseValues<'a> {
664
    data: TableDataRef<'a, BaseValuesFixedHeader>,
665
}
666
667
#[allow(clippy::needless_lifetimes)]
668
impl<'a> BaseValues<'a> {
669
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
670
    basic_table_impls!(impl_the_methods);
671
672
    /// Index number of default baseline for this script — equals
673
    /// index position of baseline tag in baselineTags array of the
674
    /// BaseTagList
675
0
    pub fn default_baseline_index(&self) -> u16 {
676
0
        self.data.header().default_baseline_index.get()
677
0
    }
678
679
    /// Number of BaseCoord tables defined — should equal
680
    /// baseTagCount in the BaseTagList
681
0
    pub fn base_coord_count(&self) -> u16 {
682
0
        self.data.header().base_coord_count.get()
683
0
    }
684
685
    /// Array of offsets to BaseCoord tables, from beginning of
686
    /// BaseValues table — order matches baselineTags array in the
687
    /// BaseTagList
688
0
    pub fn base_coord_offsets(&self) -> &'a [BigEndian<Offset16>] {
689
0
        let range = self.base_coord_offsets_byte_range();
690
0
        self.offset_data()
691
0
            .read_array(range)
692
0
            .ok()
693
0
            .unwrap_or_default()
694
0
    }
695
696
    /// A dynamically resolving wrapper for [`base_coord_offsets`][Self::base_coord_offsets].
697
0
    pub fn base_coords(&self) -> ArrayOfOffsets<'a, BaseCoord<'a>, Offset16> {
698
0
        let data = self.offset_data();
699
0
        let offsets = self.base_coord_offsets();
700
0
        ArrayOfOffsets::new(offsets, data, ())
701
0
    }
702
703
0
    pub fn default_baseline_index_byte_range(&self) -> Range<usize> {
704
0
        let start = 0;
705
0
        let end = start + u16::RAW_BYTE_LEN;
706
0
        start..end
707
0
    }
708
709
0
    pub fn base_coord_count_byte_range(&self) -> Range<usize> {
710
0
        let start = self.default_baseline_index_byte_range().end;
711
0
        let end = start + u16::RAW_BYTE_LEN;
712
0
        start..end
713
0
    }
714
715
0
    pub fn base_coord_offsets_byte_range(&self) -> Range<usize> {
716
0
        let base_coord_count = self.base_coord_count();
717
0
        let start = self.base_coord_count_byte_range().end;
718
0
        let end =
719
0
            start + (transforms::to_usize(base_coord_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
720
0
        start..end
721
0
    }
722
}
723
724
const _: () = assert!(FontData::default_data_long_enough(BaseValues::MIN_SIZE));
725
726
impl Default for BaseValues<'_> {
727
0
    fn default() -> Self {
728
        Self {
729
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
730
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
731
        }
732
0
    }
733
}
734
735
impl<'a> MinByteRange<'a> for MinMax<'a> {
736
0
    fn min_byte_range(&self) -> Range<usize> {
737
0
        0..self.feat_min_max_records_byte_range().end
738
0
    }
739
0
    fn min_table_bytes(&self) -> &'a [u8] {
740
0
        let range = self.min_byte_range();
741
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
742
0
    }
743
}
744
745
impl ReadArgs for MinMax<'_> {
746
    type Args = ();
747
}
748
749
impl<'a> FontRead<'a> for MinMax<'a> {
750
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
751
        #[allow(clippy::absurd_extreme_comparisons)]
752
0
        if data.len() < Self::MIN_SIZE {
753
0
            return Err(ReadError::OutOfBounds);
754
0
        }
755
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
756
0
            return Err(ReadError::OutOfBounds);
757
        };
758
0
        Ok(Self { data })
759
0
    }
760
}
761
762
/// The fields at the start of the table, which are read directly.
763
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
764
#[repr(C, packed)]
765
#[doc(hidden)]
766
pub struct MinMaxFixedHeader {
767
    pub min_coord_offset: BigEndian<Nullable<Offset16>>,
768
    pub max_coord_offset: BigEndian<Nullable<Offset16>>,
769
    pub feat_min_max_count: BigEndian<u16>,
770
}
771
772
#[allow(clippy::absurd_extreme_comparisons)]
773
const _: () = assert!(std::mem::size_of::<MinMaxFixedHeader>() <= MinMax::MIN_SIZE);
774
775
/// [MinMax](https://learn.microsoft.com/en-us/typography/opentype/spec/base#minmax-table) table
776
#[derive(Clone)]
777
pub struct MinMax<'a> {
778
    data: TableDataRef<'a, MinMaxFixedHeader>,
779
}
780
781
#[allow(clippy::needless_lifetimes)]
782
impl<'a> MinMax<'a> {
783
    pub const MIN_SIZE: usize =
784
        (Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
785
    basic_table_impls!(impl_the_methods);
786
787
    /// Offset to BaseCoord table that defines the minimum extent
788
    /// value, from the beginning of MinMax table (may be NULL)
789
0
    pub fn min_coord_offset(&self) -> Nullable<Offset16> {
790
0
        self.data.header().min_coord_offset.get()
791
0
    }
792
793
    /// Attempt to resolve [`min_coord_offset`][Self::min_coord_offset].
794
0
    pub fn min_coord(&self) -> Option<Result<BaseCoord<'a>, ReadError>> {
795
0
        let data = self.offset_data();
796
0
        self.min_coord_offset().resolve(data)
797
0
    }
798
799
    /// Offset to BaseCoord table that defines maximum extent value,
800
    /// from the beginning of MinMax table (may be NULL)
801
0
    pub fn max_coord_offset(&self) -> Nullable<Offset16> {
802
0
        self.data.header().max_coord_offset.get()
803
0
    }
804
805
    /// Attempt to resolve [`max_coord_offset`][Self::max_coord_offset].
806
0
    pub fn max_coord(&self) -> Option<Result<BaseCoord<'a>, ReadError>> {
807
0
        let data = self.offset_data();
808
0
        self.max_coord_offset().resolve(data)
809
0
    }
810
811
    /// Number of FeatMinMaxRecords — may be zero (0)
812
0
    pub fn feat_min_max_count(&self) -> u16 {
813
0
        self.data.header().feat_min_max_count.get()
814
0
    }
815
816
    /// Array of FeatMinMaxRecords, in alphabetical order by
817
    /// featureTableTag
818
0
    pub fn feat_min_max_records(&self) -> &'a [FeatMinMaxRecord] {
819
0
        let range = self.feat_min_max_records_byte_range();
820
0
        self.offset_data()
821
0
            .read_array(range)
822
0
            .ok()
823
0
            .unwrap_or_default()
824
0
    }
825
826
0
    pub fn min_coord_offset_byte_range(&self) -> Range<usize> {
827
0
        let start = 0;
828
0
        let end = start + Offset16::RAW_BYTE_LEN;
829
0
        start..end
830
0
    }
831
832
0
    pub fn max_coord_offset_byte_range(&self) -> Range<usize> {
833
0
        let start = self.min_coord_offset_byte_range().end;
834
0
        let end = start + Offset16::RAW_BYTE_LEN;
835
0
        start..end
836
0
    }
837
838
0
    pub fn feat_min_max_count_byte_range(&self) -> Range<usize> {
839
0
        let start = self.max_coord_offset_byte_range().end;
840
0
        let end = start + u16::RAW_BYTE_LEN;
841
0
        start..end
842
0
    }
843
844
0
    pub fn feat_min_max_records_byte_range(&self) -> Range<usize> {
845
0
        let feat_min_max_count = self.feat_min_max_count();
846
0
        let start = self.feat_min_max_count_byte_range().end;
847
0
        let end = start
848
0
            + (transforms::to_usize(feat_min_max_count))
849
0
                .saturating_mul(FeatMinMaxRecord::RAW_BYTE_LEN);
850
0
        start..end
851
0
    }
852
}
853
854
const _: () = assert!(FontData::default_data_long_enough(MinMax::MIN_SIZE));
855
856
impl Default for MinMax<'_> {
857
0
    fn default() -> Self {
858
        Self {
859
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
860
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
861
        }
862
0
    }
863
}
864
865
/// [FeatMinMaxRecord](https://learn.microsoft.com/en-us/typography/opentype/spec/base#baselangsysrecord)
866
#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
867
#[repr(C)]
868
#[repr(packed)]
869
pub struct FeatMinMaxRecord {
870
    /// 4-byte feature identification tag — must match feature tag in
871
    /// FeatureList
872
    pub feature_table_tag: BigEndian<Tag>,
873
    /// Offset to BaseCoord table that defines the minimum extent
874
    /// value, from beginning of MinMax table (may be NULL)
875
    pub min_coord_offset: BigEndian<Nullable<Offset16>>,
876
    /// Offset to BaseCoord table that defines the maximum extent
877
    /// value, from beginning of MinMax table (may be NULL)
878
    pub max_coord_offset: BigEndian<Nullable<Offset16>>,
879
}
880
881
impl FeatMinMaxRecord {
882
    /// 4-byte feature identification tag — must match feature tag in
883
    /// FeatureList
884
0
    pub fn feature_table_tag(&self) -> Tag {
885
0
        self.feature_table_tag.get()
886
0
    }
887
888
    /// Offset to BaseCoord table that defines the minimum extent
889
    /// value, from beginning of MinMax table (may be NULL)
890
0
    pub fn min_coord_offset(&self) -> Nullable<Offset16> {
891
0
        self.min_coord_offset.get()
892
0
    }
893
894
    /// Offset to BaseCoord table that defines the minimum extent
895
    /// value, from beginning of MinMax table (may be NULL)
896
    ///
897
    /// The `data` argument should be retrieved from the parent table
898
    /// By calling its `offset_data` method.
899
0
    pub fn min_coord<'a>(&self, data: FontData<'a>) -> Option<Result<BaseCoord<'a>, ReadError>> {
900
0
        self.min_coord_offset().resolve(data)
901
0
    }
902
903
    /// Offset to BaseCoord table that defines the maximum extent
904
    /// value, from beginning of MinMax table (may be NULL)
905
0
    pub fn max_coord_offset(&self) -> Nullable<Offset16> {
906
0
        self.max_coord_offset.get()
907
0
    }
908
909
    /// Offset to BaseCoord table that defines the maximum extent
910
    /// value, from beginning of MinMax table (may be NULL)
911
    ///
912
    /// The `data` argument should be retrieved from the parent table
913
    /// By calling its `offset_data` method.
914
0
    pub fn max_coord<'a>(&self, data: FontData<'a>) -> Option<Result<BaseCoord<'a>, ReadError>> {
915
0
        self.max_coord_offset().resolve(data)
916
0
    }
917
}
918
919
impl FixedSize for FeatMinMaxRecord {
920
    const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
921
}
922
923
#[derive(Clone)]
924
pub enum BaseCoord<'a> {
925
    Format1(BaseCoordFormat1<'a>),
926
    Format2(BaseCoordFormat2<'a>),
927
    Format3(BaseCoordFormat3<'a>),
928
}
929
930
impl Default for BaseCoord<'_> {
931
0
    fn default() -> Self {
932
0
        Self::Format1(Default::default())
933
0
    }
934
}
935
936
impl<'a> BaseCoord<'a> {
937
    ///Return the `FontData` used to resolve offsets for this table.
938
0
    pub fn offset_data(&self) -> FontData<'a> {
939
0
        match self {
940
0
            Self::Format1(item) => item.offset_data(),
941
0
            Self::Format2(item) => item.offset_data(),
942
0
            Self::Format3(item) => item.offset_data(),
943
        }
944
0
    }
945
946
    /// Format identifier — format = 1
947
0
    pub fn base_coord_format(&self) -> u16 {
948
0
        match self {
949
0
            Self::Format1(item) => item.base_coord_format(),
950
0
            Self::Format2(item) => item.base_coord_format(),
951
0
            Self::Format3(item) => item.base_coord_format(),
952
        }
953
0
    }
954
955
    /// X or Y value, in design units
956
0
    pub fn coordinate(&self) -> i16 {
957
0
        match self {
958
0
            Self::Format1(item) => item.coordinate(),
959
0
            Self::Format2(item) => item.coordinate(),
960
0
            Self::Format3(item) => item.coordinate(),
961
        }
962
0
    }
963
}
964
965
impl ReadArgs for BaseCoord<'_> {
966
    type Args = ();
967
}
968
969
impl<'a> FontRead<'a> for BaseCoord<'a> {
970
    #[inline]
971
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
972
0
        let format: u16 = data.read_at(0usize)?;
973
0
        match format {
974
0
            BaseCoordFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
975
0
            BaseCoordFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
976
0
            BaseCoordFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
977
0
            other => Err(ReadError::InvalidFormat(other.into())),
978
        }
979
0
    }
980
}
981
982
impl<'a> MinByteRange<'a> for BaseCoord<'a> {
983
0
    fn min_byte_range(&self) -> Range<usize> {
984
0
        match self {
985
0
            Self::Format1(item) => item.min_byte_range(),
986
0
            Self::Format2(item) => item.min_byte_range(),
987
0
            Self::Format3(item) => item.min_byte_range(),
988
        }
989
0
    }
990
0
    fn min_table_bytes(&self) -> &'a [u8] {
991
0
        match self {
992
0
            Self::Format1(item) => item.min_table_bytes(),
993
0
            Self::Format2(item) => item.min_table_bytes(),
994
0
            Self::Format3(item) => item.min_table_bytes(),
995
        }
996
0
    }
997
}
998
999
impl Format<u16> for BaseCoordFormat1<'_> {
1000
    const FORMAT: u16 = 1;
1001
}
1002
1003
impl<'a> MinByteRange<'a> for BaseCoordFormat1<'a> {
1004
0
    fn min_byte_range(&self) -> Range<usize> {
1005
0
        0..self.coordinate_byte_range().end
1006
0
    }
1007
0
    fn min_table_bytes(&self) -> &'a [u8] {
1008
0
        let range = self.min_byte_range();
1009
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
1010
0
    }
1011
}
1012
1013
impl ReadArgs for BaseCoordFormat1<'_> {
1014
    type Args = ();
1015
}
1016
1017
impl<'a> FontRead<'a> for BaseCoordFormat1<'a> {
1018
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1019
        #[allow(clippy::absurd_extreme_comparisons)]
1020
0
        if data.len() < Self::MIN_SIZE {
1021
0
            return Err(ReadError::OutOfBounds);
1022
0
        }
1023
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1024
0
            return Err(ReadError::OutOfBounds);
1025
        };
1026
0
        Ok(Self { data })
1027
0
    }
1028
}
1029
1030
/// The fields at the start of the table, which are read directly.
1031
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1032
#[repr(C, packed)]
1033
#[doc(hidden)]
1034
pub struct BaseCoordFormat1FixedHeader {
1035
    pub base_coord_format: BigEndian<u16>,
1036
    pub coordinate: BigEndian<i16>,
1037
}
1038
1039
#[allow(clippy::absurd_extreme_comparisons)]
1040
const _: () =
1041
    assert!(std::mem::size_of::<BaseCoordFormat1FixedHeader>() <= BaseCoordFormat1::MIN_SIZE);
1042
1043
/// [BaseCoordFormat1](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basecoord-format-1)
1044
#[derive(Clone)]
1045
pub struct BaseCoordFormat1<'a> {
1046
    data: TableDataRef<'a, BaseCoordFormat1FixedHeader>,
1047
}
1048
1049
#[allow(clippy::needless_lifetimes)]
1050
impl<'a> BaseCoordFormat1<'a> {
1051
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN);
1052
    basic_table_impls!(impl_the_methods);
1053
1054
    /// Format identifier — format = 1
1055
0
    pub fn base_coord_format(&self) -> u16 {
1056
0
        self.data.header().base_coord_format.get()
1057
0
    }
1058
1059
    /// X or Y value, in design units
1060
0
    pub fn coordinate(&self) -> i16 {
1061
0
        self.data.header().coordinate.get()
1062
0
    }
1063
1064
0
    pub fn base_coord_format_byte_range(&self) -> Range<usize> {
1065
0
        let start = 0;
1066
0
        let end = start + u16::RAW_BYTE_LEN;
1067
0
        start..end
1068
0
    }
1069
1070
0
    pub fn coordinate_byte_range(&self) -> Range<usize> {
1071
0
        let start = self.base_coord_format_byte_range().end;
1072
0
        let end = start + i16::RAW_BYTE_LEN;
1073
0
        start..end
1074
0
    }
1075
}
1076
1077
const _: () = assert!(FontData::default_data_long_enough(
1078
    BaseCoordFormat1::MIN_SIZE
1079
));
1080
1081
impl Default for BaseCoordFormat1<'_> {
1082
0
    fn default() -> Self {
1083
        Self {
1084
0
            data: TableDataRef::new(FontData::default_format_1_u16_table_data().as_bytes())
1085
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1086
        }
1087
0
    }
1088
}
1089
1090
impl Format<u16> for BaseCoordFormat2<'_> {
1091
    const FORMAT: u16 = 2;
1092
}
1093
1094
impl<'a> MinByteRange<'a> for BaseCoordFormat2<'a> {
1095
0
    fn min_byte_range(&self) -> Range<usize> {
1096
0
        0..self.base_coord_point_byte_range().end
1097
0
    }
1098
0
    fn min_table_bytes(&self) -> &'a [u8] {
1099
0
        let range = self.min_byte_range();
1100
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
1101
0
    }
1102
}
1103
1104
impl ReadArgs for BaseCoordFormat2<'_> {
1105
    type Args = ();
1106
}
1107
1108
impl<'a> FontRead<'a> for BaseCoordFormat2<'a> {
1109
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1110
        #[allow(clippy::absurd_extreme_comparisons)]
1111
0
        if data.len() < Self::MIN_SIZE {
1112
0
            return Err(ReadError::OutOfBounds);
1113
0
        }
1114
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1115
0
            return Err(ReadError::OutOfBounds);
1116
        };
1117
0
        Ok(Self { data })
1118
0
    }
1119
}
1120
1121
/// The fields at the start of the table, which are read directly.
1122
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1123
#[repr(C, packed)]
1124
#[doc(hidden)]
1125
pub struct BaseCoordFormat2FixedHeader {
1126
    pub base_coord_format: BigEndian<u16>,
1127
    pub coordinate: BigEndian<i16>,
1128
    pub reference_glyph: BigEndian<u16>,
1129
    pub base_coord_point: BigEndian<u16>,
1130
}
1131
1132
#[allow(clippy::absurd_extreme_comparisons)]
1133
const _: () =
1134
    assert!(std::mem::size_of::<BaseCoordFormat2FixedHeader>() <= BaseCoordFormat2::MIN_SIZE);
1135
1136
/// [BaseCoordFormat2](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basecoord-format-2)
1137
#[derive(Clone)]
1138
pub struct BaseCoordFormat2<'a> {
1139
    data: TableDataRef<'a, BaseCoordFormat2FixedHeader>,
1140
}
1141
1142
#[allow(clippy::needless_lifetimes)]
1143
impl<'a> BaseCoordFormat2<'a> {
1144
    pub const MIN_SIZE: usize =
1145
        (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1146
    basic_table_impls!(impl_the_methods);
1147
1148
    /// Format identifier — format = 2
1149
0
    pub fn base_coord_format(&self) -> u16 {
1150
0
        self.data.header().base_coord_format.get()
1151
0
    }
1152
1153
    /// X or Y value, in design units
1154
0
    pub fn coordinate(&self) -> i16 {
1155
0
        self.data.header().coordinate.get()
1156
0
    }
1157
1158
    /// Glyph ID of control glyph
1159
0
    pub fn reference_glyph(&self) -> u16 {
1160
0
        self.data.header().reference_glyph.get()
1161
0
    }
1162
1163
    /// Index of contour point on the reference glyph
1164
0
    pub fn base_coord_point(&self) -> u16 {
1165
0
        self.data.header().base_coord_point.get()
1166
0
    }
1167
1168
0
    pub fn base_coord_format_byte_range(&self) -> Range<usize> {
1169
0
        let start = 0;
1170
0
        let end = start + u16::RAW_BYTE_LEN;
1171
0
        start..end
1172
0
    }
1173
1174
0
    pub fn coordinate_byte_range(&self) -> Range<usize> {
1175
0
        let start = self.base_coord_format_byte_range().end;
1176
0
        let end = start + i16::RAW_BYTE_LEN;
1177
0
        start..end
1178
0
    }
1179
1180
0
    pub fn reference_glyph_byte_range(&self) -> Range<usize> {
1181
0
        let start = self.coordinate_byte_range().end;
1182
0
        let end = start + u16::RAW_BYTE_LEN;
1183
0
        start..end
1184
0
    }
1185
1186
0
    pub fn base_coord_point_byte_range(&self) -> Range<usize> {
1187
0
        let start = self.reference_glyph_byte_range().end;
1188
0
        let end = start + u16::RAW_BYTE_LEN;
1189
0
        start..end
1190
0
    }
1191
}
1192
1193
impl Format<u16> for BaseCoordFormat3<'_> {
1194
    const FORMAT: u16 = 3;
1195
}
1196
1197
impl<'a> MinByteRange<'a> for BaseCoordFormat3<'a> {
1198
0
    fn min_byte_range(&self) -> Range<usize> {
1199
0
        0..self.device_offset_byte_range().end
1200
0
    }
1201
0
    fn min_table_bytes(&self) -> &'a [u8] {
1202
0
        let range = self.min_byte_range();
1203
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
1204
0
    }
1205
}
1206
1207
impl ReadArgs for BaseCoordFormat3<'_> {
1208
    type Args = ();
1209
}
1210
1211
impl<'a> FontRead<'a> for BaseCoordFormat3<'a> {
1212
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1213
        #[allow(clippy::absurd_extreme_comparisons)]
1214
0
        if data.len() < Self::MIN_SIZE {
1215
0
            return Err(ReadError::OutOfBounds);
1216
0
        }
1217
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1218
0
            return Err(ReadError::OutOfBounds);
1219
        };
1220
0
        Ok(Self { data })
1221
0
    }
1222
}
1223
1224
/// The fields at the start of the table, which are read directly.
1225
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1226
#[repr(C, packed)]
1227
#[doc(hidden)]
1228
pub struct BaseCoordFormat3FixedHeader {
1229
    pub base_coord_format: BigEndian<u16>,
1230
    pub coordinate: BigEndian<i16>,
1231
    pub device_offset: BigEndian<Nullable<Offset16>>,
1232
}
1233
1234
#[allow(clippy::absurd_extreme_comparisons)]
1235
const _: () =
1236
    assert!(std::mem::size_of::<BaseCoordFormat3FixedHeader>() <= BaseCoordFormat3::MIN_SIZE);
1237
1238
/// [BaseCoordFormat3](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basecoord-format-3)
1239
#[derive(Clone)]
1240
pub struct BaseCoordFormat3<'a> {
1241
    data: TableDataRef<'a, BaseCoordFormat3FixedHeader>,
1242
}
1243
1244
#[allow(clippy::needless_lifetimes)]
1245
impl<'a> BaseCoordFormat3<'a> {
1246
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN);
1247
    basic_table_impls!(impl_the_methods);
1248
1249
    /// Format identifier — format = 3
1250
0
    pub fn base_coord_format(&self) -> u16 {
1251
0
        self.data.header().base_coord_format.get()
1252
0
    }
1253
1254
    /// X or Y value, in design units
1255
0
    pub fn coordinate(&self) -> i16 {
1256
0
        self.data.header().coordinate.get()
1257
0
    }
1258
1259
    /// Offset to Device table (non-variable font) / Variation Index
1260
    /// table (variable font) for X or Y value, from beginning of
1261
    /// BaseCoord table (may be NULL).
1262
0
    pub fn device_offset(&self) -> Nullable<Offset16> {
1263
0
        self.data.header().device_offset.get()
1264
0
    }
1265
1266
    /// Attempt to resolve [`device_offset`][Self::device_offset].
1267
0
    pub fn device(&self) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>> {
1268
0
        let data = self.offset_data();
1269
0
        self.device_offset().resolve(data)
1270
0
    }
1271
1272
0
    pub fn base_coord_format_byte_range(&self) -> Range<usize> {
1273
0
        let start = 0;
1274
0
        let end = start + u16::RAW_BYTE_LEN;
1275
0
        start..end
1276
0
    }
1277
1278
0
    pub fn coordinate_byte_range(&self) -> Range<usize> {
1279
0
        let start = self.base_coord_format_byte_range().end;
1280
0
        let end = start + i16::RAW_BYTE_LEN;
1281
0
        start..end
1282
0
    }
1283
1284
0
    pub fn device_offset_byte_range(&self) -> Range<usize> {
1285
0
        let start = self.coordinate_byte_range().end;
1286
0
        let end = start + Offset16::RAW_BYTE_LEN;
1287
0
        start..end
1288
0
    }
1289
}