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