Coverage Report

Created: 2026-05-24 07:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fontations/read-fonts/generated/generated_cmap.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 Cmap<'a> {
9
0
    fn min_byte_range(&self) -> Range<usize> {
10
0
        0..self.encoding_records_byte_range().end
11
0
    }
12
0
    fn min_table_bytes(&self) -> &'a [u8] {
13
0
        let range = self.min_byte_range();
14
0
        self.data.as_bytes().get(range).unwrap_or_default()
15
0
    }
16
}
17
18
impl TopLevelTable for Cmap<'_> {
19
    /// `cmap`
20
    const TAG: Tag = Tag::new(b"cmap");
21
}
22
23
impl<'a> FontRead<'a> for Cmap<'a> {
24
45.5k
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
25
        #[allow(clippy::absurd_extreme_comparisons)]
26
45.5k
        if data.len() < Self::MIN_SIZE {
27
24
            return Err(ReadError::OutOfBounds);
28
45.5k
        }
29
45.5k
        Ok(Self { data })
30
45.5k
    }
31
}
32
33
/// [cmap](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#overview)
34
#[derive(Clone)]
35
pub struct Cmap<'a> {
36
    data: FontData<'a>,
37
}
38
39
#[allow(clippy::needless_lifetimes)]
40
impl<'a> Cmap<'a> {
41
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
42
    basic_table_impls!(impl_the_methods);
43
44
    /// Table version number (0).
45
0
    pub fn version(&self) -> u16 {
46
0
        let range = self.version_byte_range();
47
0
        self.data.read_at(range.start).ok().unwrap()
48
0
    }
49
50
    /// Number of encoding tables that follow.
51
45.5k
    pub fn num_tables(&self) -> u16 {
52
45.5k
        let range = self.num_tables_byte_range();
53
45.5k
        self.data.read_at(range.start).ok().unwrap()
54
45.5k
    }
55
56
45.5k
    pub fn encoding_records(&self) -> &'a [EncodingRecord] {
57
45.5k
        let range = self.encoding_records_byte_range();
58
45.5k
        self.data.read_array(range).ok().unwrap_or_default()
59
45.5k
    }
60
61
91.0k
    pub fn version_byte_range(&self) -> Range<usize> {
62
91.0k
        let start = 0;
63
91.0k
        start..start + u16::RAW_BYTE_LEN
64
91.0k
    }
65
66
91.0k
    pub fn num_tables_byte_range(&self) -> Range<usize> {
67
91.0k
        let start = self.version_byte_range().end;
68
91.0k
        start..start + u16::RAW_BYTE_LEN
69
91.0k
    }
70
71
45.5k
    pub fn encoding_records_byte_range(&self) -> Range<usize> {
72
45.5k
        let num_tables = self.num_tables();
73
45.5k
        let start = self.num_tables_byte_range().end;
74
45.5k
        start..start + (num_tables as usize).saturating_mul(EncodingRecord::RAW_BYTE_LEN)
75
45.5k
    }
76
}
77
78
#[cfg(feature = "experimental_traverse")]
79
impl<'a> SomeTable<'a> for Cmap<'a> {
80
    fn type_name(&self) -> &str {
81
        "Cmap"
82
    }
83
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
84
        match idx {
85
            0usize => Some(Field::new("version", self.version())),
86
            1usize => Some(Field::new("num_tables", self.num_tables())),
87
            2usize => Some(Field::new(
88
                "encoding_records",
89
                traversal::FieldType::array_of_records(
90
                    stringify!(EncodingRecord),
91
                    self.encoding_records(),
92
                    self.offset_data(),
93
                ),
94
            )),
95
            _ => None,
96
        }
97
    }
98
}
99
100
#[cfg(feature = "experimental_traverse")]
101
#[allow(clippy::needless_lifetimes)]
102
impl<'a> std::fmt::Debug for Cmap<'a> {
103
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104
        (self as &dyn SomeTable<'a>).fmt(f)
105
    }
106
}
107
108
/// [Encoding Record](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#encoding-records-and-encodings)
109
#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
110
#[repr(C)]
111
#[repr(packed)]
112
pub struct EncodingRecord {
113
    /// Platform ID.
114
    pub platform_id: BigEndian<PlatformId>,
115
    /// Platform-specific encoding ID.
116
    pub encoding_id: BigEndian<u16>,
117
    /// Byte offset from beginning of the [`Cmap`] table to the subtable for this
118
    /// encoding.
119
    pub subtable_offset: BigEndian<Offset32>,
120
}
121
122
impl EncodingRecord {
123
    /// Platform ID.
124
8.67M
    pub fn platform_id(&self) -> PlatformId {
125
8.67M
        self.platform_id.get()
126
8.67M
    }
127
128
    /// Platform-specific encoding ID.
129
8.67M
    pub fn encoding_id(&self) -> u16 {
130
8.67M
        self.encoding_id.get()
131
8.67M
    }
132
133
    /// Byte offset from beginning of the [`Cmap`] table to the subtable for this
134
    /// encoding.
135
3.30M
    pub fn subtable_offset(&self) -> Offset32 {
136
3.30M
        self.subtable_offset.get()
137
3.30M
    }
138
139
    /// Byte offset from beginning of the [`Cmap`] table to the subtable for this
140
    /// encoding.
141
    ///
142
    /// The `data` argument should be retrieved from the parent table
143
    /// By calling its `offset_data` method.
144
3.30M
    pub fn subtable<'a>(&self, data: FontData<'a>) -> Result<CmapSubtable<'a>, ReadError> {
145
3.30M
        self.subtable_offset().resolve(data)
146
3.30M
    }
147
}
148
149
impl FixedSize for EncodingRecord {
150
    const RAW_BYTE_LEN: usize =
151
        PlatformId::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
152
}
153
154
#[cfg(feature = "experimental_traverse")]
155
impl<'a> SomeRecord<'a> for EncodingRecord {
156
    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
157
        RecordResolver {
158
            name: "EncodingRecord",
159
            get_field: Box::new(move |idx, _data| match idx {
160
                0usize => Some(Field::new("platform_id", self.platform_id())),
161
                1usize => Some(Field::new("encoding_id", self.encoding_id())),
162
                2usize => Some(Field::new(
163
                    "subtable_offset",
164
                    FieldType::offset(self.subtable_offset(), self.subtable(_data)),
165
                )),
166
                _ => None,
167
            }),
168
            data,
169
        }
170
    }
171
}
172
173
/// <https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#platform-ids>
174
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
175
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
176
#[repr(u16)]
177
#[allow(clippy::manual_non_exhaustive)]
178
pub enum PlatformId {
179
    #[default]
180
    Unicode = 0,
181
    Macintosh = 1,
182
    ISO = 2,
183
    Windows = 3,
184
    Custom = 4,
185
    #[doc(hidden)]
186
    /// If font data is malformed we will map unknown values to this variant
187
    Unknown,
188
}
189
190
impl PlatformId {
191
    /// Create from a raw scalar.
192
    ///
193
    /// This will never fail; unknown values will be mapped to the `Unknown` variant
194
8.67M
    pub fn new(raw: u16) -> Self {
195
8.67M
        match raw {
196
3.09M
            0 => Self::Unicode,
197
158k
            1 => Self::Macintosh,
198
116k
            2 => Self::ISO,
199
138k
            3 => Self::Windows,
200
238k
            4 => Self::Custom,
201
4.92M
            _ => Self::Unknown,
202
        }
203
8.67M
    }
204
}
205
206
impl font_types::Scalar for PlatformId {
207
    type Raw = <u16 as font_types::Scalar>::Raw;
208
0
    fn to_raw(self) -> Self::Raw {
209
0
        (self as u16).to_raw()
210
0
    }
211
8.67M
    fn from_raw(raw: Self::Raw) -> Self {
212
8.67M
        let t = <u16>::from_raw(raw);
213
8.67M
        Self::new(t)
214
8.67M
    }
215
}
216
217
#[cfg(feature = "experimental_traverse")]
218
impl<'a> From<PlatformId> for FieldType<'a> {
219
    fn from(src: PlatformId) -> FieldType<'a> {
220
        (src as u16).into()
221
    }
