Coverage Report

Created: 2026-09-14 08:06

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