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