222
}
223
224
/// The different cmap subtable formats.
225
#[derive(Clone)]
226
pub enum CmapSubtable<'a> {
227
    Format0(Cmap0<'a>),
228
    Format2(Cmap2<'a>),
229
    Format4(Cmap4<'a>),
230
    Format6(Cmap6<'a>),
231
    Format8(Cmap8<'a>),
232
    Format10(Cmap10<'a>),
233
    Format12(Cmap12<'a>),
234
    Format13(Cmap13<'a>),
235
    Format14(Cmap14<'a>),
236
}
237
238
impl<'a> CmapSubtable<'a> {
239
    ///Return the `FontData` used to resolve offsets for this table.
240
0
    pub fn offset_data(&self) -> FontData<'a> {
241
0
        match self {
242
0
            Self::Format0(item) => item.offset_data(),
243
0
            Self::Format2(item) => item.offset_data(),
244
0
            Self::Format4(item) => item.offset_data(),
245
0
            Self::Format6(item) => item.offset_data(),
246
0
            Self::Format8(item) => item.offset_data(),
247
0
            Self::Format10(item) => item.offset_data(),
248
0
            Self::Format12(item) => item.offset_data(),
249
0
            Self::Format13(item) => item.offset_data(),
250
0
            Self::Format14(item) => item.offset_data(),
251
        }
252
0
    }
253
254
    /// Format number is set to 0.
255
0
    pub fn format(&self) -> u16 {
256
0
        match self {
257
0
            Self::Format0(item) => item.format(),
258
0
            Self::Format2(item) => item.format(),
259
0
            Self::Format4(item) => item.format(),
260
0
            Self::Format6(item) => item.format(),
261
0
            Self::Format8(item) => item.format(),
262
0
            Self::Format10(item) => item.format(),
263
0
            Self::Format12(item) => item.format(),
264
0
            Self::Format13(item) => item.format(),
265
0
            Self::Format14(item) => item.format(),
266
        }
267
0
    }
268
}
269
270
impl<'a> FontRead<'a> for CmapSubtable<'a> {
271
1.12M
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
272
1.12M
        let format: u16 = data.read_at(0usize)?;
273
1.12M
        match format {
274
269k
            Cmap0::FORMAT => Ok(Self::Format0(FontRead::read(data)?)),
275
8.80k
            Cmap2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
276
94.3k
            Cmap4::FORMAT => Ok(Self::Format4(FontRead::read(data)?)),
277
4.62k
            Cmap6::FORMAT => Ok(Self::Format6(FontRead::read(data)?)),
278
7.44k
            Cmap8::FORMAT => Ok(Self::Format8(FontRead::read(data)?)),
279
4.88k
            Cmap10::FORMAT => Ok(Self::Format10(FontRead::read(data)?)),
280
43.6k
            Cmap12::FORMAT => Ok(Self::Format12(FontRead::read(data)?)),
281
1.93k
            Cmap13::FORMAT => Ok(Self::Format13(FontRead::read(data)?)),
282
23.3k
            Cmap14::FORMAT => Ok(Self::Format14(FontRead::read(data)?)),
283
667k
            other => Err(ReadError::InvalidFormat(other.into())),
284
        }
285
1.12M
    }
286
}
287
288
impl<'a> MinByteRange<'a> for CmapSubtable<'a> {
289
0
    fn min_byte_range(&self) -> Range<usize> {
290
0
        match self {
291
0
            Self::Format0(item) => item.min_byte_range(),
292
0
            Self::Format2(item) => item.min_byte_range(),
293
0
            Self::Format4(item) => item.min_byte_range(),
294
0
            Self::Format6(item) => item.min_byte_range(),
295
0
            Self::Format8(item) => item.min_byte_range(),
296
0
            Self::Format10(item) => item.min_byte_range(),
297
0
            Self::Format12(item) => item.min_byte_range(),
298
0
            Self::Format13(item) => item.min_byte_range(),
299
0
            Self::Format14(item) => item.min_byte_range(),
300
        }
301
0
    }
302
0
    fn min_table_bytes(&self) -> &'a [u8] {
303
0
        match self {
304
0
            Self::Format0(item) => item.min_table_bytes(),
305
0
            Self::Format2(item) => item.min_table_bytes(),
306
0
            Self::Format4(item) => item.min_table_bytes(),
307
0
            Self::Format6(item) => item.min_table_bytes(),
308
0
            Self::Format8(item) => item.min_table_bytes(),
309
0
            Self::Format10(item) => item.min_table_bytes(),
310
0
            Self::Format12(item) => item.min_table_bytes(),
311
0
            Self::Format13(item) => item.min_table_bytes(),
312
0
            Self::Format14(item) => item.min_table_bytes(),
313
        }
314
0
    }
315
}
316
317
#[cfg(feature = "experimental_traverse")]
318
impl<'a> CmapSubtable<'a> {
319
    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
320
        match self {
321
            Self::Format0(table) => table,
322
            Self::Format2(table) => table,
323
            Self::Format4(table) => table,
324
            Self::Format6(table) => table,
325
            Self::Format8(table) => table,
326
            Self::Format10(table) => table,
327
            Self::Format12(table) => table,
328
            Self::Format13(table) => table,
329
            Self::Format14(table) => table,
330
        }
331
    }
332
}
333
334
#[cfg(feature = "experimental_traverse")]
335
impl std::fmt::Debug for CmapSubtable<'_> {
336
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
337
        self.dyn_inner().fmt(f)
338
    }
339
}
340
341
#[cfg(feature = "experimental_traverse")]
342
impl<'a> SomeTable<'a> for CmapSubtable<'a> {
343
    fn type_name(&self) -> &str {
344
        self.dyn_inner().type_name()
345
    }
346
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
347
        self.dyn_inner().get_field(idx)
348
    }
349
}
350
351
impl Format<u16> for Cmap0<'_> {
352
    const FORMAT: u16 = 0;
353
}
354
355
impl<'a> MinByteRange<'a> for Cmap0<'a> {
356
0
    fn min_byte_range(&self) -> Range<usize> {
357
0
        0..self.glyph_id_array_byte_range().end
358
0
    }
359
0
    fn min_table_bytes(&self) -> &'a [u8] {
360
0
        let range = self.min_byte_range();
361
0
        self.data.as_bytes().get(range).unwrap_or_default()
362
0
    }
363
}
364
365
impl<'a> FontRead<'a> for Cmap0<'a> {
366
269k
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
367
        #[allow(clippy::absurd_extreme_comparisons)]
368
269k
        if data.len() < Self::MIN_SIZE {
369
3.04k
            return Err(ReadError::OutOfBounds);
370
266k
        }
371
266k
        Ok(Self { data })
372
269k
    }
373
}
374
375
/// [cmap Format 0](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-0-byte-encoding-table): Byte encoding table
376
#[derive(Clone)]
377
pub struct Cmap0<'a> {
378
    data: FontData<'a>,
379
}
380
381
#[allow(clippy::needless_lifetimes)]
382
impl<'a> Cmap0<'a> {
383
    pub const MIN_SIZE: usize =
384
        (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u8::RAW_BYTE_LEN * 256_usize);
385
    basic_table_impls!(impl_the_methods);
386
387
    /// Format number is set to 0.
388
0
    pub fn format(&self) -> u16 {
389
0
        let range = self.format_byte_range();
390
0
        self.data.read_at(range.start).ok().unwrap()
391
0
    }
392
393
    /// This is the length in bytes of the subtable.
394
0
    pub fn length(&self) -> u16 {
395
0
        let range = self.length_byte_range();
396
0
        self.data.read_at(range.start).ok().unwrap()
397
0
    }
398
399
    /// For requirements on use of the language field, see “Use of
400
    /// the language field in 'cmap' subtables” in this document.
401
0
    pub fn language(&self) -> u16 {
402
0
        let range = self.language_byte_range();
403
0
        self.data.read_at(range.start).ok().unwrap()
404
0
    }
405
406
    /// An array that maps character codes to glyph index values.
407
0
    pub fn glyph_id_array(&self) -> &'a [u8] {
408
0
        let range = self.glyph_id_array_byte_range();
409
0
        self.data.read_array(range).ok().unwrap()
410
0
    }
411
412
0
    pub fn format_byte_range(&self) -> Range<usize> {
413
0
        let start = 0;
414
0
        start..start + u16::RAW_BYTE_LEN
415
0
    }
416
417
0
    pub fn length_byte_range(&self) -> Range<usize> {
418
0
        let start = self.format_byte_range().end;
419
0
        start..start + u16::RAW_BYTE_LEN
420
0
    }
421
422
0
    pub fn language_byte_range(&self) -> Range<usize> {
423
0
        let start = self.length_byte_range().end;
424
0
        start..start + u16::RAW_BYTE_LEN
425
0
    }
426
427
0
    pub fn glyph_id_array_byte_range(&self) -> Range<usize> {
428
0
        let start = self.language_byte_range().end;
429
0
        start..start + (256_usize).saturating_mul(u8::RAW_BYTE_LEN)
430
0
    }
431
}
432
433
#[cfg(feature = "experimental_traverse")]
434
impl<'a> SomeTable<'a> for Cmap0<'a> {
435
    fn type_name(&self) -> &str {
436
        "Cmap0"
437
    }
438
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
439
        match idx {
440
            0usize => Some(Field::new("format", self.format())),
441
            1usize => Some(Field::new("length", self.length())),
442
            2usize => Some(Field::new("language", self.language())),
443
            3usize => Some(Field::new("glyph_id_array", self.glyph_id_array())),
444
            _ => None,
445
        }
446
    }
447
}
448
449
#[cfg(feature = "experimental_traverse")]
450
#[allow(clippy::needless_lifetimes)]
451
impl<'a> std::fmt::Debug for Cmap0<'a> {
452
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
453
        (self as &dyn SomeTable<'a>).fmt(f)
454
    }
455
}
456
457
impl Format<u16> for Cmap2<'_> {
458
    const FORMAT: u16 = 2;
459
}
460
461
impl<'a> MinByteRange<'a> for Cmap2<'a> {
462
0
    fn min_byte_range(&self) -> Range<usize> {
463
0
        0..self.sub_header_keys_byte_range().end
464
0
    }
465
0
    fn min_table_bytes(&self) -> &'a [u8] {
466
0
        let range = self.min_byte_range();
467
0
        self.data.as_bytes().get(range).unwrap_or_default()
468
0
    }
469
}
470
471
impl<'a> FontRead<'a> for Cmap2<'a> {
472
8.80k
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
473
        #[allow(clippy::absurd_extreme_comparisons)]
474
8.80k
        if data.len() < Self::MIN_SIZE {
475
530
            return Err(ReadError::OutOfBounds);
476
8.27k
        }
477
8.27k
        Ok(Self { data })
478
8.80k
    }
479
}
480
481
/// [cmap Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-2-high-byte-mapping-through-table): High-byte mapping through table
482
#[derive(Clone)]
483
pub struct Cmap2<'a> {
484
    data: FontData<'a>,
485
}
486
487
#[allow(clippy::needless_lifetimes)]
488
impl<'a> Cmap2<'a> {
489
    pub const MIN_SIZE: usize =
490
        (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN * 256_usize);
491
    basic_table_impls!(impl_the_methods);
492
493
    /// Format number is set to 2.
494
0
    pub fn format(&self) -> u16 {
495
0
        let range = self.format_byte_range();
496
0
        self.data.read_at(range.start).ok().unwrap()
497
0
    }
498
499
    /// This is the length in bytes of the subtable.
500
0
    pub fn length(&self) -> u16 {
501
0
        let range = self.length_byte_range();
502
0
        self.data.read_at(range.start).ok().unwrap()
503
0
    }
504
505
    /// For requirements on use of the language field, see “Use of
506
    /// the language field in 'cmap' subtables” in this document.
507
0
    pub fn language(&self) -> u16 {
508
0
        let range = self.language_byte_range();
509
0
        self.data.read_at(range.start).ok().unwrap()
510
0
    }
511
512
    /// Array that maps high bytes to subHeaders: value is subHeader
513
    /// index × 8.
514
0
    pub fn sub_header_keys(&self) -> &'a [BigEndian<u16>] {
515
0
        let range = self.sub_header_keys_byte_range();
516
0
        self.data.read_array(range).ok().unwrap()
517
0
    }
518
519
0
    pub fn format_byte_range(&self) -> Range<usize> {
520
0
        let start = 0;
521
0
        start..start + u16::RAW_BYTE_LEN
522
0
    }
523
524
0
    pub fn length_byte_range(&self) -> Range<usize> {
525
0
        let start = self.format_byte_range().end;
526
0
        start..start + u16::RAW_BYTE_LEN
527
0
    }
528
529
0
    pub fn language_byte_range(&self) -> Range<usize> {
530
0
        let start = self.length_byte_range().end;
531
0
        start..start + u16::RAW_BYTE_LEN
532
0
    }
533
534
0
    pub fn sub_header_keys_byte_range(&self) -> Range<usize> {
535
0
        let start = self.language_byte_range().end;
536
0
        start..start + (256_usize).saturating_mul(u16::RAW_BYTE_LEN)
537
0
    }
538
}
539
540
#[cfg(feature = "experimental_traverse")]
541
impl<'a> SomeTable<'a> for Cmap2<'a> {
542
    fn type_name(&self) -> &str {
543
        "Cmap2"
544
    }
