Skip to main content

read_fonts/generated/
generated_cff.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 CffHeader<'a> {
9    fn min_byte_range(&self) -> Range<usize> {
10        0..self.trailing_data_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 ReadArgs for CffHeader<'_> {
19    type Args = ();
20}
21
22impl<'a> FontRead<'a> for CffHeader<'a> {
23    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
24        #[allow(clippy::absurd_extreme_comparisons)]
25        if data.len() < Self::MIN_SIZE {
26            return Err(ReadError::OutOfBounds);
27        }
28        Ok(Self { data })
29    }
30}
31
32/// [Compact Font Format](https://learn.microsoft.com/en-us/typography/opentype/spec/cff) table header
33#[derive(Clone)]
34pub struct CffHeader<'a> {
35    data: FontData<'a>,
36}
37
38#[allow(clippy::needless_lifetimes)]
39impl<'a> CffHeader<'a> {
40    pub const MIN_SIZE: usize =
41        (u8::RAW_BYTE_LEN + u8::RAW_BYTE_LEN + u8::RAW_BYTE_LEN + u8::RAW_BYTE_LEN);
42    basic_table_impls!(impl_the_methods);
43
44    /// Format major version (starting at 1).
45    pub fn major(&self) -> u8 {
46        let range = self.major_byte_range();
47        self.data.read_at(range.start).ok().unwrap()
48    }
49
50    /// Format minor version (starting at 0).
51    pub fn minor(&self) -> u8 {
52        let range = self.minor_byte_range();
53        self.data.read_at(range.start).ok().unwrap()
54    }
55
56    /// Header size (bytes).
57    pub fn hdr_size(&self) -> u8 {
58        let range = self.hdr_size_byte_range();
59        self.data.read_at(range.start).ok().unwrap()
60    }
61
62    /// Absolute offset size.
63    pub fn off_size(&self) -> u8 {
64        let range = self.off_size_byte_range();
65        self.data.read_at(range.start).ok().unwrap()
66    }
67
68    /// Padding bytes before the start of the Name INDEX.
69    pub fn _padding(&self) -> &'a [u8] {
70        let range = self._padding_byte_range();
71        self.data.read_array(range).ok().unwrap_or_default()
72    }
73
74    /// Remaining table data.
75    pub fn trailing_data(&self) -> &'a [u8] {
76        let range = self.trailing_data_byte_range();
77        self.data.read_array(range).ok().unwrap_or_default()
78    }
79
80    pub fn major_byte_range(&self) -> Range<usize> {
81        let start = 0;
82        let end = start + u8::RAW_BYTE_LEN;
83        start..end
84    }
85
86    pub fn minor_byte_range(&self) -> Range<usize> {
87        let start = self.major_byte_range().end;
88        let end = start + u8::RAW_BYTE_LEN;
89        start..end
90    }
91
92    pub fn hdr_size_byte_range(&self) -> Range<usize> {
93        let start = self.minor_byte_range().end;
94        let end = start + u8::RAW_BYTE_LEN;
95        start..end
96    }
97
98    pub fn off_size_byte_range(&self) -> Range<usize> {
99        let start = self.hdr_size_byte_range().end;
100        let end = start + u8::RAW_BYTE_LEN;
101        start..end
102    }
103
104    pub fn _padding_byte_range(&self) -> Range<usize> {
105        let hdr_size = self.hdr_size();
106        let start = self.off_size_byte_range().end;
107        let end =
108            start + (transforms::subtract(hdr_size, 4_usize)).saturating_mul(u8::RAW_BYTE_LEN);
109        start..end
110    }
111
112    pub fn trailing_data_byte_range(&self) -> Range<usize> {
113        let start = self._padding_byte_range().end;
114        let end =
115            start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
116        start..end
117    }
118}
119
120const _: () = assert!(FontData::default_data_long_enough(CffHeader::MIN_SIZE));
121
122impl Default for CffHeader<'_> {
123    fn default() -> Self {
124        Self {
125            data: FontData::default_table_data(),
126        }
127    }
128}
129
130#[cfg(feature = "experimental_traverse")]
131impl<'a> SomeTable<'a> for CffHeader<'a> {
132    fn type_name(&self) -> &str {
133        "CffHeader"
134    }
135    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
136        match idx {
137            0usize => Some(Field::new("major", self.major())),
138            1usize => Some(Field::new("minor", self.minor())),
139            2usize => Some(Field::new("hdr_size", self.hdr_size())),
140            3usize => Some(Field::new("off_size", self.off_size())),
141            4usize => Some(Field::new("_padding", self._padding())),
142            5usize => Some(Field::new("trailing_data", self.trailing_data())),
143            _ => None,
144        }
145    }
146}
147
148#[cfg(feature = "experimental_traverse")]
149#[allow(clippy::needless_lifetimes)]
150impl<'a> std::fmt::Debug for CffHeader<'a> {
151    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
152        (self as &dyn SomeTable<'a>).fmt(f)
153    }
154}
155
156impl<'a> MinByteRange<'a> for Index<'a> {
157    fn min_byte_range(&self) -> Range<usize> {
158        0..self.data_byte_range().end
159    }
160    fn min_table_bytes(&self) -> &'a [u8] {
161        let range = self.min_byte_range();
162        self.data.as_bytes().get(range).unwrap_or_default()
163    }
164}
165
166impl ReadArgs for Index<'_> {
167    type Args = ();
168}
169
170impl<'a> FontRead<'a> for Index<'a> {
171    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
172        #[allow(clippy::absurd_extreme_comparisons)]
173        if data.len() < Self::MIN_SIZE {
174            return Err(ReadError::OutOfBounds);
175        }
176        Ok(Self { data })
177    }
178}
179
180/// An array of variable-sized objects in a `CFF` table.
181#[derive(Clone)]
182pub struct Index<'a> {
183    data: FontData<'a>,
184}
185
186#[allow(clippy::needless_lifetimes)]
187impl<'a> Index<'a> {
188    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u8::RAW_BYTE_LEN);
189    basic_table_impls!(impl_the_methods);
190
191    /// Number of objects stored in INDEX.
192    pub fn count(&self) -> u16 {
193        let range = self.count_byte_range();
194        self.data.read_at(range.start).ok().unwrap()
195    }
196
197    /// Object array element size.
198    pub fn off_size(&self) -> u8 {
199        let range = self.off_size_byte_range();
200        self.data.read_at(range.start).ok().unwrap()
201    }
202
203    /// Bytes containing `count + 1` offsets each of `off_size`.
204    pub fn offsets(&self) -> &'a [u8] {
205        let range = self.offsets_byte_range();
206        self.data.read_array(range).ok().unwrap_or_default()
207    }
208
209    /// Array containing the object data.
210    pub fn data(&self) -> &'a [u8] {
211        let range = self.data_byte_range();
212        self.data.read_array(range).ok().unwrap_or_default()
213    }
214
215    pub fn count_byte_range(&self) -> Range<usize> {
216        let start = 0;
217        let end = start + u16::RAW_BYTE_LEN;
218        start..end
219    }
220
221    pub fn off_size_byte_range(&self) -> Range<usize> {
222        let start = self.count_byte_range().end;
223        let end = start + u8::RAW_BYTE_LEN;
224        start..end
225    }
226
227    pub fn offsets_byte_range(&self) -> Range<usize> {
228        let count = self.count();
229        let off_size = self.off_size();
230        let start = self.off_size_byte_range().end;
231        let end = start
232            + (transforms::add_multiply(count, 1_usize, off_size)).saturating_mul(u8::RAW_BYTE_LEN);
233        start..end
234    }
235
236    pub fn data_byte_range(&self) -> Range<usize> {
237        let start = self.offsets_byte_range().end;
238        let end =
239            start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
240        start..end
241    }
242}
243
244const _: () = assert!(FontData::default_data_long_enough(Index::MIN_SIZE));
245
246impl Default for Index<'_> {
247    fn default() -> Self {
248        Self {
249            data: FontData::default_table_data(),
250        }
251    }
252}
253
254#[cfg(feature = "experimental_traverse")]
255impl<'a> SomeTable<'a> for Index<'a> {
256    fn type_name(&self) -> &str {
257        "Index"
258    }
259    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
260        match idx {
261            0usize => Some(Field::new("count", self.count())),
262            1usize => Some(Field::new("off_size", self.off_size())),
263            2usize => Some(Field::new("offsets", self.offsets())),
264            3usize => Some(Field::new("data", self.data())),
265            _ => None,
266        }
267    }
268}
269
270#[cfg(feature = "experimental_traverse")]
271#[allow(clippy::needless_lifetimes)]
272impl<'a> std::fmt::Debug for Index<'a> {
273    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
274        (self as &dyn SomeTable<'a>).fmt(f)
275    }
276}
277
278/// Associates a glyph identifier with a Font DICT.
279#[derive(Clone)]
280pub enum FdSelect<'a> {
281    Format0(FdSelectFormat0<'a>),
282    Format3(FdSelectFormat3<'a>),
283    Format4(FdSelectFormat4<'a>),
284}
285
286impl Default for FdSelect<'_> {
287    fn default() -> Self {
288        Self::Format0(Default::default())
289    }
290}
291
292impl<'a> FdSelect<'a> {
293    ///Return the `FontData` used to resolve offsets for this table.
294    pub fn offset_data(&self) -> FontData<'a> {
295        match self {
296            Self::Format0(item) => item.offset_data(),
297            Self::Format3(item) => item.offset_data(),
298            Self::Format4(item) => item.offset_data(),
299        }
300    }
301
302    /// Format = 0.
303    pub fn format(&self) -> u8 {
304        match self {
305            Self::Format0(item) => item.format(),
306            Self::Format3(item) => item.format(),
307            Self::Format4(item) => item.format(),
308        }
309    }
310}
311
312impl ReadArgs for FdSelect<'_> {
313    type Args = ();
314}
315
316impl<'a> FontRead<'a> for FdSelect<'a> {
317    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
318        let format: u8 = data.read_at(0usize)?;
319        match format {
320            FdSelectFormat0::FORMAT => Ok(Self::Format0(FontRead::read(data)?)),
321            FdSelectFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
322            FdSelectFormat4::FORMAT => Ok(Self::Format4(FontRead::read(data)?)),
323            other => Err(ReadError::InvalidFormat(other.into())),
324        }
325    }
326}
327
328impl<'a> MinByteRange<'a> for FdSelect<'a> {
329    fn min_byte_range(&self) -> Range<usize> {
330        match self {
331            Self::Format0(item) => item.min_byte_range(),
332            Self::Format3(item) => item.min_byte_range(),
333            Self::Format4(item) => item.min_byte_range(),
334        }
335    }
336    fn min_table_bytes(&self) -> &'a [u8] {
337        match self {
338            Self::Format0(item) => item.min_table_bytes(),
339            Self::Format3(item) => item.min_table_bytes(),
340            Self::Format4(item) => item.min_table_bytes(),
341        }
342    }
343}
344
345#[cfg(feature = "experimental_traverse")]
346impl<'a> FdSelect<'a> {
347    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
348        match self {
349            Self::Format0(table) => table,
350            Self::Format3(table) => table,
351            Self::Format4(table) => table,
352        }
353    }
354}
355
356#[cfg(feature = "experimental_traverse")]
357impl std::fmt::Debug for FdSelect<'_> {
358    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
359        self.dyn_inner().fmt(f)
360    }
361}
362
363#[cfg(feature = "experimental_traverse")]
364impl<'a> SomeTable<'a> for FdSelect<'a> {
365    fn type_name(&self) -> &str {
366        self.dyn_inner().type_name()
367    }
368    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
369        self.dyn_inner().get_field(idx)
370    }
371}
372
373impl Format<u8> for FdSelectFormat0<'_> {
374    const FORMAT: u8 = 0;
375}
376
377impl<'a> MinByteRange<'a> for FdSelectFormat0<'a> {
378    fn min_byte_range(&self) -> Range<usize> {
379        0..self.fds_byte_range().end
380    }
381    fn min_table_bytes(&self) -> &'a [u8] {
382        let range = self.min_byte_range();
383        self.data.as_bytes().get(range).unwrap_or_default()
384    }
385}
386
387impl ReadArgs for FdSelectFormat0<'_> {
388    type Args = ();
389}
390
391impl<'a> FontRead<'a> for FdSelectFormat0<'a> {
392    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
393        #[allow(clippy::absurd_extreme_comparisons)]
394        if data.len() < Self::MIN_SIZE {
395            return Err(ReadError::OutOfBounds);
396        }
397        Ok(Self { data })
398    }
399}
400
401/// FdSelect format 0.
402#[derive(Clone)]
403pub struct FdSelectFormat0<'a> {
404    data: FontData<'a>,
405}
406
407#[allow(clippy::needless_lifetimes)]
408impl<'a> FdSelectFormat0<'a> {
409    pub const MIN_SIZE: usize = u8::RAW_BYTE_LEN;
410    basic_table_impls!(impl_the_methods);
411
412    /// Format = 0.
413    pub fn format(&self) -> u8 {
414        let range = self.format_byte_range();
415        self.data.read_at(range.start).ok().unwrap()
416    }
417
418    /// FD selector array (one entry for each glyph).
419    pub fn fds(&self) -> &'a [u8] {
420        let range = self.fds_byte_range();
421        self.data.read_array(range).ok().unwrap_or_default()
422    }
423
424    pub fn format_byte_range(&self) -> Range<usize> {
425        let start = 0;
426        let end = start + u8::RAW_BYTE_LEN;
427        start..end
428    }
429
430    pub fn fds_byte_range(&self) -> Range<usize> {
431        let start = self.format_byte_range().end;
432        let end =
433            start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
434        start..end
435    }
436}
437
438const _: () = assert!(FontData::default_data_long_enough(
439    FdSelectFormat0::MIN_SIZE
440));
441
442impl Default for FdSelectFormat0<'_> {
443    fn default() -> Self {
444        Self {
445            data: FontData::default_table_data(),
446        }
447    }
448}
449
450#[cfg(feature = "experimental_traverse")]
451impl<'a> SomeTable<'a> for FdSelectFormat0<'a> {
452    fn type_name(&self) -> &str {
453        "FdSelectFormat0"
454    }
455    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
456        match idx {
457            0usize => Some(Field::new("format", self.format())),
458            1usize => Some(Field::new("fds", self.fds())),
459            _ => None,
460        }
461    }
462}
463
464#[cfg(feature = "experimental_traverse")]
465#[allow(clippy::needless_lifetimes)]
466impl<'a> std::fmt::Debug for FdSelectFormat0<'a> {
467    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
468        (self as &dyn SomeTable<'a>).fmt(f)
469    }
470}
471
472impl Format<u8> for FdSelectFormat3<'_> {
473    const FORMAT: u8 = 3;
474}
475
476impl<'a> MinByteRange<'a> for FdSelectFormat3<'a> {
477    fn min_byte_range(&self) -> Range<usize> {
478        0..self.sentinel_byte_range().end
479    }
480    fn min_table_bytes(&self) -> &'a [u8] {
481        let range = self.min_byte_range();
482        self.data.as_bytes().get(range).unwrap_or_default()
483    }
484}
485
486impl ReadArgs for FdSelectFormat3<'_> {
487    type Args = ();
488}
489
490impl<'a> FontRead<'a> for FdSelectFormat3<'a> {
491    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
492        #[allow(clippy::absurd_extreme_comparisons)]
493        if data.len() < Self::MIN_SIZE {
494            return Err(ReadError::OutOfBounds);
495        }
496        Ok(Self { data })
497    }
498}
499
500/// FdSelect format 3.
501#[derive(Clone)]
502pub struct FdSelectFormat3<'a> {
503    data: FontData<'a>,
504}
505
506#[allow(clippy::needless_lifetimes)]
507impl<'a> FdSelectFormat3<'a> {
508    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
509    basic_table_impls!(impl_the_methods);
510
511    /// Format = 3.
512    pub fn format(&self) -> u8 {
513        let range = self.format_byte_range();
514        self.data.read_at(range.start).ok().unwrap()
515    }
516
517    /// Number of ranges.
518    pub fn n_ranges(&self) -> u16 {
519        let range = self.n_ranges_byte_range();
520        self.data.read_at(range.start).ok().unwrap()
521    }
522
523    /// Range3 array.
524    pub fn ranges(&self) -> &'a [FdSelectRange3] {
525        let range = self.ranges_byte_range();
526        self.data.read_array(range).ok().unwrap_or_default()
527    }
528
529    /// Sentinel GID. Set equal to the number of glyphs in the font.
530    pub fn sentinel(&self) -> u16 {
531        let range = self.sentinel_byte_range();
532        self.data.read_at(range.start).ok().unwrap_or_default()
533    }
534
535    pub fn format_byte_range(&self) -> Range<usize> {
536        let start = 0;
537        let end = start + u8::RAW_BYTE_LEN;
538        start..end
539    }
540
541    pub fn n_ranges_byte_range(&self) -> Range<usize> {
542        let start = self.format_byte_range().end;
543        let end = start + u16::RAW_BYTE_LEN;
544        start..end
545    }
546
547    pub fn ranges_byte_range(&self) -> Range<usize> {
548        let n_ranges = self.n_ranges();
549        let start = self.n_ranges_byte_range().end;
550        let end =
551            start + (transforms::to_usize(n_ranges)).saturating_mul(FdSelectRange3::RAW_BYTE_LEN);
552        start..end
553    }
554
555    pub fn sentinel_byte_range(&self) -> Range<usize> {
556        let start = self.ranges_byte_range().end;
557        let end = start + u16::RAW_BYTE_LEN;
558        start..end
559    }
560}
561
562#[cfg(feature = "experimental_traverse")]
563impl<'a> SomeTable<'a> for FdSelectFormat3<'a> {
564    fn type_name(&self) -> &str {
565        "FdSelectFormat3"
566    }
567    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
568        match idx {
569            0usize => Some(Field::new("format", self.format())),
570            1usize => Some(Field::new("n_ranges", self.n_ranges())),
571            2usize => Some(Field::new(
572                "ranges",
573                traversal::FieldType::array_of_records(
574                    stringify!(FdSelectRange3),
575                    self.ranges(),
576                    self.offset_data(),
577                ),
578            )),
579            3usize => Some(Field::new("sentinel", self.sentinel())),
580            _ => None,
581        }
582    }
583}
584
585#[cfg(feature = "experimental_traverse")]
586#[allow(clippy::needless_lifetimes)]
587impl<'a> std::fmt::Debug for FdSelectFormat3<'a> {
588    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
589        (self as &dyn SomeTable<'a>).fmt(f)
590    }
591}
592
593/// Range struct for FdSelect format 3.
594#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
595#[repr(C)]
596#[repr(packed)]
597pub struct FdSelectRange3 {
598    /// First glyph index in range.
599    pub first: BigEndian<u16>,
600    /// FD index for all glyphs in range.
601    pub fd: u8,
602}
603
604impl FdSelectRange3 {
605    /// First glyph index in range.
606    pub fn first(&self) -> u16 {
607        self.first.get()
608    }
609
610    /// FD index for all glyphs in range.
611    pub fn fd(&self) -> u8 {
612        self.fd
613    }
614}
615
616impl FixedSize for FdSelectRange3 {
617    const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u8::RAW_BYTE_LEN;
618}
619
620#[cfg(feature = "experimental_traverse")]
621impl<'a> SomeRecord<'a> for FdSelectRange3 {
622    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
623        RecordResolver {
624            name: "FdSelectRange3",
625            get_field: Box::new(move |idx, _data| match idx {
626                0usize => Some(Field::new("first", self.first())),
627                1usize => Some(Field::new("fd", self.fd())),
628                _ => None,
629            }),
630            data,
631        }
632    }
633}
634
635impl Format<u8> for FdSelectFormat4<'_> {
636    const FORMAT: u8 = 4;
637}
638
639impl<'a> MinByteRange<'a> for FdSelectFormat4<'a> {
640    fn min_byte_range(&self) -> Range<usize> {
641        0..self.sentinel_byte_range().end
642    }
643    fn min_table_bytes(&self) -> &'a [u8] {
644        let range = self.min_byte_range();
645        self.data.as_bytes().get(range).unwrap_or_default()
646    }
647}
648
649impl ReadArgs for FdSelectFormat4<'_> {
650    type Args = ();
651}
652
653impl<'a> FontRead<'a> for FdSelectFormat4<'a> {
654    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
655        #[allow(clippy::absurd_extreme_comparisons)]
656        if data.len() < Self::MIN_SIZE {
657            return Err(ReadError::OutOfBounds);
658        }
659        Ok(Self { data })
660    }
661}
662
663/// FdSelect format 4.
664#[derive(Clone)]
665pub struct FdSelectFormat4<'a> {
666    data: FontData<'a>,
667}
668
669#[allow(clippy::needless_lifetimes)]
670impl<'a> FdSelectFormat4<'a> {
671    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
672    basic_table_impls!(impl_the_methods);
673
674    /// Format = 4.
675    pub fn format(&self) -> u8 {
676        let range = self.format_byte_range();
677        self.data.read_at(range.start).ok().unwrap()
678    }
679
680    /// Number of ranges.
681    pub fn n_ranges(&self) -> u32 {
682        let range = self.n_ranges_byte_range();
683        self.data.read_at(range.start).ok().unwrap()
684    }
685
686    /// Range4 array.
687    pub fn ranges(&self) -> &'a [FdSelectRange4] {
688        let range = self.ranges_byte_range();
689        self.data.read_array(range).ok().unwrap_or_default()
690    }
691
692    /// Sentinel GID. Set equal to the number of glyphs in the font.
693    pub fn sentinel(&self) -> u32 {
694        let range = self.sentinel_byte_range();
695        self.data.read_at(range.start).ok().unwrap_or_default()
696    }
697
698    pub fn format_byte_range(&self) -> Range<usize> {
699        let start = 0;
700        let end = start + u8::RAW_BYTE_LEN;
701        start..end
702    }
703
704    pub fn n_ranges_byte_range(&self) -> Range<usize> {
705        let start = self.format_byte_range().end;
706        let end = start + u32::RAW_BYTE_LEN;
707        start..end
708    }
709
710    pub fn ranges_byte_range(&self) -> Range<usize> {
711        let n_ranges = self.n_ranges();
712        let start = self.n_ranges_byte_range().end;
713        let end =
714            start + (transforms::to_usize(n_ranges)).saturating_mul(FdSelectRange4::RAW_BYTE_LEN);
715        start..end
716    }
717
718    pub fn sentinel_byte_range(&self) -> Range<usize> {
719        let start = self.ranges_byte_range().end;
720        let end = start + u32::RAW_BYTE_LEN;
721        start..end
722    }
723}
724
725#[cfg(feature = "experimental_traverse")]
726impl<'a> SomeTable<'a> for FdSelectFormat4<'a> {
727    fn type_name(&self) -> &str {
728        "FdSelectFormat4"
729    }
730    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
731        match idx {
732            0usize => Some(Field::new("format", self.format())),
733            1usize => Some(Field::new("n_ranges", self.n_ranges())),
734            2usize => Some(Field::new(
735                "ranges",
736                traversal::FieldType::array_of_records(
737                    stringify!(FdSelectRange4),
738                    self.ranges(),
739                    self.offset_data(),
740                ),
741            )),
742            3usize => Some(Field::new("sentinel", self.sentinel())),
743            _ => None,
744        }
745    }
746}
747
748#[cfg(feature = "experimental_traverse")]
749#[allow(clippy::needless_lifetimes)]
750impl<'a> std::fmt::Debug for FdSelectFormat4<'a> {
751    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
752        (self as &dyn SomeTable<'a>).fmt(f)
753    }
754}
755
756/// Range struct for FdSelect format 4.
757#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
758#[repr(C)]
759#[repr(packed)]
760pub struct FdSelectRange4 {
761    /// First glyph index in range.
762    pub first: BigEndian<u32>,
763    /// FD index for all glyphs in range.
764    pub fd: BigEndian<u16>,
765}
766
767impl FdSelectRange4 {
768    /// First glyph index in range.
769    pub fn first(&self) -> u32 {
770        self.first.get()
771    }
772
773    /// FD index for all glyphs in range.
774    pub fn fd(&self) -> u16 {
775        self.fd.get()
776    }
777}
778
779impl FixedSize for FdSelectRange4 {
780    const RAW_BYTE_LEN: usize = u32::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
781}
782
783#[cfg(feature = "experimental_traverse")]
784impl<'a> SomeRecord<'a> for FdSelectRange4 {
785    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
786        RecordResolver {
787            name: "FdSelectRange4",
788            get_field: Box::new(move |idx, _data| match idx {
789                0usize => Some(Field::new("first", self.first())),
790                1usize => Some(Field::new("fd", self.fd())),
791                _ => None,
792            }),
793            data,
794        }
795    }
796}
797
798/// Charset with custom glyph id to string id mappings.
799#[derive(Clone)]
800pub enum CustomCharset<'a> {
801    Format0(CharsetFormat0<'a>),
802    Format1(CharsetFormat1<'a>),
803    Format2(CharsetFormat2<'a>),
804}
805
806impl Default for CustomCharset<'_> {
807    fn default() -> Self {
808        Self::Format0(Default::default())
809    }
810}
811
812impl<'a> CustomCharset<'a> {
813    ///Return the `FontData` used to resolve offsets for this table.
814    pub fn offset_data(&self) -> FontData<'a> {
815        match self {
816            Self::Format0(item) => item.offset_data(),
817            Self::Format1(item) => item.offset_data(),
818            Self::Format2(item) => item.offset_data(),
819        }
820    }
821
822    /// Format; =0
823    pub fn format(&self) -> u8 {
824        match self {
825            Self::Format0(item) => item.format(),
826            Self::Format1(item) => item.format(),
827            Self::Format2(item) => item.format(),
828        }
829    }
830}
831
832impl ReadArgs for CustomCharset<'_> {
833    type Args = ();
834}
835
836impl<'a> FontRead<'a> for CustomCharset<'a> {
837    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
838        let format: u8 = data.read_at(0usize)?;
839        match format {
840            CharsetFormat0::FORMAT => Ok(Self::Format0(FontRead::read(data)?)),
841            CharsetFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
842            CharsetFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
843            other => Err(ReadError::InvalidFormat(other.into())),
844        }
845    }
846}
847
848impl<'a> MinByteRange<'a> for CustomCharset<'a> {
849    fn min_byte_range(&self) -> Range<usize> {
850        match self {
851            Self::Format0(item) => item.min_byte_range(),
852            Self::Format1(item) => item.min_byte_range(),
853            Self::Format2(item) => item.min_byte_range(),
854        }
855    }
856    fn min_table_bytes(&self) -> &'a [u8] {
857        match self {
858            Self::Format0(item) => item.min_table_bytes(),
859            Self::Format1(item) => item.min_table_bytes(),
860            Self::Format2(item) => item.min_table_bytes(),
861        }
862    }
863}
864
865#[cfg(feature = "experimental_traverse")]
866impl<'a> CustomCharset<'a> {
867    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
868        match self {
869            Self::Format0(table) => table,
870            Self::Format1(table) => table,
871            Self::Format2(table) => table,
872        }
873    }
874}
875
876#[cfg(feature = "experimental_traverse")]
877impl std::fmt::Debug for CustomCharset<'_> {
878    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
879        self.dyn_inner().fmt(f)
880    }
881}
882
883#[cfg(feature = "experimental_traverse")]
884impl<'a> SomeTable<'a> for CustomCharset<'a> {
885    fn type_name(&self) -> &str {
886        self.dyn_inner().type_name()
887    }
888    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
889        self.dyn_inner().get_field(idx)
890    }
891}
892
893impl Format<u8> for CharsetFormat0<'_> {
894    const FORMAT: u8 = 0;
895}
896
897impl<'a> MinByteRange<'a> for CharsetFormat0<'a> {
898    fn min_byte_range(&self) -> Range<usize> {
899        0..self.glyph_byte_range().end
900    }
901    fn min_table_bytes(&self) -> &'a [u8] {
902        let range = self.min_byte_range();
903        self.data.as_bytes().get(range).unwrap_or_default()
904    }
905}
906
907impl ReadArgs for CharsetFormat0<'_> {
908    type Args = ();
909}
910
911impl<'a> FontRead<'a> for CharsetFormat0<'a> {
912    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
913        #[allow(clippy::absurd_extreme_comparisons)]
914        if data.len() < Self::MIN_SIZE {
915            return Err(ReadError::OutOfBounds);
916        }
917        Ok(Self { data })
918    }
919}
920
921/// Charset format 0.
922#[derive(Clone)]
923pub struct CharsetFormat0<'a> {
924    data: FontData<'a>,
925}
926
927#[allow(clippy::needless_lifetimes)]
928impl<'a> CharsetFormat0<'a> {
929    pub const MIN_SIZE: usize = u8::RAW_BYTE_LEN;
930    basic_table_impls!(impl_the_methods);
931
932    /// Format; =0
933    pub fn format(&self) -> u8 {
934        let range = self.format_byte_range();
935        self.data.read_at(range.start).ok().unwrap()
936    }
937
938    /// Glyph name array.
939    pub fn glyph(&self) -> &'a [BigEndian<u16>] {
940        let range = self.glyph_byte_range();
941        self.data.read_array(range).ok().unwrap_or_default()
942    }
943
944    pub fn format_byte_range(&self) -> Range<usize> {
945        let start = 0;
946        let end = start + u8::RAW_BYTE_LEN;
947        start..end
948    }
949
950    pub fn glyph_byte_range(&self) -> Range<usize> {
951        let start = self.format_byte_range().end;
952        let end =
953            start + self.data.len().saturating_sub(start) / u16::RAW_BYTE_LEN * u16::RAW_BYTE_LEN;
954        start..end
955    }
956}
957
958const _: () = assert!(FontData::default_data_long_enough(CharsetFormat0::MIN_SIZE));
959
960impl Default for CharsetFormat0<'_> {
961    fn default() -> Self {
962        Self {
963            data: FontData::default_table_data(),
964        }
965    }
966}
967
968#[cfg(feature = "experimental_traverse")]
969impl<'a> SomeTable<'a> for CharsetFormat0<'a> {
970    fn type_name(&self) -> &str {
971        "CharsetFormat0"
972    }
973    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
974        match idx {
975            0usize => Some(Field::new("format", self.format())),
976            1usize => Some(Field::new("glyph", self.glyph())),
977            _ => None,
978        }
979    }
980}
981
982#[cfg(feature = "experimental_traverse")]
983#[allow(clippy::needless_lifetimes)]
984impl<'a> std::fmt::Debug for CharsetFormat0<'a> {
985    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
986        (self as &dyn SomeTable<'a>).fmt(f)
987    }
988}
989
990impl Format<u8> for CharsetFormat1<'_> {
991    const FORMAT: u8 = 1;
992}
993
994impl<'a> MinByteRange<'a> for CharsetFormat1<'a> {
995    fn min_byte_range(&self) -> Range<usize> {
996        0..self.ranges_byte_range().end
997    }
998    fn min_table_bytes(&self) -> &'a [u8] {
999        let range = self.min_byte_range();
1000        self.data.as_bytes().get(range).unwrap_or_default()
1001    }
1002}
1003
1004impl ReadArgs for CharsetFormat1<'_> {
1005    type Args = ();
1006}
1007
1008impl<'a> FontRead<'a> for CharsetFormat1<'a> {
1009    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1010        #[allow(clippy::absurd_extreme_comparisons)]
1011        if data.len() < Self::MIN_SIZE {
1012            return Err(ReadError::OutOfBounds);
1013        }
1014        Ok(Self { data })
1015    }
1016}
1017
1018/// Charset format 1.
1019#[derive(Clone)]
1020pub struct CharsetFormat1<'a> {
1021    data: FontData<'a>,
1022}
1023
1024#[allow(clippy::needless_lifetimes)]
1025impl<'a> CharsetFormat1<'a> {
1026    pub const MIN_SIZE: usize = u8::RAW_BYTE_LEN;
1027    basic_table_impls!(impl_the_methods);
1028
1029    /// Format; =1
1030    pub fn format(&self) -> u8 {
1031        let range = self.format_byte_range();
1032        self.data.read_at(range.start).ok().unwrap()
1033    }
1034
1035    /// Range1 array.
1036    pub fn ranges(&self) -> &'a [CharsetRange1] {
1037        let range = self.ranges_byte_range();
1038        self.data.read_array(range).ok().unwrap_or_default()
1039    }
1040
1041    pub fn format_byte_range(&self) -> Range<usize> {
1042        let start = 0;
1043        let end = start + u8::RAW_BYTE_LEN;
1044        start..end
1045    }
1046
1047    pub fn ranges_byte_range(&self) -> Range<usize> {
1048        let start = self.format_byte_range().end;
1049        let end = start
1050            + self.data.len().saturating_sub(start) / CharsetRange1::RAW_BYTE_LEN
1051                * CharsetRange1::RAW_BYTE_LEN;
1052        start..end
1053    }
1054}
1055
1056const _: () = assert!(FontData::default_data_long_enough(CharsetFormat1::MIN_SIZE));
1057
1058impl Default for CharsetFormat1<'_> {
1059    fn default() -> Self {
1060        Self {
1061            data: FontData::default_format_1_u8_table_data(),
1062        }
1063    }
1064}
1065
1066#[cfg(feature = "experimental_traverse")]
1067impl<'a> SomeTable<'a> for CharsetFormat1<'a> {
1068    fn type_name(&self) -> &str {
1069        "CharsetFormat1"
1070    }
1071    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1072        match idx {
1073            0usize => Some(Field::new("format", self.format())),
1074            1usize => Some(Field::new(
1075                "ranges",
1076                traversal::FieldType::array_of_records(
1077                    stringify!(CharsetRange1),
1078                    self.ranges(),
1079                    self.offset_data(),
1080                ),
1081            )),
1082            _ => None,
1083        }
1084    }
1085}
1086
1087#[cfg(feature = "experimental_traverse")]
1088#[allow(clippy::needless_lifetimes)]
1089impl<'a> std::fmt::Debug for CharsetFormat1<'a> {
1090    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1091        (self as &dyn SomeTable<'a>).fmt(f)
1092    }
1093}
1094
1095/// Range struct for Charset format 1.
1096#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1097#[repr(C)]
1098#[repr(packed)]
1099pub struct CharsetRange1 {
1100    /// First glyph in range.
1101    pub first: BigEndian<u16>,
1102    /// Glyphs left in range (excluding first).
1103    pub n_left: u8,
1104}
1105
1106impl CharsetRange1 {
1107    /// First glyph in range.
1108    pub fn first(&self) -> u16 {
1109        self.first.get()
1110    }
1111
1112    /// Glyphs left in range (excluding first).
1113    pub fn n_left(&self) -> u8 {
1114        self.n_left
1115    }
1116}
1117
1118impl FixedSize for CharsetRange1 {
1119    const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u8::RAW_BYTE_LEN;
1120}
1121
1122#[cfg(feature = "experimental_traverse")]
1123impl<'a> SomeRecord<'a> for CharsetRange1 {
1124    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1125        RecordResolver {
1126            name: "CharsetRange1",
1127            get_field: Box::new(move |idx, _data| match idx {
1128                0usize => Some(Field::new("first", self.first())),
1129                1usize => Some(Field::new("n_left", self.n_left())),
1130                _ => None,
1131            }),
1132            data,
1133        }
1134    }
1135}
1136
1137impl Format<u8> for CharsetFormat2<'_> {
1138    const FORMAT: u8 = 2;
1139}
1140
1141impl<'a> MinByteRange<'a> for CharsetFormat2<'a> {
1142    fn min_byte_range(&self) -> Range<usize> {
1143        0..self.ranges_byte_range().end
1144    }
1145    fn min_table_bytes(&self) -> &'a [u8] {
1146        let range = self.min_byte_range();
1147        self.data.as_bytes().get(range).unwrap_or_default()
1148    }
1149}
1150
1151impl ReadArgs for CharsetFormat2<'_> {
1152    type Args = ();
1153}
1154
1155impl<'a> FontRead<'a> for CharsetFormat2<'a> {
1156    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1157        #[allow(clippy::absurd_extreme_comparisons)]
1158        if data.len() < Self::MIN_SIZE {
1159            return Err(ReadError::OutOfBounds);
1160        }
1161        Ok(Self { data })
1162    }
1163}
1164
1165/// Charset format 2.
1166#[derive(Clone)]
1167pub struct CharsetFormat2<'a> {
1168    data: FontData<'a>,
1169}
1170
1171#[allow(clippy::needless_lifetimes)]
1172impl<'a> CharsetFormat2<'a> {
1173    pub const MIN_SIZE: usize = u8::RAW_BYTE_LEN;
1174    basic_table_impls!(impl_the_methods);
1175
1176    /// Format; =2
1177    pub fn format(&self) -> u8 {
1178        let range = self.format_byte_range();
1179        self.data.read_at(range.start).ok().unwrap()
1180    }
1181
1182    /// Range2 array.
1183    pub fn ranges(&self) -> &'a [CharsetRange2] {
1184        let range = self.ranges_byte_range();
1185        self.data.read_array(range).ok().unwrap_or_default()
1186    }
1187
1188    pub fn format_byte_range(&self) -> Range<usize> {
1189        let start = 0;
1190        let end = start + u8::RAW_BYTE_LEN;
1191        start..end
1192    }
1193
1194    pub fn ranges_byte_range(&self) -> Range<usize> {
1195        let start = self.format_byte_range().end;
1196        let end = start
1197            + self.data.len().saturating_sub(start) / CharsetRange2::RAW_BYTE_LEN
1198                * CharsetRange2::RAW_BYTE_LEN;
1199        start..end
1200    }
1201}
1202
1203#[cfg(feature = "experimental_traverse")]
1204impl<'a> SomeTable<'a> for CharsetFormat2<'a> {
1205    fn type_name(&self) -> &str {
1206        "CharsetFormat2"
1207    }
1208    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1209        match idx {
1210            0usize => Some(Field::new("format", self.format())),
1211            1usize => Some(Field::new(
1212                "ranges",
1213                traversal::FieldType::array_of_records(
1214                    stringify!(CharsetRange2),
1215                    self.ranges(),
1216                    self.offset_data(),
1217                ),
1218            )),
1219            _ => None,
1220        }
1221    }
1222}
1223
1224#[cfg(feature = "experimental_traverse")]
1225#[allow(clippy::needless_lifetimes)]
1226impl<'a> std::fmt::Debug for CharsetFormat2<'a> {
1227    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1228        (self as &dyn SomeTable<'a>).fmt(f)
1229    }
1230}
1231
1232/// Range struct for Charset format 2.
1233#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1234#[repr(C)]
1235#[repr(packed)]
1236pub struct CharsetRange2 {
1237    /// First glyph in range.
1238    pub first: BigEndian<u16>,
1239    /// Glyphs left in range (excluding first).
1240    pub n_left: BigEndian<u16>,
1241}
1242
1243impl CharsetRange2 {
1244    /// First glyph in range.
1245    pub fn first(&self) -> u16 {
1246        self.first.get()
1247    }
1248
1249    /// Glyphs left in range (excluding first).
1250    pub fn n_left(&self) -> u16 {
1251        self.n_left.get()
1252    }
1253}
1254
1255impl FixedSize for CharsetRange2 {
1256    const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
1257}
1258
1259#[cfg(feature = "experimental_traverse")]
1260impl<'a> SomeRecord<'a> for CharsetRange2 {
1261    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1262        RecordResolver {
1263            name: "CharsetRange2",
1264            get_field: Box::new(move |idx, _data| match idx {
1265                0usize => Some(Field::new("first", self.first())),
1266                1usize => Some(Field::new("n_left", self.n_left())),
1267                _ => None,
1268            }),
1269            data,
1270        }
1271    }
1272}
1273
1274/// Range struct for Encoding format 1.
1275#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1276#[repr(C)]
1277#[repr(packed)]
1278pub struct EncodingRange1 {
1279    /// First code in range.
1280    pub first: u8,
1281    /// Codes left in range (excluding first).
1282    pub n_left: u8,
1283}
1284
1285impl EncodingRange1 {
1286    /// First code in range.
1287    pub fn first(&self) -> u8 {
1288        self.first
1289    }
1290
1291    /// Codes left in range (excluding first).
1292    pub fn n_left(&self) -> u8 {
1293        self.n_left
1294    }
1295}
1296
1297impl FixedSize for EncodingRange1 {
1298    const RAW_BYTE_LEN: usize = u8::RAW_BYTE_LEN + u8::RAW_BYTE_LEN;
1299}
1300
1301#[cfg(feature = "experimental_traverse")]
1302impl<'a> SomeRecord<'a> for EncodingRange1 {
1303    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1304        RecordResolver {
1305            name: "EncodingRange1",
1306            get_field: Box::new(move |idx, _data| match idx {
1307                0usize => Some(Field::new("first", self.first())),
1308                1usize => Some(Field::new("n_left", self.n_left())),
1309                _ => None,
1310            }),
1311            data,
1312        }
1313    }
1314}
1315
1316/// Supplemental encoding record.
1317#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1318#[repr(C)]
1319#[repr(packed)]
1320pub struct EncodingSupplement {
1321    /// Encoding.
1322    pub code: u8,
1323    /// Name.
1324    pub glyph: BigEndian<u16>,
1325}
1326
1327impl EncodingSupplement {
1328    /// Encoding.
1329    pub fn code(&self) -> u8 {
1330        self.code
1331    }
1332
1333    /// Name.
1334    pub fn glyph(&self) -> u16 {
1335        self.glyph.get()
1336    }
1337}
1338
1339impl FixedSize for EncodingSupplement {
1340    const RAW_BYTE_LEN: usize = u8::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
1341}
1342
1343#[cfg(feature = "experimental_traverse")]
1344impl<'a> SomeRecord<'a> for EncodingSupplement {
1345    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1346        RecordResolver {
1347            name: "EncodingSupplement",
1348            get_field: Box::new(move |idx, _data| match idx {
1349                0usize => Some(Field::new("code", self.code())),
1350                1usize => Some(Field::new("glyph", self.glyph())),
1351                _ => None,
1352            }),
1353            data,
1354        }
1355    }
1356}