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