545
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
546
        match idx {
547
            0usize => Some(Field::new("format", self.format())),
548
            1usize => Some(Field::new("length", self.length())),
549
            2usize => Some(Field::new("language", self.language())),
550
            3usize => Some(Field::new("sub_header_keys", self.sub_header_keys())),
551
            _ => None,
552
        }
553
    }
554
}
555
556
#[cfg(feature = "experimental_traverse")]
557
#[allow(clippy::needless_lifetimes)]
558
impl<'a> std::fmt::Debug for Cmap2<'a> {
559
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
560
        (self as &dyn SomeTable<'a>).fmt(f)
561
    }
562
}
563
564
/// Part of [Cmap2]
565
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
566
#[repr(C)]
567
#[repr(packed)]
568
pub struct SubHeader {
569
    /// First valid low byte for this SubHeader.
570
    pub first_code: BigEndian<u16>,
571
    /// Number of valid low bytes for this SubHeader.
572
    pub entry_count: BigEndian<u16>,
573
    /// See text below.
574
    pub id_delta: BigEndian<i16>,
575
    /// See text below.
576
    pub id_range_offset: BigEndian<u16>,
577
}
578
579
impl SubHeader {
580
    /// First valid low byte for this SubHeader.
581
0
    pub fn first_code(&self) -> u16 {
582
0
        self.first_code.get()
583
0
    }
584
585
    /// Number of valid low bytes for this SubHeader.
586
0
    pub fn entry_count(&self) -> u16 {
587
0
        self.entry_count.get()
588
0
    }
589
590
    /// See text below.
591
0
    pub fn id_delta(&self) -> i16 {
592
0
        self.id_delta.get()
593
0
    }
594
595
    /// See text below.
596
0
    pub fn id_range_offset(&self) -> u16 {
597
0
        self.id_range_offset.get()
598
0
    }
599
}
600
601
impl FixedSize for SubHeader {
602
    const RAW_BYTE_LEN: usize =
603
        u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
604
}
605
606
#[cfg(feature = "experimental_traverse")]
607
impl<'a> SomeRecord<'a> for SubHeader {
608
    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
609
        RecordResolver {
610
            name: "SubHeader",
611
            get_field: Box::new(move |idx, _data| match idx {
612
                0usize => Some(Field::new("first_code", self.first_code())),
613
                1usize => Some(Field::new("entry_count", self.entry_count())),
614
                2usize => Some(Field::new("id_delta", self.id_delta())),
615
                3usize => Some(Field::new("id_range_offset", self.id_range_offset())),
616
                _ => None,
617
            }),
618
            data,
619
        }
620
    }
621
}
622
623
impl Format<u16> for Cmap4<'_> {
624
    const FORMAT: u16 = 4;
625
}
626
627
impl<'a> MinByteRange<'a> for Cmap4<'a> {
628
0
    fn min_byte_range(&self) -> Range<usize> {
629
0
        0..self.glyph_id_array_byte_range().end
630
0
    }
631
0
    fn min_table_bytes(&self) -> &'a [u8] {
632
0
        let range = self.min_byte_range();
633
0
        self.data.as_bytes().get(range).unwrap_or_default()
634
0
    }
635
}
636
637
impl<'a> FontRead<'a> for Cmap4<'a> {
638
94.3k
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
639
        #[allow(clippy::absurd_extreme_comparisons)]
640
94.3k
        if data.len() < Self::MIN_SIZE {
641
527
            return Err(ReadError::OutOfBounds);
642
93.8k
        }
643
93.8k
        Ok(Self { data })
644
94.3k
    }
645
}
646
647
/// [cmap Format 4](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-4-segment-mapping-to-delta-values): Segment mapping to delta values
648
#[derive(Clone)]
649
pub struct Cmap4<'a> {
650
    data: FontData<'a>,
651
}
652
653
#[allow(clippy::needless_lifetimes)]
654
impl<'a> Cmap4<'a> {
655
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
656
        + u16::RAW_BYTE_LEN
657
        + u16::RAW_BYTE_LEN
658
        + u16::RAW_BYTE_LEN
659
        + u16::RAW_BYTE_LEN
660
        + u16::RAW_BYTE_LEN
661
        + u16::RAW_BYTE_LEN
662
        + u16::RAW_BYTE_LEN);
663
    basic_table_impls!(impl_the_methods);
664
665
    /// Format number is set to 4.
666
0
    pub fn format(&self) -> u16 {
667
0
        let range = self.format_byte_range();
668
0
        self.data.read_at(range.start).ok().unwrap()
669
0
    }
670
671
    /// This is the length in bytes of the subtable.
672
0
    pub fn length(&self) -> u16 {
673
0
        let range = self.length_byte_range();
674
0
        self.data.read_at(range.start).ok().unwrap()
675
0
    }
676
677
    /// For requirements on use of the language field, see “Use of
678
    /// the language field in 'cmap' subtables” in this document.
679
0
    pub fn language(&self) -> u16 {
680
0
        let range = self.language_byte_range();
681
0
        self.data.read_at(range.start).ok().unwrap()
682
0
    }
683
684
    /// 2 × segCount.
685
713M
    pub fn seg_count_x2(&self) -> u16 {
686
713M
        let range = self.seg_count_x2_byte_range();
687
713M
        self.data.read_at(range.start).ok().unwrap()
688
713M
    }
689
690
    /// Maximum power of 2 less than or equal to segCount, times 2
691
    /// ((2**floor(log2(segCount))) * 2, where “**” is an
692
    /// exponentiation operator)
693
0
    pub fn search_range(&self) -> u16 {
694
0
        let range = self.search_range_byte_range();
695
0
        self.data.read_at(range.start).ok().unwrap()
696
0
    }
697
698
    /// Log2 of the maximum power of 2 less than or equal to numTables
699
    /// (log2(searchRange/2), which is equal to floor(log2(segCount)))
700
0
    pub fn entry_selector(&self) -> u16 {
701
0
        let range = self.entry_selector_byte_range();
702
0
        self.data.read_at(range.start).ok().unwrap()
703
0
    }
704
705
    /// segCount times 2, minus searchRange ((segCount * 2) -
706
    /// searchRange)
707
0
    pub fn range_shift(&self) -> u16 {
708
0
        let range = self.range_shift_byte_range();
709
0
        self.data.read_at(range.start).ok().unwrap()
710
0
    }
711
712
    /// End characterCode for each segment, last=0xFFFF.
713
21.8M
    pub fn end_code(&self) -> &'a [BigEndian<u16>] {
714
21.8M
        let range = self.end_code_byte_range();
715
21.8M
        self.data.read_array(range).ok().unwrap_or_default()
716
21.8M
    }
717
718
    /// Start character code for each segment.
719
21.8M
    pub fn start_code(&self) -> &'a [BigEndian<u16>] {
720
21.8M
        let range = self.start_code_byte_range();
721
21.8M
        self.data.read_array(range).ok().unwrap_or_default()
722
21.8M
    }
723
724
    /// Delta for all character codes in segment.
725
69.8M
    pub fn id_delta(&self) -> &'a [BigEndian<i16>] {
726
69.8M
        let range = self.id_delta_byte_range();
727
69.8M
        self.data.read_array(range).ok().unwrap_or_default()
728
69.8M
    }
729
730
    /// Offsets into glyphIdArray or 0
731
69.8M
    pub fn id_range_offsets(&self) -> &'a [BigEndian<u16>] {
732
69.8M
        let range = self.id_range_offsets_byte_range();
733
69.8M
        self.data.read_array(range).ok().unwrap_or_default()
734
69.8M
    }
735
736
    /// Glyph index array (arbitrary length)
737
34.8M
    pub fn glyph_id_array(&self) -> &'a [BigEndian<u16>] {
738
34.8M
        let range = self.glyph_id_array_byte_range();
739
34.8M
        self.data.read_array(range).ok().unwrap_or_default()
740
34.8M
    }
741
742
932M
    pub fn format_byte_range(&self) -> Range<usize> {
743
932M
        let start = 0;
744
932M
        start..start + u16::RAW_BYTE_LEN
745
932M
    }
746
747
932M
    pub fn length_byte_range(&self) -> Range<usize> {
748
932M
        let start = self.format_byte_range().end;
749
932M
        start..start + u16::RAW_BYTE_LEN
750
932M
    }
751
752
932M
    pub fn language_byte_range(&self) -> Range<usize> {
753
932M
        let start = self.length_byte_range().end;
754
932M
        start..start + u16::RAW_BYTE_LEN
755
932M
    }
756
757
932M
    pub fn seg_count_x2_byte_range(&self) -> Range<usize> {
758
932M
        let start = self.language_byte_range().end;
759
932M
        start..start + u16::RAW_BYTE_LEN
760
932M
    }
761
762
218M
    pub fn search_range_byte_range(&self) -> Range<usize> {
763
218M
        let start = self.seg_count_x2_byte_range().end;
764
218M
        start..start + u16::RAW_BYTE_LEN
765
218M
    }
766
767
218M
    pub fn entry_selector_byte_range(&self) -> Range<usize> {
768
218M
        let start = self.search_range_byte_range().end;
769
218M
        start..start + u16::RAW_BYTE_LEN
770
218M
    }
771
772
218M
    pub fn range_shift_byte_range(&self) -> Range<usize> {
773
218M
        let start = self.entry_selector_byte_range().end;
774
218M
        start..start + u16::RAW_BYTE_LEN
775
218M
    }
776
777
218M
    pub fn end_code_byte_range(&self) -> Range<usize> {
778
218M
        let seg_count_x2 = self.seg_count_x2();
779
218M
        let start = self.range_shift_byte_range().end;
780
218M
        start..start + (transforms::half(seg_count_x2)).saturating_mul(u16::RAW_BYTE_LEN)
781
218M
    }
782
783
196M
    pub fn reserved_pad_byte_range(&self) -> Range<usize> {
784
196M
        let start = self.end_code_byte_range().end;
785
196M
        start..start + u16::RAW_BYTE_LEN
786
196M
    }
787
788
196M
    pub fn start_code_byte_range(&self) -> Range<usize> {
789
196M
        let seg_count_x2 = self.seg_count_x2();
790
196M
        let start = self.reserved_pad_byte_range().end;
791
196M
        start..start + (transforms::half(seg_count_x2)).saturating_mul(u16::RAW_BYTE_LEN)
792
196M
    }
793
794
174M
    pub fn id_delta_byte_range(&self) -> Range<usize> {
795
174M
        let seg_count_x2 = self.seg_count_x2();
796
174M
        let start = self.start_code_byte_range().end;
797
174M
        start..start + (transforms::half(seg_count_x2)).saturating_mul(i16::RAW_BYTE_LEN)
798
174M
    }
799
800
104M
    pub fn id_range_offsets_byte_range(&self) -> Range<usize> {
801
104M
        let seg_count_x2 = self.seg_count_x2();
802
104M
        let start = self.id_delta_byte_range().end;
803
104M
        start..start + (transforms::half(seg_count_x2)).saturating_mul(u16::RAW_BYTE_LEN)
804
104M
    }
