Skip to main content

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