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