805
806
34.8M
    pub fn glyph_id_array_byte_range(&self) -> Range<usize> {
807
34.8M
        let start = self.id_range_offsets_byte_range().end;
808
34.8M
        start..start + self.data.len().saturating_sub(start) / u16::RAW_BYTE_LEN * u16::RAW_BYTE_LEN
809
34.8M
    }
810
}
811
812
#[cfg(feature = "experimental_traverse")]
813
impl<'a> SomeTable<'a> for Cmap4<'a> {
814
    fn type_name(&self) -> &str {
815
        "Cmap4"
816
    }
817
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
818
        match idx {
819
            0usize => Some(Field::new("format", self.format())),
820
            1usize => Some(Field::new("length", self.length())),
821
            2usize => Some(Field::new("language", self.language())),
822
            3usize => Some(Field::new("seg_count_x2", self.seg_count_x2())),
823
            4usize => Some(Field::new("search_range", self.search_range())),
824
            5usize => Some(Field::new("entry_selector", self.entry_selector())),
825
            6usize => Some(Field::new("range_shift", self.range_shift())),
826
            7usize => Some(Field::new("end_code", self.end_code())),
827
            8usize => Some(Field::new("start_code", self.start_code())),
828
            9usize => Some(Field::new("id_delta", self.id_delta())),
829
            10usize => Some(Field::new("id_range_offsets", self.id_range_offsets())),
830
            11usize => Some(Field::new("glyph_id_array", self.glyph_id_array())),
831
            _ => None,
832
        }
833
    }
834
}
835
836
#[cfg(feature = "experimental_traverse")]
837
#[allow(clippy::needless_lifetimes)]
838
impl<'a> std::fmt::Debug for Cmap4<'a> {
839
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
840
        (self as &dyn SomeTable<'a>).fmt(f)
841
    }
842
}
843
844
impl Format<u16> for Cmap6<'_> {
845
    const FORMAT: u16 = 6;
846
}
847
848
impl<'a> MinByteRange<'a> for Cmap6<'a> {
849
0
    fn min_byte_range(&self) -> Range<usize> {
850
0
        0..self.glyph_id_array_byte_range().end
851
0
    }
852
0
    fn min_table_bytes(&self) -> &'a [u8] {
853
0
        let range = self.min_byte_range();
854
0
        self.data.as_bytes().get(range).unwrap_or_default()
855
0
    }
856
}
857
858
impl<'a> FontRead<'a> for Cmap6<'a> {
859
4.62k
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
860
        #[allow(clippy::absurd_extreme_comparisons)]
861
4.62k
        if data.len() < Self::MIN_SIZE {
862
420
            return Err(ReadError::OutOfBounds);
863
4.20k
        }
864
4.20k
        Ok(Self { data })
865
4.62k
    }
866
}
867
868
/// [cmap Format 6](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-6-trimmed-table-mapping): Trimmed table mapping
869
#[derive(Clone)]
870
pub struct Cmap6<'a> {
871
    data: FontData<'a>,
872
}
873
874
#[allow(clippy::needless_lifetimes)]
875
impl<'a> Cmap6<'a> {
876
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
877
        + u16::RAW_BYTE_LEN
878
        + u16::RAW_BYTE_LEN
879
        + u16::RAW_BYTE_LEN
880
        + u16::RAW_BYTE_LEN);
881
    basic_table_impls!(impl_the_methods);
882
883
    /// Format number is set to 6.
884
0
    pub fn format(&self) -> u16 {
885
0
        let range = self.format_byte_range();
886
0
        self.data.read_at(range.start).ok().unwrap()
887
0
    }
888
889
    /// This is the length in bytes of the subtable.
890
0
    pub fn length(&self) -> u16 {
891
0
        let range = self.length_byte_range();
892
0
        self.data.read_at(range.start).ok().unwrap()
893
0
    }
894
895
    /// For requirements on use of the language field, see “Use of
896
    /// the language field in 'cmap' subtables” in this document.
897
0
    pub fn language(&self) -> u16 {
898
0
        let range = self.language_byte_range();
899
0
        self.data.read_at(range.start).ok().unwrap()
900
0
    }
901
902
    /// First character code of subrange.
903
0
    pub fn first_code(&self) -> u16 {
904
0
        let range = self.first_code_byte_range();
905
0
        self.data.read_at(range.start).ok().unwrap()
906
0
    }
907
908
    /// Number of character codes in subrange.
909
0
    pub fn entry_count(&self) -> u16 {
910
0
        let range = self.entry_count_byte_range();
911
0
        self.data.read_at(range.start).ok().unwrap()
912
0
    }
913
914
    /// Array of glyph index values for character codes in the range.
915
0
    pub fn glyph_id_array(&self) -> &'a [BigEndian<u16>] {
916
0
        let range = self.glyph_id_array_byte_range();
917
0
        self.data.read_array(range).ok().unwrap_or_default()
918
0
    }
919
920
0
    pub fn format_byte_range(&self) -> Range<usize> {
921
0
        let start = 0;
922
0
        start..start + u16::RAW_BYTE_LEN
923
0
    }
924
925
0
    pub fn length_byte_range(&self) -> Range<usize> {
926
0
        let start = self.format_byte_range().end;
927
0
        start..start + u16::RAW_BYTE_LEN
928
0
    }
929
930
0
    pub fn language_byte_range(&self) -> Range<usize> {
931
0
        let start = self.length_byte_range().end;
932
0
        start..start + u16::RAW_BYTE_LEN
933
0
    }
934
935
0
    pub fn first_code_byte_range(&self) -> Range<usize> {
936
0
        let start = self.language_byte_range().end;
937
0
        start..start + u16::RAW_BYTE_LEN
938
0
    }
939
940
0
    pub fn entry_count_byte_range(&self) -> Range<usize> {
941
0
        let start = self.first_code_byte_range().end;
942
0
        start..start + u16::RAW_BYTE_LEN
943
0
    }
944
945
0
    pub fn glyph_id_array_byte_range(&self) -> Range<usize> {
946
0
        let entry_count = self.entry_count();
947
0
        let start = self.entry_count_byte_range().end;
948
0
        start..start + (entry_count as usize).saturating_mul(u16::RAW_BYTE_LEN)
949
0
    }
950
}
951
952
#[cfg(feature = "experimental_traverse")]
953
impl<'a> SomeTable<'a> for Cmap6<'a> {
954
    fn type_name(&self) -> &str {
955
        "Cmap6"
956
    }
957
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
958
        match idx {
959
            0usize => Some(Field::new("format", self.format())),
960
            1usize => Some(Field::new("length", self.length())),
961
            2usize => Some(Field::new("language", self.language())),
962
            3usize => Some(Field::new("first_code", self.first_code())),
963
            4usize => Some(Field::new("entry_count", self.entry_count())),
964
            5usize => Some(Field::new("glyph_id_array", self.glyph_id_array())),
965
            _ => None,
966
        }
967
    }
968
}
969
970
#[cfg(feature = "experimental_traverse")]
971
#[allow(clippy::needless_lifetimes)]
972
impl<'a> std::fmt::Debug for Cmap6<'a> {
973
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
974
        (self as &dyn SomeTable<'a>).fmt(f)
975
    }
976
}
977
978
impl Format<u16> for Cmap8<'_> {
979
    const FORMAT: u16 = 8;
980
}
981
982
impl<'a> MinByteRange<'a> for Cmap8<'a> {
983
0
    fn min_byte_range(&self) -> Range<usize> {
984
0
        0..self.groups_byte_range().end
985
0
    }
986
0
    fn min_table_bytes(&self) -> &'a [u8] {
987
0
        let range = self.min_byte_range();
988
0
        self.data.as_bytes().get(range).unwrap_or_default()
989
0
    }
990
}
991
992
impl<'a> FontRead<'a> for Cmap8<'a> {
993
7.44k
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
994
        #[allow(clippy::absurd_extreme_comparisons)]
995
7.44k
        if data.len() < Self::MIN_SIZE {
996
971
            return Err(ReadError::OutOfBounds);
997
6.47k
        }
998
6.47k
        Ok(Self { data })
999
7.44k
    }
1000
}
1001
1002
/// [cmap Format 8](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-8-mixed-16-bit-and-32-bit-coverage): mixed 16-bit and 32-bit coverage
1003
#[derive(Clone)]
1004
pub struct Cmap8<'a> {
1005
    data: FontData<'a>,
1006
}
1007
1008
#[allow(clippy::needless_lifetimes)]
1009
impl<'a> Cmap8<'a> {
1010
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1011
        + u16::RAW_BYTE_LEN
1012
        + u32::RAW_BYTE_LEN
1013
        + u32::RAW_BYTE_LEN
1014
        + u8::RAW_BYTE_LEN * 8192_usize
1015
        + u32::RAW_BYTE_LEN);
1016
    basic_table_impls!(impl_the_methods);
1017
1018
    /// Subtable format; set to 8.
1019
0
    pub fn format(&self) -> u16 {
1020
0
        let range = self.format_byte_range();
1021
0
        self.data.read_at(range.start).ok().unwrap()
1022
0
    }
1023
1024
    /// Byte length of this subtable (including the header)
1025
0
    pub fn length(&self) -> u32 {
1026
0
        let range = self.length_byte_range();
1027
0
        self.data.read_at(range.start).ok().unwrap()
1028
0
    }
1029
1030
    /// For requirements on use of the language field, see “Use of
1031
    /// the language field in 'cmap' subtables” in this document.
1032
0
    pub fn language(&self) -> u32 {
1033
0
        let range = self.language_byte_range();
1034
0
        self.data.read_at(range.start).ok().unwrap()
1035
0
    }
1036
1037
    /// Tightly packed array of bits (8K bytes total) indicating
1038
    /// whether the particular 16-bit (index) value is the start of a
1039
    /// 32-bit character code
1040
0
    pub fn is32(&self) -> &'a [u8] {
1041
0
        let range = self.is32_byte_range();
1042
0
        self.data.read_array(range).ok().unwrap()
1043
0
    }
1044
1045
    /// Number of groupings which follow
1046
0
    pub fn num_groups(&self) -> u32 {
1047
0
        let range = self.num_groups_byte_range();
1048
0
        self.data.read_at(range.start).ok().unwrap()
1049
0
    }
1050
1051
    /// Array of SequentialMapGroup records.
1052
0
    pub fn groups(&self) -> &'a [SequentialMapGroup] {
1053
0
        let range = self.groups_byte_range();
1054
0
        self.data.read_array(range).ok().unwrap_or_default()
1055
0
    }
1056
1057
0
    pub fn format_byte_range(&self) -> Range<usize> {
1058
0
        let start = 0;
1059
0
        start..start + u16::RAW_BYTE_LEN
1060
0
    }
