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