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