1061
1062
0
    pub fn reserved_byte_range(&self) -> Range<usize> {
1063
0
        let start = self.format_byte_range().end;
1064
0
        start..start + u16::RAW_BYTE_LEN
1065
0
    }
1066
1067
0
    pub fn length_byte_range(&self) -> Range<usize> {
1068
0
        let start = self.reserved_byte_range().end;
1069
0
        start..start + u32::RAW_BYTE_LEN
1070
0
    }
1071
1072
0
    pub fn language_byte_range(&self) -> Range<usize> {
1073
0
        let start = self.length_byte_range().end;
1074
0
        start..start + u32::RAW_BYTE_LEN
1075
0
    }
1076
1077
0
    pub fn is32_byte_range(&self) -> Range<usize> {
1078
0
        let start = self.language_byte_range().end;
1079
0
        start..start + (8192_usize).saturating_mul(u8::RAW_BYTE_LEN)
1080
0
    }
1081
1082
0
    pub fn num_groups_byte_range(&self) -> Range<usize> {
1083
0
        let start = self.is32_byte_range().end;
1084
0
        start..start + u32::RAW_BYTE_LEN
1085
0
    }
1086
1087
0
    pub fn groups_byte_range(&self) -> Range<usize> {
1088
0
        let num_groups = self.num_groups();
1089
0
        let start = self.num_groups_byte_range().end;
1090
0
        start..start + (num_groups as usize).saturating_mul(SequentialMapGroup::RAW_BYTE_LEN)
1091
0
    }
1092
}
1093
1094
#[cfg(feature = "experimental_traverse")]
1095
impl<'a> SomeTable<'a> for Cmap8<'a> {
1096
    fn type_name(&self) -> &str {
1097
        "Cmap8"
1098
    }
1099
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1100
        match idx {
1101
            0usize => Some(Field::new("format", self.format())),
1102
            1usize => Some(Field::new("length", self.length())),
1103
            2usize => Some(Field::new("language", self.language())),
1104
            3usize => Some(Field::new("is32", self.is32())),
1105
            4usize => Some(Field::new("num_groups", self.num_groups())),
1106
            5usize => Some(Field::new(
1107
                "groups",
1108
                traversal::FieldType::array_of_records(
1109
                    stringify!(SequentialMapGroup),
1110
                    self.groups(),
1111
                    self.offset_data(),
1112
                ),
1113
            )),
1114
            _ => None,
1115
        }
1116
    }
1117
}
1118
1119
#[cfg(feature = "experimental_traverse")]
1120
#[allow(clippy::needless_lifetimes)]
1121
impl<'a> std::fmt::Debug for Cmap8<'a> {
1122
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1123
        (self as &dyn SomeTable<'a>).fmt(f)
1124
    }
1125
}
1126
1127
/// Used in [Cmap8] and [Cmap12]
1128
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1129
#[repr(C)]
1130
#[repr(packed)]
1131
pub struct SequentialMapGroup {
1132
    /// First character code in this group; note that if this group is
1133
    /// for one or more 16-bit character codes (which is determined
1134
    /// from the is32 array), this 32-bit value will have the high
1135
    /// 16-bits set to zero
1136
    pub start_char_code: BigEndian<u32>,
1137
    /// Last character code in this group; same condition as listed
1138
    /// above for the startCharCode
1139
    pub end_char_code: BigEndian<u32>,
1140
    /// Glyph index corresponding to the starting character code
1141
    pub start_glyph_id: BigEndian<u32>,
1142
}
1143
1144
impl SequentialMapGroup {
1145
    /// First character code in this group; note that if this group is
1146
    /// for one or more 16-bit character codes (which is determined
1147
    /// from the is32 array), this 32-bit value will have the high
1148
    /// 16-bits set to zero
1149
330M
    pub fn start_char_code(&self) -> u32 {
1150
330M
        self.start_char_code.get()
1151
330M
    }
1152
1153
    /// Last character code in this group; same condition as listed
1154
    /// above for the startCharCode
1155
124M
    pub fn end_char_code(&self) -> u32 {
1156
124M
        self.end_char_code.get()
1157
124M
    }
1158
1159
    /// Glyph index corresponding to the starting character code
1160
55.0M
    pub fn start_glyph_id(&self) -> u32 {
1161
55.0M
        self.start_glyph_id.get()
1162
55.0M
    }
1163
}
1164
1165
impl FixedSize for SequentialMapGroup {
1166
    const RAW_BYTE_LEN: usize = u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN;
1167
}
1168
1169
#[cfg(feature = "experimental_traverse")]
1170
impl<'a> SomeRecord<'a> for SequentialMapGroup {
1171
    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1172
        RecordResolver {
1173
            name: "SequentialMapGroup",
1174
            get_field: Box::new(move |idx, _data| match idx {
1175
                0usize => Some(Field::new("start_char_code", self.start_char_code())),
1176
                1usize => Some(Field::new("end_char_code", self.end_char_code())),
1177
                2usize => Some(Field::new("start_glyph_id", self.start_glyph_id())),
1178
                _ => None,
1179
            }),
1180
            data,
1181
        }
1182
    }
1183
}
1184
1185
impl Format<u16> for Cmap10<'_> {
1186
    const FORMAT: u16 = 10;
1187
}
1188
1189
impl<'a> MinByteRange<'a> for Cmap10<'a> {
1190
0
    fn min_byte_range(&self) -> Range<usize> {
1191
0
        0..self.glyph_id_array_byte_range().end
1192
0
    }
1193
0
    fn min_table_bytes(&self) -> &'a [u8] {
1194
0
        let range = self.min_byte_range();
1195
0
        self.data.as_bytes().get(range).unwrap_or_default()
1196
0
    }
1197
}
1198
1199
impl<'a> FontRead<'a> for Cmap10<'a> {
1200
4.88k
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1201
        #[allow(clippy::absurd_extreme_comparisons)]
1202
4.88k
        if data.len() < Self::MIN_SIZE {
1203
243
            return Err(ReadError::OutOfBounds);
1204
4.63k
        }
1205
4.63k
        Ok(Self { data })
1206
4.88k
    }
1207
}
1208
1209
/// [cmap Format 10](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-10-trimmed-array): Tr
1210
#[derive(Clone)]
1211
pub struct Cmap10<'a> {
1212
    data: FontData<'a>,
1213
}
1214
1215
#[allow(clippy::needless_lifetimes)]
1216
impl<'a> Cmap10<'a> {
1217
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1218
        + u16::RAW_BYTE_LEN
1219
        + u32::RAW_BYTE_LEN
1220
        + u32::RAW_BYTE_LEN
1221
        + u32::RAW_BYTE_LEN
1222
        + u32::RAW_BYTE_LEN);
1223
    basic_table_impls!(impl_the_methods);
1224
1225
    /// Subtable format; set to 10.
1226
0
    pub fn format(&self) -> u16 {
1227
0
        let range = self.format_byte_range();
1228
0
        self.data.read_at(range.start).ok().unwrap()
1229
0
    }
1230
1231
    /// Byte length of this subtable (including the header)
1232
0
    pub fn length(&self) -> u32 {
1233
0
        let range = self.length_byte_range();
1234
0
        self.data.read_at(range.start).ok().unwrap()
1235
0
    }
1236
1237
    /// For requirements on use of the language field, see “Use of
1238
    /// the language field in 'cmap' subtables” in this document.
1239
0
    pub fn language(&self) -> u32 {
1240
0
        let range = self.language_byte_range();
1241
0
        self.data.read_at(range.start).ok().unwrap()
1242
0
    }
1243
1244
    /// First character code covered
1245
0
    pub fn start_char_code(&self) -> u32 {
1246
0
        let range = self.start_char_code_byte_range();
1247
0
        self.data.read_at(range.start).ok().unwrap()
1248
0
    }
1249
1250
    /// Number of character codes covered
1251
0
    pub fn num_chars(&self) -> u32 {
1252
0
        let range = self.num_chars_byte_range();
1253
0
        self.data.read_at(range.start).ok().unwrap()
1254
0
    }
1255
1256
    /// Array of glyph indices for the character codes covered
1257
0
    pub fn glyph_id_array(&self) -> &'a [BigEndian<u16>] {
1258
0
        let range = self.glyph_id_array_byte_range();
1259
0
        self.data.read_array(range).ok().unwrap_or_default()
1260
0
    }
1261
1262
0
    pub fn format_byte_range(&self) -> Range<usize> {
1263
0
        let start = 0;
1264
0
        start..start + u16::RAW_BYTE_LEN
1265
0
    }
1266
1267
0
    pub fn reserved_byte_range(&self) -> Range<usize> {
1268
0
        let start = self.format_byte_range().end;
1269
0
        start..start + u16::RAW_BYTE_LEN
1270
0
    }
1271
1272
0
    pub fn length_byte_range(&self) -> Range<usize> {
1273
0
        let start = self.reserved_byte_range().end;
1274
0
        start..start + u32::RAW_BYTE_LEN
1275
0
    }
1276
1277
0
    pub fn language_byte_range(&self) -> Range<usize> {
1278
0
        let start = self.length_byte_range().end;
1279
0
        start..start + u32::RAW_BYTE_LEN
1280
0
    }
1281
1282
0
    pub fn start_char_code_byte_range(&self) -> Range<usize> {
1283
0
        let start = self.language_byte_range().end;
1284
0
        start..start + u32::RAW_BYTE_LEN
1285
0
    }
1286
1287
0
    pub fn num_chars_byte_range(&self) -> Range<usize> {
1288
0
        let start = self.start_char_code_byte_range().end;
1289
0
        start..start + u32::RAW_BYTE_LEN
1290
0
    }
1291
1292
0
    pub fn glyph_id_array_byte_range(&self) -> Range<usize> {
1293
0
        let num_chars = self.num_chars();
1294
0
        let start = self.num_chars_byte_range().end;
1295
0
        start..start + (num_chars as usize).saturating_mul(u16::RAW_BYTE_LEN)
1296
0
    }
1297
}
1298
1299
#[cfg(feature = "experimental_traverse")]
1300
impl<'a> SomeTable<'a> for Cmap10<'a> {
1301
    fn type_name(&self) -> &str {
1302
        "Cmap10"
1303
    }
1304
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1305
        match idx {
1306
            0usize => Some(Field::new("format", self.format())),
1307
            1usize => Some(Field::new("length", self.length())),
1308
            2usize => Some(Field::new("language", self.language())),
1309
            3usize => Some(Field::new("start_char_code", self.start_char_code())),
1310
            4usize => Some(Field::new("num_chars", self.num_chars())),
1311
            5usize => Some(Field::new("glyph_id_array", self.glyph_id_array())),
1312
            _ => None,
1313
        }
1314
    }
