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