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