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