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