read_fonts/generated/
generated_cmap.rs

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