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