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