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