Coverage Report

Created: 2026-02-14 06:54

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