1315
}
1316
1317
#[cfg(feature = "experimental_traverse")]
1318
#[allow(clippy::needless_lifetimes)]
1319
impl<'a> std::fmt::Debug for Cmap10<'a> {
1320
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1321
        (self as &dyn SomeTable<'a>).fmt(f)
1322
    }
1323
}
1324
1325
impl Format<u16> for Cmap12<'_> {
1326
    const FORMAT: u16 = 12;
1327
}
1328
1329
impl<'a> MinByteRange<'a> for Cmap12<'a> {
1330
0
    fn min_byte_range(&self) -> Range<usize> {
1331
0
        0..self.groups_byte_range().end
1332
0
    }
1333
0
    fn min_table_bytes(&self) -> &'a [u8] {
1334
0
        let range = self.min_byte_range();
1335
0
        self.data.as_bytes().get(range).unwrap_or_default()
1336
0
    }
1337
}
1338
1339
impl<'a> FontRead<'a> for Cmap12<'a> {
1340
43.6k
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1341
        #[allow(clippy::absurd_extreme_comparisons)]
1342
43.6k
        if data.len() < Self::MIN_SIZE {
1343
242
            return Err(ReadError::OutOfBounds);
1344
43.4k
        }
1345
43.4k
        Ok(Self { data })
1346
43.6k
    }
1347
}
1348
1349
/// [cmap Format 12](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-12-segmented-coverage): Segmented coverage
1350
#[derive(Clone)]
1351
pub struct Cmap12<'a> {
1352
    data: FontData<'a>,
1353
}
1354
1355
#[allow(clippy::needless_lifetimes)]
1356
impl<'a> Cmap12<'a> {
1357
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1358
        + u16::RAW_BYTE_LEN
1359
        + u32::RAW_BYTE_LEN
1360
        + u32::RAW_BYTE_LEN
1361
        + u32::RAW_BYTE_LEN);
1362
    basic_table_impls!(impl_the_methods);
1363
1364
    /// Subtable format; set to 12.
1365
0
    pub fn format(&self) -> u16 {
1366
0
        let range = self.format_byte_range();
1367
0
        self.data.read_at(range.start).ok().unwrap()
1368
0
    }
1369
1370
    /// Byte length of this subtable (including the header)
1371
0
    pub fn length(&self) -> u32 {
1372
0
        let range = self.length_byte_range();
1373
0
        self.data.read_at(range.start).ok().unwrap()
1374
0
    }
1375
1376
    /// For requirements on use of the language field, see “Use of
1377
    /// the language field in 'cmap' subtables” in this document.
1378
0
    pub fn language(&self) -> u32 {
1379
0
        let range = self.language_byte_range();
1380
0
        self.data.read_at(range.start).ok().unwrap()
1381
0
    }
1382
1383
    /// Number of groupings which follow
1384
76.1M
    pub fn num_groups(&self) -> u32 {
1385
76.1M
        let range = self.num_groups_byte_range();
1386
76.1M
        self.data.read_at(range.start).ok().unwrap()
1387
76.1M
    }
1388
1389
    /// Array of SequentialMapGroup records.
1390
76.1M
    pub fn groups(&self) -> &'a [SequentialMapGroup] {
1391
76.1M
        let range = self.groups_byte_range();
1392
76.1M
        self.data.read_array(range).ok().unwrap_or_default()
1393
76.1M
    }
1394
1395
152M
    pub fn format_byte_range(&self) -> Range<usize> {
1396
152M
        let start = 0;
1397
152M
        start..start + u16::RAW_BYTE_LEN
1398
152M
    }
1399
1400
152M
    pub fn reserved_byte_range(&self) -> Range<usize> {
1401
152M
        let start = self.format_byte_range().end;
1402
152M
        start..start + u16::RAW_BYTE_LEN
1403
152M
    }
1404
1405
152M
    pub fn length_byte_range(&self) -> Range<usize> {
1406
152M
        let start = self.reserved_byte_range().end;
1407
152M
        start..start + u32::RAW_BYTE_LEN
1408
152M
    }
1409
1410
152M
    pub fn language_byte_range(&self) -> Range<usize> {
1411
152M
        let start = self.length_byte_range().end;
1412
152M
        start..start + u32::RAW_BYTE_LEN
1413
152M
    }
1414
1415
152M
    pub fn num_groups_byte_range(&self) -> Range<usize> {
1416
152M
        let start = self.language_byte_range().end;
1417
152M
        start..start + u32::RAW_BYTE_LEN
1418
152M
    }
1419
1420
76.1M
    pub fn groups_byte_range(&self) -> Range<usize> {
1421
76.1M
        let num_groups = self.num_groups();
1422
76.1M
        let start = self.num_groups_byte_range().end;
1423
76.1M
        start..start + (num_groups as usize).saturating_mul(SequentialMapGroup::RAW_BYTE_LEN)
1424
76.1M
    }
1425
}
1426
1427
#[cfg(feature = "experimental_traverse")]
1428
impl<'a> SomeTable<'a> for Cmap12<'a> {
1429
    fn type_name(&self) -> &str {
1430
        "Cmap12"
1431
    }
1432
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1433
        match idx {
1434
            0usize => Some(Field::new("format", self.format())),
1435
            1usize => Some(Field::new("length", self.length())),
1436
            2usize => Some(Field::new("language", self.language())),
1437
            3usize => Some(Field::new("num_groups", self.num_groups())),
1438
            4usize => Some(Field::new(
1439
                "groups",
1440
                traversal::FieldType::array_of_records(
1441
                    stringify!(SequentialMapGroup),
1442
                    self.groups(),
1443
                    self.offset_data(),
1444
                ),
1445
            )),
1446
            _ => None,
1447
        }
1448
    }
1449
}
1450
1451
#[cfg(feature = "experimental_traverse")]
1452
#[allow(clippy::needless_lifetimes)]
1453
impl<'a> std::fmt::Debug for Cmap12<'a> {
1454
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1455
        (self as &dyn SomeTable<'a>).fmt(f)
1456
    }
1457
}
1458
1459
impl Format<u16> for Cmap13<'_> {
1460
    const FORMAT: u16 = 13;
1461
}
1462
1463
impl<'a> MinByteRange<'a> for Cmap13<'a> {
1464
0
    fn min_byte_range(&self) -> Range<usize> {
1465
0
        0..self.groups_byte_range().end
1466
0
    }
1467
0
    fn min_table_bytes(&self) -> &'a [u8] {
1468
0
        let range = self.min_byte_range();
1469
0
        self.data.as_bytes().get(range).unwrap_or_default()
1470
0
    }
1471
}
1472
1473
impl<'a> FontRead<'a> for Cmap13<'a> {
1474
1.93k
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1475
        #[allow(clippy::absurd_extreme_comparisons)]
1476
1.93k
        if data.len() < Self::MIN_SIZE {
1477
264
            return Err(ReadError::OutOfBounds);
1478
1.66k
        }
1479
1.66k
        Ok(Self { data })
1480
1.93k
    }
1481
}
1482
1483
/// [cmap Format 13](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-13-many-to-one-range-mappings): Many-to-one range mappings
1484
#[derive(Clone)]
1485
pub struct Cmap13<'a> {
1486
    data: FontData<'a>,
1487
}
1488
1489
#[allow(clippy::needless_lifetimes)]
1490
impl<'a> Cmap13<'a> {
1491
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1492
        + u16::RAW_BYTE_LEN
1493
        + u32::RAW_BYTE_LEN
1494
        + u32::RAW_BYTE_LEN
1495
        + u32::RAW_BYTE_LEN);
1496
    basic_table_impls!(impl_the_methods);
1497
1498
    /// Subtable format; set to 13.
1499
0
    pub fn format(&self) -> u16 {
1500
0
        let range = self.format_byte_range();
1501
0
        self.data.read_at(range.start).ok().unwrap()
1502
0
    }
1503
1504
    /// Byte length of this subtable (including the header)
1505
0
    pub fn length(&self) -> u32 {
1506
0
        let range = self.length_byte_range();
1507
0
        self.data.read_at(range.start).ok().unwrap()
1508
0
    }
1509
1510
    /// For requirements on use of the language field, see “Use of
1511
    /// the language field in 'cmap' subtables” in this document.
1512
0
    pub fn language(&self) -> u32 {
1513
0
        let range = self.language_byte_range();
1514
0
        self.data.read_at(range.start).ok().unwrap()
1515
0
    }
1516
1517
    /// Number of groupings which follow
1518
0
    pub fn num_groups(&self) -> u32 {
1519
0
        let range = self.num_groups_byte_range();
1520
0
        self.data.read_at(range.start).ok().unwrap()
1521
0
    }
1522
1523
    /// Array of ConstantMapGroup records.
1524
0
    pub fn groups(&self) -> &'a [ConstantMapGroup] {
1525
0
        let range = self.groups_byte_range();
1526
0
        self.data.read_array(range).ok().unwrap_or_default()
1527
0
    }
1528
1529
0
    pub fn format_byte_range(&self) -> Range<usize> {
1530
0
        let start = 0;
1531
0
        start..start + u16::RAW_BYTE_LEN
1532
0
    }
1533
1534
0
    pub fn reserved_byte_range(&self) -> Range<usize> {
1535
0
        let start = self.format_byte_range().end;
1536
0
        start..start + u16::RAW_BYTE_LEN
1537
0
    }
1538
1539
0
    pub fn length_byte_range(&self) -> Range<usize> {
1540
0
        let start = self.reserved_byte_range().end;
1541
0
        start..start + u32::RAW_BYTE_LEN
1542
0
    }
1543
1544
0
    pub fn language_byte_range(&self) -> Range<usize> {
1545
0
        let start = self.length_byte_range().end;
1546
0
        start..start + u32::RAW_BYTE_LEN
1547
0
    }
1548
1549
0
    pub fn num_groups_byte_range(&self) -> Range<usize> {
1550
0
        let start = self.language_byte_range().end;
1551
0
        start..start + u32::RAW_BYTE_LEN
1552
0
    }
1553
1554
0
    pub fn groups_byte_range(&self) -> Range<usize> {
1555
0
        let num_groups = self.num_groups();
1556
0
        let start = self.num_groups_byte_range().end;
1557
0
        start..start + (num_groups as usize).saturating_mul(ConstantMapGroup::RAW_BYTE_LEN)
1558
0
    }
1559
}
1560
1561
#[cfg(feature = "experimental_traverse")]
1562
impl<'a> SomeTable<'a> for Cmap13<'a> {
1563
    fn type_name(&self) -> &str {
1564
        "Cmap13"
1565
    }
