1#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8impl<'a> MinByteRange<'a> for Gpos<'a> {
9 fn min_byte_range(&self) -> Range<usize> {
10 0..self.lookup_list_offset_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 Gpos<'_> {
19 const TAG: Tag = Tag::new(b"GPOS");
21}
22
23impl<'a> FontRead<'a> for Gpos<'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)]
36pub struct Gpos<'a> {
37 data: FontData<'a>,
38}
39
40#[allow(clippy::needless_lifetimes)]
41impl<'a> Gpos<'a> {
42 pub const MIN_SIZE: usize = (MajorMinor::RAW_BYTE_LEN
43 + Offset16::RAW_BYTE_LEN
44 + Offset16::RAW_BYTE_LEN
45 + Offset16::RAW_BYTE_LEN);
46 basic_table_impls!(impl_the_methods);
47
48 pub fn version(&self) -> MajorMinor {
50 let range = self.version_byte_range();
51 self.data.read_at(range.start).ok().unwrap()
52 }
53
54 pub fn script_list_offset(&self) -> Offset16 {
56 let range = self.script_list_offset_byte_range();
57 self.data.read_at(range.start).ok().unwrap()
58 }
59
60 pub fn script_list(&self) -> Result<ScriptList<'a>, ReadError> {
62 let data = self.data;
63 self.script_list_offset().resolve(data)
64 }
65
66 pub fn feature_list_offset(&self) -> Offset16 {
68 let range = self.feature_list_offset_byte_range();
69 self.data.read_at(range.start).ok().unwrap()
70 }
71
72 pub fn feature_list(&self) -> Result<FeatureList<'a>, ReadError> {
74 let data = self.data;
75 self.feature_list_offset().resolve(data)
76 }
77
78 pub fn lookup_list_offset(&self) -> Offset16 {
80 let range = self.lookup_list_offset_byte_range();
81 self.data.read_at(range.start).ok().unwrap()
82 }
83
84 pub fn lookup_list(&self) -> Result<PositionLookupList<'a>, ReadError> {
86 let data = self.data;
87 self.lookup_list_offset().resolve(data)
88 }
89
90 pub fn feature_variations_offset(&self) -> Option<Nullable<Offset32>> {
91 let range = self.feature_variations_offset_byte_range();
92 (!range.is_empty())
93 .then(|| self.data.read_at(range.start).ok())
94 .flatten()
95 }
96
97 pub fn feature_variations(&self) -> Option<Result<FeatureVariations<'a>, ReadError>> {
99 let data = self.data;
100 self.feature_variations_offset().map(|x| x.resolve(data))?
101 }
102
103 pub fn version_byte_range(&self) -> Range<usize> {
104 let start = 0;
105 start..start + MajorMinor::RAW_BYTE_LEN
106 }
107
108 pub fn script_list_offset_byte_range(&self) -> Range<usize> {
109 let start = self.version_byte_range().end;
110 start..start + Offset16::RAW_BYTE_LEN
111 }
112
113 pub fn feature_list_offset_byte_range(&self) -> Range<usize> {
114 let start = self.script_list_offset_byte_range().end;
115 start..start + Offset16::RAW_BYTE_LEN
116 }
117
118 pub fn lookup_list_offset_byte_range(&self) -> Range<usize> {
119 let start = self.feature_list_offset_byte_range().end;
120 start..start + Offset16::RAW_BYTE_LEN
121 }
122
123 pub fn feature_variations_offset_byte_range(&self) -> Range<usize> {
124 let start = self.lookup_list_offset_byte_range().end;
125 start
126 ..(self.version().compatible((1u16, 1u16)))
127 .then(|| start + Offset32::RAW_BYTE_LEN)
128 .unwrap_or(start)
129 }
130}
131
132const _: () = assert!(FontData::default_data_long_enough(Gpos::MIN_SIZE));
133
134impl Default for Gpos<'_> {
135 fn default() -> Self {
136 Self {
137 data: FontData::default_table_data(),
138 }
139 }
140}
141
142#[cfg(feature = "experimental_traverse")]
143impl<'a> SomeTable<'a> for Gpos<'a> {
144 fn type_name(&self) -> &str {
145 "Gpos"
146 }
147 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
148 match idx {
149 0usize => Some(Field::new("version", self.version())),
150 1usize => Some(Field::new(
151 "script_list_offset",
152 FieldType::offset(self.script_list_offset(), self.script_list()),
153 )),
154 2usize => Some(Field::new(
155 "feature_list_offset",
156 FieldType::offset(self.feature_list_offset(), self.feature_list()),
157 )),
158 3usize => Some(Field::new(
159 "lookup_list_offset",
160 FieldType::offset(self.lookup_list_offset(), self.lookup_list()),
161 )),
162 4usize if self.version().compatible((1u16, 1u16)) => Some(Field::new(
163 "feature_variations_offset",
164 FieldType::offset(
165 self.feature_variations_offset().unwrap(),
166 self.feature_variations(),
167 ),
168 )),
169 _ => None,
170 }
171 }
172}
173
174#[cfg(feature = "experimental_traverse")]
175#[allow(clippy::needless_lifetimes)]
176impl<'a> std::fmt::Debug for Gpos<'a> {
177 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
178 (self as &dyn SomeTable<'a>).fmt(f)
179 }
180}
181
182pub enum PositionLookup<'a> {
184 Single(Lookup<'a, SinglePos<'a>>),
185 Pair(Lookup<'a, PairPos<'a>>),
186 Cursive(Lookup<'a, CursivePosFormat1<'a>>),
187 MarkToBase(Lookup<'a, MarkBasePosFormat1<'a>>),
188 MarkToLig(Lookup<'a, MarkLigPosFormat1<'a>>),
189 MarkToMark(Lookup<'a, MarkMarkPosFormat1<'a>>),
190 Contextual(Lookup<'a, PositionSequenceContext<'a>>),
191 ChainContextual(Lookup<'a, PositionChainContext<'a>>),
192 Extension(Lookup<'a, ExtensionSubtable<'a>>),
193}
194
195impl Default for PositionLookup<'_> {
196 fn default() -> Self {
197 Self::Single(Default::default())
198 }
199}
200
201impl<'a> FontRead<'a> for PositionLookup<'a> {
202 fn read(bytes: FontData<'a>) -> Result<Self, ReadError> {
203 let discriminant = Lookup::read_discriminant(bytes)?;
204 match discriminant {
205 1 => Ok(PositionLookup::Single(FontRead::read(bytes)?)),
206 2 => Ok(PositionLookup::Pair(FontRead::read(bytes)?)),
207 3 => Ok(PositionLookup::Cursive(FontRead::read(bytes)?)),
208 4 => Ok(PositionLookup::MarkToBase(FontRead::read(bytes)?)),
209 5 => Ok(PositionLookup::MarkToLig(FontRead::read(bytes)?)),
210 6 => Ok(PositionLookup::MarkToMark(FontRead::read(bytes)?)),
211 7 => Ok(PositionLookup::Contextual(FontRead::read(bytes)?)),
212 8 => Ok(PositionLookup::ChainContextual(FontRead::read(bytes)?)),
213 9 => Ok(PositionLookup::Extension(FontRead::read(bytes)?)),
214 other => Err(ReadError::InvalidFormat(other.into())),
215 }
216 }
217}
218
219impl<'a> PositionLookup<'a> {
220 #[allow(dead_code)]
221 pub(crate) fn of_unit_type(&self) -> Lookup<'a, ()> {
225 match self {
226 PositionLookup::Single(inner) => inner.of_unit_type(),
227 PositionLookup::Pair(inner) => inner.of_unit_type(),
228 PositionLookup::Cursive(inner) => inner.of_unit_type(),
229 PositionLookup::MarkToBase(inner) => inner.of_unit_type(),
230 PositionLookup::MarkToLig(inner) => inner.of_unit_type(),
231 PositionLookup::MarkToMark(inner) => inner.of_unit_type(),
232 PositionLookup::Contextual(inner) => inner.of_unit_type(),
233 PositionLookup::ChainContextual(inner) => inner.of_unit_type(),
234 PositionLookup::Extension(inner) => inner.of_unit_type(),
235 }
236 }
237}
238
239#[cfg(feature = "experimental_traverse")]
240impl<'a> PositionLookup<'a> {
241 fn dyn_inner(&self) -> &(dyn SomeTable<'a> + 'a) {
242 match self {
243 PositionLookup::Single(table) => table,
244 PositionLookup::Pair(table) => table,
245 PositionLookup::Cursive(table) => table,
246 PositionLookup::MarkToBase(table) => table,
247 PositionLookup::MarkToLig(table) => table,
248 PositionLookup::MarkToMark(table) => table,
249 PositionLookup::Contextual(table) => table,
250 PositionLookup::ChainContextual(table) => table,
251 PositionLookup::Extension(table) => table,
252 }
253 }
254}
255
256#[cfg(feature = "experimental_traverse")]
257impl<'a> SomeTable<'a> for PositionLookup<'a> {
258 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
259 self.dyn_inner().get_field(idx)
260 }
261 fn type_name(&self) -> &str {
262 self.dyn_inner().type_name()
263 }
264}
265
266#[cfg(feature = "experimental_traverse")]
267impl std::fmt::Debug for PositionLookup<'_> {
268 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
269 self.dyn_inner().fmt(f)
270 }
271}
272
273#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, bytemuck :: AnyBitPattern)]
275#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
276#[repr(transparent)]
277pub struct ValueFormat {
278 bits: u16,
279}
280
281impl ValueFormat {
282 pub const X_PLACEMENT: Self = Self { bits: 0x0001 };
284
285 pub const Y_PLACEMENT: Self = Self { bits: 0x0002 };
287
288 pub const X_ADVANCE: Self = Self { bits: 0x0004 };
290
291 pub const Y_ADVANCE: Self = Self { bits: 0x0008 };
293
294 pub const X_PLACEMENT_DEVICE: Self = Self { bits: 0x0010 };
297
298 pub const Y_PLACEMENT_DEVICE: Self = Self { bits: 0x0020 };
301
302 pub const X_ADVANCE_DEVICE: Self = Self { bits: 0x0040 };
305
306 pub const Y_ADVANCE_DEVICE: Self = Self { bits: 0x0080 };
309}
310
311impl ValueFormat {
312 #[inline]
314 pub const fn empty() -> Self {
315 Self { bits: 0 }
316 }
317
318 #[inline]
320 pub const fn all() -> Self {
321 Self {
322 bits: Self::X_PLACEMENT.bits
323 | Self::Y_PLACEMENT.bits
324 | Self::X_ADVANCE.bits
325 | Self::Y_ADVANCE.bits
326 | Self::X_PLACEMENT_DEVICE.bits
327 | Self::Y_PLACEMENT_DEVICE.bits
328 | Self::X_ADVANCE_DEVICE.bits
329 | Self::Y_ADVANCE_DEVICE.bits,
330 }
331 }
332
333 #[inline]
335 pub const fn bits(&self) -> u16 {
336 self.bits
337 }
338
339 #[inline]
342 pub const fn from_bits(bits: u16) -> Option<Self> {
343 if (bits & !Self::all().bits()) == 0 {
344 Some(Self { bits })
345 } else {
346 None
347 }
348 }
349
350 #[inline]
353 pub const fn from_bits_truncate(bits: u16) -> Self {
354 Self {
355 bits: bits & Self::all().bits,
356 }
357 }
358
359 #[inline]
361 pub const fn is_empty(&self) -> bool {
362 self.bits() == Self::empty().bits()
363 }
364
365 #[inline]
367 pub const fn intersects(&self, other: Self) -> bool {
368 !(Self {
369 bits: self.bits & other.bits,
370 })
371 .is_empty()
372 }
373
374 #[inline]
376 pub const fn contains(&self, other: Self) -> bool {
377 (self.bits & other.bits) == other.bits
378 }
379
380 #[inline]
382 pub fn insert(&mut self, other: Self) {
383 self.bits |= other.bits;
384 }
385
386 #[inline]
388 pub fn remove(&mut self, other: Self) {
389 self.bits &= !other.bits;
390 }
391
392 #[inline]
394 pub fn toggle(&mut self, other: Self) {
395 self.bits ^= other.bits;
396 }
397
398 #[inline]
409 #[must_use]
410 pub const fn intersection(self, other: Self) -> Self {
411 Self {
412 bits: self.bits & other.bits,
413 }
414 }
415
416 #[inline]
427 #[must_use]
428 pub const fn union(self, other: Self) -> Self {
429 Self {
430 bits: self.bits | other.bits,
431 }
432 }
433
434 #[inline]
447 #[must_use]
448 pub const fn difference(self, other: Self) -> Self {
449 Self {
450 bits: self.bits & !other.bits,
451 }
452 }
453}
454
455impl std::ops::BitOr for ValueFormat {
456 type Output = Self;
457
458 #[inline]
460 fn bitor(self, other: ValueFormat) -> Self {
461 Self {
462 bits: self.bits | other.bits,
463 }
464 }
465}
466
467impl std::ops::BitOrAssign for ValueFormat {
468 #[inline]
470 fn bitor_assign(&mut self, other: Self) {
471 self.bits |= other.bits;
472 }
473}
474
475impl std::ops::BitXor for ValueFormat {
476 type Output = Self;
477
478 #[inline]
480 fn bitxor(self, other: Self) -> Self {
481 Self {
482 bits: self.bits ^ other.bits,
483 }
484 }
485}
486
487impl std::ops::BitXorAssign for ValueFormat {
488 #[inline]
490 fn bitxor_assign(&mut self, other: Self) {
491 self.bits ^= other.bits;
492 }
493}
494
495impl std::ops::BitAnd for ValueFormat {
496 type Output = Self;
497
498 #[inline]
500 fn bitand(self, other: Self) -> Self {
501 Self {
502 bits: self.bits & other.bits,
503 }
504 }
505}
506
507impl std::ops::BitAndAssign for ValueFormat {
508 #[inline]
510 fn bitand_assign(&mut self, other: Self) {
511 self.bits &= other.bits;
512 }
513}
514
515impl std::ops::Sub for ValueFormat {
516 type Output = Self;
517
518 #[inline]
520 fn sub(self, other: Self) -> Self {
521 Self {
522 bits: self.bits & !other.bits,
523 }
524 }
525}
526
527impl std::ops::SubAssign for ValueFormat {
528 #[inline]
530 fn sub_assign(&mut self, other: Self) {
531 self.bits &= !other.bits;
532 }
533}
534
535impl std::ops::Not for ValueFormat {
536 type Output = Self;
537
538 #[inline]
540 fn not(self) -> Self {
541 Self { bits: !self.bits } & Self::all()
542 }
543}
544
545impl std::fmt::Debug for ValueFormat {
546 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
547 let members: &[(&str, Self)] = &[
548 ("X_PLACEMENT", Self::X_PLACEMENT),
549 ("Y_PLACEMENT", Self::Y_PLACEMENT),
550 ("X_ADVANCE", Self::X_ADVANCE),
551 ("Y_ADVANCE", Self::Y_ADVANCE),
552 ("X_PLACEMENT_DEVICE", Self::X_PLACEMENT_DEVICE),
553 ("Y_PLACEMENT_DEVICE", Self::Y_PLACEMENT_DEVICE),
554 ("X_ADVANCE_DEVICE", Self::X_ADVANCE_DEVICE),
555 ("Y_ADVANCE_DEVICE", Self::Y_ADVANCE_DEVICE),
556 ];
557 let mut first = true;
558 for (name, value) in members {
559 if self.contains(*value) {
560 if !first {
561 f.write_str(" | ")?;
562 }
563 first = false;
564 f.write_str(name)?;
565 }
566 }
567 if first {
568 f.write_str("(empty)")?;
569 }
570 Ok(())
571 }
572}
573
574impl std::fmt::Binary for ValueFormat {
575 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
576 std::fmt::Binary::fmt(&self.bits, f)
577 }
578}
579
580impl std::fmt::Octal for ValueFormat {
581 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
582 std::fmt::Octal::fmt(&self.bits, f)
583 }
584}
585
586impl std::fmt::LowerHex for ValueFormat {
587 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
588 std::fmt::LowerHex::fmt(&self.bits, f)
589 }
590}
591
592impl std::fmt::UpperHex for ValueFormat {
593 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
594 std::fmt::UpperHex::fmt(&self.bits, f)
595 }
596}
597
598impl font_types::Scalar for ValueFormat {
599 type Raw = <u16 as font_types::Scalar>::Raw;
600 fn to_raw(self) -> Self::Raw {
601 self.bits().to_raw()
602 }
603 fn from_raw(raw: Self::Raw) -> Self {
604 let t = <u16>::from_raw(raw);
605 Self::from_bits_truncate(t)
606 }
607}
608
609#[cfg(feature = "experimental_traverse")]
610impl<'a> From<ValueFormat> for FieldType<'a> {
611 fn from(src: ValueFormat) -> FieldType<'a> {
612 src.bits().into()
613 }
614}
615
616#[derive(Clone)]
619pub enum AnchorTable<'a> {
620 Format1(AnchorFormat1<'a>),
621 Format2(AnchorFormat2<'a>),
622 Format3(AnchorFormat3<'a>),
623}
624
625impl Default for AnchorTable<'_> {
626 fn default() -> Self {
627 Self::Format1(Default::default())
628 }
629}
630
631impl<'a> AnchorTable<'a> {
632 pub fn offset_data(&self) -> FontData<'a> {
634 match self {
635 Self::Format1(item) => item.offset_data(),
636 Self::Format2(item) => item.offset_data(),
637 Self::Format3(item) => item.offset_data(),
638 }
639 }
640
641 pub fn anchor_format(&self) -> u16 {
643 match self {
644 Self::Format1(item) => item.anchor_format(),
645 Self::Format2(item) => item.anchor_format(),
646 Self::Format3(item) => item.anchor_format(),
647 }
648 }
649
650 pub fn x_coordinate(&self) -> i16 {
652 match self {
653 Self::Format1(item) => item.x_coordinate(),
654 Self::Format2(item) => item.x_coordinate(),
655 Self::Format3(item) => item.x_coordinate(),
656 }
657 }
658
659 pub fn y_coordinate(&self) -> i16 {
661 match self {
662 Self::Format1(item) => item.y_coordinate(),
663 Self::Format2(item) => item.y_coordinate(),
664 Self::Format3(item) => item.y_coordinate(),
665 }
666 }
667}
668
669impl<'a> FontRead<'a> for AnchorTable<'a> {
670 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
671 let format: u16 = data.read_at(0usize)?;
672 match format {
673 AnchorFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
674 AnchorFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
675 AnchorFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
676 other => Err(ReadError::InvalidFormat(other.into())),
677 }
678 }
679}
680
681impl<'a> MinByteRange<'a> for AnchorTable<'a> {
682 fn min_byte_range(&self) -> Range<usize> {
683 match self {
684 Self::Format1(item) => item.min_byte_range(),
685 Self::Format2(item) => item.min_byte_range(),
686 Self::Format3(item) => item.min_byte_range(),
687 }
688 }
689 fn min_table_bytes(&self) -> &'a [u8] {
690 match self {
691 Self::Format1(item) => item.min_table_bytes(),
692 Self::Format2(item) => item.min_table_bytes(),
693 Self::Format3(item) => item.min_table_bytes(),
694 }
695 }
696}
697
698#[cfg(feature = "experimental_traverse")]
699impl<'a> AnchorTable<'a> {
700 fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
701 match self {
702 Self::Format1(table) => table,
703 Self::Format2(table) => table,
704 Self::Format3(table) => table,
705 }
706 }
707}
708
709#[cfg(feature = "experimental_traverse")]
710impl std::fmt::Debug for AnchorTable<'_> {
711 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
712 self.dyn_inner().fmt(f)
713 }
714}
715
716#[cfg(feature = "experimental_traverse")]
717impl<'a> SomeTable<'a> for AnchorTable<'a> {
718 fn type_name(&self) -> &str {
719 self.dyn_inner().type_name()
720 }
721 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
722 self.dyn_inner().get_field(idx)
723 }
724}
725
726impl Format<u16> for AnchorFormat1<'_> {
727 const FORMAT: u16 = 1;
728}
729
730impl<'a> MinByteRange<'a> for AnchorFormat1<'a> {
731 fn min_byte_range(&self) -> Range<usize> {
732 0..self.y_coordinate_byte_range().end
733 }
734 fn min_table_bytes(&self) -> &'a [u8] {
735 let range = self.min_byte_range();
736 self.data.as_bytes().get(range).unwrap_or_default()
737 }
738}
739
740impl<'a> FontRead<'a> for AnchorFormat1<'a> {
741 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
742 #[allow(clippy::absurd_extreme_comparisons)]
743 if data.len() < Self::MIN_SIZE {
744 return Err(ReadError::OutOfBounds);
745 }
746 Ok(Self { data })
747 }
748}
749
750#[derive(Clone)]
752pub struct AnchorFormat1<'a> {
753 data: FontData<'a>,
754}
755
756#[allow(clippy::needless_lifetimes)]
757impl<'a> AnchorFormat1<'a> {
758 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN);
759 basic_table_impls!(impl_the_methods);
760
761 pub fn anchor_format(&self) -> u16 {
763 let range = self.anchor_format_byte_range();
764 self.data.read_at(range.start).ok().unwrap()
765 }
766
767 pub fn x_coordinate(&self) -> i16 {
769 let range = self.x_coordinate_byte_range();
770 self.data.read_at(range.start).ok().unwrap()
771 }
772
773 pub fn y_coordinate(&self) -> i16 {
775 let range = self.y_coordinate_byte_range();
776 self.data.read_at(range.start).ok().unwrap()
777 }
778
779 pub fn anchor_format_byte_range(&self) -> Range<usize> {
780 let start = 0;
781 start..start + u16::RAW_BYTE_LEN
782 }
783
784 pub fn x_coordinate_byte_range(&self) -> Range<usize> {
785 let start = self.anchor_format_byte_range().end;
786 start..start + i16::RAW_BYTE_LEN
787 }
788
789 pub fn y_coordinate_byte_range(&self) -> Range<usize> {
790 let start = self.x_coordinate_byte_range().end;
791 start..start + i16::RAW_BYTE_LEN
792 }
793}
794
795const _: () = assert!(FontData::default_data_long_enough(AnchorFormat1::MIN_SIZE));
796
797impl Default for AnchorFormat1<'_> {
798 fn default() -> Self {
799 Self {
800 data: FontData::default_format_1_u16_table_data(),
801 }
802 }
803}
804
805#[cfg(feature = "experimental_traverse")]
806impl<'a> SomeTable<'a> for AnchorFormat1<'a> {
807 fn type_name(&self) -> &str {
808 "AnchorFormat1"
809 }
810 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
811 match idx {
812 0usize => Some(Field::new("anchor_format", self.anchor_format())),
813 1usize => Some(Field::new("x_coordinate", self.x_coordinate())),
814 2usize => Some(Field::new("y_coordinate", self.y_coordinate())),
815 _ => None,
816 }
817 }
818}
819
820#[cfg(feature = "experimental_traverse")]
821#[allow(clippy::needless_lifetimes)]
822impl<'a> std::fmt::Debug for AnchorFormat1<'a> {
823 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
824 (self as &dyn SomeTable<'a>).fmt(f)
825 }
826}
827
828impl Format<u16> for AnchorFormat2<'_> {
829 const FORMAT: u16 = 2;
830}
831
832impl<'a> MinByteRange<'a> for AnchorFormat2<'a> {
833 fn min_byte_range(&self) -> Range<usize> {
834 0..self.anchor_point_byte_range().end
835 }
836 fn min_table_bytes(&self) -> &'a [u8] {
837 let range = self.min_byte_range();
838 self.data.as_bytes().get(range).unwrap_or_default()
839 }
840}
841
842impl<'a> FontRead<'a> for AnchorFormat2<'a> {
843 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
844 #[allow(clippy::absurd_extreme_comparisons)]
845 if data.len() < Self::MIN_SIZE {
846 return Err(ReadError::OutOfBounds);
847 }
848 Ok(Self { data })
849 }
850}
851
852#[derive(Clone)]
854pub struct AnchorFormat2<'a> {
855 data: FontData<'a>,
856}
857
858#[allow(clippy::needless_lifetimes)]
859impl<'a> AnchorFormat2<'a> {
860 pub const MIN_SIZE: usize =
861 (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
862 basic_table_impls!(impl_the_methods);
863
864 pub fn anchor_format(&self) -> u16 {
866 let range = self.anchor_format_byte_range();
867 self.data.read_at(range.start).ok().unwrap()
868 }
869
870 pub fn x_coordinate(&self) -> i16 {
872 let range = self.x_coordinate_byte_range();
873 self.data.read_at(range.start).ok().unwrap()
874 }
875
876 pub fn y_coordinate(&self) -> i16 {
878 let range = self.y_coordinate_byte_range();
879 self.data.read_at(range.start).ok().unwrap()
880 }
881
882 pub fn anchor_point(&self) -> u16 {
884 let range = self.anchor_point_byte_range();
885 self.data.read_at(range.start).ok().unwrap()
886 }
887
888 pub fn anchor_format_byte_range(&self) -> Range<usize> {
889 let start = 0;
890 start..start + u16::RAW_BYTE_LEN
891 }
892
893 pub fn x_coordinate_byte_range(&self) -> Range<usize> {
894 let start = self.anchor_format_byte_range().end;
895 start..start + i16::RAW_BYTE_LEN
896 }
897
898 pub fn y_coordinate_byte_range(&self) -> Range<usize> {
899 let start = self.x_coordinate_byte_range().end;
900 start..start + i16::RAW_BYTE_LEN
901 }
902
903 pub fn anchor_point_byte_range(&self) -> Range<usize> {
904 let start = self.y_coordinate_byte_range().end;
905 start..start + u16::RAW_BYTE_LEN
906 }
907}
908
909#[cfg(feature = "experimental_traverse")]
910impl<'a> SomeTable<'a> for AnchorFormat2<'a> {
911 fn type_name(&self) -> &str {
912 "AnchorFormat2"
913 }
914 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
915 match idx {
916 0usize => Some(Field::new("anchor_format", self.anchor_format())),
917 1usize => Some(Field::new("x_coordinate", self.x_coordinate())),
918 2usize => Some(Field::new("y_coordinate", self.y_coordinate())),
919 3usize => Some(Field::new("anchor_point", self.anchor_point())),
920 _ => None,
921 }
922 }
923}
924
925#[cfg(feature = "experimental_traverse")]
926#[allow(clippy::needless_lifetimes)]
927impl<'a> std::fmt::Debug for AnchorFormat2<'a> {
928 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
929 (self as &dyn SomeTable<'a>).fmt(f)
930 }
931}
932
933impl Format<u16> for AnchorFormat3<'_> {
934 const FORMAT: u16 = 3;
935}
936
937impl<'a> MinByteRange<'a> for AnchorFormat3<'a> {
938 fn min_byte_range(&self) -> Range<usize> {
939 0..self.y_device_offset_byte_range().end
940 }
941 fn min_table_bytes(&self) -> &'a [u8] {
942 let range = self.min_byte_range();
943 self.data.as_bytes().get(range).unwrap_or_default()
944 }
945}
946
947impl<'a> FontRead<'a> for AnchorFormat3<'a> {
948 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
949 #[allow(clippy::absurd_extreme_comparisons)]
950 if data.len() < Self::MIN_SIZE {
951 return Err(ReadError::OutOfBounds);
952 }
953 Ok(Self { data })
954 }
955}
956
957#[derive(Clone)]
959pub struct AnchorFormat3<'a> {
960 data: FontData<'a>,
961}
962
963#[allow(clippy::needless_lifetimes)]
964impl<'a> AnchorFormat3<'a> {
965 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
966 + i16::RAW_BYTE_LEN
967 + i16::RAW_BYTE_LEN
968 + Offset16::RAW_BYTE_LEN
969 + Offset16::RAW_BYTE_LEN);
970 basic_table_impls!(impl_the_methods);
971
972 pub fn anchor_format(&self) -> u16 {
974 let range = self.anchor_format_byte_range();
975 self.data.read_at(range.start).ok().unwrap()
976 }
977
978 pub fn x_coordinate(&self) -> i16 {
980 let range = self.x_coordinate_byte_range();
981 self.data.read_at(range.start).ok().unwrap()
982 }
983
984 pub fn y_coordinate(&self) -> i16 {
986 let range = self.y_coordinate_byte_range();
987 self.data.read_at(range.start).ok().unwrap()
988 }
989
990 pub fn x_device_offset(&self) -> Nullable<Offset16> {
994 let range = self.x_device_offset_byte_range();
995 self.data.read_at(range.start).ok().unwrap()
996 }
997
998 pub fn x_device(&self) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>> {
1000 let data = self.data;
1001 self.x_device_offset().resolve(data)
1002 }
1003
1004 pub fn y_device_offset(&self) -> Nullable<Offset16> {
1008 let range = self.y_device_offset_byte_range();
1009 self.data.read_at(range.start).ok().unwrap()
1010 }
1011
1012 pub fn y_device(&self) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>> {
1014 let data = self.data;
1015 self.y_device_offset().resolve(data)
1016 }
1017
1018 pub fn anchor_format_byte_range(&self) -> Range<usize> {
1019 let start = 0;
1020 start..start + u16::RAW_BYTE_LEN
1021 }
1022
1023 pub fn x_coordinate_byte_range(&self) -> Range<usize> {
1024 let start = self.anchor_format_byte_range().end;
1025 start..start + i16::RAW_BYTE_LEN
1026 }
1027
1028 pub fn y_coordinate_byte_range(&self) -> Range<usize> {
1029 let start = self.x_coordinate_byte_range().end;
1030 start..start + i16::RAW_BYTE_LEN
1031 }
1032
1033 pub fn x_device_offset_byte_range(&self) -> Range<usize> {
1034 let start = self.y_coordinate_byte_range().end;
1035 start..start + Offset16::RAW_BYTE_LEN
1036 }
1037
1038 pub fn y_device_offset_byte_range(&self) -> Range<usize> {
1039 let start = self.x_device_offset_byte_range().end;
1040 start..start + Offset16::RAW_BYTE_LEN
1041 }
1042}
1043
1044#[cfg(feature = "experimental_traverse")]
1045impl<'a> SomeTable<'a> for AnchorFormat3<'a> {
1046 fn type_name(&self) -> &str {
1047 "AnchorFormat3"
1048 }
1049 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1050 match idx {
1051 0usize => Some(Field::new("anchor_format", self.anchor_format())),
1052 1usize => Some(Field::new("x_coordinate", self.x_coordinate())),
1053 2usize => Some(Field::new("y_coordinate", self.y_coordinate())),
1054 3usize => Some(Field::new(
1055 "x_device_offset",
1056 FieldType::offset(self.x_device_offset(), self.x_device()),
1057 )),
1058 4usize => Some(Field::new(
1059 "y_device_offset",
1060 FieldType::offset(self.y_device_offset(), self.y_device()),
1061 )),
1062 _ => None,
1063 }
1064 }
1065}
1066
1067#[cfg(feature = "experimental_traverse")]
1068#[allow(clippy::needless_lifetimes)]
1069impl<'a> std::fmt::Debug for AnchorFormat3<'a> {
1070 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1071 (self as &dyn SomeTable<'a>).fmt(f)
1072 }
1073}
1074
1075impl<'a> MinByteRange<'a> for MarkArray<'a> {
1076 fn min_byte_range(&self) -> Range<usize> {
1077 0..self.mark_records_byte_range().end
1078 }
1079 fn min_table_bytes(&self) -> &'a [u8] {
1080 let range = self.min_byte_range();
1081 self.data.as_bytes().get(range).unwrap_or_default()
1082 }
1083}
1084
1085impl<'a> FontRead<'a> for MarkArray<'a> {
1086 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1087 #[allow(clippy::absurd_extreme_comparisons)]
1088 if data.len() < Self::MIN_SIZE {
1089 return Err(ReadError::OutOfBounds);
1090 }
1091 Ok(Self { data })
1092 }
1093}
1094
1095#[derive(Clone)]
1097pub struct MarkArray<'a> {
1098 data: FontData<'a>,
1099}
1100
1101#[allow(clippy::needless_lifetimes)]
1102impl<'a> MarkArray<'a> {
1103 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
1104 basic_table_impls!(impl_the_methods);
1105
1106 pub fn mark_count(&self) -> u16 {
1108 let range = self.mark_count_byte_range();
1109 self.data.read_at(range.start).ok().unwrap()
1110 }
1111
1112 pub fn mark_records(&self) -> &'a [MarkRecord] {
1115 let range = self.mark_records_byte_range();
1116 self.data.read_array(range).ok().unwrap_or_default()
1117 }
1118
1119 pub fn mark_count_byte_range(&self) -> Range<usize> {
1120 let start = 0;
1121 start..start + u16::RAW_BYTE_LEN
1122 }
1123
1124 pub fn mark_records_byte_range(&self) -> Range<usize> {
1125 let mark_count = self.mark_count();
1126 let start = self.mark_count_byte_range().end;
1127 start..start + (mark_count as usize).saturating_mul(MarkRecord::RAW_BYTE_LEN)
1128 }
1129}
1130
1131const _: () = assert!(FontData::default_data_long_enough(MarkArray::MIN_SIZE));
1132
1133impl Default for MarkArray<'_> {
1134 fn default() -> Self {
1135 Self {
1136 data: FontData::default_table_data(),
1137 }
1138 }
1139}
1140
1141#[cfg(feature = "experimental_traverse")]
1142impl<'a> SomeTable<'a> for MarkArray<'a> {
1143 fn type_name(&self) -> &str {
1144 "MarkArray"
1145 }
1146 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1147 match idx {
1148 0usize => Some(Field::new("mark_count", self.mark_count())),
1149 1usize => Some(Field::new(
1150 "mark_records",
1151 traversal::FieldType::array_of_records(
1152 stringify!(MarkRecord),
1153 self.mark_records(),
1154 self.offset_data(),
1155 ),
1156 )),
1157 _ => None,
1158 }
1159 }
1160}
1161
1162#[cfg(feature = "experimental_traverse")]
1163#[allow(clippy::needless_lifetimes)]
1164impl<'a> std::fmt::Debug for MarkArray<'a> {
1165 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1166 (self as &dyn SomeTable<'a>).fmt(f)
1167 }
1168}
1169
1170#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
1172#[repr(C)]
1173#[repr(packed)]
1174pub struct MarkRecord {
1175 pub mark_class: BigEndian<u16>,
1177 pub mark_anchor_offset: BigEndian<Offset16>,
1179}
1180
1181impl MarkRecord {
1182 pub fn mark_class(&self) -> u16 {
1184 self.mark_class.get()
1185 }
1186
1187 pub fn mark_anchor_offset(&self) -> Offset16 {
1189 self.mark_anchor_offset.get()
1190 }
1191
1192 pub fn mark_anchor<'a>(&self, data: FontData<'a>) -> Result<AnchorTable<'a>, ReadError> {
1197 self.mark_anchor_offset().resolve(data)
1198 }
1199}
1200
1201impl FixedSize for MarkRecord {
1202 const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
1203}
1204
1205#[cfg(feature = "experimental_traverse")]
1206impl<'a> SomeRecord<'a> for MarkRecord {
1207 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1208 RecordResolver {
1209 name: "MarkRecord",
1210 get_field: Box::new(move |idx, _data| match idx {
1211 0usize => Some(Field::new("mark_class", self.mark_class())),
1212 1usize => Some(Field::new(
1213 "mark_anchor_offset",
1214 FieldType::offset(self.mark_anchor_offset(), self.mark_anchor(_data)),
1215 )),
1216 _ => None,
1217 }),
1218 data,
1219 }
1220 }
1221}
1222
1223#[derive(Clone)]
1225pub enum SinglePos<'a> {
1226 Format1(SinglePosFormat1<'a>),
1227 Format2(SinglePosFormat2<'a>),
1228}
1229
1230impl Default for SinglePos<'_> {
1231 fn default() -> Self {
1232 Self::Format1(Default::default())
1233 }
1234}
1235
1236impl<'a> SinglePos<'a> {
1237 pub fn offset_data(&self) -> FontData<'a> {
1239 match self {
1240 Self::Format1(item) => item.offset_data(),
1241 Self::Format2(item) => item.offset_data(),
1242 }
1243 }
1244
1245 pub fn pos_format(&self) -> u16 {
1247 match self {
1248 Self::Format1(item) => item.pos_format(),
1249 Self::Format2(item) => item.pos_format(),
1250 }
1251 }
1252
1253 pub fn coverage_offset(&self) -> Offset16 {
1255 match self {
1256 Self::Format1(item) => item.coverage_offset(),
1257 Self::Format2(item) => item.coverage_offset(),
1258 }
1259 }
1260
1261 pub fn value_format(&self) -> ValueFormat {
1263 match self {
1264 Self::Format1(item) => item.value_format(),
1265 Self::Format2(item) => item.value_format(),
1266 }
1267 }
1268}
1269
1270impl<'a> FontRead<'a> for SinglePos<'a> {
1271 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1272 let format: u16 = data.read_at(0usize)?;
1273 match format {
1274 SinglePosFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
1275 SinglePosFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
1276 other => Err(ReadError::InvalidFormat(other.into())),
1277 }
1278 }
1279}
1280
1281impl<'a> MinByteRange<'a> for SinglePos<'a> {
1282 fn min_byte_range(&self) -> Range<usize> {
1283 match self {
1284 Self::Format1(item) => item.min_byte_range(),
1285 Self::Format2(item) => item.min_byte_range(),
1286 }
1287 }
1288 fn min_table_bytes(&self) -> &'a [u8] {
1289 match self {
1290 Self::Format1(item) => item.min_table_bytes(),
1291 Self::Format2(item) => item.min_table_bytes(),
1292 }
1293 }
1294}
1295
1296#[cfg(feature = "experimental_traverse")]
1297impl<'a> SinglePos<'a> {
1298 fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
1299 match self {
1300 Self::Format1(table) => table,
1301 Self::Format2(table) => table,
1302 }
1303 }
1304}
1305
1306#[cfg(feature = "experimental_traverse")]
1307impl std::fmt::Debug for SinglePos<'_> {
1308 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1309 self.dyn_inner().fmt(f)
1310 }
1311}
1312
1313#[cfg(feature = "experimental_traverse")]
1314impl<'a> SomeTable<'a> for SinglePos<'a> {
1315 fn type_name(&self) -> &str {
1316 self.dyn_inner().type_name()
1317 }
1318 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1319 self.dyn_inner().get_field(idx)
1320 }
1321}
1322
1323impl Format<u16> for SinglePosFormat1<'_> {
1324 const FORMAT: u16 = 1;
1325}
1326
1327impl<'a> MinByteRange<'a> for SinglePosFormat1<'a> {
1328 fn min_byte_range(&self) -> Range<usize> {
1329 0..self.value_record_byte_range().end
1330 }
1331 fn min_table_bytes(&self) -> &'a [u8] {
1332 let range = self.min_byte_range();
1333 self.data.as_bytes().get(range).unwrap_or_default()
1334 }
1335}
1336
1337impl<'a> FontRead<'a> for SinglePosFormat1<'a> {
1338 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1339 #[allow(clippy::absurd_extreme_comparisons)]
1340 if data.len() < Self::MIN_SIZE {
1341 return Err(ReadError::OutOfBounds);
1342 }
1343 Ok(Self { data })
1344 }
1345}
1346
1347#[derive(Clone)]
1349pub struct SinglePosFormat1<'a> {
1350 data: FontData<'a>,
1351}
1352
1353#[allow(clippy::needless_lifetimes)]
1354impl<'a> SinglePosFormat1<'a> {
1355 pub const MIN_SIZE: usize =
1356 (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + ValueFormat::RAW_BYTE_LEN);
1357 basic_table_impls!(impl_the_methods);
1358
1359 pub fn pos_format(&self) -> u16 {
1361 let range = self.pos_format_byte_range();
1362 self.data.read_at(range.start).ok().unwrap()
1363 }
1364
1365 pub fn coverage_offset(&self) -> Offset16 {
1367 let range = self.coverage_offset_byte_range();
1368 self.data.read_at(range.start).ok().unwrap()
1369 }
1370
1371 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
1373 let data = self.data;
1374 self.coverage_offset().resolve(data)
1375 }
1376
1377 pub fn value_format(&self) -> ValueFormat {
1379 let range = self.value_format_byte_range();
1380 self.data.read_at(range.start).ok().unwrap()
1381 }
1382
1383 pub fn value_record(&self) -> ValueRecord {
1386 let range = self.value_record_byte_range();
1387 self.data
1388 .read_with_args(range, &self.value_format())
1389 .unwrap_or_default()
1390 }
1391
1392 pub fn pos_format_byte_range(&self) -> Range<usize> {
1393 let start = 0;
1394 start..start + u16::RAW_BYTE_LEN
1395 }
1396
1397 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
1398 let start = self.pos_format_byte_range().end;
1399 start..start + Offset16::RAW_BYTE_LEN
1400 }
1401
1402 pub fn value_format_byte_range(&self) -> Range<usize> {
1403 let start = self.coverage_offset_byte_range().end;
1404 start..start + ValueFormat::RAW_BYTE_LEN
1405 }
1406
1407 pub fn value_record_byte_range(&self) -> Range<usize> {
1408 let start = self.value_format_byte_range().end;
1409 start..start + <ValueRecord as ComputeSize>::compute_size(&self.value_format()).unwrap_or(0)
1410 }
1411}
1412
1413const _: () = assert!(FontData::default_data_long_enough(
1414 SinglePosFormat1::MIN_SIZE
1415));
1416
1417impl Default for SinglePosFormat1<'_> {
1418 fn default() -> Self {
1419 Self {
1420 data: FontData::default_format_1_u16_table_data(),
1421 }
1422 }
1423}
1424
1425#[cfg(feature = "experimental_traverse")]
1426impl<'a> SomeTable<'a> for SinglePosFormat1<'a> {
1427 fn type_name(&self) -> &str {
1428 "SinglePosFormat1"
1429 }
1430 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1431 match idx {
1432 0usize => Some(Field::new("pos_format", self.pos_format())),
1433 1usize => Some(Field::new(
1434 "coverage_offset",
1435 FieldType::offset(self.coverage_offset(), self.coverage()),
1436 )),
1437 2usize => Some(Field::new("value_format", self.value_format())),
1438 3usize => Some(Field::new(
1439 "value_record",
1440 self.value_record().traversal_type(self.offset_data()),
1441 )),
1442 _ => None,
1443 }
1444 }
1445}
1446
1447#[cfg(feature = "experimental_traverse")]
1448#[allow(clippy::needless_lifetimes)]
1449impl<'a> std::fmt::Debug for SinglePosFormat1<'a> {
1450 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1451 (self as &dyn SomeTable<'a>).fmt(f)
1452 }
1453}
1454
1455impl Format<u16> for SinglePosFormat2<'_> {
1456 const FORMAT: u16 = 2;
1457}
1458
1459impl<'a> MinByteRange<'a> for SinglePosFormat2<'a> {
1460 fn min_byte_range(&self) -> Range<usize> {
1461 0..self.value_records_byte_range().end
1462 }
1463 fn min_table_bytes(&self) -> &'a [u8] {
1464 let range = self.min_byte_range();
1465 self.data.as_bytes().get(range).unwrap_or_default()
1466 }
1467}
1468
1469impl<'a> FontRead<'a> for SinglePosFormat2<'a> {
1470 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1471 #[allow(clippy::absurd_extreme_comparisons)]
1472 if data.len() < Self::MIN_SIZE {
1473 return Err(ReadError::OutOfBounds);
1474 }
1475 Ok(Self { data })
1476 }
1477}
1478
1479#[derive(Clone)]
1481pub struct SinglePosFormat2<'a> {
1482 data: FontData<'a>,
1483}
1484
1485#[allow(clippy::needless_lifetimes)]
1486impl<'a> SinglePosFormat2<'a> {
1487 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1488 + Offset16::RAW_BYTE_LEN
1489 + ValueFormat::RAW_BYTE_LEN
1490 + u16::RAW_BYTE_LEN);
1491 basic_table_impls!(impl_the_methods);
1492
1493 pub fn pos_format(&self) -> u16 {
1495 let range = self.pos_format_byte_range();
1496 self.data.read_at(range.start).ok().unwrap()
1497 }
1498
1499 pub fn coverage_offset(&self) -> Offset16 {
1501 let range = self.coverage_offset_byte_range();
1502 self.data.read_at(range.start).ok().unwrap()
1503 }
1504
1505 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
1507 let data = self.data;
1508 self.coverage_offset().resolve(data)
1509 }
1510
1511 pub fn value_format(&self) -> ValueFormat {
1513 let range = self.value_format_byte_range();
1514 self.data.read_at(range.start).ok().unwrap()
1515 }
1516
1517 pub fn value_count(&self) -> u16 {
1520 let range = self.value_count_byte_range();
1521 self.data.read_at(range.start).ok().unwrap()
1522 }
1523
1524 pub fn value_records(&self) -> ComputedArray<'a, ValueRecord> {
1526 let range = self.value_records_byte_range();
1527 self.data
1528 .read_with_args(range, &self.value_format())
1529 .unwrap_or_default()
1530 }
1531
1532 pub fn pos_format_byte_range(&self) -> Range<usize> {
1533 let start = 0;
1534 start..start + u16::RAW_BYTE_LEN
1535 }
1536
1537 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
1538 let start = self.pos_format_byte_range().end;
1539 start..start + Offset16::RAW_BYTE_LEN
1540 }
1541
1542 pub fn value_format_byte_range(&self) -> Range<usize> {
1543 let start = self.coverage_offset_byte_range().end;
1544 start..start + ValueFormat::RAW_BYTE_LEN
1545 }
1546
1547 pub fn value_count_byte_range(&self) -> Range<usize> {
1548 let start = self.value_format_byte_range().end;
1549 start..start + u16::RAW_BYTE_LEN
1550 }
1551
1552 pub fn value_records_byte_range(&self) -> Range<usize> {
1553 let value_count = self.value_count();
1554 let start = self.value_count_byte_range().end;
1555 start
1556 ..start
1557 + (value_count as usize).saturating_mul(
1558 <ValueRecord as ComputeSize>::compute_size(&self.value_format()).unwrap_or(0),
1559 )
1560 }
1561}
1562
1563#[cfg(feature = "experimental_traverse")]
1564impl<'a> SomeTable<'a> for SinglePosFormat2<'a> {
1565 fn type_name(&self) -> &str {
1566 "SinglePosFormat2"
1567 }
1568 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1569 match idx {
1570 0usize => Some(Field::new("pos_format", self.pos_format())),
1571 1usize => Some(Field::new(
1572 "coverage_offset",
1573 FieldType::offset(self.coverage_offset(), self.coverage()),
1574 )),
1575 2usize => Some(Field::new("value_format", self.value_format())),
1576 3usize => Some(Field::new("value_count", self.value_count())),
1577 4usize => Some(Field::new(
1578 "value_records",
1579 traversal::FieldType::computed_array(
1580 "ValueRecord",
1581 self.value_records(),
1582 self.offset_data(),
1583 ),
1584 )),
1585 _ => None,
1586 }
1587 }
1588}
1589
1590#[cfg(feature = "experimental_traverse")]
1591#[allow(clippy::needless_lifetimes)]
1592impl<'a> std::fmt::Debug for SinglePosFormat2<'a> {
1593 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1594 (self as &dyn SomeTable<'a>).fmt(f)
1595 }
1596}
1597
1598#[derive(Clone)]
1600pub enum PairPos<'a> {
1601 Format1(PairPosFormat1<'a>),
1602 Format2(PairPosFormat2<'a>),
1603}
1604
1605impl Default for PairPos<'_> {
1606 fn default() -> Self {
1607 Self::Format1(Default::default())
1608 }
1609}
1610
1611impl<'a> PairPos<'a> {
1612 pub fn offset_data(&self) -> FontData<'a> {
1614 match self {
1615 Self::Format1(item) => item.offset_data(),
1616 Self::Format2(item) => item.offset_data(),
1617 }
1618 }
1619
1620 pub fn pos_format(&self) -> u16 {
1622 match self {
1623 Self::Format1(item) => item.pos_format(),
1624 Self::Format2(item) => item.pos_format(),
1625 }
1626 }
1627
1628 pub fn coverage_offset(&self) -> Offset16 {
1630 match self {
1631 Self::Format1(item) => item.coverage_offset(),
1632 Self::Format2(item) => item.coverage_offset(),
1633 }
1634 }
1635
1636 pub fn value_format1(&self) -> ValueFormat {
1639 match self {
1640 Self::Format1(item) => item.value_format1(),
1641 Self::Format2(item) => item.value_format1(),
1642 }
1643 }
1644
1645 pub fn value_format2(&self) -> ValueFormat {
1648 match self {
1649 Self::Format1(item) => item.value_format2(),
1650 Self::Format2(item) => item.value_format2(),
1651 }
1652 }
1653}
1654
1655impl<'a> FontRead<'a> for PairPos<'a> {
1656 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1657 let format: u16 = data.read_at(0usize)?;
1658 match format {
1659 PairPosFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
1660 PairPosFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
1661 other => Err(ReadError::InvalidFormat(other.into())),
1662 }
1663 }
1664}
1665
1666impl<'a> MinByteRange<'a> for PairPos<'a> {
1667 fn min_byte_range(&self) -> Range<usize> {
1668 match self {
1669 Self::Format1(item) => item.min_byte_range(),
1670 Self::Format2(item) => item.min_byte_range(),
1671 }
1672 }
1673 fn min_table_bytes(&self) -> &'a [u8] {
1674 match self {
1675 Self::Format1(item) => item.min_table_bytes(),
1676 Self::Format2(item) => item.min_table_bytes(),
1677 }
1678 }
1679}
1680
1681#[cfg(feature = "experimental_traverse")]
1682impl<'a> PairPos<'a> {
1683 fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
1684 match self {
1685 Self::Format1(table) => table,
1686 Self::Format2(table) => table,
1687 }
1688 }
1689}
1690
1691#[cfg(feature = "experimental_traverse")]
1692impl std::fmt::Debug for PairPos<'_> {
1693 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1694 self.dyn_inner().fmt(f)
1695 }
1696}
1697
1698#[cfg(feature = "experimental_traverse")]
1699impl<'a> SomeTable<'a> for PairPos<'a> {
1700 fn type_name(&self) -> &str {
1701 self.dyn_inner().type_name()
1702 }
1703 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1704 self.dyn_inner().get_field(idx)
1705 }
1706}
1707
1708impl Format<u16> for PairPosFormat1<'_> {
1709 const FORMAT: u16 = 1;
1710}
1711
1712impl<'a> MinByteRange<'a> for PairPosFormat1<'a> {
1713 fn min_byte_range(&self) -> Range<usize> {
1714 0..self.pair_set_offsets_byte_range().end
1715 }
1716 fn min_table_bytes(&self) -> &'a [u8] {
1717 let range = self.min_byte_range();
1718 self.data.as_bytes().get(range).unwrap_or_default()
1719 }
1720}
1721
1722impl<'a> FontRead<'a> for PairPosFormat1<'a> {
1723 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1724 #[allow(clippy::absurd_extreme_comparisons)]
1725 if data.len() < Self::MIN_SIZE {
1726 return Err(ReadError::OutOfBounds);
1727 }
1728 Ok(Self { data })
1729 }
1730}
1731
1732#[derive(Clone)]
1734pub struct PairPosFormat1<'a> {
1735 data: FontData<'a>,
1736}
1737
1738#[allow(clippy::needless_lifetimes)]
1739impl<'a> PairPosFormat1<'a> {
1740 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1741 + Offset16::RAW_BYTE_LEN
1742 + ValueFormat::RAW_BYTE_LEN
1743 + ValueFormat::RAW_BYTE_LEN
1744 + u16::RAW_BYTE_LEN);
1745 basic_table_impls!(impl_the_methods);
1746
1747 pub fn pos_format(&self) -> u16 {
1749 let range = self.pos_format_byte_range();
1750 self.data.read_at(range.start).ok().unwrap()
1751 }
1752
1753 pub fn coverage_offset(&self) -> Offset16 {
1755 let range = self.coverage_offset_byte_range();
1756 self.data.read_at(range.start).ok().unwrap()
1757 }
1758
1759 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
1761 let data = self.data;
1762 self.coverage_offset().resolve(data)
1763 }
1764
1765 pub fn value_format1(&self) -> ValueFormat {
1768 let range = self.value_format1_byte_range();
1769 self.data.read_at(range.start).ok().unwrap()
1770 }
1771
1772 pub fn value_format2(&self) -> ValueFormat {
1775 let range = self.value_format2_byte_range();
1776 self.data.read_at(range.start).ok().unwrap()
1777 }
1778
1779 pub fn pair_set_count(&self) -> u16 {
1781 let range = self.pair_set_count_byte_range();
1782 self.data.read_at(range.start).ok().unwrap()
1783 }
1784
1785 pub fn pair_set_offsets(&self) -> &'a [BigEndian<Offset16>] {
1788 let range = self.pair_set_offsets_byte_range();
1789 self.data.read_array(range).ok().unwrap_or_default()
1790 }
1791
1792 pub fn pair_sets(&self) -> ArrayOfOffsets<'a, PairSet<'a>, Offset16> {
1794 let data = self.data;
1795 let offsets = self.pair_set_offsets();
1796 let args = (self.value_format1(), self.value_format2());
1797 ArrayOfOffsets::new(offsets, data, args)
1798 }
1799
1800 pub fn pos_format_byte_range(&self) -> Range<usize> {
1801 let start = 0;
1802 start..start + u16::RAW_BYTE_LEN
1803 }
1804
1805 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
1806 let start = self.pos_format_byte_range().end;
1807 start..start + Offset16::RAW_BYTE_LEN
1808 }
1809
1810 pub fn value_format1_byte_range(&self) -> Range<usize> {
1811 let start = self.coverage_offset_byte_range().end;
1812 start..start + ValueFormat::RAW_BYTE_LEN
1813 }
1814
1815 pub fn value_format2_byte_range(&self) -> Range<usize> {
1816 let start = self.value_format1_byte_range().end;
1817 start..start + ValueFormat::RAW_BYTE_LEN
1818 }
1819
1820 pub fn pair_set_count_byte_range(&self) -> Range<usize> {
1821 let start = self.value_format2_byte_range().end;
1822 start..start + u16::RAW_BYTE_LEN
1823 }
1824
1825 pub fn pair_set_offsets_byte_range(&self) -> Range<usize> {
1826 let pair_set_count = self.pair_set_count();
1827 let start = self.pair_set_count_byte_range().end;
1828 start..start + (pair_set_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
1829 }
1830}
1831
1832const _: () = assert!(FontData::default_data_long_enough(PairPosFormat1::MIN_SIZE));
1833
1834impl Default for PairPosFormat1<'_> {
1835 fn default() -> Self {
1836 Self {
1837 data: FontData::default_format_1_u16_table_data(),
1838 }
1839 }
1840}
1841
1842#[cfg(feature = "experimental_traverse")]
1843impl<'a> SomeTable<'a> for PairPosFormat1<'a> {
1844 fn type_name(&self) -> &str {
1845 "PairPosFormat1"
1846 }
1847 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1848 match idx {
1849 0usize => Some(Field::new("pos_format", self.pos_format())),
1850 1usize => Some(Field::new(
1851 "coverage_offset",
1852 FieldType::offset(self.coverage_offset(), self.coverage()),
1853 )),
1854 2usize => Some(Field::new("value_format1", self.value_format1())),
1855 3usize => Some(Field::new("value_format2", self.value_format2())),
1856 4usize => Some(Field::new("pair_set_count", self.pair_set_count())),
1857 5usize => Some(Field::new(
1858 "pair_set_offsets",
1859 FieldType::from(self.pair_sets()),
1860 )),
1861 _ => None,
1862 }
1863 }
1864}
1865
1866#[cfg(feature = "experimental_traverse")]
1867#[allow(clippy::needless_lifetimes)]
1868impl<'a> std::fmt::Debug for PairPosFormat1<'a> {
1869 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1870 (self as &dyn SomeTable<'a>).fmt(f)
1871 }
1872}
1873
1874impl<'a> MinByteRange<'a> for PairSet<'a> {
1875 fn min_byte_range(&self) -> Range<usize> {
1876 0..self.pair_value_records_byte_range().end
1877 }
1878 fn min_table_bytes(&self) -> &'a [u8] {
1879 let range = self.min_byte_range();
1880 self.data.as_bytes().get(range).unwrap_or_default()
1881 }
1882}
1883
1884impl ReadArgs for PairSet<'_> {
1885 type Args = (ValueFormat, ValueFormat);
1886}
1887
1888impl<'a> FontReadWithArgs<'a> for PairSet<'a> {
1889 fn read_with_args(
1890 data: FontData<'a>,
1891 args: &(ValueFormat, ValueFormat),
1892 ) -> Result<Self, ReadError> {
1893 let (value_format1, value_format2) = *args;
1894
1895 #[allow(clippy::absurd_extreme_comparisons)]
1896 if data.len() < Self::MIN_SIZE {
1897 return Err(ReadError::OutOfBounds);
1898 }
1899 Ok(Self {
1900 data,
1901 value_format1,
1902 value_format2,
1903 })
1904 }
1905}
1906
1907impl<'a> PairSet<'a> {
1908 pub fn read(
1913 data: FontData<'a>,
1914 value_format1: ValueFormat,
1915 value_format2: ValueFormat,
1916 ) -> Result<Self, ReadError> {
1917 let args = (value_format1, value_format2);
1918 Self::read_with_args(data, &args)
1919 }
1920}
1921
1922#[derive(Clone)]
1924pub struct PairSet<'a> {
1925 data: FontData<'a>,
1926 value_format1: ValueFormat,
1927 value_format2: ValueFormat,
1928}
1929
1930#[allow(clippy::needless_lifetimes)]
1931impl<'a> PairSet<'a> {
1932 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
1933 basic_table_impls!(impl_the_methods);
1934
1935 pub fn pair_value_count(&self) -> u16 {
1937 let range = self.pair_value_count_byte_range();
1938 self.data.read_at(range.start).ok().unwrap()
1939 }
1940
1941 pub fn pair_value_records(&self) -> ComputedArray<'a, PairValueRecord> {
1944 let range = self.pair_value_records_byte_range();
1945 self.data
1946 .read_with_args(range, &(self.value_format1(), self.value_format2()))
1947 .unwrap_or_default()
1948 }
1949
1950 pub(crate) fn value_format1(&self) -> ValueFormat {
1951 self.value_format1
1952 }
1953
1954 pub(crate) fn value_format2(&self) -> ValueFormat {
1955 self.value_format2
1956 }
1957
1958 pub fn pair_value_count_byte_range(&self) -> Range<usize> {
1959 let start = 0;
1960 start..start + u16::RAW_BYTE_LEN
1961 }
1962
1963 pub fn pair_value_records_byte_range(&self) -> Range<usize> {
1964 let pair_value_count = self.pair_value_count();
1965 let start = self.pair_value_count_byte_range().end;
1966 start
1967 ..start
1968 + (pair_value_count as usize).saturating_mul(
1969 <PairValueRecord as ComputeSize>::compute_size(&(
1970 self.value_format1(),
1971 self.value_format2(),
1972 ))
1973 .unwrap_or(0),
1974 )
1975 }
1976}
1977
1978const _: () = assert!(FontData::default_data_long_enough(PairSet::MIN_SIZE));
1979
1980impl Default for PairSet<'_> {
1981 fn default() -> Self {
1982 Self {
1983 data: FontData::default_table_data(),
1984 value_format1: Default::default(),
1985 value_format2: Default::default(),
1986 }
1987 }
1988}
1989
1990#[cfg(feature = "experimental_traverse")]
1991impl<'a> SomeTable<'a> for PairSet<'a> {
1992 fn type_name(&self) -> &str {
1993 "PairSet"
1994 }
1995 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1996 match idx {
1997 0usize => Some(Field::new("pair_value_count", self.pair_value_count())),
1998 1usize => Some(Field::new(
1999 "pair_value_records",
2000 traversal::FieldType::computed_array(
2001 "PairValueRecord",
2002 self.pair_value_records(),
2003 self.offset_data(),
2004 ),
2005 )),
2006 _ => None,
2007 }
2008 }
2009}
2010
2011#[cfg(feature = "experimental_traverse")]
2012#[allow(clippy::needless_lifetimes)]
2013impl<'a> std::fmt::Debug for PairSet<'a> {
2014 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2015 (self as &dyn SomeTable<'a>).fmt(f)
2016 }
2017}
2018
2019#[derive(Clone, Debug)]
2021pub struct PairValueRecord {
2022 pub second_glyph: BigEndian<GlyphId16>,
2025 pub value_record1: ValueRecord,
2027 pub value_record2: ValueRecord,
2029}
2030
2031impl PairValueRecord {
2032 pub fn second_glyph(&self) -> GlyphId16 {
2035 self.second_glyph.get()
2036 }
2037
2038 pub fn value_record1(&self) -> &ValueRecord {
2040 &self.value_record1
2041 }
2042
2043 pub fn value_record2(&self) -> &ValueRecord {
2045 &self.value_record2
2046 }
2047}
2048
2049impl ReadArgs for PairValueRecord {
2050 type Args = (ValueFormat, ValueFormat);
2051}
2052
2053impl ComputeSize for PairValueRecord {
2054 #[allow(clippy::needless_question_mark)]
2055 fn compute_size(args: &(ValueFormat, ValueFormat)) -> Result<usize, ReadError> {
2056 let (value_format1, value_format2) = *args;
2057 let mut result = 0usize;
2058 result = result
2059 .checked_add(GlyphId16::RAW_BYTE_LEN)
2060 .ok_or(ReadError::OutOfBounds)?;
2061 result = result
2062 .checked_add(<ValueRecord as ComputeSize>::compute_size(&value_format1).unwrap_or(0))
2063 .ok_or(ReadError::OutOfBounds)?;
2064 result = result
2065 .checked_add(<ValueRecord as ComputeSize>::compute_size(&value_format2).unwrap_or(0))
2066 .ok_or(ReadError::OutOfBounds)?;
2067 Ok(result)
2068 }
2069}
2070
2071impl<'a> FontReadWithArgs<'a> for PairValueRecord {
2072 fn read_with_args(
2073 data: FontData<'a>,
2074 args: &(ValueFormat, ValueFormat),
2075 ) -> Result<Self, ReadError> {
2076 let mut cursor = data.cursor();
2077 let (value_format1, value_format2) = *args;
2078 Ok(Self {
2079 second_glyph: cursor.read_be()?,
2080 value_record1: cursor.read_with_args(&value_format1)?,
2081 value_record2: cursor.read_with_args(&value_format2)?,
2082 })
2083 }
2084}
2085
2086#[allow(clippy::needless_lifetimes)]
2087impl<'a> PairValueRecord {
2088 pub fn read(
2093 data: FontData<'a>,
2094 value_format1: ValueFormat,
2095 value_format2: ValueFormat,
2096 ) -> Result<Self, ReadError> {
2097 let args = (value_format1, value_format2);
2098 Self::read_with_args(data, &args)
2099 }
2100}
2101
2102#[cfg(feature = "experimental_traverse")]
2103impl<'a> SomeRecord<'a> for PairValueRecord {
2104 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
2105 RecordResolver {
2106 name: "PairValueRecord",
2107 get_field: Box::new(move |idx, _data| match idx {
2108 0usize => Some(Field::new("second_glyph", self.second_glyph())),
2109 1usize => Some(Field::new(
2110 "value_record1",
2111 self.value_record1().traversal_type(_data),
2112 )),
2113 2usize => Some(Field::new(
2114 "value_record2",
2115 self.value_record2().traversal_type(_data),
2116 )),
2117 _ => None,
2118 }),
2119 data,
2120 }
2121 }
2122}
2123
2124impl Format<u16> for PairPosFormat2<'_> {
2125 const FORMAT: u16 = 2;
2126}
2127
2128impl<'a> MinByteRange<'a> for PairPosFormat2<'a> {
2129 fn min_byte_range(&self) -> Range<usize> {
2130 0..self.class1_records_byte_range().end
2131 }
2132 fn min_table_bytes(&self) -> &'a [u8] {
2133 let range = self.min_byte_range();
2134 self.data.as_bytes().get(range).unwrap_or_default()
2135 }
2136}
2137
2138impl<'a> FontRead<'a> for PairPosFormat2<'a> {
2139 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2140 #[allow(clippy::absurd_extreme_comparisons)]
2141 if data.len() < Self::MIN_SIZE {
2142 return Err(ReadError::OutOfBounds);
2143 }
2144 Ok(Self { data })
2145 }
2146}
2147
2148#[derive(Clone)]
2150pub struct PairPosFormat2<'a> {
2151 data: FontData<'a>,
2152}
2153
2154#[allow(clippy::needless_lifetimes)]
2155impl<'a> PairPosFormat2<'a> {
2156 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
2157 + Offset16::RAW_BYTE_LEN
2158 + ValueFormat::RAW_BYTE_LEN
2159 + ValueFormat::RAW_BYTE_LEN
2160 + Offset16::RAW_BYTE_LEN
2161 + Offset16::RAW_BYTE_LEN
2162 + u16::RAW_BYTE_LEN
2163 + u16::RAW_BYTE_LEN);
2164 basic_table_impls!(impl_the_methods);
2165
2166 pub fn pos_format(&self) -> u16 {
2168 let range = self.pos_format_byte_range();
2169 self.data.read_at(range.start).ok().unwrap()
2170 }
2171
2172 pub fn coverage_offset(&self) -> Offset16 {
2174 let range = self.coverage_offset_byte_range();
2175 self.data.read_at(range.start).ok().unwrap()
2176 }
2177
2178 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2180 let data = self.data;
2181 self.coverage_offset().resolve(data)
2182 }
2183
2184 pub fn value_format1(&self) -> ValueFormat {
2187 let range = self.value_format1_byte_range();
2188 self.data.read_at(range.start).ok().unwrap()
2189 }
2190
2191 pub fn value_format2(&self) -> ValueFormat {
2194 let range = self.value_format2_byte_range();
2195 self.data.read_at(range.start).ok().unwrap()
2196 }
2197
2198 pub fn class_def1_offset(&self) -> Offset16 {
2201 let range = self.class_def1_offset_byte_range();
2202 self.data.read_at(range.start).ok().unwrap()
2203 }
2204
2205 pub fn class_def1(&self) -> Result<ClassDef<'a>, ReadError> {
2207 let data = self.data;
2208 self.class_def1_offset().resolve(data)
2209 }
2210
2211 pub fn class_def2_offset(&self) -> Offset16 {
2214 let range = self.class_def2_offset_byte_range();
2215 self.data.read_at(range.start).ok().unwrap()
2216 }
2217
2218 pub fn class_def2(&self) -> Result<ClassDef<'a>, ReadError> {
2220 let data = self.data;
2221 self.class_def2_offset().resolve(data)
2222 }
2223
2224 pub fn class1_count(&self) -> u16 {
2226 let range = self.class1_count_byte_range();
2227 self.data.read_at(range.start).ok().unwrap()
2228 }
2229
2230 pub fn class2_count(&self) -> u16 {
2232 let range = self.class2_count_byte_range();
2233 self.data.read_at(range.start).ok().unwrap()
2234 }
2235
2236 pub fn class1_records(&self) -> ComputedArray<'a, Class1Record<'a>> {
2238 let range = self.class1_records_byte_range();
2239 self.data
2240 .read_with_args(
2241 range,
2242 &(
2243 self.class2_count(),
2244 self.value_format1(),
2245 self.value_format2(),
2246 ),
2247 )
2248 .unwrap_or_default()
2249 }
2250
2251 pub fn pos_format_byte_range(&self) -> Range<usize> {
2252 let start = 0;
2253 start..start + u16::RAW_BYTE_LEN
2254 }
2255
2256 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
2257 let start = self.pos_format_byte_range().end;
2258 start..start + Offset16::RAW_BYTE_LEN
2259 }
2260
2261 pub fn value_format1_byte_range(&self) -> Range<usize> {
2262 let start = self.coverage_offset_byte_range().end;
2263 start..start + ValueFormat::RAW_BYTE_LEN
2264 }
2265
2266 pub fn value_format2_byte_range(&self) -> Range<usize> {
2267 let start = self.value_format1_byte_range().end;
2268 start..start + ValueFormat::RAW_BYTE_LEN
2269 }
2270
2271 pub fn class_def1_offset_byte_range(&self) -> Range<usize> {
2272 let start = self.value_format2_byte_range().end;
2273 start..start + Offset16::RAW_BYTE_LEN
2274 }
2275
2276 pub fn class_def2_offset_byte_range(&self) -> Range<usize> {
2277 let start = self.class_def1_offset_byte_range().end;
2278 start..start + Offset16::RAW_BYTE_LEN
2279 }
2280
2281 pub fn class1_count_byte_range(&self) -> Range<usize> {
2282 let start = self.class_def2_offset_byte_range().end;
2283 start..start + u16::RAW_BYTE_LEN
2284 }
2285
2286 pub fn class2_count_byte_range(&self) -> Range<usize> {
2287 let start = self.class1_count_byte_range().end;
2288 start..start + u16::RAW_BYTE_LEN
2289 }
2290
2291 pub fn class1_records_byte_range(&self) -> Range<usize> {
2292 let class1_count = self.class1_count();
2293 let start = self.class2_count_byte_range().end;
2294 start
2295 ..start
2296 + (class1_count as usize).saturating_mul(
2297 <Class1Record as ComputeSize>::compute_size(&(
2298 self.class2_count(),
2299 self.value_format1(),
2300 self.value_format2(),
2301 ))
2302 .unwrap_or(0),
2303 )
2304 }
2305}
2306
2307#[cfg(feature = "experimental_traverse")]
2308impl<'a> SomeTable<'a> for PairPosFormat2<'a> {
2309 fn type_name(&self) -> &str {
2310 "PairPosFormat2"
2311 }
2312 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2313 match idx {
2314 0usize => Some(Field::new("pos_format", self.pos_format())),
2315 1usize => Some(Field::new(
2316 "coverage_offset",
2317 FieldType::offset(self.coverage_offset(), self.coverage()),
2318 )),
2319 2usize => Some(Field::new("value_format1", self.value_format1())),
2320 3usize => Some(Field::new("value_format2", self.value_format2())),
2321 4usize => Some(Field::new(
2322 "class_def1_offset",
2323 FieldType::offset(self.class_def1_offset(), self.class_def1()),
2324 )),
2325 5usize => Some(Field::new(
2326 "class_def2_offset",
2327 FieldType::offset(self.class_def2_offset(), self.class_def2()),
2328 )),
2329 6usize => Some(Field::new("class1_count", self.class1_count())),
2330 7usize => Some(Field::new("class2_count", self.class2_count())),
2331 8usize => Some(Field::new(
2332 "class1_records",
2333 traversal::FieldType::computed_array(
2334 "Class1Record",
2335 self.class1_records(),
2336 self.offset_data(),
2337 ),
2338 )),
2339 _ => None,
2340 }
2341 }
2342}
2343
2344#[cfg(feature = "experimental_traverse")]
2345#[allow(clippy::needless_lifetimes)]
2346impl<'a> std::fmt::Debug for PairPosFormat2<'a> {
2347 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2348 (self as &dyn SomeTable<'a>).fmt(f)
2349 }
2350}
2351
2352#[derive(Clone, Debug)]
2354pub struct Class1Record<'a> {
2355 pub class2_records: ComputedArray<'a, Class2Record>,
2357}
2358
2359impl<'a> Class1Record<'a> {
2360 pub fn class2_records(&self) -> &ComputedArray<'a, Class2Record> {
2362 &self.class2_records
2363 }
2364}
2365
2366impl ReadArgs for Class1Record<'_> {
2367 type Args = (u16, ValueFormat, ValueFormat);
2368}
2369
2370impl ComputeSize for Class1Record<'_> {
2371 #[allow(clippy::needless_question_mark)]
2372 fn compute_size(args: &(u16, ValueFormat, ValueFormat)) -> Result<usize, ReadError> {
2373 let (class2_count, value_format1, value_format2) = *args;
2374 Ok((class2_count as usize).saturating_mul(
2375 <Class2Record as ComputeSize>::compute_size(&(value_format1, value_format2))
2376 .unwrap_or(0),
2377 ))
2378 }
2379}
2380
2381impl<'a> FontReadWithArgs<'a> for Class1Record<'a> {
2382 fn read_with_args(
2383 data: FontData<'a>,
2384 args: &(u16, ValueFormat, ValueFormat),
2385 ) -> Result<Self, ReadError> {
2386 let mut cursor = data.cursor();
2387 let (class2_count, value_format1, value_format2) = *args;
2388 Ok(Self {
2389 class2_records: cursor
2390 .read_computed_array(class2_count as usize, &(value_format1, value_format2))?,
2391 })
2392 }
2393}
2394
2395#[allow(clippy::needless_lifetimes)]
2396impl<'a> Class1Record<'a> {
2397 pub fn read(
2402 data: FontData<'a>,
2403 class2_count: u16,
2404 value_format1: ValueFormat,
2405 value_format2: ValueFormat,
2406 ) -> Result<Self, ReadError> {
2407 let args = (class2_count, value_format1, value_format2);
2408 Self::read_with_args(data, &args)
2409 }
2410}
2411
2412#[cfg(feature = "experimental_traverse")]
2413impl<'a> SomeRecord<'a> for Class1Record<'a> {
2414 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
2415 RecordResolver {
2416 name: "Class1Record",
2417 get_field: Box::new(move |idx, _data| match idx {
2418 0usize => Some(Field::new(
2419 "class2_records",
2420 traversal::FieldType::computed_array(
2421 "Class2Record",
2422 self.class2_records().clone(),
2423 FontData::new(&[]),
2424 ),
2425 )),
2426 _ => None,
2427 }),
2428 data,
2429 }
2430 }
2431}
2432
2433#[derive(Clone, Debug)]
2435pub struct Class2Record {
2436 pub value_record1: ValueRecord,
2438 pub value_record2: ValueRecord,
2440}
2441
2442impl Class2Record {
2443 pub fn value_record1(&self) -> &ValueRecord {
2445 &self.value_record1
2446 }
2447
2448 pub fn value_record2(&self) -> &ValueRecord {
2450 &self.value_record2
2451 }
2452}
2453
2454impl ReadArgs for Class2Record {
2455 type Args = (ValueFormat, ValueFormat);
2456}
2457
2458impl ComputeSize for Class2Record {
2459 #[allow(clippy::needless_question_mark)]
2460 fn compute_size(args: &(ValueFormat, ValueFormat)) -> Result<usize, ReadError> {
2461 let (value_format1, value_format2) = *args;
2462 let mut result = 0usize;
2463 result = result
2464 .checked_add(<ValueRecord as ComputeSize>::compute_size(&value_format1).unwrap_or(0))
2465 .ok_or(ReadError::OutOfBounds)?;
2466 result = result
2467 .checked_add(<ValueRecord as ComputeSize>::compute_size(&value_format2).unwrap_or(0))
2468 .ok_or(ReadError::OutOfBounds)?;
2469 Ok(result)
2470 }
2471}
2472
2473impl<'a> FontReadWithArgs<'a> for Class2Record {
2474 fn read_with_args(
2475 data: FontData<'a>,
2476 args: &(ValueFormat, ValueFormat),
2477 ) -> Result<Self, ReadError> {
2478 let mut cursor = data.cursor();
2479 let (value_format1, value_format2) = *args;
2480 Ok(Self {
2481 value_record1: cursor.read_with_args(&value_format1)?,
2482 value_record2: cursor.read_with_args(&value_format2)?,
2483 })
2484 }
2485}
2486
2487#[allow(clippy::needless_lifetimes)]
2488impl<'a> Class2Record {
2489 pub fn read(
2494 data: FontData<'a>,
2495 value_format1: ValueFormat,
2496 value_format2: ValueFormat,
2497 ) -> Result<Self, ReadError> {
2498 let args = (value_format1, value_format2);
2499 Self::read_with_args(data, &args)
2500 }
2501}
2502
2503#[cfg(feature = "experimental_traverse")]
2504impl<'a> SomeRecord<'a> for Class2Record {
2505 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
2506 RecordResolver {
2507 name: "Class2Record",
2508 get_field: Box::new(move |idx, _data| match idx {
2509 0usize => Some(Field::new(
2510 "value_record1",
2511 self.value_record1().traversal_type(_data),
2512 )),
2513 1usize => Some(Field::new(
2514 "value_record2",
2515 self.value_record2().traversal_type(_data),
2516 )),
2517 _ => None,
2518 }),
2519 data,
2520 }
2521 }
2522}
2523
2524impl Format<u16> for CursivePosFormat1<'_> {
2525 const FORMAT: u16 = 1;
2526}
2527
2528impl<'a> MinByteRange<'a> for CursivePosFormat1<'a> {
2529 fn min_byte_range(&self) -> Range<usize> {
2530 0..self.entry_exit_record_byte_range().end
2531 }
2532 fn min_table_bytes(&self) -> &'a [u8] {
2533 let range = self.min_byte_range();
2534 self.data.as_bytes().get(range).unwrap_or_default()
2535 }
2536}
2537
2538impl<'a> FontRead<'a> for CursivePosFormat1<'a> {
2539 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2540 #[allow(clippy::absurd_extreme_comparisons)]
2541 if data.len() < Self::MIN_SIZE {
2542 return Err(ReadError::OutOfBounds);
2543 }
2544 Ok(Self { data })
2545 }
2546}
2547
2548#[derive(Clone)]
2550pub struct CursivePosFormat1<'a> {
2551 data: FontData<'a>,
2552}
2553
2554#[allow(clippy::needless_lifetimes)]
2555impl<'a> CursivePosFormat1<'a> {
2556 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
2557 basic_table_impls!(impl_the_methods);
2558
2559 pub fn pos_format(&self) -> u16 {
2561 let range = self.pos_format_byte_range();
2562 self.data.read_at(range.start).ok().unwrap()
2563 }
2564
2565 pub fn coverage_offset(&self) -> Offset16 {
2567 let range = self.coverage_offset_byte_range();
2568 self.data.read_at(range.start).ok().unwrap()
2569 }
2570
2571 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2573 let data = self.data;
2574 self.coverage_offset().resolve(data)
2575 }
2576
2577 pub fn entry_exit_count(&self) -> u16 {
2579 let range = self.entry_exit_count_byte_range();
2580 self.data.read_at(range.start).ok().unwrap()
2581 }
2582
2583 pub fn entry_exit_record(&self) -> &'a [EntryExitRecord] {
2585 let range = self.entry_exit_record_byte_range();
2586 self.data.read_array(range).ok().unwrap_or_default()
2587 }
2588
2589 pub fn pos_format_byte_range(&self) -> Range<usize> {
2590 let start = 0;
2591 start..start + u16::RAW_BYTE_LEN
2592 }
2593
2594 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
2595 let start = self.pos_format_byte_range().end;
2596 start..start + Offset16::RAW_BYTE_LEN
2597 }
2598
2599 pub fn entry_exit_count_byte_range(&self) -> Range<usize> {
2600 let start = self.coverage_offset_byte_range().end;
2601 start..start + u16::RAW_BYTE_LEN
2602 }
2603
2604 pub fn entry_exit_record_byte_range(&self) -> Range<usize> {
2605 let entry_exit_count = self.entry_exit_count();
2606 let start = self.entry_exit_count_byte_range().end;
2607 start..start + (entry_exit_count as usize).saturating_mul(EntryExitRecord::RAW_BYTE_LEN)
2608 }
2609}
2610
2611const _: () = assert!(FontData::default_data_long_enough(
2612 CursivePosFormat1::MIN_SIZE
2613));
2614
2615impl Default for CursivePosFormat1<'_> {
2616 fn default() -> Self {
2617 Self {
2618 data: FontData::default_format_1_u16_table_data(),
2619 }
2620 }
2621}
2622
2623#[cfg(feature = "experimental_traverse")]
2624impl<'a> SomeTable<'a> for CursivePosFormat1<'a> {
2625 fn type_name(&self) -> &str {
2626 "CursivePosFormat1"
2627 }
2628 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2629 match idx {
2630 0usize => Some(Field::new("pos_format", self.pos_format())),
2631 1usize => Some(Field::new(
2632 "coverage_offset",
2633 FieldType::offset(self.coverage_offset(), self.coverage()),
2634 )),
2635 2usize => Some(Field::new("entry_exit_count", self.entry_exit_count())),
2636 3usize => Some(Field::new(
2637 "entry_exit_record",
2638 traversal::FieldType::array_of_records(
2639 stringify!(EntryExitRecord),
2640 self.entry_exit_record(),
2641 self.offset_data(),
2642 ),
2643 )),
2644 _ => None,
2645 }
2646 }
2647}
2648
2649#[cfg(feature = "experimental_traverse")]
2650#[allow(clippy::needless_lifetimes)]
2651impl<'a> std::fmt::Debug for CursivePosFormat1<'a> {
2652 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2653 (self as &dyn SomeTable<'a>).fmt(f)
2654 }
2655}
2656
2657#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
2659#[repr(C)]
2660#[repr(packed)]
2661pub struct EntryExitRecord {
2662 pub entry_anchor_offset: BigEndian<Nullable<Offset16>>,
2665 pub exit_anchor_offset: BigEndian<Nullable<Offset16>>,
2668}
2669
2670impl EntryExitRecord {
2671 pub fn entry_anchor_offset(&self) -> Nullable<Offset16> {
2674 self.entry_anchor_offset.get()
2675 }
2676
2677 pub fn entry_anchor<'a>(
2683 &self,
2684 data: FontData<'a>,
2685 ) -> Option<Result<AnchorTable<'a>, ReadError>> {
2686 self.entry_anchor_offset().resolve(data)
2687 }
2688
2689 pub fn exit_anchor_offset(&self) -> Nullable<Offset16> {
2692 self.exit_anchor_offset.get()
2693 }
2694
2695 pub fn exit_anchor<'a>(
2701 &self,
2702 data: FontData<'a>,
2703 ) -> Option<Result<AnchorTable<'a>, ReadError>> {
2704 self.exit_anchor_offset().resolve(data)
2705 }
2706}
2707
2708impl FixedSize for EntryExitRecord {
2709 const RAW_BYTE_LEN: usize = Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
2710}
2711
2712#[cfg(feature = "experimental_traverse")]
2713impl<'a> SomeRecord<'a> for EntryExitRecord {
2714 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
2715 RecordResolver {
2716 name: "EntryExitRecord",
2717 get_field: Box::new(move |idx, _data| match idx {
2718 0usize => Some(Field::new(
2719 "entry_anchor_offset",
2720 FieldType::offset(self.entry_anchor_offset(), self.entry_anchor(_data)),
2721 )),
2722 1usize => Some(Field::new(
2723 "exit_anchor_offset",
2724 FieldType::offset(self.exit_anchor_offset(), self.exit_anchor(_data)),
2725 )),
2726 _ => None,
2727 }),
2728 data,
2729 }
2730 }
2731}
2732
2733impl Format<u16> for MarkBasePosFormat1<'_> {
2734 const FORMAT: u16 = 1;
2735}
2736
2737impl<'a> MinByteRange<'a> for MarkBasePosFormat1<'a> {
2738 fn min_byte_range(&self) -> Range<usize> {
2739 0..self.base_array_offset_byte_range().end
2740 }
2741 fn min_table_bytes(&self) -> &'a [u8] {
2742 let range = self.min_byte_range();
2743 self.data.as_bytes().get(range).unwrap_or_default()
2744 }
2745}
2746
2747impl<'a> FontRead<'a> for MarkBasePosFormat1<'a> {
2748 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2749 #[allow(clippy::absurd_extreme_comparisons)]
2750 if data.len() < Self::MIN_SIZE {
2751 return Err(ReadError::OutOfBounds);
2752 }
2753 Ok(Self { data })
2754 }
2755}
2756
2757#[derive(Clone)]
2759pub struct MarkBasePosFormat1<'a> {
2760 data: FontData<'a>,
2761}
2762
2763#[allow(clippy::needless_lifetimes)]
2764impl<'a> MarkBasePosFormat1<'a> {
2765 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
2766 + Offset16::RAW_BYTE_LEN
2767 + Offset16::RAW_BYTE_LEN
2768 + u16::RAW_BYTE_LEN
2769 + Offset16::RAW_BYTE_LEN
2770 + Offset16::RAW_BYTE_LEN);
2771 basic_table_impls!(impl_the_methods);
2772
2773 pub fn pos_format(&self) -> u16 {
2775 let range = self.pos_format_byte_range();
2776 self.data.read_at(range.start).ok().unwrap()
2777 }
2778
2779 pub fn mark_coverage_offset(&self) -> Offset16 {
2782 let range = self.mark_coverage_offset_byte_range();
2783 self.data.read_at(range.start).ok().unwrap()
2784 }
2785
2786 pub fn mark_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2788 let data = self.data;
2789 self.mark_coverage_offset().resolve(data)
2790 }
2791
2792 pub fn base_coverage_offset(&self) -> Offset16 {
2795 let range = self.base_coverage_offset_byte_range();
2796 self.data.read_at(range.start).ok().unwrap()
2797 }
2798
2799 pub fn base_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2801 let data = self.data;
2802 self.base_coverage_offset().resolve(data)
2803 }
2804
2805 pub fn mark_class_count(&self) -> u16 {
2807 let range = self.mark_class_count_byte_range();
2808 self.data.read_at(range.start).ok().unwrap()
2809 }
2810
2811 pub fn mark_array_offset(&self) -> Offset16 {
2814 let range = self.mark_array_offset_byte_range();
2815 self.data.read_at(range.start).ok().unwrap()
2816 }
2817
2818 pub fn mark_array(&self) -> Result<MarkArray<'a>, ReadError> {
2820 let data = self.data;
2821 self.mark_array_offset().resolve(data)
2822 }
2823
2824 pub fn base_array_offset(&self) -> Offset16 {
2827 let range = self.base_array_offset_byte_range();
2828 self.data.read_at(range.start).ok().unwrap()
2829 }
2830
2831 pub fn base_array(&self) -> Result<BaseArray<'a>, ReadError> {
2833 let data = self.data;
2834 let args = self.mark_class_count();
2835 self.base_array_offset().resolve_with_args(data, &args)
2836 }
2837
2838 pub fn pos_format_byte_range(&self) -> Range<usize> {
2839 let start = 0;
2840 start..start + u16::RAW_BYTE_LEN
2841 }
2842
2843 pub fn mark_coverage_offset_byte_range(&self) -> Range<usize> {
2844 let start = self.pos_format_byte_range().end;
2845 start..start + Offset16::RAW_BYTE_LEN
2846 }
2847
2848 pub fn base_coverage_offset_byte_range(&self) -> Range<usize> {
2849 let start = self.mark_coverage_offset_byte_range().end;
2850 start..start + Offset16::RAW_BYTE_LEN
2851 }
2852
2853 pub fn mark_class_count_byte_range(&self) -> Range<usize> {
2854 let start = self.base_coverage_offset_byte_range().end;
2855 start..start + u16::RAW_BYTE_LEN
2856 }
2857
2858 pub fn mark_array_offset_byte_range(&self) -> Range<usize> {
2859 let start = self.mark_class_count_byte_range().end;
2860 start..start + Offset16::RAW_BYTE_LEN
2861 }
2862
2863 pub fn base_array_offset_byte_range(&self) -> Range<usize> {
2864 let start = self.mark_array_offset_byte_range().end;
2865 start..start + Offset16::RAW_BYTE_LEN
2866 }
2867}
2868
2869const _: () = assert!(FontData::default_data_long_enough(
2870 MarkBasePosFormat1::MIN_SIZE
2871));
2872
2873impl Default for MarkBasePosFormat1<'_> {
2874 fn default() -> Self {
2875 Self {
2876 data: FontData::default_format_1_u16_table_data(),
2877 }
2878 }
2879}
2880
2881#[cfg(feature = "experimental_traverse")]
2882impl<'a> SomeTable<'a> for MarkBasePosFormat1<'a> {
2883 fn type_name(&self) -> &str {
2884 "MarkBasePosFormat1"
2885 }
2886 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2887 match idx {
2888 0usize => Some(Field::new("pos_format", self.pos_format())),
2889 1usize => Some(Field::new(
2890 "mark_coverage_offset",
2891 FieldType::offset(self.mark_coverage_offset(), self.mark_coverage()),
2892 )),
2893 2usize => Some(Field::new(
2894 "base_coverage_offset",
2895 FieldType::offset(self.base_coverage_offset(), self.base_coverage()),
2896 )),
2897 3usize => Some(Field::new("mark_class_count", self.mark_class_count())),
2898 4usize => Some(Field::new(
2899 "mark_array_offset",
2900 FieldType::offset(self.mark_array_offset(), self.mark_array()),
2901 )),
2902 5usize => Some(Field::new(
2903 "base_array_offset",
2904 FieldType::offset(self.base_array_offset(), self.base_array()),
2905 )),
2906 _ => None,
2907 }
2908 }
2909}
2910
2911#[cfg(feature = "experimental_traverse")]
2912#[allow(clippy::needless_lifetimes)]
2913impl<'a> std::fmt::Debug for MarkBasePosFormat1<'a> {
2914 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2915 (self as &dyn SomeTable<'a>).fmt(f)
2916 }
2917}
2918
2919impl<'a> MinByteRange<'a> for BaseArray<'a> {
2920 fn min_byte_range(&self) -> Range<usize> {
2921 0..self.base_records_byte_range().end
2922 }
2923 fn min_table_bytes(&self) -> &'a [u8] {
2924 let range = self.min_byte_range();
2925 self.data.as_bytes().get(range).unwrap_or_default()
2926 }
2927}
2928
2929impl ReadArgs for BaseArray<'_> {
2930 type Args = u16;
2931}
2932
2933impl<'a> FontReadWithArgs<'a> for BaseArray<'a> {
2934 fn read_with_args(data: FontData<'a>, args: &u16) -> Result<Self, ReadError> {
2935 let mark_class_count = *args;
2936
2937 #[allow(clippy::absurd_extreme_comparisons)]
2938 if data.len() < Self::MIN_SIZE {
2939 return Err(ReadError::OutOfBounds);
2940 }
2941 Ok(Self {
2942 data,
2943 mark_class_count,
2944 })
2945 }
2946}
2947
2948impl<'a> BaseArray<'a> {
2949 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
2954 let args = mark_class_count;
2955 Self::read_with_args(data, &args)
2956 }
2957}
2958
2959#[derive(Clone)]
2961pub struct BaseArray<'a> {
2962 data: FontData<'a>,
2963 mark_class_count: u16,
2964}
2965
2966#[allow(clippy::needless_lifetimes)]
2967impl<'a> BaseArray<'a> {
2968 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
2969 basic_table_impls!(impl_the_methods);
2970
2971 pub fn base_count(&self) -> u16 {
2973 let range = self.base_count_byte_range();
2974 self.data.read_at(range.start).ok().unwrap()
2975 }
2976
2977 pub fn base_records(&self) -> ComputedArray<'a, BaseRecord<'a>> {
2979 let range = self.base_records_byte_range();
2980 self.data
2981 .read_with_args(range, &self.mark_class_count())
2982 .unwrap_or_default()
2983 }
2984
2985 pub(crate) fn mark_class_count(&self) -> u16 {
2986 self.mark_class_count
2987 }
2988
2989 pub fn base_count_byte_range(&self) -> Range<usize> {
2990 let start = 0;
2991 start..start + u16::RAW_BYTE_LEN
2992 }
2993
2994 pub fn base_records_byte_range(&self) -> Range<usize> {
2995 let base_count = self.base_count();
2996 let start = self.base_count_byte_range().end;
2997 start
2998 ..start
2999 + (base_count as usize).saturating_mul(
3000 <BaseRecord as ComputeSize>::compute_size(&self.mark_class_count())
3001 .unwrap_or(0),
3002 )
3003 }
3004}
3005
3006const _: () = assert!(FontData::default_data_long_enough(BaseArray::MIN_SIZE));
3007
3008impl Default for BaseArray<'_> {
3009 fn default() -> Self {
3010 Self {
3011 data: FontData::default_table_data(),
3012 mark_class_count: Default::default(),
3013 }
3014 }
3015}
3016
3017#[cfg(feature = "experimental_traverse")]
3018impl<'a> SomeTable<'a> for BaseArray<'a> {
3019 fn type_name(&self) -> &str {
3020 "BaseArray"
3021 }
3022 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3023 match idx {
3024 0usize => Some(Field::new("base_count", self.base_count())),
3025 1usize => Some(Field::new(
3026 "base_records",
3027 traversal::FieldType::computed_array(
3028 "BaseRecord",
3029 self.base_records(),
3030 self.offset_data(),
3031 ),
3032 )),
3033 _ => None,
3034 }
3035 }
3036}
3037
3038#[cfg(feature = "experimental_traverse")]
3039#[allow(clippy::needless_lifetimes)]
3040impl<'a> std::fmt::Debug for BaseArray<'a> {
3041 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3042 (self as &dyn SomeTable<'a>).fmt(f)
3043 }
3044}
3045
3046#[derive(Clone, Debug)]
3048pub struct BaseRecord<'a> {
3049 pub base_anchor_offsets: &'a [BigEndian<Nullable<Offset16>>],
3053}
3054
3055impl<'a> BaseRecord<'a> {
3056 pub fn base_anchor_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
3060 self.base_anchor_offsets
3061 }
3062
3063 pub fn base_anchors(
3070 &self,
3071 data: FontData<'a>,
3072 ) -> ArrayOfNullableOffsets<'a, AnchorTable<'a>, Offset16> {
3073 let offsets = self.base_anchor_offsets();
3074 ArrayOfNullableOffsets::new(offsets, data, ())
3075 }
3076}
3077
3078impl ReadArgs for BaseRecord<'_> {
3079 type Args = u16;
3080}
3081
3082impl ComputeSize for BaseRecord<'_> {
3083 #[allow(clippy::needless_question_mark)]
3084 fn compute_size(args: &u16) -> Result<usize, ReadError> {
3085 let mark_class_count = *args;
3086 Ok((mark_class_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN))
3087 }
3088}
3089
3090impl<'a> FontReadWithArgs<'a> for BaseRecord<'a> {
3091 fn read_with_args(data: FontData<'a>, args: &u16) -> Result<Self, ReadError> {
3092 let mut cursor = data.cursor();
3093 let mark_class_count = *args;
3094 Ok(Self {
3095 base_anchor_offsets: cursor.read_array(mark_class_count as usize)?,
3096 })
3097 }
3098}
3099
3100#[allow(clippy::needless_lifetimes)]
3101impl<'a> BaseRecord<'a> {
3102 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
3107 let args = mark_class_count;
3108 Self::read_with_args(data, &args)
3109 }
3110}
3111
3112#[cfg(feature = "experimental_traverse")]
3113impl<'a> SomeRecord<'a> for BaseRecord<'a> {
3114 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
3115 RecordResolver {
3116 name: "BaseRecord",
3117 get_field: Box::new(move |idx, _data| match idx {
3118 0usize => Some(Field::new(
3119 "base_anchor_offsets",
3120 FieldType::from(self.base_anchors(_data)),
3121 )),
3122 _ => None,
3123 }),
3124 data,
3125 }
3126 }
3127}
3128
3129impl Format<u16> for MarkLigPosFormat1<'_> {
3130 const FORMAT: u16 = 1;
3131}
3132
3133impl<'a> MinByteRange<'a> for MarkLigPosFormat1<'a> {
3134 fn min_byte_range(&self) -> Range<usize> {
3135 0..self.ligature_array_offset_byte_range().end
3136 }
3137 fn min_table_bytes(&self) -> &'a [u8] {
3138 let range = self.min_byte_range();
3139 self.data.as_bytes().get(range).unwrap_or_default()
3140 }
3141}
3142
3143impl<'a> FontRead<'a> for MarkLigPosFormat1<'a> {
3144 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3145 #[allow(clippy::absurd_extreme_comparisons)]
3146 if data.len() < Self::MIN_SIZE {
3147 return Err(ReadError::OutOfBounds);
3148 }
3149 Ok(Self { data })
3150 }
3151}
3152
3153#[derive(Clone)]
3155pub struct MarkLigPosFormat1<'a> {
3156 data: FontData<'a>,
3157}
3158
3159#[allow(clippy::needless_lifetimes)]
3160impl<'a> MarkLigPosFormat1<'a> {
3161 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
3162 + Offset16::RAW_BYTE_LEN
3163 + Offset16::RAW_BYTE_LEN
3164 + u16::RAW_BYTE_LEN
3165 + Offset16::RAW_BYTE_LEN
3166 + Offset16::RAW_BYTE_LEN);
3167 basic_table_impls!(impl_the_methods);
3168
3169 pub fn pos_format(&self) -> u16 {
3171 let range = self.pos_format_byte_range();
3172 self.data.read_at(range.start).ok().unwrap()
3173 }
3174
3175 pub fn mark_coverage_offset(&self) -> Offset16 {
3178 let range = self.mark_coverage_offset_byte_range();
3179 self.data.read_at(range.start).ok().unwrap()
3180 }
3181
3182 pub fn mark_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
3184 let data = self.data;
3185 self.mark_coverage_offset().resolve(data)
3186 }
3187
3188 pub fn ligature_coverage_offset(&self) -> Offset16 {
3191 let range = self.ligature_coverage_offset_byte_range();
3192 self.data.read_at(range.start).ok().unwrap()
3193 }
3194
3195 pub fn ligature_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
3197 let data = self.data;
3198 self.ligature_coverage_offset().resolve(data)
3199 }
3200
3201 pub fn mark_class_count(&self) -> u16 {
3203 let range = self.mark_class_count_byte_range();
3204 self.data.read_at(range.start).ok().unwrap()
3205 }
3206
3207 pub fn mark_array_offset(&self) -> Offset16 {
3210 let range = self.mark_array_offset_byte_range();
3211 self.data.read_at(range.start).ok().unwrap()
3212 }
3213
3214 pub fn mark_array(&self) -> Result<MarkArray<'a>, ReadError> {
3216 let data = self.data;
3217 self.mark_array_offset().resolve(data)
3218 }
3219
3220 pub fn ligature_array_offset(&self) -> Offset16 {
3223 let range = self.ligature_array_offset_byte_range();
3224 self.data.read_at(range.start).ok().unwrap()
3225 }
3226
3227 pub fn ligature_array(&self) -> Result<LigatureArray<'a>, ReadError> {
3229 let data = self.data;
3230 let args = self.mark_class_count();
3231 self.ligature_array_offset().resolve_with_args(data, &args)
3232 }
3233
3234 pub fn pos_format_byte_range(&self) -> Range<usize> {
3235 let start = 0;
3236 start..start + u16::RAW_BYTE_LEN
3237 }
3238
3239 pub fn mark_coverage_offset_byte_range(&self) -> Range<usize> {
3240 let start = self.pos_format_byte_range().end;
3241 start..start + Offset16::RAW_BYTE_LEN
3242 }
3243
3244 pub fn ligature_coverage_offset_byte_range(&self) -> Range<usize> {
3245 let start = self.mark_coverage_offset_byte_range().end;
3246 start..start + Offset16::RAW_BYTE_LEN
3247 }
3248
3249 pub fn mark_class_count_byte_range(&self) -> Range<usize> {
3250 let start = self.ligature_coverage_offset_byte_range().end;
3251 start..start + u16::RAW_BYTE_LEN
3252 }
3253
3254 pub fn mark_array_offset_byte_range(&self) -> Range<usize> {
3255 let start = self.mark_class_count_byte_range().end;
3256 start..start + Offset16::RAW_BYTE_LEN
3257 }
3258
3259 pub fn ligature_array_offset_byte_range(&self) -> Range<usize> {
3260 let start = self.mark_array_offset_byte_range().end;
3261 start..start + Offset16::RAW_BYTE_LEN
3262 }
3263}
3264
3265const _: () = assert!(FontData::default_data_long_enough(
3266 MarkLigPosFormat1::MIN_SIZE
3267));
3268
3269impl Default for MarkLigPosFormat1<'_> {
3270 fn default() -> Self {
3271 Self {
3272 data: FontData::default_format_1_u16_table_data(),
3273 }
3274 }
3275}
3276
3277#[cfg(feature = "experimental_traverse")]
3278impl<'a> SomeTable<'a> for MarkLigPosFormat1<'a> {
3279 fn type_name(&self) -> &str {
3280 "MarkLigPosFormat1"
3281 }
3282 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3283 match idx {
3284 0usize => Some(Field::new("pos_format", self.pos_format())),
3285 1usize => Some(Field::new(
3286 "mark_coverage_offset",
3287 FieldType::offset(self.mark_coverage_offset(), self.mark_coverage()),
3288 )),
3289 2usize => Some(Field::new(
3290 "ligature_coverage_offset",
3291 FieldType::offset(self.ligature_coverage_offset(), self.ligature_coverage()),
3292 )),
3293 3usize => Some(Field::new("mark_class_count", self.mark_class_count())),
3294 4usize => Some(Field::new(
3295 "mark_array_offset",
3296 FieldType::offset(self.mark_array_offset(), self.mark_array()),
3297 )),
3298 5usize => Some(Field::new(
3299 "ligature_array_offset",
3300 FieldType::offset(self.ligature_array_offset(), self.ligature_array()),
3301 )),
3302 _ => None,
3303 }
3304 }
3305}
3306
3307#[cfg(feature = "experimental_traverse")]
3308#[allow(clippy::needless_lifetimes)]
3309impl<'a> std::fmt::Debug for MarkLigPosFormat1<'a> {
3310 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3311 (self as &dyn SomeTable<'a>).fmt(f)
3312 }
3313}
3314
3315impl<'a> MinByteRange<'a> for LigatureArray<'a> {
3316 fn min_byte_range(&self) -> Range<usize> {
3317 0..self.ligature_attach_offsets_byte_range().end
3318 }
3319 fn min_table_bytes(&self) -> &'a [u8] {
3320 let range = self.min_byte_range();
3321 self.data.as_bytes().get(range).unwrap_or_default()
3322 }
3323}
3324
3325impl ReadArgs for LigatureArray<'_> {
3326 type Args = u16;
3327}
3328
3329impl<'a> FontReadWithArgs<'a> for LigatureArray<'a> {
3330 fn read_with_args(data: FontData<'a>, args: &u16) -> Result<Self, ReadError> {
3331 let mark_class_count = *args;
3332
3333 #[allow(clippy::absurd_extreme_comparisons)]
3334 if data.len() < Self::MIN_SIZE {
3335 return Err(ReadError::OutOfBounds);
3336 }
3337 Ok(Self {
3338 data,
3339 mark_class_count,
3340 })
3341 }
3342}
3343
3344impl<'a> LigatureArray<'a> {
3345 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
3350 let args = mark_class_count;
3351 Self::read_with_args(data, &args)
3352 }
3353}
3354
3355#[derive(Clone)]
3357pub struct LigatureArray<'a> {
3358 data: FontData<'a>,
3359 mark_class_count: u16,
3360}
3361
3362#[allow(clippy::needless_lifetimes)]
3363impl<'a> LigatureArray<'a> {
3364 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
3365 basic_table_impls!(impl_the_methods);
3366
3367 pub fn ligature_count(&self) -> u16 {
3369 let range = self.ligature_count_byte_range();
3370 self.data.read_at(range.start).ok().unwrap()
3371 }
3372
3373 pub fn ligature_attach_offsets(&self) -> &'a [BigEndian<Offset16>] {
3377 let range = self.ligature_attach_offsets_byte_range();
3378 self.data.read_array(range).ok().unwrap_or_default()
3379 }
3380
3381 pub fn ligature_attaches(&self) -> ArrayOfOffsets<'a, LigatureAttach<'a>, Offset16> {
3383 let data = self.data;
3384 let offsets = self.ligature_attach_offsets();
3385 let args = self.mark_class_count();
3386 ArrayOfOffsets::new(offsets, data, args)
3387 }
3388
3389 pub(crate) fn mark_class_count(&self) -> u16 {
3390 self.mark_class_count
3391 }
3392
3393 pub fn ligature_count_byte_range(&self) -> Range<usize> {
3394 let start = 0;
3395 start..start + u16::RAW_BYTE_LEN
3396 }
3397
3398 pub fn ligature_attach_offsets_byte_range(&self) -> Range<usize> {
3399 let ligature_count = self.ligature_count();
3400 let start = self.ligature_count_byte_range().end;
3401 start..start + (ligature_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
3402 }
3403}
3404
3405const _: () = assert!(FontData::default_data_long_enough(LigatureArray::MIN_SIZE));
3406
3407impl Default for LigatureArray<'_> {
3408 fn default() -> Self {
3409 Self {
3410 data: FontData::default_table_data(),
3411 mark_class_count: Default::default(),
3412 }
3413 }
3414}
3415
3416#[cfg(feature = "experimental_traverse")]
3417impl<'a> SomeTable<'a> for LigatureArray<'a> {
3418 fn type_name(&self) -> &str {
3419 "LigatureArray"
3420 }
3421 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3422 match idx {
3423 0usize => Some(Field::new("ligature_count", self.ligature_count())),
3424 1usize => Some(Field::new(
3425 "ligature_attach_offsets",
3426 FieldType::from(self.ligature_attaches()),
3427 )),
3428 _ => None,
3429 }
3430 }
3431}
3432
3433#[cfg(feature = "experimental_traverse")]
3434#[allow(clippy::needless_lifetimes)]
3435impl<'a> std::fmt::Debug for LigatureArray<'a> {
3436 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3437 (self as &dyn SomeTable<'a>).fmt(f)
3438 }
3439}
3440
3441impl<'a> MinByteRange<'a> for LigatureAttach<'a> {
3442 fn min_byte_range(&self) -> Range<usize> {
3443 0..self.component_records_byte_range().end
3444 }
3445 fn min_table_bytes(&self) -> &'a [u8] {
3446 let range = self.min_byte_range();
3447 self.data.as_bytes().get(range).unwrap_or_default()
3448 }
3449}
3450
3451impl ReadArgs for LigatureAttach<'_> {
3452 type Args = u16;
3453}
3454
3455impl<'a> FontReadWithArgs<'a> for LigatureAttach<'a> {
3456 fn read_with_args(data: FontData<'a>, args: &u16) -> Result<Self, ReadError> {
3457 let mark_class_count = *args;
3458
3459 #[allow(clippy::absurd_extreme_comparisons)]
3460 if data.len() < Self::MIN_SIZE {
3461 return Err(ReadError::OutOfBounds);
3462 }
3463 Ok(Self {
3464 data,
3465 mark_class_count,
3466 })
3467 }
3468}
3469
3470impl<'a> LigatureAttach<'a> {
3471 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
3476 let args = mark_class_count;
3477 Self::read_with_args(data, &args)
3478 }
3479}
3480
3481#[derive(Clone)]
3483pub struct LigatureAttach<'a> {
3484 data: FontData<'a>,
3485 mark_class_count: u16,
3486}
3487
3488#[allow(clippy::needless_lifetimes)]
3489impl<'a> LigatureAttach<'a> {
3490 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
3491 basic_table_impls!(impl_the_methods);
3492
3493 pub fn component_count(&self) -> u16 {
3495 let range = self.component_count_byte_range();
3496 self.data.read_at(range.start).ok().unwrap()
3497 }
3498
3499 pub fn component_records(&self) -> ComputedArray<'a, ComponentRecord<'a>> {
3501 let range = self.component_records_byte_range();
3502 self.data
3503 .read_with_args(range, &self.mark_class_count())
3504 .unwrap_or_default()
3505 }
3506
3507 pub(crate) fn mark_class_count(&self) -> u16 {
3508 self.mark_class_count
3509 }
3510
3511 pub fn component_count_byte_range(&self) -> Range<usize> {
3512 let start = 0;
3513 start..start + u16::RAW_BYTE_LEN
3514 }
3515
3516 pub fn component_records_byte_range(&self) -> Range<usize> {
3517 let component_count = self.component_count();
3518 let start = self.component_count_byte_range().end;
3519 start
3520 ..start
3521 + (component_count as usize).saturating_mul(
3522 <ComponentRecord as ComputeSize>::compute_size(&self.mark_class_count())
3523 .unwrap_or(0),
3524 )
3525 }
3526}
3527
3528const _: () = assert!(FontData::default_data_long_enough(LigatureAttach::MIN_SIZE));
3529
3530impl Default for LigatureAttach<'_> {
3531 fn default() -> Self {
3532 Self {
3533 data: FontData::default_table_data(),
3534 mark_class_count: Default::default(),
3535 }
3536 }
3537}
3538
3539#[cfg(feature = "experimental_traverse")]
3540impl<'a> SomeTable<'a> for LigatureAttach<'a> {
3541 fn type_name(&self) -> &str {
3542 "LigatureAttach"
3543 }
3544 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3545 match idx {
3546 0usize => Some(Field::new("component_count", self.component_count())),
3547 1usize => Some(Field::new(
3548 "component_records",
3549 traversal::FieldType::computed_array(
3550 "ComponentRecord",
3551 self.component_records(),
3552 self.offset_data(),
3553 ),
3554 )),
3555 _ => None,
3556 }
3557 }
3558}
3559
3560#[cfg(feature = "experimental_traverse")]
3561#[allow(clippy::needless_lifetimes)]
3562impl<'a> std::fmt::Debug for LigatureAttach<'a> {
3563 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3564 (self as &dyn SomeTable<'a>).fmt(f)
3565 }
3566}
3567
3568#[derive(Clone, Debug)]
3570pub struct ComponentRecord<'a> {
3571 pub ligature_anchor_offsets: &'a [BigEndian<Nullable<Offset16>>],
3575}
3576
3577impl<'a> ComponentRecord<'a> {
3578 pub fn ligature_anchor_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
3582 self.ligature_anchor_offsets
3583 }
3584
3585 pub fn ligature_anchors(
3592 &self,
3593 data: FontData<'a>,
3594 ) -> ArrayOfNullableOffsets<'a, AnchorTable<'a>, Offset16> {
3595 let offsets = self.ligature_anchor_offsets();
3596 ArrayOfNullableOffsets::new(offsets, data, ())
3597 }
3598}
3599
3600impl ReadArgs for ComponentRecord<'_> {
3601 type Args = u16;
3602}
3603
3604impl ComputeSize for ComponentRecord<'_> {
3605 #[allow(clippy::needless_question_mark)]
3606 fn compute_size(args: &u16) -> Result<usize, ReadError> {
3607 let mark_class_count = *args;
3608 Ok((mark_class_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN))
3609 }
3610}
3611
3612impl<'a> FontReadWithArgs<'a> for ComponentRecord<'a> {
3613 fn read_with_args(data: FontData<'a>, args: &u16) -> Result<Self, ReadError> {
3614 let mut cursor = data.cursor();
3615 let mark_class_count = *args;
3616 Ok(Self {
3617 ligature_anchor_offsets: cursor.read_array(mark_class_count as usize)?,
3618 })
3619 }
3620}
3621
3622#[allow(clippy::needless_lifetimes)]
3623impl<'a> ComponentRecord<'a> {
3624 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
3629 let args = mark_class_count;
3630 Self::read_with_args(data, &args)
3631 }
3632}
3633
3634#[cfg(feature = "experimental_traverse")]
3635impl<'a> SomeRecord<'a> for ComponentRecord<'a> {
3636 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
3637 RecordResolver {
3638 name: "ComponentRecord",
3639 get_field: Box::new(move |idx, _data| match idx {
3640 0usize => Some(Field::new(
3641 "ligature_anchor_offsets",
3642 FieldType::from(self.ligature_anchors(_data)),
3643 )),
3644 _ => None,
3645 }),
3646 data,
3647 }
3648 }
3649}
3650
3651impl Format<u16> for MarkMarkPosFormat1<'_> {
3652 const FORMAT: u16 = 1;
3653}
3654
3655impl<'a> MinByteRange<'a> for MarkMarkPosFormat1<'a> {
3656 fn min_byte_range(&self) -> Range<usize> {
3657 0..self.mark2_array_offset_byte_range().end
3658 }
3659 fn min_table_bytes(&self) -> &'a [u8] {
3660 let range = self.min_byte_range();
3661 self.data.as_bytes().get(range).unwrap_or_default()
3662 }
3663}
3664
3665impl<'a> FontRead<'a> for MarkMarkPosFormat1<'a> {
3666 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3667 #[allow(clippy::absurd_extreme_comparisons)]
3668 if data.len() < Self::MIN_SIZE {
3669 return Err(ReadError::OutOfBounds);
3670 }
3671 Ok(Self { data })
3672 }
3673}
3674
3675#[derive(Clone)]
3677pub struct MarkMarkPosFormat1<'a> {
3678 data: FontData<'a>,
3679}
3680
3681#[allow(clippy::needless_lifetimes)]
3682impl<'a> MarkMarkPosFormat1<'a> {
3683 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
3684 + Offset16::RAW_BYTE_LEN
3685 + Offset16::RAW_BYTE_LEN
3686 + u16::RAW_BYTE_LEN
3687 + Offset16::RAW_BYTE_LEN
3688 + Offset16::RAW_BYTE_LEN);
3689 basic_table_impls!(impl_the_methods);
3690
3691 pub fn pos_format(&self) -> u16 {
3693 let range = self.pos_format_byte_range();
3694 self.data.read_at(range.start).ok().unwrap()
3695 }
3696
3697 pub fn mark1_coverage_offset(&self) -> Offset16 {
3700 let range = self.mark1_coverage_offset_byte_range();
3701 self.data.read_at(range.start).ok().unwrap()
3702 }
3703
3704 pub fn mark1_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
3706 let data = self.data;
3707 self.mark1_coverage_offset().resolve(data)
3708 }
3709
3710 pub fn mark2_coverage_offset(&self) -> Offset16 {
3713 let range = self.mark2_coverage_offset_byte_range();
3714 self.data.read_at(range.start).ok().unwrap()
3715 }
3716
3717 pub fn mark2_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
3719 let data = self.data;
3720 self.mark2_coverage_offset().resolve(data)
3721 }
3722
3723 pub fn mark_class_count(&self) -> u16 {
3725 let range = self.mark_class_count_byte_range();
3726 self.data.read_at(range.start).ok().unwrap()
3727 }
3728
3729 pub fn mark1_array_offset(&self) -> Offset16 {
3732 let range = self.mark1_array_offset_byte_range();
3733 self.data.read_at(range.start).ok().unwrap()
3734 }
3735
3736 pub fn mark1_array(&self) -> Result<MarkArray<'a>, ReadError> {
3738 let data = self.data;
3739 self.mark1_array_offset().resolve(data)
3740 }
3741
3742 pub fn mark2_array_offset(&self) -> Offset16 {
3745 let range = self.mark2_array_offset_byte_range();
3746 self.data.read_at(range.start).ok().unwrap()
3747 }
3748
3749 pub fn mark2_array(&self) -> Result<Mark2Array<'a>, ReadError> {
3751 let data = self.data;
3752 let args = self.mark_class_count();
3753 self.mark2_array_offset().resolve_with_args(data, &args)
3754 }
3755
3756 pub fn pos_format_byte_range(&self) -> Range<usize> {
3757 let start = 0;
3758 start..start + u16::RAW_BYTE_LEN
3759 }
3760
3761 pub fn mark1_coverage_offset_byte_range(&self) -> Range<usize> {
3762 let start = self.pos_format_byte_range().end;
3763 start..start + Offset16::RAW_BYTE_LEN
3764 }
3765
3766 pub fn mark2_coverage_offset_byte_range(&self) -> Range<usize> {
3767 let start = self.mark1_coverage_offset_byte_range().end;
3768 start..start + Offset16::RAW_BYTE_LEN
3769 }
3770
3771 pub fn mark_class_count_byte_range(&self) -> Range<usize> {
3772 let start = self.mark2_coverage_offset_byte_range().end;
3773 start..start + u16::RAW_BYTE_LEN
3774 }
3775
3776 pub fn mark1_array_offset_byte_range(&self) -> Range<usize> {
3777 let start = self.mark_class_count_byte_range().end;
3778 start..start + Offset16::RAW_BYTE_LEN
3779 }
3780
3781 pub fn mark2_array_offset_byte_range(&self) -> Range<usize> {
3782 let start = self.mark1_array_offset_byte_range().end;
3783 start..start + Offset16::RAW_BYTE_LEN
3784 }
3785}
3786
3787const _: () = assert!(FontData::default_data_long_enough(
3788 MarkMarkPosFormat1::MIN_SIZE
3789));
3790
3791impl Default for MarkMarkPosFormat1<'_> {
3792 fn default() -> Self {
3793 Self {
3794 data: FontData::default_format_1_u16_table_data(),
3795 }
3796 }
3797}
3798
3799#[cfg(feature = "experimental_traverse")]
3800impl<'a> SomeTable<'a> for MarkMarkPosFormat1<'a> {
3801 fn type_name(&self) -> &str {
3802 "MarkMarkPosFormat1"
3803 }
3804 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3805 match idx {
3806 0usize => Some(Field::new("pos_format", self.pos_format())),
3807 1usize => Some(Field::new(
3808 "mark1_coverage_offset",
3809 FieldType::offset(self.mark1_coverage_offset(), self.mark1_coverage()),
3810 )),
3811 2usize => Some(Field::new(
3812 "mark2_coverage_offset",
3813 FieldType::offset(self.mark2_coverage_offset(), self.mark2_coverage()),
3814 )),
3815 3usize => Some(Field::new("mark_class_count", self.mark_class_count())),
3816 4usize => Some(Field::new(
3817 "mark1_array_offset",
3818 FieldType::offset(self.mark1_array_offset(), self.mark1_array()),
3819 )),
3820 5usize => Some(Field::new(
3821 "mark2_array_offset",
3822 FieldType::offset(self.mark2_array_offset(), self.mark2_array()),
3823 )),
3824 _ => None,
3825 }
3826 }
3827}
3828
3829#[cfg(feature = "experimental_traverse")]
3830#[allow(clippy::needless_lifetimes)]
3831impl<'a> std::fmt::Debug for MarkMarkPosFormat1<'a> {
3832 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3833 (self as &dyn SomeTable<'a>).fmt(f)
3834 }
3835}
3836
3837impl<'a> MinByteRange<'a> for Mark2Array<'a> {
3838 fn min_byte_range(&self) -> Range<usize> {
3839 0..self.mark2_records_byte_range().end
3840 }
3841 fn min_table_bytes(&self) -> &'a [u8] {
3842 let range = self.min_byte_range();
3843 self.data.as_bytes().get(range).unwrap_or_default()
3844 }
3845}
3846
3847impl ReadArgs for Mark2Array<'_> {
3848 type Args = u16;
3849}
3850
3851impl<'a> FontReadWithArgs<'a> for Mark2Array<'a> {
3852 fn read_with_args(data: FontData<'a>, args: &u16) -> Result<Self, ReadError> {
3853 let mark_class_count = *args;
3854
3855 #[allow(clippy::absurd_extreme_comparisons)]
3856 if data.len() < Self::MIN_SIZE {
3857 return Err(ReadError::OutOfBounds);
3858 }
3859 Ok(Self {
3860 data,
3861 mark_class_count,
3862 })
3863 }
3864}
3865
3866impl<'a> Mark2Array<'a> {
3867 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
3872 let args = mark_class_count;
3873 Self::read_with_args(data, &args)
3874 }
3875}
3876
3877#[derive(Clone)]
3879pub struct Mark2Array<'a> {
3880 data: FontData<'a>,
3881 mark_class_count: u16,
3882}
3883
3884#[allow(clippy::needless_lifetimes)]
3885impl<'a> Mark2Array<'a> {
3886 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
3887 basic_table_impls!(impl_the_methods);
3888
3889 pub fn mark2_count(&self) -> u16 {
3891 let range = self.mark2_count_byte_range();
3892 self.data.read_at(range.start).ok().unwrap()
3893 }
3894
3895 pub fn mark2_records(&self) -> ComputedArray<'a, Mark2Record<'a>> {
3897 let range = self.mark2_records_byte_range();
3898 self.data
3899 .read_with_args(range, &self.mark_class_count())
3900 .unwrap_or_default()
3901 }
3902
3903 pub(crate) fn mark_class_count(&self) -> u16 {
3904 self.mark_class_count
3905 }
3906
3907 pub fn mark2_count_byte_range(&self) -> Range<usize> {
3908 let start = 0;
3909 start..start + u16::RAW_BYTE_LEN
3910 }
3911
3912 pub fn mark2_records_byte_range(&self) -> Range<usize> {
3913 let mark2_count = self.mark2_count();
3914 let start = self.mark2_count_byte_range().end;
3915 start
3916 ..start
3917 + (mark2_count as usize).saturating_mul(
3918 <Mark2Record as ComputeSize>::compute_size(&self.mark_class_count())
3919 .unwrap_or(0),
3920 )
3921 }
3922}
3923
3924const _: () = assert!(FontData::default_data_long_enough(Mark2Array::MIN_SIZE));
3925
3926impl Default for Mark2Array<'_> {
3927 fn default() -> Self {
3928 Self {
3929 data: FontData::default_table_data(),
3930 mark_class_count: Default::default(),
3931 }
3932 }
3933}
3934
3935#[cfg(feature = "experimental_traverse")]
3936impl<'a> SomeTable<'a> for Mark2Array<'a> {
3937 fn type_name(&self) -> &str {
3938 "Mark2Array"
3939 }
3940 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3941 match idx {
3942 0usize => Some(Field::new("mark2_count", self.mark2_count())),
3943 1usize => Some(Field::new(
3944 "mark2_records",
3945 traversal::FieldType::computed_array(
3946 "Mark2Record",
3947 self.mark2_records(),
3948 self.offset_data(),
3949 ),
3950 )),
3951 _ => None,
3952 }
3953 }
3954}
3955
3956#[cfg(feature = "experimental_traverse")]
3957#[allow(clippy::needless_lifetimes)]
3958impl<'a> std::fmt::Debug for Mark2Array<'a> {
3959 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3960 (self as &dyn SomeTable<'a>).fmt(f)
3961 }
3962}
3963
3964#[derive(Clone, Debug)]
3966pub struct Mark2Record<'a> {
3967 pub mark2_anchor_offsets: &'a [BigEndian<Nullable<Offset16>>],
3971}
3972
3973impl<'a> Mark2Record<'a> {
3974 pub fn mark2_anchor_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
3978 self.mark2_anchor_offsets
3979 }
3980
3981 pub fn mark2_anchors(
3988 &self,
3989 data: FontData<'a>,
3990 ) -> ArrayOfNullableOffsets<'a, AnchorTable<'a>, Offset16> {
3991 let offsets = self.mark2_anchor_offsets();
3992 ArrayOfNullableOffsets::new(offsets, data, ())
3993 }
3994}
3995
3996impl ReadArgs for Mark2Record<'_> {
3997 type Args = u16;
3998}
3999
4000impl ComputeSize for Mark2Record<'_> {
4001 #[allow(clippy::needless_question_mark)]
4002 fn compute_size(args: &u16) -> Result<usize, ReadError> {
4003 let mark_class_count = *args;
4004 Ok((mark_class_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN))
4005 }
4006}
4007
4008impl<'a> FontReadWithArgs<'a> for Mark2Record<'a> {
4009 fn read_with_args(data: FontData<'a>, args: &u16) -> Result<Self, ReadError> {
4010 let mut cursor = data.cursor();
4011 let mark_class_count = *args;
4012 Ok(Self {
4013 mark2_anchor_offsets: cursor.read_array(mark_class_count as usize)?,
4014 })
4015 }
4016}
4017
4018#[allow(clippy::needless_lifetimes)]
4019impl<'a> Mark2Record<'a> {
4020 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
4025 let args = mark_class_count;
4026 Self::read_with_args(data, &args)
4027 }
4028}
4029
4030#[cfg(feature = "experimental_traverse")]
4031impl<'a> SomeRecord<'a> for Mark2Record<'a> {
4032 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
4033 RecordResolver {
4034 name: "Mark2Record",
4035 get_field: Box::new(move |idx, _data| match idx {
4036 0usize => Some(Field::new(
4037 "mark2_anchor_offsets",
4038 FieldType::from(self.mark2_anchors(_data)),
4039 )),
4040 _ => None,
4041 }),
4042 data,
4043 }
4044 }
4045}
4046
4047impl Format<u16> for ExtensionPosFormat1<'_> {
4048 const FORMAT: u16 = 1;
4049}
4050
4051impl Discriminant for ExtensionPosFormat1<'_, ()> {
4052 fn read_discriminant(data: FontData<'_>) -> Result<u16, ReadError> {
4053 data.read_at(u16::RAW_BYTE_LEN)
4054 }
4055}
4056
4057impl<'a, T> MinByteRange<'a> for ExtensionPosFormat1<'a, T> {
4058 fn min_byte_range(&self) -> Range<usize> {
4059 0..self.extension_offset_byte_range().end
4060 }
4061 fn min_table_bytes(&self) -> &'a [u8] {
4062 let range = self.min_byte_range();
4063 self.data.as_bytes().get(range).unwrap_or_default()
4064 }
4065}
4066
4067impl<'a, T> FontRead<'a> for ExtensionPosFormat1<'a, T> {
4068 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4069 #[allow(clippy::absurd_extreme_comparisons)]
4070 if data.len() < Self::MIN_SIZE {
4071 return Err(ReadError::OutOfBounds);
4072 }
4073 Ok(Self {
4074 data,
4075 offset_type: std::marker::PhantomData,
4076 })
4077 }
4078}
4079
4080impl<'a, T> ExtensionPosFormat1<'a, T> {
4081 #[allow(dead_code)]
4082 pub(crate) fn of_unit_type(&self) -> ExtensionPosFormat1<'a, ()> {
4084 ExtensionPosFormat1 {
4085 data: self.data,
4086 offset_type: std::marker::PhantomData,
4087 }
4088 }
4089}
4090
4091#[derive(Clone)]
4093pub struct ExtensionPosFormat1<'a, T = ()> {
4094 data: FontData<'a>,
4095 offset_type: std::marker::PhantomData<*const T>,
4096}
4097
4098#[allow(clippy::needless_lifetimes)]
4099impl<'a, T> ExtensionPosFormat1<'a, T> {
4100 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN);
4101 basic_table_impls!(impl_the_methods);
4102
4103 pub fn pos_format(&self) -> u16 {
4105 let range = self.pos_format_byte_range();
4106 self.data.read_at(range.start).ok().unwrap()
4107 }
4108
4109 pub fn extension_lookup_type(&self) -> u16 {
4112 let range = self.extension_lookup_type_byte_range();
4113 self.data.read_at(range.start).ok().unwrap()
4114 }
4115
4116 pub fn extension_offset(&self) -> Offset32 {
4120 let range = self.extension_offset_byte_range();
4121 self.data.read_at(range.start).ok().unwrap()
4122 }
4123
4124 pub fn extension(&self) -> Result<T, ReadError>
4126 where
4127 T: FontRead<'a>,
4128 {
4129 let data = self.data;
4130 self.extension_offset().resolve(data)
4131 }
4132
4133 pub fn pos_format_byte_range(&self) -> Range<usize> {
4134 let start = 0;
4135 start..start + u16::RAW_BYTE_LEN
4136 }
4137
4138 pub fn extension_lookup_type_byte_range(&self) -> Range<usize> {
4139 let start = self.pos_format_byte_range().end;
4140 start..start + u16::RAW_BYTE_LEN
4141 }
4142
4143 pub fn extension_offset_byte_range(&self) -> Range<usize> {
4144 let start = self.extension_lookup_type_byte_range().end;
4145 start..start + Offset32::RAW_BYTE_LEN
4146 }
4147}
4148
4149const _: () = assert!(FontData::default_data_long_enough(
4150 ExtensionPosFormat1::<()>::MIN_SIZE
4151));
4152
4153impl<T> Default for ExtensionPosFormat1<'_, T> {
4154 fn default() -> Self {
4155 Self {
4156 data: FontData::default_format_1_u16_table_data(),
4157 offset_type: std::marker::PhantomData,
4158 }
4159 }
4160}
4161
4162#[cfg(feature = "experimental_traverse")]
4163impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> SomeTable<'a> for ExtensionPosFormat1<'a, T> {
4164 fn type_name(&self) -> &str {
4165 "ExtensionPosFormat1"
4166 }
4167 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4168 match idx {
4169 0usize => Some(Field::new("pos_format", self.pos_format())),
4170 1usize => Some(Field::new(
4171 "extension_lookup_type",
4172 self.extension_lookup_type(),
4173 )),
4174 2usize => Some(Field::new(
4175 "extension_offset",
4176 FieldType::offset(self.extension_offset(), self.extension()),
4177 )),
4178 _ => None,
4179 }
4180 }
4181}
4182
4183#[cfg(feature = "experimental_traverse")]
4184#[allow(clippy::needless_lifetimes)]
4185impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> std::fmt::Debug for ExtensionPosFormat1<'a, T> {
4186 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4187 (self as &dyn SomeTable<'a>).fmt(f)
4188 }
4189}
4190
4191pub enum ExtensionSubtable<'a> {
4193 Single(ExtensionPosFormat1<'a, SinglePos<'a>>),
4194 Pair(ExtensionPosFormat1<'a, PairPos<'a>>),
4195 Cursive(ExtensionPosFormat1<'a, CursivePosFormat1<'a>>),
4196 MarkToBase(ExtensionPosFormat1<'a, MarkBasePosFormat1<'a>>),
4197 MarkToLig(ExtensionPosFormat1<'a, MarkLigPosFormat1<'a>>),
4198 MarkToMark(ExtensionPosFormat1<'a, MarkMarkPosFormat1<'a>>),
4199 Contextual(ExtensionPosFormat1<'a, PositionSequenceContext<'a>>),
4200 ChainContextual(ExtensionPosFormat1<'a, PositionChainContext<'a>>),
4201}
4202
4203impl Default for ExtensionSubtable<'_> {
4204 fn default() -> Self {
4205 Self::Single(Default::default())
4206 }
4207}
4208
4209impl<'a> FontRead<'a> for ExtensionSubtable<'a> {
4210 fn read(bytes: FontData<'a>) -> Result<Self, ReadError> {
4211 let discriminant = ExtensionPosFormat1::read_discriminant(bytes)?;
4212 match discriminant {
4213 1 => Ok(ExtensionSubtable::Single(FontRead::read(bytes)?)),
4214 2 => Ok(ExtensionSubtable::Pair(FontRead::read(bytes)?)),
4215 3 => Ok(ExtensionSubtable::Cursive(FontRead::read(bytes)?)),
4216 4 => Ok(ExtensionSubtable::MarkToBase(FontRead::read(bytes)?)),
4217 5 => Ok(ExtensionSubtable::MarkToLig(FontRead::read(bytes)?)),
4218 6 => Ok(ExtensionSubtable::MarkToMark(FontRead::read(bytes)?)),
4219 7 => Ok(ExtensionSubtable::Contextual(FontRead::read(bytes)?)),
4220 8 => Ok(ExtensionSubtable::ChainContextual(FontRead::read(bytes)?)),
4221 other => Err(ReadError::InvalidFormat(other.into())),
4222 }
4223 }
4224}
4225
4226impl<'a> ExtensionSubtable<'a> {
4227 #[allow(dead_code)]
4228 pub(crate) fn of_unit_type(&self) -> ExtensionPosFormat1<'a, ()> {
4232 match self {
4233 ExtensionSubtable::Single(inner) => inner.of_unit_type(),
4234 ExtensionSubtable::Pair(inner) => inner.of_unit_type(),
4235 ExtensionSubtable::Cursive(inner) => inner.of_unit_type(),
4236 ExtensionSubtable::MarkToBase(inner) => inner.of_unit_type(),
4237 ExtensionSubtable::MarkToLig(inner) => inner.of_unit_type(),
4238 ExtensionSubtable::MarkToMark(inner) => inner.of_unit_type(),
4239 ExtensionSubtable::Contextual(inner) => inner.of_unit_type(),
4240 ExtensionSubtable::ChainContextual(inner) => inner.of_unit_type(),
4241 }
4242 }
4243}
4244
4245#[cfg(feature = "experimental_traverse")]
4246impl<'a> ExtensionSubtable<'a> {
4247 fn dyn_inner(&self) -> &(dyn SomeTable<'a> + 'a) {
4248 match self {
4249 ExtensionSubtable::Single(table) => table,
4250 ExtensionSubtable::Pair(table) => table,
4251 ExtensionSubtable::Cursive(table) => table,
4252 ExtensionSubtable::MarkToBase(table) => table,
4253 ExtensionSubtable::MarkToLig(table) => table,
4254 ExtensionSubtable::MarkToMark(table) => table,
4255 ExtensionSubtable::Contextual(table) => table,
4256 ExtensionSubtable::ChainContextual(table) => table,
4257 }
4258 }
4259}
4260
4261#[cfg(feature = "experimental_traverse")]
4262impl<'a> SomeTable<'a> for ExtensionSubtable<'a> {
4263 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4264 self.dyn_inner().get_field(idx)
4265 }
4266 fn type_name(&self) -> &str {
4267 self.dyn_inner().type_name()
4268 }
4269}
4270
4271#[cfg(feature = "experimental_traverse")]
4272impl std::fmt::Debug for ExtensionSubtable<'_> {
4273 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4274 self.dyn_inner().fmt(f)
4275 }
4276}