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