1566
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1567
        match idx {
1568
            0usize => Some(Field::new("format", self.format())),
1569
            1usize => Some(Field::new("length", self.length())),
1570
            2usize => Some(Field::new("language", self.language())),
1571
            3usize => Some(Field::new("num_groups", self.num_groups())),
1572
            4usize => Some(Field::new(
1573
                "groups",
1574
                traversal::FieldType::array_of_records(
1575
                    stringify!(ConstantMapGroup),
1576
                    self.groups(),
1577
                    self.offset_data(),
1578
                ),
1579
            )),
1580
            _ => None,
1581
        }
1582
    }
1583
}
1584
1585
#[cfg(feature = "experimental_traverse")]
1586
#[allow(clippy::needless_lifetimes)]
1587
impl<'a> std::fmt::Debug for Cmap13<'a> {
1588
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1589
        (self as &dyn SomeTable<'a>).fmt(f)
1590
    }
1591
}
1592
1593
/// Part of [Cmap13]
1594
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1595
#[repr(C)]
1596
#[repr(packed)]
1597
pub struct ConstantMapGroup {
1598
    /// First character code in this group
1599
    pub start_char_code: BigEndian<u32>,
1600
    /// Last character code in this group
1601
    pub end_char_code: BigEndian<u32>,
1602
    /// Glyph index to be used for all the characters in the group’s
1603
    /// range.
1604
    pub glyph_id: BigEndian<u32>,
1605
}
1606
1607
impl ConstantMapGroup {
1608
    /// First character code in this group
1609
0
    pub fn start_char_code(&self) -> u32 {
1610
0
        self.start_char_code.get()
1611
0
    }
1612
1613
    /// Last character code in this group
1614
0
    pub fn end_char_code(&self) -> u32 {
1615
0
        self.end_char_code.get()
1616
0
    }
1617
1618
    /// Glyph index to be used for all the characters in the group’s
1619
    /// range.
1620
0
    pub fn glyph_id(&self) -> u32 {
1621
0
        self.glyph_id.get()
1622
0
    }
1623
}
1624
1625
impl FixedSize for ConstantMapGroup {
1626
    const RAW_BYTE_LEN: usize = u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN;
1627
}
1628
1629
#[cfg(feature = "experimental_traverse")]
1630
impl<'a> SomeRecord<'a> for ConstantMapGroup {
1631
    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1632
        RecordResolver {
1633
            name: "ConstantMapGroup",
1634
            get_field: Box::new(move |idx, _data| match idx {
1635
                0usize => Some(Field::new("start_char_code", self.start_char_code())),
1636
                1usize => Some(Field::new("end_char_code", self.end_char_code())),
1637
                2usize => Some(Field::new("glyph_id", self.glyph_id())),
1638
                _ => None,
1639
            }),
1640
            data,
1641
        }
1642
    }
1643
}
1644
1645
impl Format<u16> for Cmap14<'_> {
1646
    const FORMAT: u16 = 14;
1647
}
1648
1649
impl<'a> MinByteRange<'a> for Cmap14<'a> {
1650
0
    fn min_byte_range(&self) -> Range<usize> {
1651
0
        0..self.var_selector_byte_range().end
1652
0
    }
1653
0
    fn min_table_bytes(&self) -> &'a [u8] {
1654
0
        let range = self.min_byte_range();
1655
0
        self.data.as_bytes().get(range).unwrap_or_default()
1656
0
    }
1657
}
1658
1659
impl<'a> FontRead<'a> for Cmap14<'a> {
1660
23.3k
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1661
        #[allow(clippy::absurd_extreme_comparisons)]
1662
23.3k
        if data.len() < Self::MIN_SIZE {
1663
239
            return Err(ReadError::OutOfBounds);
1664
23.0k
        }
1665
23.0k
        Ok(Self { data })
1666
23.3k
    }
1667
}
1668
1669
/// [cmap Format 14](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-14-unicode-variation-sequences): Unicode Variation Sequences
1670
#[derive(Clone)]
1671
pub struct Cmap14<'a> {
1672
    data: FontData<'a>,
1673
}
1674
1675
#[allow(clippy::needless_lifetimes)]
1676
impl<'a> Cmap14<'a> {
1677
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
1678
    basic_table_impls!(impl_the_methods);
1679
1680
    /// Subtable format. Set to 14.
1681
0
    pub fn format(&self) -> u16 {
1682
0
        let range = self.format_byte_range();
1683
0
        self.data.read_at(range.start).ok().unwrap()
1684
0
    }
1685
1686
    /// Byte length of this subtable (including this header)
1687
0
    pub fn length(&self) -> u32 {
1688
0
        let range = self.length_byte_range();
1689
0
        self.data.read_at(range.start).ok().unwrap()
1690
0
    }
1691
1692
    /// Number of variation Selector Records
1693
61.6M
    pub fn num_var_selector_records(&self) -> u32 {
1694
61.6M
        let range = self.num_var_selector_records_byte_range();
1695
61.6M
        self.data.read_at(range.start).ok().unwrap()
1696
61.6M
    }
1697
1698
    /// Array of VariationSelector records.
1699
61.6M
    pub fn var_selector(&self) -> &'a [VariationSelector] {
1700
61.6M
        let range = self.var_selector_byte_range();
1701
61.6M
        self.data.read_array(range).ok().unwrap_or_default()
1702
61.6M
    }
1703
1704
123M
    pub fn format_byte_range(&self) -> Range<usize> {
1705
123M
        let start = 0;
1706
123M
        start..start + u16::RAW_BYTE_LEN
1707
123M
    }
1708
1709
123M
    pub fn length_byte_range(&self) -> Range<usize> {
1710
123M
        let start = self.format_byte_range().end;
1711
123M
        start..start + u32::RAW_BYTE_LEN
1712
123M
    }
1713
1714
123M
    pub fn num_var_selector_records_byte_range(&self) -> Range<usize> {
1715
123M
        let start = self.length_byte_range().end;
1716
123M
        start..start + u32::RAW_BYTE_LEN
1717
123M
    }
1718
1719
61.6M
    pub fn var_selector_byte_range(&self) -> Range<usize> {
1720
61.6M
        let num_var_selector_records = self.num_var_selector_records();
1721
61.6M
        let start = self.num_var_selector_records_byte_range().end;
1722
61.6M
        start
1723
61.6M
            ..start
1724
61.6M
                + (num_var_selector_records as usize)
1725
61.6M
                    .saturating_mul(VariationSelector::RAW_BYTE_LEN)
1726
61.6M
    }
1727
}
1728
1729
#[cfg(feature = "experimental_traverse")]
1730
impl<'a> SomeTable<'a> for Cmap14<'a> {
1731
    fn type_name(&self) -> &str {
1732
        "Cmap14"
1733
    }
1734
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1735
        match idx {
1736
            0usize => Some(Field::new("format", self.format())),
1737
            1usize => Some(Field::new("length", self.length())),
1738
            2usize => Some(Field::new(
1739
                "num_var_selector_records",
1740
                self.num_var_selector_records(),
1741
            )),
1742
            3usize => Some(Field::new(
1743
                "var_selector",
1744
                traversal::FieldType::array_of_records(
1745
                    stringify!(VariationSelector),
1746
                    self.var_selector(),
1747
                    self.offset_data(),
1748
                ),
1749
            )),
1750
            _ => None,
1751
        }
1752
    }
1753
}
1754
1755
#[cfg(feature = "experimental_traverse")]
1756
#[allow(clippy::needless_lifetimes)]
1757
impl<'a> std::fmt::Debug for Cmap14<'a> {
1758
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1759
        (self as &dyn SomeTable<'a>).fmt(f)
1760
    }
1761
}
1762
1763
/// Part of [Cmap14]
1764
#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
1765
#[repr(C)]
1766
#[repr(packed)]
1767
pub struct VariationSelector {
1768
    /// Variation selector
1769
    pub var_selector: BigEndian<Uint24>,
1770
    /// Offset from the start of the [`Cmap14`] subtable to Default UVS
1771
    /// Table. May be NULL.
1772
    pub default_uvs_offset: BigEndian<Nullable<Offset32>>,
1773
    /// Offset from the start of the [`Cmap14`] subtable to Non-Default
1774
    /// UVS Table. May be NULL.
1775
    pub non_default_uvs_offset: BigEndian<Nullable<Offset32>>,
1776
}
1777
1778
impl VariationSelector {
1779
    /// Variation selector
1780
763M
    pub fn var_selector(&self) -> Uint24 {
1781
763M
        self.var_selector.get()
1782
763M
    }
1783
1784
    /// Offset from the start of the [`Cmap14`] subtable to Default UVS
1785
    /// Table. May be NULL.
1786
21.9M
    pub fn default_uvs_offset(&self) -> Nullable<Offset32> {
1787
21.9M
        self.default_uvs_offset.get()
1788
21.9M
    }
1789
1790
    /// Offset from the start of the [`Cmap14`] subtable to Default UVS
1791
    /// Table. May be NULL.
1792
    ///
1793
    /// The `data` argument should be retrieved from the parent table
1794
    /// By calling its `offset_data` method.
1795
21.9M
    pub fn default_uvs<'a>(&self, data: FontData<'a>) -> Option<Result<DefaultUvs<'a>, ReadError>> {
1796
21.9M
        self.default_uvs_offset().resolve(data)
1797
21.9M
    }
1798
1799
    /// Offset from the start of the [`Cmap14`] subtable to Non-Default
1800
    /// UVS Table. May be NULL.
1801
21.9M
    pub fn non_default_uvs_offset(&self) -> Nullable<Offset32> {
1802
21.9M
        self.non_default_uvs_offset.get()
1803
21.9M
    }
1804
1805
    /// Offset from the start of the [`Cmap14`] subtable to Non-Default
1806
    /// UVS Table. May be NULL.
1807
    ///
1808
    /// The `data` argument should be retrieved from the parent table
1809
    /// By calling its `offset_data` method.
1810
21.9M
    pub fn non_default_uvs<'a>(
1811
21.9M
        &self,
1812
21.9M
        data: FontData<'a>,
1813
21.9M
    ) -> Option<Result<NonDefaultUvs<'a>, ReadError>> {
1814
21.9M
        self.non_default_uvs_offset().resolve(data)
1815
21.9M
    }
1816
}
1817
1818
impl FixedSize for VariationSelector {
1819
    const RAW_BYTE_LEN: usize =
1820
        Uint24::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
1821
}
1822
1823
#[cfg(feature = "experimental_traverse")]
1824
impl<'a> SomeRecord<'a> for VariationSelector {
1825
    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1826
        RecordResolver {
1827
            name: "VariationSelector",
1828
            get_field: Box::new(move |idx, _data| match idx {
1829
                0usize => Some(Field::new("var_selector", self.var_selector())),
1830
                1usize => Some(Field::new(
1831
                    "default_uvs_offset",
1832
                    FieldType::offset(self.default_uvs_offset(), self.default_uvs(_data)),
1833
                )),
1834
                2usize => Some(Field::new(
1835
                    "non_default_uvs_offset",
1836
                    FieldType::offset(self.non_default_uvs_offset(), self.non_default_uvs(_data)),
1837
                )),
1838
                _ => None,
1839
            }),
1840
            data,
1841
        }
1842
    }
