1#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8impl<'a> MinByteRange<'a> for Cmap<'a> {
9 fn min_byte_range(&self) -> Range<usize> {
10 0..self.encoding_records_byte_range().end
11 }
12 fn min_table_bytes(&self) -> &'a [u8] {
13 let range = self.min_byte_range();
14 self.data.as_bytes().get(range).unwrap_or_default()
15 }
16}
17
18impl TopLevelTable for Cmap<'_> {
19 const TAG: Tag = Tag::new(b"cmap");
21}
22
23impl<'a> FontRead<'a> for Cmap<'a> {
24 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
25 #[allow(clippy::absurd_extreme_comparisons)]
26 if data.len() < Self::MIN_SIZE {
27 return Err(ReadError::OutOfBounds);
28 }
29 Ok(Self { data })
30 }
31}
32
33#[derive(Clone)]
35pub struct Cmap<'a> {
36 data: FontData<'a>,
37}
38
39#[allow(clippy::needless_lifetimes)]
40impl<'a> Cmap<'a> {
41 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
42 basic_table_impls!(impl_the_methods);
43
44 pub fn version(&self) -> u16 {
46 let range = self.version_byte_range();
47 self.data.read_at(range.start).ok().unwrap()
48 }
49
50 pub fn num_tables(&self) -> u16 {
52 let range = self.num_tables_byte_range();
53 self.data.read_at(range.start).ok().unwrap()
54 }
55
56 pub fn encoding_records(&self) -> &'a [EncodingRecord] {
57 let range = self.encoding_records_byte_range();
58 self.data.read_array(range).ok().unwrap_or_default()
59 }
60
61 pub fn version_byte_range(&self) -> Range<usize> {
62 let start = 0;
63 let end = start + u16::RAW_BYTE_LEN;
64 start..end
65 }
66
67 pub fn num_tables_byte_range(&self) -> Range<usize> {
68 let start = self.version_byte_range().end;
69 let end = start + u16::RAW_BYTE_LEN;
70 start..end
71 }
72
73 pub fn encoding_records_byte_range(&self) -> Range<usize> {
74 let num_tables = self.num_tables();
75 let start = self.num_tables_byte_range().end;
76 let end =
77 start + (transforms::to_usize(num_tables)).saturating_mul(EncodingRecord::RAW_BYTE_LEN);
78 start..end
79 }
80}
81
82const _: () = assert!(FontData::default_data_long_enough(Cmap::MIN_SIZE));
83
84impl Default for Cmap<'_> {
85 fn default() -> Self {
86 Self {
87 data: FontData::default_table_data(),
88 }
89 }
90}
91
92#[cfg(feature = "experimental_traverse")]
93impl<'a> SomeTable<'a> for Cmap<'a> {
94 fn type_name(&self) -> &str {
95 "Cmap"
96 }
97 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
98 match idx {
99 0usize => Some(Field::new("version", self.version())),
100 1usize => Some(Field::new("num_tables", self.num_tables())),
101 2usize => Some(Field::new(
102 "encoding_records",
103 traversal::FieldType::array_of_records(
104 stringify!(EncodingRecord),
105 self.encoding_records(),
106 self.offset_data(),
107 ),
108 )),
109 _ => None,
110 }
111 }
112}
113
114#[cfg(feature = "experimental_traverse")]
115#[allow(clippy::needless_lifetimes)]
116impl<'a> std::fmt::Debug for Cmap<'a> {
117 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
118 (self as &dyn SomeTable<'a>).fmt(f)
119 }
120}
121
122#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
124#[repr(C)]
125#[repr(packed)]
126pub struct EncodingRecord {
127 pub platform_id: BigEndian<PlatformId>,
129 pub encoding_id: BigEndian<u16>,
131 pub subtable_offset: BigEndian<Offset32>,
134}
135
136impl EncodingRecord {
137 pub fn platform_id(&self) -> PlatformId {
139 self.platform_id.get()
140 }
141
142 pub fn encoding_id(&self) -> u16 {
144 self.encoding_id.get()
145 }
146
147 pub fn subtable_offset(&self) -> Offset32 {
150 self.subtable_offset.get()
151 }
152
153 pub fn subtable<'a>(&self, data: FontData<'a>) -> Result<CmapSubtable<'a>, ReadError> {
159 self.subtable_offset().resolve(data)
160 }
161}
162
163impl FixedSize for EncodingRecord {
164 const RAW_BYTE_LEN: usize =
165 PlatformId::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
166}
167
168#[cfg(feature = "experimental_traverse")]
169impl<'a> SomeRecord<'a> for EncodingRecord {
170 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
171 RecordResolver {
172 name: "EncodingRecord",
173 get_field: Box::new(move |idx, _data| match idx {
174 0usize => Some(Field::new("platform_id", self.platform_id())),
175 1usize => Some(Field::new("encoding_id", self.encoding_id())),
176 2usize => Some(Field::new(
177 "subtable_offset",
178 FieldType::offset(self.subtable_offset(), self.subtable(_data)),
179 )),
180 _ => None,
181 }),
182 data,
183 }
184 }
185}
186
187#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
189#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
190#[repr(u16)]
191#[allow(clippy::manual_non_exhaustive)]
192pub enum PlatformId {
193 #[default]
194 Unicode = 0,
195 Macintosh = 1,
196 ISO = 2,
197 Windows = 3,
198 Custom = 4,
199 #[doc(hidden)]
200 Unknown,
202}
203
204impl PlatformId {
205 pub fn new(raw: u16) -> Self {
209 match raw {
210 0 => Self::Unicode,
211 1 => Self::Macintosh,
212 2 => Self::ISO,
213 3 => Self::Windows,
214 4 => Self::Custom,
215 _ => Self::Unknown,
216 }
217 }
218}
219
220impl font_types::Scalar for PlatformId {
221 type Raw = <u16 as font_types::Scalar>::Raw;
222 fn to_raw(self) -> Self::Raw {
223 (self as u16).to_raw()
224 }
225 fn from_raw(raw: Self::Raw) -> Self {
226 let t = <u16>::from_raw(raw);
227 Self::new(t)
228 }
229}
230
231#[cfg(feature = "experimental_traverse")]
232impl<'a> From<PlatformId> for FieldType<'a> {
233 fn from(src: PlatformId) -> FieldType<'a> {
234 (src as u16).into()
235 }
236}
237
238#[derive(Clone)]
240pub enum CmapSubtable<'a> {
241 Format0(Cmap0<'a>),
242 Format2(Cmap2<'a>),
243 Format4(Cmap4<'a>),
244 Format6(Cmap6<'a>),
245 Format8(Cmap8<'a>),
246 Format10(Cmap10<'a>),
247 Format12(Cmap12<'a>),
248 Format13(Cmap13<'a>),
249 Format14(Cmap14<'a>),
250}
251
252impl Default for CmapSubtable<'_> {
253 fn default() -> Self {
254 Self::Format0(Default::default())
255 }
256}
257
258impl<'a> CmapSubtable<'a> {
259 pub fn offset_data(&self) -> FontData<'a> {
261 match self {
262 Self::Format0(item) => item.offset_data(),
263 Self::Format2(item) => item.offset_data(),
264 Self::Format4(item) => item.offset_data(),
265 Self::Format6(item) => item.offset_data(),
266 Self::Format8(item) => item.offset_data(),
267 Self::Format10(item) => item.offset_data(),
268 Self::Format12(item) => item.offset_data(),
269 Self::Format13(item) => item.offset_data(),
270 Self::Format14(item) => item.offset_data(),
271 }
272 }
273
274 pub fn format(&self) -> u16 {
276 match self {
277 Self::Format0(item) => item.format(),
278 Self::Format2(item) => item.format(),
279 Self::Format4(item) => item.format(),
280 Self::Format6(item) => item.format(),
281 Self::Format8(item) => item.format(),
282 Self::Format10(item) => item.format(),
283 Self::Format12(item) => item.format(),
284 Self::Format13(item) => item.format(),
285 Self::Format14(item) => item.format(),
286 }
287 }
288}
289
290impl<'a> FontRead<'a> for CmapSubtable<'a> {
291 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
292 let format: u16 = data.read_at(0usize)?;
293 match format {
294 Cmap0::FORMAT => Ok(Self::Format0(FontRead::read(data)?)),
295 Cmap2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
296 Cmap4::FORMAT => Ok(Self::Format4(FontRead::read(data)?)),
297 Cmap6::FORMAT => Ok(Self::Format6(FontRead::read(data)?)),
298 Cmap8::FORMAT => Ok(Self::Format8(FontRead::read(data)?)),
299 Cmap10::FORMAT => Ok(Self::Format10(FontRead::read(data)?)),
300 Cmap12::FORMAT => Ok(Self::Format12(FontRead::read(data)?)),
301 Cmap13::FORMAT => Ok(Self::Format13(FontRead::read(data)?)),
302 Cmap14::FORMAT => Ok(Self::Format14(FontRead::read(data)?)),
303 other => Err(ReadError::InvalidFormat(other.into())),
304 }
305 }
306}
307
308impl<'a> MinByteRange<'a> for CmapSubtable<'a> {
309 fn min_byte_range(&self) -> Range<usize> {
310 match self {
311 Self::Format0(item) => item.min_byte_range(),
312 Self::Format2(item) => item.min_byte_range(),
313 Self::Format4(item) => item.min_byte_range(),
314 Self::Format6(item) => item.min_byte_range(),
315 Self::Format8(item) => item.min_byte_range(),
316 Self::Format10(item) => item.min_byte_range(),
317 Self::Format12(item) => item.min_byte_range(),
318 Self::Format13(item) => item.min_byte_range(),
319 Self::Format14(item) => item.min_byte_range(),
320 }
321 }
322 fn min_table_bytes(&self) -> &'a [u8] {
323 match self {
324 Self::Format0(item) => item.min_table_bytes(),
325 Self::Format2(item) => item.min_table_bytes(),
326 Self::Format4(item) => item.min_table_bytes(),
327 Self::Format6(item) => item.min_table_bytes(),
328 Self::Format8(item) => item.min_table_bytes(),
329 Self::Format10(item) => item.min_table_bytes(),
330 Self::Format12(item) => item.min_table_bytes(),
331 Self::Format13(item) => item.min_table_bytes(),
332 Self::Format14(item) => item.min_table_bytes(),
333 }
334 }
335}
336
337#[cfg(feature = "experimental_traverse")]
338impl<'a> CmapSubtable<'a> {
339 fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
340 match self {
341 Self::Format0(table) => table,
342 Self::Format2(table) => table,
343 Self::Format4(table) => table,
344 Self::Format6(table) => table,
345 Self::Format8(table) => table,
346 Self::Format10(table) => table,
347 Self::Format12(table) => table,
348 Self::Format13(table) => table,
349 Self::Format14(table) => table,
350 }
351 }
352}
353
354#[cfg(feature = "experimental_traverse")]
355impl std::fmt::Debug for CmapSubtable<'_> {
356 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
357 self.dyn_inner().fmt(f)
358 }
359}
360
361#[cfg(feature = "experimental_traverse")]
362impl<'a> SomeTable<'a> for CmapSubtable<'a> {
363 fn type_name(&self) -> &str {
364 self.dyn_inner().type_name()
365 }
366 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
367 self.dyn_inner().get_field(idx)
368 }
369}
370
371impl Format<u16> for Cmap0<'_> {
372 const FORMAT: u16 = 0;
373}
374
375impl<'a> MinByteRange<'a> for Cmap0<'a> {
376 fn min_byte_range(&self) -> Range<usize> {
377 0..self.glyph_id_array_byte_range().end
378 }
379 fn min_table_bytes(&self) -> &'a [u8] {
380 let range = self.min_byte_range();
381 self.data.as_bytes().get(range).unwrap_or_default()
382 }
383}
384
385impl<'a> FontRead<'a> for Cmap0<'a> {
386 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
387 #[allow(clippy::absurd_extreme_comparisons)]
388 if data.len() < Self::MIN_SIZE {
389 return Err(ReadError::OutOfBounds);
390 }
391 Ok(Self { data })
392 }
393}
394
395#[derive(Clone)]
397pub struct Cmap0<'a> {
398 data: FontData<'a>,
399}
400
401#[allow(clippy::needless_lifetimes)]
402impl<'a> Cmap0<'a> {
403 pub const MIN_SIZE: usize =
404 (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u8::RAW_BYTE_LEN * 256_usize);
405 basic_table_impls!(impl_the_methods);
406
407 pub fn format(&self) -> u16 {
409 let range = self.format_byte_range();
410 self.data.read_at(range.start).ok().unwrap()
411 }
412
413 pub fn length(&self) -> u16 {
415 let range = self.length_byte_range();
416 self.data.read_at(range.start).ok().unwrap()
417 }
418
419 pub fn language(&self) -> u16 {
422 let range = self.language_byte_range();
423 self.data.read_at(range.start).ok().unwrap()
424 }
425
426 pub fn glyph_id_array(&self) -> &'a [u8] {
428 let range = self.glyph_id_array_byte_range();
429 self.data.read_array(range).ok().unwrap()
430 }
431
432 pub fn format_byte_range(&self) -> Range<usize> {
433 let start = 0;
434 let end = start + u16::RAW_BYTE_LEN;
435 start..end
436 }
437
438 pub fn length_byte_range(&self) -> Range<usize> {
439 let start = self.format_byte_range().end;
440 let end = start + u16::RAW_BYTE_LEN;
441 start..end
442 }
443
444 pub fn language_byte_range(&self) -> Range<usize> {
445 let start = self.length_byte_range().end;
446 let end = start + u16::RAW_BYTE_LEN;
447 start..end
448 }
449
450 pub fn glyph_id_array_byte_range(&self) -> Range<usize> {
451 let start = self.language_byte_range().end;
452 let end = start + (256_usize).saturating_mul(u8::RAW_BYTE_LEN);
453 start..end
454 }
455}
456
457const _: () = assert!(FontData::default_data_long_enough(Cmap0::MIN_SIZE));
458
459impl Default for Cmap0<'_> {
460 fn default() -> Self {
461 Self {
462 data: FontData::default_table_data(),
463 }
464 }
465}
466
467#[cfg(feature = "experimental_traverse")]
468impl<'a> SomeTable<'a> for Cmap0<'a> {
469 fn type_name(&self) -> &str {
470 "Cmap0"
471 }
472 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
473 match idx {
474 0usize => Some(Field::new("format", self.format())),
475 1usize => Some(Field::new("length", self.length())),
476 2usize => Some(Field::new("language", self.language())),
477 3usize => Some(Field::new("glyph_id_array", self.glyph_id_array())),
478 _ => None,
479 }
480 }
481}
482
483#[cfg(feature = "experimental_traverse")]
484#[allow(clippy::needless_lifetimes)]
485impl<'a> std::fmt::Debug for Cmap0<'a> {
486 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
487 (self as &dyn SomeTable<'a>).fmt(f)
488 }
489}
490
491impl Format<u16> for Cmap2<'_> {
492 const FORMAT: u16 = 2;
493}
494
495impl<'a> MinByteRange<'a> for Cmap2<'a> {
496 fn min_byte_range(&self) -> Range<usize> {
497 0..self.sub_header_keys_byte_range().end
498 }
499 fn min_table_bytes(&self) -> &'a [u8] {
500 let range = self.min_byte_range();
501 self.data.as_bytes().get(range).unwrap_or_default()
502 }
503}
504
505impl<'a> FontRead<'a> for Cmap2<'a> {
506 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
507 #[allow(clippy::absurd_extreme_comparisons)]
508 if data.len() < Self::MIN_SIZE {
509 return Err(ReadError::OutOfBounds);
510 }
511 Ok(Self { data })
512 }
513}
514
515#[derive(Clone)]
517pub struct Cmap2<'a> {
518 data: FontData<'a>,
519}
520
521#[allow(clippy::needless_lifetimes)]
522impl<'a> Cmap2<'a> {
523 pub const MIN_SIZE: usize =
524 (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN * 256_usize);
525 basic_table_impls!(impl_the_methods);
526
527 pub fn format(&self) -> u16 {
529 let range = self.format_byte_range();
530 self.data.read_at(range.start).ok().unwrap()
531 }
532
533 pub fn length(&self) -> u16 {
535 let range = self.length_byte_range();
536 self.data.read_at(range.start).ok().unwrap()
537 }
538
539 pub fn language(&self) -> u16 {
542 let range = self.language_byte_range();
543 self.data.read_at(range.start).ok().unwrap()
544 }
545
546 pub fn sub_header_keys(&self) -> &'a [BigEndian<u16>] {
549 let range = self.sub_header_keys_byte_range();
550 self.data.read_array(range).ok().unwrap()
551 }
552
553 pub fn format_byte_range(&self) -> Range<usize> {
554 let start = 0;
555 let end = start + u16::RAW_BYTE_LEN;
556 start..end
557 }
558
559 pub fn length_byte_range(&self) -> Range<usize> {
560 let start = self.format_byte_range().end;
561 let end = start + u16::RAW_BYTE_LEN;
562 start..end
563 }
564
565 pub fn language_byte_range(&self) -> Range<usize> {
566 let start = self.length_byte_range().end;
567 let end = start + u16::RAW_BYTE_LEN;
568 start..end
569 }
570
571 pub fn sub_header_keys_byte_range(&self) -> Range<usize> {
572 let start = self.language_byte_range().end;
573 let end = start + (256_usize).saturating_mul(u16::RAW_BYTE_LEN);
574 start..end
575 }
576}
577
578#[cfg(feature = "experimental_traverse")]
579impl<'a> SomeTable<'a> for Cmap2<'a> {
580 fn type_name(&self) -> &str {
581 "Cmap2"
582 }
583 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
584 match idx {
585 0usize => Some(Field::new("format", self.format())),
586 1usize => Some(Field::new("length", self.length())),
587 2usize => Some(Field::new("language", self.language())),
588 3usize => Some(Field::new("sub_header_keys", self.sub_header_keys())),
589 _ => None,
590 }
591 }
592}
593
594#[cfg(feature = "experimental_traverse")]
595#[allow(clippy::needless_lifetimes)]
596impl<'a> std::fmt::Debug for Cmap2<'a> {
597 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
598 (self as &dyn SomeTable<'a>).fmt(f)
599 }
600}
601
602#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
604#[repr(C)]
605#[repr(packed)]
606pub struct SubHeader {
607 pub first_code: BigEndian<u16>,
609 pub entry_count: BigEndian<u16>,
611 pub id_delta: BigEndian<i16>,
613 pub id_range_offset: BigEndian<u16>,
615}
616
617impl SubHeader {
618 pub fn first_code(&self) -> u16 {
620 self.first_code.get()
621 }
622
623 pub fn entry_count(&self) -> u16 {
625 self.entry_count.get()
626 }
627
628 pub fn id_delta(&self) -> i16 {
630 self.id_delta.get()
631 }
632
633 pub fn id_range_offset(&self) -> u16 {
635 self.id_range_offset.get()
636 }
637}
638
639impl FixedSize for SubHeader {
640 const RAW_BYTE_LEN: usize =
641 u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
642}
643
644#[cfg(feature = "experimental_traverse")]
645impl<'a> SomeRecord<'a> for SubHeader {
646 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
647 RecordResolver {
648 name: "SubHeader",
649 get_field: Box::new(move |idx, _data| match idx {
650 0usize => Some(Field::new("first_code", self.first_code())),
651 1usize => Some(Field::new("entry_count", self.entry_count())),
652 2usize => Some(Field::new("id_delta", self.id_delta())),
653 3usize => Some(Field::new("id_range_offset", self.id_range_offset())),
654 _ => None,
655 }),
656 data,
657 }
658 }
659}
660
661impl Format<u16> for Cmap4<'_> {
662 const FORMAT: u16 = 4;
663}
664
665impl<'a> MinByteRange<'a> for Cmap4<'a> {
666 fn min_byte_range(&self) -> Range<usize> {
667 0..self.glyph_id_array_byte_range().end
668 }
669 fn min_table_bytes(&self) -> &'a [u8] {
670 let range = self.min_byte_range();
671 self.data.as_bytes().get(range).unwrap_or_default()
672 }
673}
674
675impl<'a> FontRead<'a> for Cmap4<'a> {
676 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
677 #[allow(clippy::absurd_extreme_comparisons)]
678 if data.len() < Self::MIN_SIZE {
679 return Err(ReadError::OutOfBounds);
680 }
681 Ok(Self { data })
682 }
683}
684
685#[derive(Clone)]
687pub struct Cmap4<'a> {
688 data: FontData<'a>,
689}
690
691#[allow(clippy::needless_lifetimes)]
692impl<'a> Cmap4<'a> {
693 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
694 + u16::RAW_BYTE_LEN
695 + u16::RAW_BYTE_LEN
696 + u16::RAW_BYTE_LEN
697 + u16::RAW_BYTE_LEN
698 + u16::RAW_BYTE_LEN
699 + u16::RAW_BYTE_LEN
700 + u16::RAW_BYTE_LEN);
701 basic_table_impls!(impl_the_methods);
702
703 pub fn format(&self) -> u16 {
705 let range = self.format_byte_range();
706 self.data.read_at(range.start).ok().unwrap()
707 }
708
709 pub fn length(&self) -> u16 {
711 let range = self.length_byte_range();
712 self.data.read_at(range.start).ok().unwrap()
713 }
714
715 pub fn language(&self) -> u16 {
718 let range = self.language_byte_range();
719 self.data.read_at(range.start).ok().unwrap()
720 }
721
722 pub fn seg_count_x2(&self) -> u16 {
724 let range = self.seg_count_x2_byte_range();
725 self.data.read_at(range.start).ok().unwrap()
726 }
727
728 pub fn search_range(&self) -> u16 {
732 let range = self.search_range_byte_range();
733 self.data.read_at(range.start).ok().unwrap()
734 }
735
736 pub fn entry_selector(&self) -> u16 {
739 let range = self.entry_selector_byte_range();
740 self.data.read_at(range.start).ok().unwrap()
741 }
742
743 pub fn range_shift(&self) -> u16 {
746 let range = self.range_shift_byte_range();
747 self.data.read_at(range.start).ok().unwrap()
748 }
749
750 pub fn end_code(&self) -> &'a [BigEndian<u16>] {
752 let range = self.end_code_byte_range();
753 self.data.read_array(range).ok().unwrap_or_default()
754 }
755
756 pub fn start_code(&self) -> &'a [BigEndian<u16>] {
758 let range = self.start_code_byte_range();
759 self.data.read_array(range).ok().unwrap_or_default()
760 }
761
762 pub fn id_delta(&self) -> &'a [BigEndian<i16>] {
764 let range = self.id_delta_byte_range();
765 self.data.read_array(range).ok().unwrap_or_default()
766 }
767
768 pub fn id_range_offsets(&self) -> &'a [BigEndian<u16>] {
770 let range = self.id_range_offsets_byte_range();
771 self.data.read_array(range).ok().unwrap_or_default()
772 }
773
774 pub fn glyph_id_array(&self) -> &'a [BigEndian<u16>] {
776 let range = self.glyph_id_array_byte_range();
777 self.data.read_array(range).ok().unwrap_or_default()
778 }
779
780 pub fn format_byte_range(&self) -> Range<usize> {
781 let start = 0;
782 let end = start + u16::RAW_BYTE_LEN;
783 start..end
784 }
785
786 pub fn length_byte_range(&self) -> Range<usize> {
787 let start = self.format_byte_range().end;
788 let end = start + u16::RAW_BYTE_LEN;
789 start..end
790 }
791
792 pub fn language_byte_range(&self) -> Range<usize> {
793 let start = self.length_byte_range().end;
794 let end = start + u16::RAW_BYTE_LEN;
795 start..end
796 }
797
798 pub fn seg_count_x2_byte_range(&self) -> Range<usize> {
799 let start = self.language_byte_range().end;
800 let end = start + u16::RAW_BYTE_LEN;
801 start..end
802 }
803
804 pub fn search_range_byte_range(&self) -> Range<usize> {
805 let start = self.seg_count_x2_byte_range().end;
806 let end = start + u16::RAW_BYTE_LEN;
807 start..end
808 }
809
810 pub fn entry_selector_byte_range(&self) -> Range<usize> {
811 let start = self.search_range_byte_range().end;
812 let end = start + u16::RAW_BYTE_LEN;
813 start..end
814 }
815
816 pub fn range_shift_byte_range(&self) -> Range<usize> {
817 let start = self.entry_selector_byte_range().end;
818 let end = start + u16::RAW_BYTE_LEN;
819 start..end
820 }
821
822 pub fn end_code_byte_range(&self) -> Range<usize> {
823 let seg_count_x2 = self.seg_count_x2();
824 let start = self.range_shift_byte_range().end;
825 let end = start + (transforms::half(seg_count_x2)).saturating_mul(u16::RAW_BYTE_LEN);
826 start..end
827 }
828
829 pub fn reserved_pad_byte_range(&self) -> Range<usize> {
830 let start = self.end_code_byte_range().end;
831 let end = start + u16::RAW_BYTE_LEN;
832 start..end
833 }
834
835 pub fn start_code_byte_range(&self) -> Range<usize> {
836 let seg_count_x2 = self.seg_count_x2();
837 let start = self.reserved_pad_byte_range().end;
838 let end = start + (transforms::half(seg_count_x2)).saturating_mul(u16::RAW_BYTE_LEN);
839 start..end
840 }
841
842 pub fn id_delta_byte_range(&self) -> Range<usize> {
843 let seg_count_x2 = self.seg_count_x2();
844 let start = self.start_code_byte_range().end;
845 let end = start + (transforms::half(seg_count_x2)).saturating_mul(i16::RAW_BYTE_LEN);
846 start..end
847 }
848
849 pub fn id_range_offsets_byte_range(&self) -> Range<usize> {
850 let seg_count_x2 = self.seg_count_x2();
851 let start = self.id_delta_byte_range().end;
852 let end = start + (transforms::half(seg_count_x2)).saturating_mul(u16::RAW_BYTE_LEN);
853 start..end
854 }
855
856 pub fn glyph_id_array_byte_range(&self) -> Range<usize> {
857 let start = self.id_range_offsets_byte_range().end;
858 let end =
859 start + self.data.len().saturating_sub(start) / u16::RAW_BYTE_LEN * u16::RAW_BYTE_LEN;
860 start..end
861 }
862}
863
864#[cfg(feature = "experimental_traverse")]
865impl<'a> SomeTable<'a> for Cmap4<'a> {
866 fn type_name(&self) -> &str {
867 "Cmap4"
868 }
869 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
870 match idx {
871 0usize => Some(Field::new("format", self.format())),
872 1usize => Some(Field::new("length", self.length())),
873 2usize => Some(Field::new("language", self.language())),
874 3usize => Some(Field::new("seg_count_x2", self.seg_count_x2())),
875 4usize => Some(Field::new("search_range", self.search_range())),
876 5usize => Some(Field::new("entry_selector", self.entry_selector())),
877 6usize => Some(Field::new("range_shift", self.range_shift())),
878 7usize => Some(Field::new("end_code", self.end_code())),
879 8usize => Some(Field::new("start_code", self.start_code())),
880 9usize => Some(Field::new("id_delta", self.id_delta())),
881 10usize => Some(Field::new("id_range_offsets", self.id_range_offsets())),
882 11usize => Some(Field::new("glyph_id_array", self.glyph_id_array())),
883 _ => None,
884 }
885 }
886}
887
888#[cfg(feature = "experimental_traverse")]
889#[allow(clippy::needless_lifetimes)]
890impl<'a> std::fmt::Debug for Cmap4<'a> {
891 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
892 (self as &dyn SomeTable<'a>).fmt(f)
893 }
894}
895
896impl Format<u16> for Cmap6<'_> {
897 const FORMAT: u16 = 6;
898}
899
900impl<'a> MinByteRange<'a> for Cmap6<'a> {
901 fn min_byte_range(&self) -> Range<usize> {
902 0..self.glyph_id_array_byte_range().end
903 }
904 fn min_table_bytes(&self) -> &'a [u8] {
905 let range = self.min_byte_range();
906 self.data.as_bytes().get(range).unwrap_or_default()
907 }
908}
909
910impl<'a> FontRead<'a> for Cmap6<'a> {
911 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
912 #[allow(clippy::absurd_extreme_comparisons)]
913 if data.len() < Self::MIN_SIZE {
914 return Err(ReadError::OutOfBounds);
915 }
916 Ok(Self { data })
917 }
918}
919
920#[derive(Clone)]
922pub struct Cmap6<'a> {
923 data: FontData<'a>,
924}
925
926#[allow(clippy::needless_lifetimes)]
927impl<'a> Cmap6<'a> {
928 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
929 + u16::RAW_BYTE_LEN
930 + u16::RAW_BYTE_LEN
931 + u16::RAW_BYTE_LEN
932 + u16::RAW_BYTE_LEN);
933 basic_table_impls!(impl_the_methods);
934
935 pub fn format(&self) -> u16 {
937 let range = self.format_byte_range();
938 self.data.read_at(range.start).ok().unwrap()
939 }
940
941 pub fn length(&self) -> u16 {
943 let range = self.length_byte_range();
944 self.data.read_at(range.start).ok().unwrap()
945 }
946
947 pub fn language(&self) -> u16 {
950 let range = self.language_byte_range();
951 self.data.read_at(range.start).ok().unwrap()
952 }
953
954 pub fn first_code(&self) -> u16 {
956 let range = self.first_code_byte_range();
957 self.data.read_at(range.start).ok().unwrap()
958 }
959
960 pub fn entry_count(&self) -> u16 {
962 let range = self.entry_count_byte_range();
963 self.data.read_at(range.start).ok().unwrap()
964 }
965
966 pub fn glyph_id_array(&self) -> &'a [BigEndian<u16>] {
968 let range = self.glyph_id_array_byte_range();
969 self.data.read_array(range).ok().unwrap_or_default()
970 }
971
972 pub fn format_byte_range(&self) -> Range<usize> {
973 let start = 0;
974 let end = start + u16::RAW_BYTE_LEN;
975 start..end
976 }
977
978 pub fn length_byte_range(&self) -> Range<usize> {
979 let start = self.format_byte_range().end;
980 let end = start + u16::RAW_BYTE_LEN;
981 start..end
982 }
983
984 pub fn language_byte_range(&self) -> Range<usize> {
985 let start = self.length_byte_range().end;
986 let end = start + u16::RAW_BYTE_LEN;
987 start..end
988 }
989
990 pub fn first_code_byte_range(&self) -> Range<usize> {
991 let start = self.language_byte_range().end;
992 let end = start + u16::RAW_BYTE_LEN;
993 start..end
994 }
995
996 pub fn entry_count_byte_range(&self) -> Range<usize> {
997 let start = self.first_code_byte_range().end;
998 let end = start + u16::RAW_BYTE_LEN;
999 start..end
1000 }
1001
1002 pub fn glyph_id_array_byte_range(&self) -> Range<usize> {
1003 let entry_count = self.entry_count();
1004 let start = self.entry_count_byte_range().end;
1005 let end = start + (transforms::to_usize(entry_count)).saturating_mul(u16::RAW_BYTE_LEN);
1006 start..end
1007 }
1008}
1009
1010#[cfg(feature = "experimental_traverse")]
1011impl<'a> SomeTable<'a> for Cmap6<'a> {
1012 fn type_name(&self) -> &str {
1013 "Cmap6"
1014 }
1015 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1016 match idx {
1017 0usize => Some(Field::new("format", self.format())),
1018 1usize => Some(Field::new("length", self.length())),
1019 2usize => Some(Field::new("language", self.language())),
1020 3usize => Some(Field::new("first_code", self.first_code())),
1021 4usize => Some(Field::new("entry_count", self.entry_count())),
1022 5usize => Some(Field::new("glyph_id_array", self.glyph_id_array())),
1023 _ => None,
1024 }
1025 }
1026}
1027
1028#[cfg(feature = "experimental_traverse")]
1029#[allow(clippy::needless_lifetimes)]
1030impl<'a> std::fmt::Debug for Cmap6<'a> {
1031 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1032 (self as &dyn SomeTable<'a>).fmt(f)
1033 }
1034}
1035
1036impl Format<u16> for Cmap8<'_> {
1037 const FORMAT: u16 = 8;
1038}
1039
1040impl<'a> MinByteRange<'a> for Cmap8<'a> {
1041 fn min_byte_range(&self) -> Range<usize> {
1042 0..self.groups_byte_range().end
1043 }
1044 fn min_table_bytes(&self) -> &'a [u8] {
1045 let range = self.min_byte_range();
1046 self.data.as_bytes().get(range).unwrap_or_default()
1047 }
1048}
1049
1050impl<'a> FontRead<'a> for Cmap8<'a> {
1051 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1052 #[allow(clippy::absurd_extreme_comparisons)]
1053 if data.len() < Self::MIN_SIZE {
1054 return Err(ReadError::OutOfBounds);
1055 }
1056 Ok(Self { data })
1057 }
1058}
1059
1060#[derive(Clone)]
1062pub struct Cmap8<'a> {
1063 data: FontData<'a>,
1064}
1065
1066#[allow(clippy::needless_lifetimes)]
1067impl<'a> Cmap8<'a> {
1068 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1069 + u16::RAW_BYTE_LEN
1070 + u32::RAW_BYTE_LEN
1071 + u32::RAW_BYTE_LEN
1072 + u8::RAW_BYTE_LEN * 8192_usize
1073 + u32::RAW_BYTE_LEN);
1074 basic_table_impls!(impl_the_methods);
1075
1076 pub fn format(&self) -> u16 {
1078 let range = self.format_byte_range();
1079 self.data.read_at(range.start).ok().unwrap()
1080 }
1081
1082 pub fn length(&self) -> u32 {
1084 let range = self.length_byte_range();
1085 self.data.read_at(range.start).ok().unwrap()
1086 }
1087
1088 pub fn language(&self) -> u32 {
1091 let range = self.language_byte_range();
1092 self.data.read_at(range.start).ok().unwrap()
1093 }
1094
1095 pub fn is32(&self) -> &'a [u8] {
1099 let range = self.is32_byte_range();
1100 self.data.read_array(range).ok().unwrap()
1101 }
1102
1103 pub fn num_groups(&self) -> u32 {
1105 let range = self.num_groups_byte_range();
1106 self.data.read_at(range.start).ok().unwrap()
1107 }
1108
1109 pub fn groups(&self) -> &'a [SequentialMapGroup] {
1111 let range = self.groups_byte_range();
1112 self.data.read_array(range).ok().unwrap_or_default()
1113 }
1114
1115 pub fn format_byte_range(&self) -> Range<usize> {
1116 let start = 0;
1117 let end = start + u16::RAW_BYTE_LEN;
1118 start..end
1119 }
1120
1121 pub fn reserved_byte_range(&self) -> Range<usize> {
1122 let start = self.format_byte_range().end;
1123 let end = start + u16::RAW_BYTE_LEN;
1124 start..end
1125 }
1126
1127 pub fn length_byte_range(&self) -> Range<usize> {
1128 let start = self.reserved_byte_range().end;
1129 let end = start + u32::RAW_BYTE_LEN;
1130 start..end
1131 }
1132
1133 pub fn language_byte_range(&self) -> Range<usize> {
1134 let start = self.length_byte_range().end;
1135 let end = start + u32::RAW_BYTE_LEN;
1136 start..end
1137 }
1138
1139 pub fn is32_byte_range(&self) -> Range<usize> {
1140 let start = self.language_byte_range().end;
1141 let end = start + (8192_usize).saturating_mul(u8::RAW_BYTE_LEN);
1142 start..end
1143 }
1144
1145 pub fn num_groups_byte_range(&self) -> Range<usize> {
1146 let start = self.is32_byte_range().end;
1147 let end = start + u32::RAW_BYTE_LEN;
1148 start..end
1149 }
1150
1151 pub fn groups_byte_range(&self) -> Range<usize> {
1152 let num_groups = self.num_groups();
1153 let start = self.num_groups_byte_range().end;
1154 let end = start
1155 + (transforms::to_usize(num_groups)).saturating_mul(SequentialMapGroup::RAW_BYTE_LEN);
1156 start..end
1157 }
1158}
1159
1160#[cfg(feature = "experimental_traverse")]
1161impl<'a> SomeTable<'a> for Cmap8<'a> {
1162 fn type_name(&self) -> &str {
1163 "Cmap8"
1164 }
1165 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1166 match idx {
1167 0usize => Some(Field::new("format", self.format())),
1168 1usize => Some(Field::new("length", self.length())),
1169 2usize => Some(Field::new("language", self.language())),
1170 3usize => Some(Field::new("is32", self.is32())),
1171 4usize => Some(Field::new("num_groups", self.num_groups())),
1172 5usize => Some(Field::new(
1173 "groups",
1174 traversal::FieldType::array_of_records(
1175 stringify!(SequentialMapGroup),
1176 self.groups(),
1177 self.offset_data(),
1178 ),
1179 )),
1180 _ => None,
1181 }
1182 }
1183}
1184
1185#[cfg(feature = "experimental_traverse")]
1186#[allow(clippy::needless_lifetimes)]
1187impl<'a> std::fmt::Debug for Cmap8<'a> {
1188 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1189 (self as &dyn SomeTable<'a>).fmt(f)
1190 }
1191}
1192
1193#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1195#[repr(C)]
1196#[repr(packed)]
1197pub struct SequentialMapGroup {
1198 pub start_char_code: BigEndian<u32>,
1203 pub end_char_code: BigEndian<u32>,
1206 pub start_glyph_id: BigEndian<u32>,
1208}
1209
1210impl SequentialMapGroup {
1211 pub fn start_char_code(&self) -> u32 {
1216 self.start_char_code.get()
1217 }
1218
1219 pub fn end_char_code(&self) -> u32 {
1222 self.end_char_code.get()
1223 }
1224
1225 pub fn start_glyph_id(&self) -> u32 {
1227 self.start_glyph_id.get()
1228 }
1229}
1230
1231impl FixedSize for SequentialMapGroup {
1232 const RAW_BYTE_LEN: usize = u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN;
1233}
1234
1235#[cfg(feature = "experimental_traverse")]
1236impl<'a> SomeRecord<'a> for SequentialMapGroup {
1237 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1238 RecordResolver {
1239 name: "SequentialMapGroup",
1240 get_field: Box::new(move |idx, _data| match idx {
1241 0usize => Some(Field::new("start_char_code", self.start_char_code())),
1242 1usize => Some(Field::new("end_char_code", self.end_char_code())),
1243 2usize => Some(Field::new("start_glyph_id", self.start_glyph_id())),
1244 _ => None,
1245 }),
1246 data,
1247 }
1248 }
1249}
1250
1251impl Format<u16> for Cmap10<'_> {
1252 const FORMAT: u16 = 10;
1253}
1254
1255impl<'a> MinByteRange<'a> for Cmap10<'a> {
1256 fn min_byte_range(&self) -> Range<usize> {
1257 0..self.glyph_id_array_byte_range().end
1258 }
1259 fn min_table_bytes(&self) -> &'a [u8] {
1260 let range = self.min_byte_range();
1261 self.data.as_bytes().get(range).unwrap_or_default()
1262 }
1263}
1264
1265impl<'a> FontRead<'a> for Cmap10<'a> {
1266 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1267 #[allow(clippy::absurd_extreme_comparisons)]
1268 if data.len() < Self::MIN_SIZE {
1269 return Err(ReadError::OutOfBounds);
1270 }
1271 Ok(Self { data })
1272 }
1273}
1274
1275#[derive(Clone)]
1277pub struct Cmap10<'a> {
1278 data: FontData<'a>,
1279}
1280
1281#[allow(clippy::needless_lifetimes)]
1282impl<'a> Cmap10<'a> {
1283 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1284 + u16::RAW_BYTE_LEN
1285 + u32::RAW_BYTE_LEN
1286 + u32::RAW_BYTE_LEN
1287 + u32::RAW_BYTE_LEN
1288 + u32::RAW_BYTE_LEN);
1289 basic_table_impls!(impl_the_methods);
1290
1291 pub fn format(&self) -> u16 {
1293 let range = self.format_byte_range();
1294 self.data.read_at(range.start).ok().unwrap()
1295 }
1296
1297 pub fn length(&self) -> u32 {
1299 let range = self.length_byte_range();
1300 self.data.read_at(range.start).ok().unwrap()
1301 }
1302
1303 pub fn language(&self) -> u32 {
1306 let range = self.language_byte_range();
1307 self.data.read_at(range.start).ok().unwrap()
1308 }
1309
1310 pub fn start_char_code(&self) -> u32 {
1312 let range = self.start_char_code_byte_range();
1313 self.data.read_at(range.start).ok().unwrap()
1314 }
1315
1316 pub fn num_chars(&self) -> u32 {
1318 let range = self.num_chars_byte_range();
1319 self.data.read_at(range.start).ok().unwrap()
1320 }
1321
1322 pub fn glyph_id_array(&self) -> &'a [BigEndian<u16>] {
1324 let range = self.glyph_id_array_byte_range();
1325 self.data.read_array(range).ok().unwrap_or_default()
1326 }
1327
1328 pub fn format_byte_range(&self) -> Range<usize> {
1329 let start = 0;
1330 let end = start + u16::RAW_BYTE_LEN;
1331 start..end
1332 }
1333
1334 pub fn reserved_byte_range(&self) -> Range<usize> {
1335 let start = self.format_byte_range().end;
1336 let end = start + u16::RAW_BYTE_LEN;
1337 start..end
1338 }
1339
1340 pub fn length_byte_range(&self) -> Range<usize> {
1341 let start = self.reserved_byte_range().end;
1342 let end = start + u32::RAW_BYTE_LEN;
1343 start..end
1344 }
1345
1346 pub fn language_byte_range(&self) -> Range<usize> {
1347 let start = self.length_byte_range().end;
1348 let end = start + u32::RAW_BYTE_LEN;
1349 start..end
1350 }
1351
1352 pub fn start_char_code_byte_range(&self) -> Range<usize> {
1353 let start = self.language_byte_range().end;
1354 let end = start + u32::RAW_BYTE_LEN;
1355 start..end
1356 }
1357
1358 pub fn num_chars_byte_range(&self) -> Range<usize> {
1359 let start = self.start_char_code_byte_range().end;
1360 let end = start + u32::RAW_BYTE_LEN;
1361 start..end
1362 }
1363
1364 pub fn glyph_id_array_byte_range(&self) -> Range<usize> {
1365 let num_chars = self.num_chars();
1366 let start = self.num_chars_byte_range().end;
1367 let end = start + (transforms::to_usize(num_chars)).saturating_mul(u16::RAW_BYTE_LEN);
1368 start..end
1369 }
1370}
1371
1372#[cfg(feature = "experimental_traverse")]
1373impl<'a> SomeTable<'a> for Cmap10<'a> {
1374 fn type_name(&self) -> &str {
1375 "Cmap10"
1376 }
1377 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1378 match idx {
1379 0usize => Some(Field::new("format", self.format())),
1380 1usize => Some(Field::new("length", self.length())),
1381 2usize => Some(Field::new("language", self.language())),
1382 3usize => Some(Field::new("start_char_code", self.start_char_code())),
1383 4usize => Some(Field::new("num_chars", self.num_chars())),
1384 5usize => Some(Field::new("glyph_id_array", self.glyph_id_array())),
1385 _ => None,
1386 }
1387 }
1388}
1389
1390#[cfg(feature = "experimental_traverse")]
1391#[allow(clippy::needless_lifetimes)]
1392impl<'a> std::fmt::Debug for Cmap10<'a> {
1393 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1394 (self as &dyn SomeTable<'a>).fmt(f)
1395 }
1396}
1397
1398impl Format<u16> for Cmap12<'_> {
1399 const FORMAT: u16 = 12;
1400}
1401
1402impl<'a> MinByteRange<'a> for Cmap12<'a> {
1403 fn min_byte_range(&self) -> Range<usize> {
1404 0..self.groups_byte_range().end
1405 }
1406 fn min_table_bytes(&self) -> &'a [u8] {
1407 let range = self.min_byte_range();
1408 self.data.as_bytes().get(range).unwrap_or_default()
1409 }
1410}
1411
1412impl<'a> FontRead<'a> for Cmap12<'a> {
1413 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1414 #[allow(clippy::absurd_extreme_comparisons)]
1415 if data.len() < Self::MIN_SIZE {
1416 return Err(ReadError::OutOfBounds);
1417 }
1418 Ok(Self { data })
1419 }
1420}
1421
1422#[derive(Clone)]
1424pub struct Cmap12<'a> {
1425 data: FontData<'a>,
1426}
1427
1428#[allow(clippy::needless_lifetimes)]
1429impl<'a> Cmap12<'a> {
1430 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1431 + u16::RAW_BYTE_LEN
1432 + u32::RAW_BYTE_LEN
1433 + u32::RAW_BYTE_LEN
1434 + u32::RAW_BYTE_LEN);
1435 basic_table_impls!(impl_the_methods);
1436
1437 pub fn format(&self) -> u16 {
1439 let range = self.format_byte_range();
1440 self.data.read_at(range.start).ok().unwrap()
1441 }
1442
1443 pub fn length(&self) -> u32 {
1445 let range = self.length_byte_range();
1446 self.data.read_at(range.start).ok().unwrap()
1447 }
1448
1449 pub fn language(&self) -> u32 {
1452 let range = self.language_byte_range();
1453 self.data.read_at(range.start).ok().unwrap()
1454 }
1455
1456 pub fn num_groups(&self) -> u32 {
1458 let range = self.num_groups_byte_range();
1459 self.data.read_at(range.start).ok().unwrap()
1460 }
1461
1462 pub fn groups(&self) -> &'a [SequentialMapGroup] {
1464 let range = self.groups_byte_range();
1465 self.data.read_array(range).ok().unwrap_or_default()
1466 }
1467
1468 pub fn format_byte_range(&self) -> Range<usize> {
1469 let start = 0;
1470 let end = start + u16::RAW_BYTE_LEN;
1471 start..end
1472 }
1473
1474 pub fn reserved_byte_range(&self) -> Range<usize> {
1475 let start = self.format_byte_range().end;
1476 let end = start + u16::RAW_BYTE_LEN;
1477 start..end
1478 }
1479
1480 pub fn length_byte_range(&self) -> Range<usize> {
1481 let start = self.reserved_byte_range().end;
1482 let end = start + u32::RAW_BYTE_LEN;
1483 start..end
1484 }
1485
1486 pub fn language_byte_range(&self) -> Range<usize> {
1487 let start = self.length_byte_range().end;
1488 let end = start + u32::RAW_BYTE_LEN;
1489 start..end
1490 }
1491
1492 pub fn num_groups_byte_range(&self) -> Range<usize> {
1493 let start = self.language_byte_range().end;
1494 let end = start + u32::RAW_BYTE_LEN;
1495 start..end
1496 }
1497
1498 pub fn groups_byte_range(&self) -> Range<usize> {
1499 let num_groups = self.num_groups();
1500 let start = self.num_groups_byte_range().end;
1501 let end = start
1502 + (transforms::to_usize(num_groups)).saturating_mul(SequentialMapGroup::RAW_BYTE_LEN);
1503 start..end
1504 }
1505}
1506
1507#[cfg(feature = "experimental_traverse")]
1508impl<'a> SomeTable<'a> for Cmap12<'a> {
1509 fn type_name(&self) -> &str {
1510 "Cmap12"
1511 }
1512 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1513 match idx {
1514 0usize => Some(Field::new("format", self.format())),
1515 1usize => Some(Field::new("length", self.length())),
1516 2usize => Some(Field::new("language", self.language())),
1517 3usize => Some(Field::new("num_groups", self.num_groups())),
1518 4usize => Some(Field::new(
1519 "groups",
1520 traversal::FieldType::array_of_records(
1521 stringify!(SequentialMapGroup),
1522 self.groups(),
1523 self.offset_data(),
1524 ),
1525 )),
1526 _ => None,
1527 }
1528 }
1529}
1530
1531#[cfg(feature = "experimental_traverse")]
1532#[allow(clippy::needless_lifetimes)]
1533impl<'a> std::fmt::Debug for Cmap12<'a> {
1534 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1535 (self as &dyn SomeTable<'a>).fmt(f)
1536 }
1537}
1538
1539impl Format<u16> for Cmap13<'_> {
1540 const FORMAT: u16 = 13;
1541}
1542
1543impl<'a> MinByteRange<'a> for Cmap13<'a> {
1544 fn min_byte_range(&self) -> Range<usize> {
1545 0..self.groups_byte_range().end
1546 }
1547 fn min_table_bytes(&self) -> &'a [u8] {
1548 let range = self.min_byte_range();
1549 self.data.as_bytes().get(range).unwrap_or_default()
1550 }
1551}
1552
1553impl<'a> FontRead<'a> for Cmap13<'a> {
1554 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1555 #[allow(clippy::absurd_extreme_comparisons)]
1556 if data.len() < Self::MIN_SIZE {
1557 return Err(ReadError::OutOfBounds);
1558 }
1559 Ok(Self { data })
1560 }
1561}
1562
1563#[derive(Clone)]
1565pub struct Cmap13<'a> {
1566 data: FontData<'a>,
1567}
1568
1569#[allow(clippy::needless_lifetimes)]
1570impl<'a> Cmap13<'a> {
1571 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1572 + u16::RAW_BYTE_LEN
1573 + u32::RAW_BYTE_LEN
1574 + u32::RAW_BYTE_LEN
1575 + u32::RAW_BYTE_LEN);
1576 basic_table_impls!(impl_the_methods);
1577
1578 pub fn format(&self) -> u16 {
1580 let range = self.format_byte_range();
1581 self.data.read_at(range.start).ok().unwrap()
1582 }
1583
1584 pub fn length(&self) -> u32 {
1586 let range = self.length_byte_range();
1587 self.data.read_at(range.start).ok().unwrap()
1588 }
1589
1590 pub fn language(&self) -> u32 {
1593 let range = self.language_byte_range();
1594 self.data.read_at(range.start).ok().unwrap()
1595 }
1596
1597 pub fn num_groups(&self) -> u32 {
1599 let range = self.num_groups_byte_range();
1600 self.data.read_at(range.start).ok().unwrap()
1601 }
1602
1603 pub fn groups(&self) -> &'a [ConstantMapGroup] {
1605 let range = self.groups_byte_range();
1606 self.data.read_array(range).ok().unwrap_or_default()
1607 }
1608
1609 pub fn format_byte_range(&self) -> Range<usize> {
1610 let start = 0;
1611 let end = start + u16::RAW_BYTE_LEN;
1612 start..end
1613 }
1614
1615 pub fn reserved_byte_range(&self) -> Range<usize> {
1616 let start = self.format_byte_range().end;
1617 let end = start + u16::RAW_BYTE_LEN;
1618 start..end
1619 }
1620
1621 pub fn length_byte_range(&self) -> Range<usize> {
1622 let start = self.reserved_byte_range().end;
1623 let end = start + u32::RAW_BYTE_LEN;
1624 start..end
1625 }
1626
1627 pub fn language_byte_range(&self) -> Range<usize> {
1628 let start = self.length_byte_range().end;
1629 let end = start + u32::RAW_BYTE_LEN;
1630 start..end
1631 }
1632
1633 pub fn num_groups_byte_range(&self) -> Range<usize> {
1634 let start = self.language_byte_range().end;
1635 let end = start + u32::RAW_BYTE_LEN;
1636 start..end
1637 }
1638
1639 pub fn groups_byte_range(&self) -> Range<usize> {
1640 let num_groups = self.num_groups();
1641 let start = self.num_groups_byte_range().end;
1642 let end = start
1643 + (transforms::to_usize(num_groups)).saturating_mul(ConstantMapGroup::RAW_BYTE_LEN);
1644 start..end
1645 }
1646}
1647
1648#[cfg(feature = "experimental_traverse")]
1649impl<'a> SomeTable<'a> for Cmap13<'a> {
1650 fn type_name(&self) -> &str {
1651 "Cmap13"
1652 }
1653 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1654 match idx {
1655 0usize => Some(Field::new("format", self.format())),
1656 1usize => Some(Field::new("length", self.length())),
1657 2usize => Some(Field::new("language", self.language())),
1658 3usize => Some(Field::new("num_groups", self.num_groups())),
1659 4usize => Some(Field::new(
1660 "groups",
1661 traversal::FieldType::array_of_records(
1662 stringify!(ConstantMapGroup),
1663 self.groups(),
1664 self.offset_data(),
1665 ),
1666 )),
1667 _ => None,
1668 }
1669 }
1670}
1671
1672#[cfg(feature = "experimental_traverse")]
1673#[allow(clippy::needless_lifetimes)]
1674impl<'a> std::fmt::Debug for Cmap13<'a> {
1675 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1676 (self as &dyn SomeTable<'a>).fmt(f)
1677 }
1678}
1679
1680#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1682#[repr(C)]
1683#[repr(packed)]
1684pub struct ConstantMapGroup {
1685 pub start_char_code: BigEndian<u32>,
1687 pub end_char_code: BigEndian<u32>,
1689 pub glyph_id: BigEndian<u32>,
1692}
1693
1694impl ConstantMapGroup {
1695 pub fn start_char_code(&self) -> u32 {
1697 self.start_char_code.get()
1698 }
1699
1700 pub fn end_char_code(&self) -> u32 {
1702 self.end_char_code.get()
1703 }
1704
1705 pub fn glyph_id(&self) -> u32 {
1708 self.glyph_id.get()
1709 }
1710}
1711
1712impl FixedSize for ConstantMapGroup {
1713 const RAW_BYTE_LEN: usize = u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN;
1714}
1715
1716#[cfg(feature = "experimental_traverse")]
1717impl<'a> SomeRecord<'a> for ConstantMapGroup {
1718 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1719 RecordResolver {
1720 name: "ConstantMapGroup",
1721 get_field: Box::new(move |idx, _data| match idx {
1722 0usize => Some(Field::new("start_char_code", self.start_char_code())),
1723 1usize => Some(Field::new("end_char_code", self.end_char_code())),
1724 2usize => Some(Field::new("glyph_id", self.glyph_id())),
1725 _ => None,
1726 }),
1727 data,
1728 }
1729 }
1730}
1731
1732impl Format<u16> for Cmap14<'_> {
1733 const FORMAT: u16 = 14;
1734}
1735
1736impl<'a> MinByteRange<'a> for Cmap14<'a> {
1737 fn min_byte_range(&self) -> Range<usize> {
1738 0..self.var_selector_byte_range().end
1739 }
1740 fn min_table_bytes(&self) -> &'a [u8] {
1741 let range = self.min_byte_range();
1742 self.data.as_bytes().get(range).unwrap_or_default()
1743 }
1744}
1745
1746impl<'a> FontRead<'a> for Cmap14<'a> {
1747 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1748 #[allow(clippy::absurd_extreme_comparisons)]
1749 if data.len() < Self::MIN_SIZE {
1750 return Err(ReadError::OutOfBounds);
1751 }
1752 Ok(Self { data })
1753 }
1754}
1755
1756#[derive(Clone)]
1758pub struct Cmap14<'a> {
1759 data: FontData<'a>,
1760}
1761
1762#[allow(clippy::needless_lifetimes)]
1763impl<'a> Cmap14<'a> {
1764 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
1765 basic_table_impls!(impl_the_methods);
1766
1767 pub fn format(&self) -> u16 {
1769 let range = self.format_byte_range();
1770 self.data.read_at(range.start).ok().unwrap()
1771 }
1772
1773 pub fn length(&self) -> u32 {
1775 let range = self.length_byte_range();
1776 self.data.read_at(range.start).ok().unwrap()
1777 }
1778
1779 pub fn num_var_selector_records(&self) -> u32 {
1781 let range = self.num_var_selector_records_byte_range();
1782 self.data.read_at(range.start).ok().unwrap()
1783 }
1784
1785 pub fn var_selector(&self) -> &'a [VariationSelector] {
1787 let range = self.var_selector_byte_range();
1788 self.data.read_array(range).ok().unwrap_or_default()
1789 }
1790
1791 pub fn format_byte_range(&self) -> Range<usize> {
1792 let start = 0;
1793 let end = start + u16::RAW_BYTE_LEN;
1794 start..end
1795 }
1796
1797 pub fn length_byte_range(&self) -> Range<usize> {
1798 let start = self.format_byte_range().end;
1799 let end = start + u32::RAW_BYTE_LEN;
1800 start..end
1801 }
1802
1803 pub fn num_var_selector_records_byte_range(&self) -> Range<usize> {
1804 let start = self.length_byte_range().end;
1805 let end = start + u32::RAW_BYTE_LEN;
1806 start..end
1807 }
1808
1809 pub fn var_selector_byte_range(&self) -> Range<usize> {
1810 let num_var_selector_records = self.num_var_selector_records();
1811 let start = self.num_var_selector_records_byte_range().end;
1812 let end = start
1813 + (transforms::to_usize(num_var_selector_records))
1814 .saturating_mul(VariationSelector::RAW_BYTE_LEN);
1815 start..end
1816 }
1817}
1818
1819#[cfg(feature = "experimental_traverse")]
1820impl<'a> SomeTable<'a> for Cmap14<'a> {
1821 fn type_name(&self) -> &str {
1822 "Cmap14"
1823 }
1824 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1825 match idx {
1826 0usize => Some(Field::new("format", self.format())),
1827 1usize => Some(Field::new("length", self.length())),
1828 2usize => Some(Field::new(
1829 "num_var_selector_records",
1830 self.num_var_selector_records(),
1831 )),
1832 3usize => Some(Field::new(
1833 "var_selector",
1834 traversal::FieldType::array_of_records(
1835 stringify!(VariationSelector),
1836 self.var_selector(),
1837 self.offset_data(),
1838 ),
1839 )),
1840 _ => None,
1841 }
1842 }
1843}
1844
1845#[cfg(feature = "experimental_traverse")]
1846#[allow(clippy::needless_lifetimes)]
1847impl<'a> std::fmt::Debug for Cmap14<'a> {
1848 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1849 (self as &dyn SomeTable<'a>).fmt(f)
1850 }
1851}
1852
1853#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
1855#[repr(C)]
1856#[repr(packed)]
1857pub struct VariationSelector {
1858 pub var_selector: BigEndian<Uint24>,
1860 pub default_uvs_offset: BigEndian<Nullable<Offset32>>,
1863 pub non_default_uvs_offset: BigEndian<Nullable<Offset32>>,
1866}
1867
1868impl VariationSelector {
1869 pub fn var_selector(&self) -> Uint24 {
1871 self.var_selector.get()
1872 }
1873
1874 pub fn default_uvs_offset(&self) -> Nullable<Offset32> {
1877 self.default_uvs_offset.get()
1878 }
1879
1880 pub fn default_uvs<'a>(&self, data: FontData<'a>) -> Option<Result<DefaultUvs<'a>, ReadError>> {
1886 self.default_uvs_offset().resolve(data)
1887 }
1888
1889 pub fn non_default_uvs_offset(&self) -> Nullable<Offset32> {
1892 self.non_default_uvs_offset.get()
1893 }
1894
1895 pub fn non_default_uvs<'a>(
1901 &self,
1902 data: FontData<'a>,
1903 ) -> Option<Result<NonDefaultUvs<'a>, ReadError>> {
1904 self.non_default_uvs_offset().resolve(data)
1905 }
1906}
1907
1908impl FixedSize for VariationSelector {
1909 const RAW_BYTE_LEN: usize =
1910 Uint24::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
1911}
1912
1913#[cfg(feature = "experimental_traverse")]
1914impl<'a> SomeRecord<'a> for VariationSelector {
1915 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1916 RecordResolver {
1917 name: "VariationSelector",
1918 get_field: Box::new(move |idx, _data| match idx {
1919 0usize => Some(Field::new("var_selector", self.var_selector())),
1920 1usize => Some(Field::new(
1921 "default_uvs_offset",
1922 FieldType::offset(self.default_uvs_offset(), self.default_uvs(_data)),
1923 )),
1924 2usize => Some(Field::new(
1925 "non_default_uvs_offset",
1926 FieldType::offset(self.non_default_uvs_offset(), self.non_default_uvs(_data)),
1927 )),
1928 _ => None,
1929 }),
1930 data,
1931 }
1932 }
1933}
1934
1935impl<'a> MinByteRange<'a> for DefaultUvs<'a> {
1936 fn min_byte_range(&self) -> Range<usize> {
1937 0..self.ranges_byte_range().end
1938 }
1939 fn min_table_bytes(&self) -> &'a [u8] {
1940 let range = self.min_byte_range();
1941 self.data.as_bytes().get(range).unwrap_or_default()
1942 }
1943}
1944
1945impl<'a> FontRead<'a> for DefaultUvs<'a> {
1946 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1947 #[allow(clippy::absurd_extreme_comparisons)]
1948 if data.len() < Self::MIN_SIZE {
1949 return Err(ReadError::OutOfBounds);
1950 }
1951 Ok(Self { data })
1952 }
1953}
1954
1955#[derive(Clone)]
1957pub struct DefaultUvs<'a> {
1958 data: FontData<'a>,
1959}
1960
1961#[allow(clippy::needless_lifetimes)]
1962impl<'a> DefaultUvs<'a> {
1963 pub const MIN_SIZE: usize = u32::RAW_BYTE_LEN;
1964 basic_table_impls!(impl_the_methods);
1965
1966 pub fn num_unicode_value_ranges(&self) -> u32 {
1968 let range = self.num_unicode_value_ranges_byte_range();
1969 self.data.read_at(range.start).ok().unwrap()
1970 }
1971
1972 pub fn ranges(&self) -> &'a [UnicodeRange] {
1974 let range = self.ranges_byte_range();
1975 self.data.read_array(range).ok().unwrap_or_default()
1976 }
1977
1978 pub fn num_unicode_value_ranges_byte_range(&self) -> Range<usize> {
1979 let start = 0;
1980 let end = start + u32::RAW_BYTE_LEN;
1981 start..end
1982 }
1983
1984 pub fn ranges_byte_range(&self) -> Range<usize> {
1985 let num_unicode_value_ranges = self.num_unicode_value_ranges();
1986 let start = self.num_unicode_value_ranges_byte_range().end;
1987 let end = start
1988 + (transforms::to_usize(num_unicode_value_ranges))
1989 .saturating_mul(UnicodeRange::RAW_BYTE_LEN);
1990 start..end
1991 }
1992}
1993
1994const _: () = assert!(FontData::default_data_long_enough(DefaultUvs::MIN_SIZE));
1995
1996impl Default for DefaultUvs<'_> {
1997 fn default() -> Self {
1998 Self {
1999 data: FontData::default_table_data(),
2000 }
2001 }
2002}
2003
2004#[cfg(feature = "experimental_traverse")]
2005impl<'a> SomeTable<'a> for DefaultUvs<'a> {
2006 fn type_name(&self) -> &str {
2007 "DefaultUvs"
2008 }
2009 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2010 match idx {
2011 0usize => Some(Field::new(
2012 "num_unicode_value_ranges",
2013 self.num_unicode_value_ranges(),
2014 )),
2015 1usize => Some(Field::new(
2016 "ranges",
2017 traversal::FieldType::array_of_records(
2018 stringify!(UnicodeRange),
2019 self.ranges(),
2020 self.offset_data(),
2021 ),
2022 )),
2023 _ => None,
2024 }
2025 }
2026}
2027
2028#[cfg(feature = "experimental_traverse")]
2029#[allow(clippy::needless_lifetimes)]
2030impl<'a> std::fmt::Debug for DefaultUvs<'a> {
2031 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2032 (self as &dyn SomeTable<'a>).fmt(f)
2033 }
2034}
2035
2036impl<'a> MinByteRange<'a> for NonDefaultUvs<'a> {
2037 fn min_byte_range(&self) -> Range<usize> {
2038 0..self.uvs_mapping_byte_range().end
2039 }
2040 fn min_table_bytes(&self) -> &'a [u8] {
2041 let range = self.min_byte_range();
2042 self.data.as_bytes().get(range).unwrap_or_default()
2043 }
2044}
2045
2046impl<'a> FontRead<'a> for NonDefaultUvs<'a> {
2047 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2048 #[allow(clippy::absurd_extreme_comparisons)]
2049 if data.len() < Self::MIN_SIZE {
2050 return Err(ReadError::OutOfBounds);
2051 }
2052 Ok(Self { data })
2053 }
2054}
2055
2056#[derive(Clone)]
2058pub struct NonDefaultUvs<'a> {
2059 data: FontData<'a>,
2060}
2061
2062#[allow(clippy::needless_lifetimes)]
2063impl<'a> NonDefaultUvs<'a> {
2064 pub const MIN_SIZE: usize = u32::RAW_BYTE_LEN;
2065 basic_table_impls!(impl_the_methods);
2066
2067 pub fn num_uvs_mappings(&self) -> u32 {
2068 let range = self.num_uvs_mappings_byte_range();
2069 self.data.read_at(range.start).ok().unwrap()
2070 }
2071
2072 pub fn uvs_mapping(&self) -> &'a [UvsMapping] {
2073 let range = self.uvs_mapping_byte_range();
2074 self.data.read_array(range).ok().unwrap_or_default()
2075 }
2076
2077 pub fn num_uvs_mappings_byte_range(&self) -> Range<usize> {
2078 let start = 0;
2079 let end = start + u32::RAW_BYTE_LEN;
2080 start..end
2081 }
2082
2083 pub fn uvs_mapping_byte_range(&self) -> Range<usize> {
2084 let num_uvs_mappings = self.num_uvs_mappings();
2085 let start = self.num_uvs_mappings_byte_range().end;
2086 let end = start
2087 + (transforms::to_usize(num_uvs_mappings)).saturating_mul(UvsMapping::RAW_BYTE_LEN);
2088 start..end
2089 }
2090}
2091
2092const _: () = assert!(FontData::default_data_long_enough(NonDefaultUvs::MIN_SIZE));
2093
2094impl Default for NonDefaultUvs<'_> {
2095 fn default() -> Self {
2096 Self {
2097 data: FontData::default_table_data(),
2098 }
2099 }
2100}
2101
2102#[cfg(feature = "experimental_traverse")]
2103impl<'a> SomeTable<'a> for NonDefaultUvs<'a> {
2104 fn type_name(&self) -> &str {
2105 "NonDefaultUvs"
2106 }
2107 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2108 match idx {
2109 0usize => Some(Field::new("num_uvs_mappings", self.num_uvs_mappings())),
2110 1usize => Some(Field::new(
2111 "uvs_mapping",
2112 traversal::FieldType::array_of_records(
2113 stringify!(UvsMapping),
2114 self.uvs_mapping(),
2115 self.offset_data(),
2116 ),
2117 )),
2118 _ => None,
2119 }
2120 }
2121}
2122
2123#[cfg(feature = "experimental_traverse")]
2124#[allow(clippy::needless_lifetimes)]
2125impl<'a> std::fmt::Debug for NonDefaultUvs<'a> {
2126 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2127 (self as &dyn SomeTable<'a>).fmt(f)
2128 }
2129}
2130
2131#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
2133#[repr(C)]
2134#[repr(packed)]
2135pub struct UvsMapping {
2136 pub unicode_value: BigEndian<Uint24>,
2138 pub glyph_id: BigEndian<u16>,
2140}
2141
2142impl UvsMapping {
2143 pub fn unicode_value(&self) -> Uint24 {
2145 self.unicode_value.get()
2146 }
2147
2148 pub fn glyph_id(&self) -> u16 {
2150 self.glyph_id.get()
2151 }
2152}
2153
2154impl FixedSize for UvsMapping {
2155 const RAW_BYTE_LEN: usize = Uint24::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
2156}
2157
2158#[cfg(feature = "experimental_traverse")]
2159impl<'a> SomeRecord<'a> for UvsMapping {
2160 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
2161 RecordResolver {
2162 name: "UvsMapping",
2163 get_field: Box::new(move |idx, _data| match idx {
2164 0usize => Some(Field::new("unicode_value", self.unicode_value())),
2165 1usize => Some(Field::new("glyph_id", self.glyph_id())),
2166 _ => None,
2167 }),
2168 data,
2169 }
2170 }
2171}
2172
2173#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
2175#[repr(C)]
2176#[repr(packed)]
2177pub struct UnicodeRange {
2178 pub start_unicode_value: BigEndian<Uint24>,
2180 pub additional_count: u8,
2182}
2183
2184impl UnicodeRange {
2185 pub fn start_unicode_value(&self) -> Uint24 {
2187 self.start_unicode_value.get()
2188 }
2189
2190 pub fn additional_count(&self) -> u8 {
2192 self.additional_count
2193 }
2194}
2195
2196impl FixedSize for UnicodeRange {
2197 const RAW_BYTE_LEN: usize = Uint24::RAW_BYTE_LEN + u8::RAW_BYTE_LEN;
2198}
2199
2200#[cfg(feature = "experimental_traverse")]
2201impl<'a> SomeRecord<'a> for UnicodeRange {
2202 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
2203 RecordResolver {
2204 name: "UnicodeRange",
2205 get_field: Box::new(move |idx, _data| match idx {
2206 0usize => Some(Field::new(
2207 "start_unicode_value",
2208 self.start_unicode_value(),
2209 )),
2210 1usize => Some(Field::new("additional_count", self.additional_count())),
2211 _ => None,
2212 }),
2213 data,
2214 }
2215 }
2216}