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