1843
}
1844
1845
impl<'a> MinByteRange<'a> for DefaultUvs<'a> {
1846
0
    fn min_byte_range(&self) -> Range<usize> {
1847
0
        0..self.ranges_byte_range().end
1848
0
    }
1849
0
    fn min_table_bytes(&self) -> &'a [u8] {
1850
0
        let range = self.min_byte_range();
1851
0
        self.data.as_bytes().get(range).unwrap_or_default()
1852
0
    }
1853
}
1854
1855
impl<'a> FontRead<'a> for DefaultUvs<'a> {
1856
14.8M
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1857
        #[allow(clippy::absurd_extreme_comparisons)]
1858
14.8M
        if data.len() < Self::MIN_SIZE {
1859
215k
            return Err(ReadError::OutOfBounds);
1860
14.6M
        }
1861
14.6M
        Ok(Self { data })
1862
14.8M
    }
1863
}
1864
1865
/// [Default UVS table](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#default-uvs-table)
1866
#[derive(Clone)]
1867
pub struct DefaultUvs<'a> {
1868
    data: FontData<'a>,
1869
}
1870
1871
#[allow(clippy::needless_lifetimes)]
1872
impl<'a> DefaultUvs<'a> {
1873
    pub const MIN_SIZE: usize = u32::RAW_BYTE_LEN;
1874
    basic_table_impls!(impl_the_methods);
1875
1876
    /// Number of Unicode character ranges.
1877
14.6M
    pub fn num_unicode_value_ranges(&self) -> u32 {
1878
14.6M
        let range = self.num_unicode_value_ranges_byte_range();
1879
14.6M
        self.data.read_at(range.start).ok().unwrap()
1880
14.6M
    }
1881
1882
    /// Array of UnicodeRange records.
1883
14.6M
    pub fn ranges(&self) -> &'a [UnicodeRange] {
1884
14.6M
        let range = self.ranges_byte_range();
1885
14.6M
        self.data.read_array(range).ok().unwrap_or_default()
1886
14.6M
    }
1887
1888
29.2M
    pub fn num_unicode_value_ranges_byte_range(&self) -> Range<usize> {
1889
29.2M
        let start = 0;
1890
29.2M
        start..start + u32::RAW_BYTE_LEN
1891
29.2M
    }
1892
1893
14.6M
    pub fn ranges_byte_range(&self) -> Range<usize> {
1894
14.6M
        let num_unicode_value_ranges = self.num_unicode_value_ranges();
1895
14.6M
        let start = self.num_unicode_value_ranges_byte_range().end;
1896
14.6M
        start
1897
14.6M
            ..start + (num_unicode_value_ranges as usize).saturating_mul(UnicodeRange::RAW_BYTE_LEN)
1898
14.6M
    }
1899
}
1900
1901
#[cfg(feature = "experimental_traverse")]
1902
impl<'a> SomeTable<'a> for DefaultUvs<'a> {
1903
    fn type_name(&self) -> &str {
1904
        "DefaultUvs"
1905
    }
1906
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1907
        match idx {
1908
            0usize => Some(Field::new(
1909
                "num_unicode_value_ranges",
1910
                self.num_unicode_value_ranges(),
1911
            )),
1912
            1usize => Some(Field::new(
1913
                "ranges",
1914
                traversal::FieldType::array_of_records(
1915
                    stringify!(UnicodeRange),
1916
                    self.ranges(),
1917
                    self.offset_data(),
1918
                ),
1919
            )),
1920
            _ => None,
1921
        }
1922
    }
1923
}
1924
1925
#[cfg(feature = "experimental_traverse")]
1926
#[allow(clippy::needless_lifetimes)]
1927
impl<'a> std::fmt::Debug for DefaultUvs<'a> {
1928
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1929
        (self as &dyn SomeTable<'a>).fmt(f)
1930
    }
1931
}
1932
1933
impl<'a> MinByteRange<'a> for NonDefaultUvs<'a> {
1934
0
    fn min_byte_range(&self) -> Range<usize> {
1935
0
        0..self.uvs_mapping_byte_range().end
1936
0
    }
1937
0
    fn min_table_bytes(&self) -> &'a [u8] {
1938
0
        let range = self.min_byte_range();
1939
0
        self.data.as_bytes().get(range).unwrap_or_default()
1940
0
    }
1941
}
1942
1943
impl<'a> FontRead<'a> for NonDefaultUvs<'a> {
1944
10.9M
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1945
        #[allow(clippy::absurd_extreme_comparisons)]
1946
10.9M
        if data.len() < Self::MIN_SIZE {
1947
348k
            return Err(ReadError::OutOfBounds);
1948
10.5M
        }
1949
10.5M
        Ok(Self { data })
1950
10.9M
    }
1951
}
1952
1953
/// [Non-Default UVS table](https://learn.microsoft.com/en-us/typography/opentype/spec/cmap#non-default-uvs-table)
1954
#[derive(Clone)]
1955
pub struct NonDefaultUvs<'a> {
1956
    data: FontData<'a>,
1957
}
1958
1959
#[allow(clippy::needless_lifetimes)]
1960
impl<'a> NonDefaultUvs<'a> {
1961
    pub const MIN_SIZE: usize = u32::RAW_BYTE_LEN;
1962
    basic_table_impls!(impl_the_methods);
1963
1964
10.5M
    pub fn num_uvs_mappings(&self) -> u32 {
1965
10.5M
        let range = self.num_uvs_mappings_byte_range();
1966
10.5M
        self.data.read_at(range.start).ok().unwrap()
1967
10.5M
    }
1968
1969
10.5M
    pub fn uvs_mapping(&self) -> &'a [UvsMapping] {
1970
10.5M
        let range = self.uvs_mapping_byte_range();
1971
10.5M
        self.data.read_array(range).ok().unwrap_or_default()
1972
10.5M
    }
1973
1974
21.1M
    pub fn num_uvs_mappings_byte_range(&self) -> Range<usize> {
1975
21.1M
        let start = 0;
1976
21.1M
        start..start + u32::RAW_BYTE_LEN
1977
21.1M
    }
1978
1979
10.5M
    pub fn uvs_mapping_byte_range(&self) -> Range<usize> {
1980
10.5M
        let num_uvs_mappings = self.num_uvs_mappings();
1981
10.5M
        let start = self.num_uvs_mappings_byte_range().end;
1982
10.5M
        start..start + (num_uvs_mappings as usize).saturating_mul(UvsMapping::RAW_BYTE_LEN)
1983
10.5M
    }
1984
}
1985
1986
#[cfg(feature = "experimental_traverse")]
1987
impl<'a> SomeTable<'a> for NonDefaultUvs<'a> {
1988
    fn type_name(&self) -> &str {
1989
        "NonDefaultUvs"
1990
    }
1991
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1992
        match idx {
1993
            0usize => Some(Field::new("num_uvs_mappings", self.num_uvs_mappings())),
1994
            1usize => Some(Field::new(
1995
                "uvs_mapping",
1996
                traversal::FieldType::array_of_records(
1997
                    stringify!(UvsMapping),
1998
                    self.uvs_mapping(),
1999
                    self.offset_data(),
2000
                ),
2001
            )),
2002
            _ => None,
2003
        }
2004
    }
2005
}
2006
2007
#[cfg(feature = "experimental_traverse")]
2008
#[allow(clippy::needless_lifetimes)]
2009
impl<'a> std::fmt::Debug for NonDefaultUvs<'a> {
2010
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2011
        (self as &dyn SomeTable<'a>).fmt(f)
2012
    }
2013
}
2014
2015
/// Part of [Cmap14]
2016
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
2017
#[repr(C)]
2018
#[repr(packed)]
2019
pub struct UvsMapping {
2020
    /// Base Unicode value of the UVS
2021
    pub unicode_value: BigEndian<Uint24>,
2022
    /// Glyph ID of the UVS
2023
    pub glyph_id: BigEndian<u16>,
2024
}
2025
2026
impl UvsMapping {
2027
    /// Base Unicode value of the UVS
2028
69.6M
    pub fn unicode_value(&self) -> Uint24 {
2029
69.6M
        self.unicode_value.get()
2030
69.6M
    }
2031
2032
    /// Glyph ID of the UVS
2033
8.65M
    pub fn glyph_id(&self) -> u16 {
2034
8.65M
        self.glyph_id.get()
2035
8.65M
    }
2036
}
2037
2038
impl FixedSize for UvsMapping {
2039
    const RAW_BYTE_LEN: usize = Uint24::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
2040
}
2041
2042
#[cfg(feature = "experimental_traverse")]
2043
impl<'a> SomeRecord<'a> for UvsMapping {
2044
    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
2045
        RecordResolver {
2046
            name: "UvsMapping",
2047
            get_field: Box::new(move |idx, _data| match idx {
2048
                0usize => Some(Field::new("unicode_value", self.unicode_value())),
2049
                1usize => Some(Field::new("glyph_id", self.glyph_id())),
2050
                _ => None,
2051
            }),
2052
            data,
2053
        }
2054
    }
2055
}
2056
2057
/// Part of [Cmap14]
2058
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
2059
#[repr(C)]
2060
#[repr(packed)]
2061
pub struct UnicodeRange {
2062
    /// First value in this range
2063
    pub start_unicode_value: BigEndian<Uint24>,
2064
    /// Number of additional values in this range
2065
    pub additional_count: u8,
2066
}
2067
2068
impl UnicodeRange {
2069
    /// First value in this range
2070
52.3M
    pub fn start_unicode_value(&self) -> Uint24 {
2071
52.3M
        self.start_unicode_value.get()
2072
52.3M
    }
2073
2074
    /// Number of additional values in this range
2075
29.2M
    pub fn additional_count(&self) -> u8 {
2076
29.2M
        self.additional_count
2077
29.2M
    }
2078
}
2079
2080
impl FixedSize for UnicodeRange {
2081
    const RAW_BYTE_LEN: usize = Uint24::RAW_BYTE_LEN + u8::RAW_BYTE_LEN;
2082
}
2083
2084
#[cfg(feature = "experimental_traverse")]
2085
impl<'a> SomeRecord<'a> for UnicodeRange {
2086
    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
2087
        RecordResolver {
2088
            name: "UnicodeRange",
2089
            get_field: Box::new(move |idx, _data| match idx {
2090
                0usize => Some(Field::new(
2091
                    "start_unicode_value",
2092
                    self.start_unicode_value(),
2093
                )),
2094
                1usize => Some(Field::new("additional_count", self.additional_count())),
2095
                _ => None,
2096
            }),
2097
            data,
2098
        }
2099
    }
2100
}