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.offset_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 ReadArgs for Gpos<'_> {
24 type Args = ();
25}
26
27impl<'a> FontRead<'a> for Gpos<'a> {
28 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
29 #[allow(clippy::absurd_extreme_comparisons)]
30 if data.len() < Self::MIN_SIZE {
31 return Err(ReadError::OutOfBounds);
32 }
33 let Some(data) = TableDataRef::new(data.as_bytes()) else {
34 return Err(ReadError::OutOfBounds);
35 };
36 Ok(Self { data })
37 }
38}
39
40#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
42#[repr(C, packed)]
43#[doc(hidden)]
44pub struct GposFixedHeader {
45 pub version: BigEndian<MajorMinor>,
46 pub script_list_offset: BigEndian<Nullable<Offset16>>,
47 pub feature_list_offset: BigEndian<Nullable<Offset16>>,
48 pub lookup_list_offset: BigEndian<Nullable<Offset16>>,
49}
50
51#[allow(clippy::absurd_extreme_comparisons)]
52const _: () = assert!(std::mem::size_of::<GposFixedHeader>() <= Gpos::MIN_SIZE);
53
54#[derive(Clone)]
57pub struct Gpos<'a> {
58 data: TableDataRef<'a, GposFixedHeader>,
59}
60
61#[allow(clippy::needless_lifetimes)]
62impl<'a> Gpos<'a> {
63 pub const MIN_SIZE: usize = (MajorMinor::RAW_BYTE_LEN
64 + Offset16::RAW_BYTE_LEN
65 + Offset16::RAW_BYTE_LEN
66 + Offset16::RAW_BYTE_LEN);
67 basic_table_impls!(impl_the_methods);
68
69 pub fn version(&self) -> MajorMinor {
71 self.data.header().version.get()
72 }
73
74 pub fn script_list_offset(&self) -> Nullable<Offset16> {
76 self.data.header().script_list_offset.get()
77 }
78
79 pub fn feature_list_offset(&self) -> Nullable<Offset16> {
81 self.data.header().feature_list_offset.get()
82 }
83
84 pub fn lookup_list_offset(&self) -> Nullable<Offset16> {
86 self.data.header().lookup_list_offset.get()
87 }
88
89 pub fn feature_variations_offset(&self) -> Option<Nullable<Offset32>> {
90 let range = self.feature_variations_offset_byte_range();
91 (!range.is_empty())
92 .then(|| self.offset_data().read_at(range.start).ok())
93 .flatten()
94 }
95
96 pub fn feature_variations(&self) -> Option<Result<FeatureVariations<'a>, ReadError>> {
98 let data = self.offset_data();
99 self.feature_variations_offset().map(|x| x.resolve(data))?
100 }
101
102 pub fn script_list2_offset(&self) -> Option<Nullable<Offset32>> {
104 let range = self.script_list2_offset_byte_range();
105 (!range.is_empty())
106 .then(|| self.offset_data().read_at(range.start).ok())
107 .flatten()
108 }
109
110 pub fn script_list2(&self) -> Option<Result<ScriptList<'a>, ReadError>> {
112 let data = self.offset_data();
113 self.script_list2_offset().map(|x| x.resolve(data))?
114 }
115
116 pub fn feature_list2_offset(&self) -> Option<Nullable<Offset32>> {
118 let range = self.feature_list2_offset_byte_range();
119 (!range.is_empty())
120 .then(|| self.offset_data().read_at(range.start).ok())
121 .flatten()
122 }
123
124 pub fn feature_list2(&self) -> Option<Result<FeatureList<'a>, ReadError>> {
126 let data = self.offset_data();
127 self.feature_list2_offset().map(|x| x.resolve(data))?
128 }
129
130 pub fn lookup_list2_offset(&self) -> Option<Nullable<Offset32>> {
132 let range = self.lookup_list2_offset_byte_range();
133 (!range.is_empty())
134 .then(|| self.offset_data().read_at(range.start).ok())
135 .flatten()
136 }
137
138 pub fn lookup_list2(&self) -> Option<Result<PositionLookupList2<'a>, ReadError>> {
140 let data = self.offset_data();
141 self.lookup_list2_offset().map(|x| x.resolve(data))?
142 }
143
144 pub fn version_byte_range(&self) -> Range<usize> {
145 let start = 0;
146 let end = start + MajorMinor::RAW_BYTE_LEN;
147 start..end
148 }
149
150 pub fn script_list_offset_byte_range(&self) -> Range<usize> {
151 let start = self.version_byte_range().end;
152 let end = start + Offset16::RAW_BYTE_LEN;
153 start..end
154 }
155
156 pub fn feature_list_offset_byte_range(&self) -> Range<usize> {
157 let start = self.script_list_offset_byte_range().end;
158 let end = start + Offset16::RAW_BYTE_LEN;
159 start..end
160 }
161
162 pub fn lookup_list_offset_byte_range(&self) -> Range<usize> {
163 let start = self.feature_list_offset_byte_range().end;
164 let end = start + Offset16::RAW_BYTE_LEN;
165 start..end
166 }
167
168 pub fn feature_variations_offset_byte_range(&self) -> Range<usize> {
169 let start = self.lookup_list_offset_byte_range().end;
170 let end = if self.version().compatible((1u16, 1u16)) {
171 start + Offset32::RAW_BYTE_LEN
172 } else {
173 start
174 };
175 start..end
176 }
177
178 pub fn script_list2_offset_byte_range(&self) -> Range<usize> {
179 let start = self.feature_variations_offset_byte_range().end;
180 let end = if self.version().compatible((1u16, 2u16)) {
181 start + Offset32::RAW_BYTE_LEN
182 } else {
183 start
184 };
185 start..end
186 }
187
188 pub fn feature_list2_offset_byte_range(&self) -> Range<usize> {
189 let start = self.script_list2_offset_byte_range().end;
190 let end = if self.version().compatible((1u16, 2u16)) {
191 start + Offset32::RAW_BYTE_LEN
192 } else {
193 start
194 };
195 start..end
196 }
197
198 pub fn lookup_list2_offset_byte_range(&self) -> Range<usize> {
199 let start = self.feature_list2_offset_byte_range().end;
200 let end = if self.version().compatible((1u16, 2u16)) {
201 start + Offset32::RAW_BYTE_LEN
202 } else {
203 start
204 };
205 start..end
206 }
207}
208
209const _: () = assert!(FontData::default_data_long_enough(Gpos::MIN_SIZE));
210
211impl Default for Gpos<'_> {
212 fn default() -> Self {
213 Self {
214 data: TableDataRef::new(FontData::default_table_data().as_bytes())
215 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
216 }
217 }
218}
219
220pub enum PositionLookup<'a> {
222 Single(Lookup<'a, SinglePos<'a>>),
223 Pair(Lookup<'a, PairPos<'a>>),
224 Cursive(Lookup<'a, CursivePos<'a>>),
225 MarkToBase(Lookup<'a, MarkBasePos<'a>>),
226 MarkToLig(Lookup<'a, MarkLigPos<'a>>),
227 MarkToMark(Lookup<'a, MarkMarkPos<'a>>),
228 Contextual(Lookup<'a, PositionSequenceContext<'a>>),
229 ChainContextual(Lookup<'a, PositionChainContext<'a>>),
230 Extension(Lookup<'a, ExtensionSubtable<'a>>),
231}
232
233impl Default for PositionLookup<'_> {
234 fn default() -> Self {
235 Self::Single(Default::default())
236 }
237}
238
239impl ReadArgs for PositionLookup<'_> {
240 type Args = ();
241}
242
243impl<'a> FontRead<'a> for PositionLookup<'a> {
244 fn read_with_args(bytes: FontData<'a>, _: ()) -> Result<Self, ReadError> {
245 let discriminant = Lookup::read_discriminant(bytes)?;
246 match discriminant {
247 1 => Ok(PositionLookup::Single(FontRead::read(bytes)?)),
248 2 => Ok(PositionLookup::Pair(FontRead::read(bytes)?)),
249 3 => Ok(PositionLookup::Cursive(FontRead::read(bytes)?)),
250 4 => Ok(PositionLookup::MarkToBase(FontRead::read(bytes)?)),
251 5 => Ok(PositionLookup::MarkToLig(FontRead::read(bytes)?)),
252 6 => Ok(PositionLookup::MarkToMark(FontRead::read(bytes)?)),
253 7 => Ok(PositionLookup::Contextual(FontRead::read(bytes)?)),
254 8 => Ok(PositionLookup::ChainContextual(FontRead::read(bytes)?)),
255 9 => Ok(PositionLookup::Extension(FontRead::read(bytes)?)),
256 other => Err(ReadError::InvalidFormat(other.into())),
257 }
258 }
259}
260
261impl<'a> PositionLookup<'a> {
262 #[allow(dead_code)]
263 pub(crate) fn of_unit_type(&self) -> Lookup<'a, ()> {
267 match self {
268 PositionLookup::Single(inner) => inner.of_unit_type(),
269 PositionLookup::Pair(inner) => inner.of_unit_type(),
270 PositionLookup::Cursive(inner) => inner.of_unit_type(),
271 PositionLookup::MarkToBase(inner) => inner.of_unit_type(),
272 PositionLookup::MarkToLig(inner) => inner.of_unit_type(),
273 PositionLookup::MarkToMark(inner) => inner.of_unit_type(),
274 PositionLookup::Contextual(inner) => inner.of_unit_type(),
275 PositionLookup::ChainContextual(inner) => inner.of_unit_type(),
276 PositionLookup::Extension(inner) => inner.of_unit_type(),
277 }
278 }
279}
280
281#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, bytemuck :: AnyBitPattern)]
283#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
284#[repr(transparent)]
285pub struct ValueFormat {
286 bits: u16,
287}
288
289impl ValueFormat {
290 pub const X_PLACEMENT: Self = Self { bits: 0x0001 };
292
293 pub const Y_PLACEMENT: Self = Self { bits: 0x0002 };
295
296 pub const X_ADVANCE: Self = Self { bits: 0x0004 };
298
299 pub const Y_ADVANCE: Self = Self { bits: 0x0008 };
301
302 pub const X_PLACEMENT_DEVICE: Self = Self { bits: 0x0010 };
305
306 pub const Y_PLACEMENT_DEVICE: Self = Self { bits: 0x0020 };
309
310 pub const X_ADVANCE_DEVICE: Self = Self { bits: 0x0040 };
313
314 pub const Y_ADVANCE_DEVICE: Self = Self { bits: 0x0080 };
317}
318
319impl ValueFormat {
320 #[inline]
322 pub const fn empty() -> Self {
323 Self { bits: 0 }
324 }
325
326 #[inline]
328 pub const fn all() -> Self {
329 Self {
330 bits: Self::X_PLACEMENT.bits
331 | Self::Y_PLACEMENT.bits
332 | Self::X_ADVANCE.bits
333 | Self::Y_ADVANCE.bits
334 | Self::X_PLACEMENT_DEVICE.bits
335 | Self::Y_PLACEMENT_DEVICE.bits
336 | Self::X_ADVANCE_DEVICE.bits
337 | Self::Y_ADVANCE_DEVICE.bits,
338 }
339 }
340
341 #[inline]
343 pub const fn bits(&self) -> u16 {
344 self.bits
345 }
346
347 #[inline]
350 pub const fn from_bits(bits: u16) -> Option<Self> {
351 if (bits & !Self::all().bits()) == 0 {
352 Some(Self { bits })
353 } else {
354 None
355 }
356 }
357
358 #[inline]
361 pub const fn from_bits_truncate(bits: u16) -> Self {
362 Self {
363 bits: bits & Self::all().bits,
364 }
365 }
366
367 #[inline]
369 pub const fn is_empty(&self) -> bool {
370 self.bits() == Self::empty().bits()
371 }
372
373 #[inline]
375 pub const fn intersects(&self, other: Self) -> bool {
376 !(Self {
377 bits: self.bits & other.bits,
378 })
379 .is_empty()
380 }
381
382 #[inline]
384 pub const fn contains(&self, other: Self) -> bool {
385 (self.bits & other.bits) == other.bits
386 }
387
388 #[inline]
390 pub fn insert(&mut self, other: Self) {
391 self.bits |= other.bits;
392 }
393
394 #[inline]
396 pub fn remove(&mut self, other: Self) {
397 self.bits &= !other.bits;
398 }
399
400 #[inline]
402 pub fn toggle(&mut self, other: Self) {
403 self.bits ^= other.bits;
404 }
405
406 #[inline]
417 #[must_use]
418 pub const fn intersection(self, other: Self) -> Self {
419 Self {
420 bits: self.bits & other.bits,
421 }
422 }
423
424 #[inline]
435 #[must_use]
436 pub const fn union(self, other: Self) -> Self {
437 Self {
438 bits: self.bits | other.bits,
439 }
440 }
441
442 #[inline]
455 #[must_use]
456 pub const fn difference(self, other: Self) -> Self {
457 Self {
458 bits: self.bits & !other.bits,
459 }
460 }
461}
462
463impl std::ops::BitOr for ValueFormat {
464 type Output = Self;
465
466 #[inline]
468 fn bitor(self, other: ValueFormat) -> Self {
469 Self {
470 bits: self.bits | other.bits,
471 }
472 }
473}
474
475impl std::ops::BitOrAssign for ValueFormat {
476 #[inline]
478 fn bitor_assign(&mut self, other: Self) {
479 self.bits |= other.bits;
480 }
481}
482
483impl std::ops::BitXor for ValueFormat {
484 type Output = Self;
485
486 #[inline]
488 fn bitxor(self, other: Self) -> Self {
489 Self {
490 bits: self.bits ^ other.bits,
491 }
492 }
493}
494
495impl std::ops::BitXorAssign for ValueFormat {
496 #[inline]
498 fn bitxor_assign(&mut self, other: Self) {
499 self.bits ^= other.bits;
500 }
501}
502
503impl std::ops::BitAnd for ValueFormat {
504 type Output = Self;
505
506 #[inline]
508 fn bitand(self, other: Self) -> Self {
509 Self {
510 bits: self.bits & other.bits,
511 }
512 }
513}
514
515impl std::ops::BitAndAssign for ValueFormat {
516 #[inline]
518 fn bitand_assign(&mut self, other: Self) {
519 self.bits &= other.bits;
520 }
521}
522
523impl std::ops::Sub for ValueFormat {
524 type Output = Self;
525
526 #[inline]
528 fn sub(self, other: Self) -> Self {
529 Self {
530 bits: self.bits & !other.bits,
531 }
532 }
533}
534
535impl std::ops::SubAssign for ValueFormat {
536 #[inline]
538 fn sub_assign(&mut self, other: Self) {
539 self.bits &= !other.bits;
540 }
541}
542
543impl std::ops::Not for ValueFormat {
544 type Output = Self;
545
546 #[inline]
548 fn not(self) -> Self {
549 Self { bits: !self.bits } & Self::all()
550 }
551}
552
553impl std::fmt::Debug for ValueFormat {
554 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
555 let members: &[(&str, Self)] = &[
556 ("X_PLACEMENT", Self::X_PLACEMENT),
557 ("Y_PLACEMENT", Self::Y_PLACEMENT),
558 ("X_ADVANCE", Self::X_ADVANCE),
559 ("Y_ADVANCE", Self::Y_ADVANCE),
560 ("X_PLACEMENT_DEVICE", Self::X_PLACEMENT_DEVICE),
561 ("Y_PLACEMENT_DEVICE", Self::Y_PLACEMENT_DEVICE),
562 ("X_ADVANCE_DEVICE", Self::X_ADVANCE_DEVICE),
563 ("Y_ADVANCE_DEVICE", Self::Y_ADVANCE_DEVICE),
564 ];
565 let mut first = true;
566 for (name, value) in members {
567 if self.contains(*value) {
568 if !first {
569 f.write_str(" | ")?;
570 }
571 first = false;
572 f.write_str(name)?;
573 }
574 }
575 if first {
576 f.write_str("(empty)")?;
577 }
578 Ok(())
579 }
580}
581
582impl std::fmt::Binary for ValueFormat {
583 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
584 std::fmt::Binary::fmt(&self.bits, f)
585 }
586}
587
588impl std::fmt::Octal for ValueFormat {
589 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
590 std::fmt::Octal::fmt(&self.bits, f)
591 }
592}
593
594impl std::fmt::LowerHex for ValueFormat {
595 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
596 std::fmt::LowerHex::fmt(&self.bits, f)
597 }
598}
599
600impl std::fmt::UpperHex for ValueFormat {
601 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
602 std::fmt::UpperHex::fmt(&self.bits, f)
603 }
604}
605
606impl font_types::Scalar for ValueFormat {
607 type Raw = <u16 as font_types::Scalar>::Raw;
608 fn to_raw(self) -> Self::Raw {
609 self.bits().to_raw()
610 }
611 fn from_raw(raw: Self::Raw) -> Self {
612 let t = <u16>::from_raw(raw);
613 Self::from_bits_truncate(t)
614 }
615}
616
617#[derive(Clone)]
620pub enum AnchorTable<'a> {
621 Format1(AnchorFormat1<'a>),
622 Format2(AnchorFormat2<'a>),
623 Format3(AnchorFormat3<'a>),
624}
625
626impl Default for AnchorTable<'_> {
627 fn default() -> Self {
628 Self::Format1(Default::default())
629 }
630}
631
632impl<'a> AnchorTable<'a> {
633 pub fn offset_data(&self) -> FontData<'a> {
635 match self {
636 Self::Format1(item) => item.offset_data(),
637 Self::Format2(item) => item.offset_data(),
638 Self::Format3(item) => item.offset_data(),
639 }
640 }
641
642 pub fn anchor_format(&self) -> u16 {
644 match self {
645 Self::Format1(item) => item.anchor_format(),
646 Self::Format2(item) => item.anchor_format(),
647 Self::Format3(item) => item.anchor_format(),
648 }
649 }
650
651 pub fn x_coordinate(&self) -> i16 {
653 match self {
654 Self::Format1(item) => item.x_coordinate(),
655 Self::Format2(item) => item.x_coordinate(),
656 Self::Format3(item) => item.x_coordinate(),
657 }
658 }
659
660 pub fn y_coordinate(&self) -> i16 {
662 match self {
663 Self::Format1(item) => item.y_coordinate(),
664 Self::Format2(item) => item.y_coordinate(),
665 Self::Format3(item) => item.y_coordinate(),
666 }
667 }
668}
669
670impl ReadArgs for AnchorTable<'_> {
671 type Args = ();
672}
673
674impl<'a> FontRead<'a> for AnchorTable<'a> {
675 #[inline]
676 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
677 let format: u16 = data.read_at(0usize)?;
678 match format {
679 AnchorFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
680 AnchorFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
681 AnchorFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
682 other => Err(ReadError::InvalidFormat(other.into())),
683 }
684 }
685}
686
687impl<'a> MinByteRange<'a> for AnchorTable<'a> {
688 fn min_byte_range(&self) -> Range<usize> {
689 match self {
690 Self::Format1(item) => item.min_byte_range(),
691 Self::Format2(item) => item.min_byte_range(),
692 Self::Format3(item) => item.min_byte_range(),
693 }
694 }
695 fn min_table_bytes(&self) -> &'a [u8] {
696 match self {
697 Self::Format1(item) => item.min_table_bytes(),
698 Self::Format2(item) => item.min_table_bytes(),
699 Self::Format3(item) => item.min_table_bytes(),
700 }
701 }
702}
703
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.offset_data().as_bytes().get(range).unwrap_or_default()
715 }
716}
717
718impl ReadArgs for AnchorFormat1<'_> {
719 type Args = ();
720}
721
722impl<'a> FontRead<'a> for AnchorFormat1<'a> {
723 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
724 #[allow(clippy::absurd_extreme_comparisons)]
725 if data.len() < Self::MIN_SIZE {
726 return Err(ReadError::OutOfBounds);
727 }
728 let Some(data) = TableDataRef::new(data.as_bytes()) else {
729 return Err(ReadError::OutOfBounds);
730 };
731 Ok(Self { data })
732 }
733}
734
735#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
737#[repr(C, packed)]
738#[doc(hidden)]
739pub struct AnchorFormat1FixedHeader {
740 pub anchor_format: BigEndian<u16>,
741 pub x_coordinate: BigEndian<i16>,
742 pub y_coordinate: BigEndian<i16>,
743}
744
745#[allow(clippy::absurd_extreme_comparisons)]
746const _: () = assert!(std::mem::size_of::<AnchorFormat1FixedHeader>() <= AnchorFormat1::MIN_SIZE);
747
748#[derive(Clone)]
750pub struct AnchorFormat1<'a> {
751 data: TableDataRef<'a, AnchorFormat1FixedHeader>,
752}
753
754#[allow(clippy::needless_lifetimes)]
755impl<'a> AnchorFormat1<'a> {
756 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN);
757 basic_table_impls!(impl_the_methods);
758
759 pub fn anchor_format(&self) -> u16 {
761 self.data.header().anchor_format.get()
762 }
763
764 pub fn x_coordinate(&self) -> i16 {
766 self.data.header().x_coordinate.get()
767 }
768
769 pub fn y_coordinate(&self) -> i16 {
771 self.data.header().y_coordinate.get()
772 }
773
774 pub fn anchor_format_byte_range(&self) -> Range<usize> {
775 let start = 0;
776 let end = start + u16::RAW_BYTE_LEN;
777 start..end
778 }
779
780 pub fn x_coordinate_byte_range(&self) -> Range<usize> {
781 let start = self.anchor_format_byte_range().end;
782 let end = start + i16::RAW_BYTE_LEN;
783 start..end
784 }
785
786 pub fn y_coordinate_byte_range(&self) -> Range<usize> {
787 let start = self.x_coordinate_byte_range().end;
788 let end = start + i16::RAW_BYTE_LEN;
789 start..end
790 }
791}
792
793const _: () = assert!(FontData::default_data_long_enough(AnchorFormat1::MIN_SIZE));
794
795impl Default for AnchorFormat1<'_> {
796 fn default() -> Self {
797 Self {
798 data: TableDataRef::new(FontData::default_format_1_u16_table_data().as_bytes())
799 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
800 }
801 }
802}
803
804impl Format<u16> for AnchorFormat2<'_> {
805 const FORMAT: u16 = 2;
806}
807
808impl<'a> MinByteRange<'a> for AnchorFormat2<'a> {
809 fn min_byte_range(&self) -> Range<usize> {
810 0..self.anchor_point_byte_range().end
811 }
812 fn min_table_bytes(&self) -> &'a [u8] {
813 let range = self.min_byte_range();
814 self.offset_data().as_bytes().get(range).unwrap_or_default()
815 }
816}
817
818impl ReadArgs for AnchorFormat2<'_> {
819 type Args = ();
820}
821
822impl<'a> FontRead<'a> for AnchorFormat2<'a> {
823 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
824 #[allow(clippy::absurd_extreme_comparisons)]
825 if data.len() < Self::MIN_SIZE {
826 return Err(ReadError::OutOfBounds);
827 }
828 let Some(data) = TableDataRef::new(data.as_bytes()) else {
829 return Err(ReadError::OutOfBounds);
830 };
831 Ok(Self { data })
832 }
833}
834
835#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
837#[repr(C, packed)]
838#[doc(hidden)]
839pub struct AnchorFormat2FixedHeader {
840 pub anchor_format: BigEndian<u16>,
841 pub x_coordinate: BigEndian<i16>,
842 pub y_coordinate: BigEndian<i16>,
843 pub anchor_point: BigEndian<u16>,
844}
845
846#[allow(clippy::absurd_extreme_comparisons)]
847const _: () = assert!(std::mem::size_of::<AnchorFormat2FixedHeader>() <= AnchorFormat2::MIN_SIZE);
848
849#[derive(Clone)]
851pub struct AnchorFormat2<'a> {
852 data: TableDataRef<'a, AnchorFormat2FixedHeader>,
853}
854
855#[allow(clippy::needless_lifetimes)]
856impl<'a> AnchorFormat2<'a> {
857 pub const MIN_SIZE: usize =
858 (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
859 basic_table_impls!(impl_the_methods);
860
861 pub fn anchor_format(&self) -> u16 {
863 self.data.header().anchor_format.get()
864 }
865
866 pub fn x_coordinate(&self) -> i16 {
868 self.data.header().x_coordinate.get()
869 }
870
871 pub fn y_coordinate(&self) -> i16 {
873 self.data.header().y_coordinate.get()
874 }
875
876 pub fn anchor_point(&self) -> u16 {
878 self.data.header().anchor_point.get()
879 }
880
881 pub fn anchor_format_byte_range(&self) -> Range<usize> {
882 let start = 0;
883 let end = start + u16::RAW_BYTE_LEN;
884 start..end
885 }
886
887 pub fn x_coordinate_byte_range(&self) -> Range<usize> {
888 let start = self.anchor_format_byte_range().end;
889 let end = start + i16::RAW_BYTE_LEN;
890 start..end
891 }
892
893 pub fn y_coordinate_byte_range(&self) -> Range<usize> {
894 let start = self.x_coordinate_byte_range().end;
895 let end = start + i16::RAW_BYTE_LEN;
896 start..end
897 }
898
899 pub fn anchor_point_byte_range(&self) -> Range<usize> {
900 let start = self.y_coordinate_byte_range().end;
901 let end = start + u16::RAW_BYTE_LEN;
902 start..end
903 }
904}
905
906impl Format<u16> for AnchorFormat3<'_> {
907 const FORMAT: u16 = 3;
908}
909
910impl<'a> MinByteRange<'a> for AnchorFormat3<'a> {
911 fn min_byte_range(&self) -> Range<usize> {
912 0..self.y_device_offset_byte_range().end
913 }
914 fn min_table_bytes(&self) -> &'a [u8] {
915 let range = self.min_byte_range();
916 self.offset_data().as_bytes().get(range).unwrap_or_default()
917 }
918}
919
920impl ReadArgs for AnchorFormat3<'_> {
921 type Args = ();
922}
923
924impl<'a> FontRead<'a> for AnchorFormat3<'a> {
925 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
926 #[allow(clippy::absurd_extreme_comparisons)]
927 if data.len() < Self::MIN_SIZE {
928 return Err(ReadError::OutOfBounds);
929 }
930 let Some(data) = TableDataRef::new(data.as_bytes()) else {
931 return Err(ReadError::OutOfBounds);
932 };
933 Ok(Self { data })
934 }
935}
936
937#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
939#[repr(C, packed)]
940#[doc(hidden)]
941pub struct AnchorFormat3FixedHeader {
942 pub anchor_format: BigEndian<u16>,
943 pub x_coordinate: BigEndian<i16>,
944 pub y_coordinate: BigEndian<i16>,
945 pub x_device_offset: BigEndian<Nullable<Offset16>>,
946 pub y_device_offset: BigEndian<Nullable<Offset16>>,
947}
948
949#[allow(clippy::absurd_extreme_comparisons)]
950const _: () = assert!(std::mem::size_of::<AnchorFormat3FixedHeader>() <= AnchorFormat3::MIN_SIZE);
951
952#[derive(Clone)]
954pub struct AnchorFormat3<'a> {
955 data: TableDataRef<'a, AnchorFormat3FixedHeader>,
956}
957
958#[allow(clippy::needless_lifetimes)]
959impl<'a> AnchorFormat3<'a> {
960 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
961 + i16::RAW_BYTE_LEN
962 + i16::RAW_BYTE_LEN
963 + Offset16::RAW_BYTE_LEN
964 + Offset16::RAW_BYTE_LEN);
965 basic_table_impls!(impl_the_methods);
966
967 pub fn anchor_format(&self) -> u16 {
969 self.data.header().anchor_format.get()
970 }
971
972 pub fn x_coordinate(&self) -> i16 {
974 self.data.header().x_coordinate.get()
975 }
976
977 pub fn y_coordinate(&self) -> i16 {
979 self.data.header().y_coordinate.get()
980 }
981
982 pub fn x_device_offset(&self) -> Nullable<Offset16> {
986 self.data.header().x_device_offset.get()
987 }
988
989 pub fn x_device(&self) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>> {
991 let data = self.offset_data();
992 self.x_device_offset().resolve(data)
993 }
994
995 pub fn y_device_offset(&self) -> Nullable<Offset16> {
999 self.data.header().y_device_offset.get()
1000 }
1001
1002 pub fn y_device(&self) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>> {
1004 let data = self.offset_data();
1005 self.y_device_offset().resolve(data)
1006 }
1007
1008 pub fn anchor_format_byte_range(&self) -> Range<usize> {
1009 let start = 0;
1010 let end = start + u16::RAW_BYTE_LEN;
1011 start..end
1012 }
1013
1014 pub fn x_coordinate_byte_range(&self) -> Range<usize> {
1015 let start = self.anchor_format_byte_range().end;
1016 let end = start + i16::RAW_BYTE_LEN;
1017 start..end
1018 }
1019
1020 pub fn y_coordinate_byte_range(&self) -> Range<usize> {
1021 let start = self.x_coordinate_byte_range().end;
1022 let end = start + i16::RAW_BYTE_LEN;
1023 start..end
1024 }
1025
1026 pub fn x_device_offset_byte_range(&self) -> Range<usize> {
1027 let start = self.y_coordinate_byte_range().end;
1028 let end = start + Offset16::RAW_BYTE_LEN;
1029 start..end
1030 }
1031
1032 pub fn y_device_offset_byte_range(&self) -> Range<usize> {
1033 let start = self.x_device_offset_byte_range().end;
1034 let end = start + Offset16::RAW_BYTE_LEN;
1035 start..end
1036 }
1037}
1038
1039impl<'a> MinByteRange<'a> for MarkArray<'a> {
1040 fn min_byte_range(&self) -> Range<usize> {
1041 0..self.mark_records_byte_range().end
1042 }
1043 fn min_table_bytes(&self) -> &'a [u8] {
1044 let range = self.min_byte_range();
1045 self.offset_data().as_bytes().get(range).unwrap_or_default()
1046 }
1047}
1048
1049impl ReadArgs for MarkArray<'_> {
1050 type Args = ();
1051}
1052
1053impl<'a> FontRead<'a> for MarkArray<'a> {
1054 fn read_with_args(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 let Some(data) = TableDataRef::new(data.as_bytes()) else {
1060 return Err(ReadError::OutOfBounds);
1061 };
1062 Ok(Self { data })
1063 }
1064}
1065
1066#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1068#[repr(C, packed)]
1069#[doc(hidden)]
1070pub struct MarkArrayFixedHeader {
1071 pub mark_count: BigEndian<u16>,
1072}
1073
1074#[allow(clippy::absurd_extreme_comparisons)]
1075const _: () = assert!(std::mem::size_of::<MarkArrayFixedHeader>() <= MarkArray::MIN_SIZE);
1076
1077#[derive(Clone)]
1079pub struct MarkArray<'a> {
1080 data: TableDataRef<'a, MarkArrayFixedHeader>,
1081}
1082
1083#[allow(clippy::needless_lifetimes)]
1084impl<'a> MarkArray<'a> {
1085 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
1086 basic_table_impls!(impl_the_methods);
1087
1088 pub fn mark_count(&self) -> u16 {
1090 self.data.header().mark_count.get()
1091 }
1092
1093 pub fn mark_records(&self) -> &'a [MarkRecord] {
1096 let range = self.mark_records_byte_range();
1097 self.offset_data()
1098 .read_array(range)
1099 .ok()
1100 .unwrap_or_default()
1101 }
1102
1103 pub fn mark_count_byte_range(&self) -> Range<usize> {
1104 let start = 0;
1105 let end = start + u16::RAW_BYTE_LEN;
1106 start..end
1107 }
1108
1109 pub fn mark_records_byte_range(&self) -> Range<usize> {
1110 let mark_count = self.mark_count();
1111 let start = self.mark_count_byte_range().end;
1112 let end =
1113 start + (transforms::to_usize(mark_count)).saturating_mul(MarkRecord::RAW_BYTE_LEN);
1114 start..end
1115 }
1116}
1117
1118const _: () = assert!(FontData::default_data_long_enough(MarkArray::MIN_SIZE));
1119
1120impl Default for MarkArray<'_> {
1121 fn default() -> Self {
1122 Self {
1123 data: TableDataRef::new(FontData::default_table_data().as_bytes())
1124 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1125 }
1126 }
1127}
1128
1129#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
1131#[repr(C)]
1132#[repr(packed)]
1133pub struct MarkRecord {
1134 pub mark_class: BigEndian<u16>,
1136 pub mark_anchor_offset: BigEndian<Offset16>,
1138}
1139
1140impl MarkRecord {
1141 pub fn mark_class(&self) -> u16 {
1143 self.mark_class.get()
1144 }
1145
1146 pub fn mark_anchor_offset(&self) -> Offset16 {
1148 self.mark_anchor_offset.get()
1149 }
1150
1151 pub fn mark_anchor<'a>(&self, data: FontData<'a>) -> Result<AnchorTable<'a>, ReadError> {
1156 self.mark_anchor_offset().resolve(data)
1157 }
1158}
1159
1160impl FixedSize for MarkRecord {
1161 const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
1162}
1163
1164#[derive(Clone)]
1166pub enum SinglePos<'a> {
1167 Format1(SinglePosFormat1<'a>),
1168 Format2(SinglePosFormat2<'a>),
1169 Format3(SinglePosFormat3<'a>),
1170 Format4(SinglePosFormat4<'a>),
1171}
1172
1173impl Default for SinglePos<'_> {
1174 fn default() -> Self {
1175 Self::Format1(Default::default())
1176 }
1177}
1178
1179impl<'a> SinglePos<'a> {
1180 pub fn offset_data(&self) -> FontData<'a> {
1182 match self {
1183 Self::Format1(item) => item.offset_data(),
1184 Self::Format2(item) => item.offset_data(),
1185 Self::Format3(item) => item.offset_data(),
1186 Self::Format4(item) => item.offset_data(),
1187 }
1188 }
1189
1190 pub fn pos_format(&self) -> u16 {
1192 match self {
1193 Self::Format1(item) => item.pos_format(),
1194 Self::Format2(item) => item.pos_format(),
1195 Self::Format3(item) => item.pos_format(),
1196 Self::Format4(item) => item.pos_format(),
1197 }
1198 }
1199
1200 pub fn value_format(&self) -> ValueFormat {
1202 match self {
1203 Self::Format1(item) => item.value_format(),
1204 Self::Format2(item) => item.value_format(),
1205 Self::Format3(item) => item.value_format(),
1206 Self::Format4(item) => item.value_format(),
1207 }
1208 }
1209}
1210
1211impl ReadArgs for SinglePos<'_> {
1212 type Args = ();
1213}
1214
1215impl<'a> FontRead<'a> for SinglePos<'a> {
1216 #[inline]
1217 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1218 let format: u16 = data.read_at(0usize)?;
1219 match format {
1220 SinglePosFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
1221 SinglePosFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
1222 SinglePosFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
1223 SinglePosFormat4::FORMAT => Ok(Self::Format4(FontRead::read(data)?)),
1224 other => Err(ReadError::InvalidFormat(other.into())),
1225 }
1226 }
1227}
1228
1229impl<'a> MinByteRange<'a> for SinglePos<'a> {
1230 fn min_byte_range(&self) -> Range<usize> {
1231 match self {
1232 Self::Format1(item) => item.min_byte_range(),
1233 Self::Format2(item) => item.min_byte_range(),
1234 Self::Format3(item) => item.min_byte_range(),
1235 Self::Format4(item) => item.min_byte_range(),
1236 }
1237 }
1238 fn min_table_bytes(&self) -> &'a [u8] {
1239 match self {
1240 Self::Format1(item) => item.min_table_bytes(),
1241 Self::Format2(item) => item.min_table_bytes(),
1242 Self::Format3(item) => item.min_table_bytes(),
1243 Self::Format4(item) => item.min_table_bytes(),
1244 }
1245 }
1246}
1247
1248impl Format<u16> for SinglePosFormat1<'_> {
1249 const FORMAT: u16 = 1;
1250}
1251
1252impl<'a> MinByteRange<'a> for SinglePosFormat1<'a> {
1253 fn min_byte_range(&self) -> Range<usize> {
1254 0..self.value_record_byte_range().end
1255 }
1256 fn min_table_bytes(&self) -> &'a [u8] {
1257 let range = self.min_byte_range();
1258 self.offset_data().as_bytes().get(range).unwrap_or_default()
1259 }
1260}
1261
1262impl ReadArgs for SinglePosFormat1<'_> {
1263 type Args = ();
1264}
1265
1266impl<'a> FontRead<'a> for SinglePosFormat1<'a> {
1267 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1268 #[allow(clippy::absurd_extreme_comparisons)]
1269 if data.len() < Self::MIN_SIZE {
1270 return Err(ReadError::OutOfBounds);
1271 }
1272 let Some(data) = TableDataRef::new(data.as_bytes()) else {
1273 return Err(ReadError::OutOfBounds);
1274 };
1275 Ok(Self { data })
1276 }
1277}
1278
1279#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1281#[repr(C, packed)]
1282#[doc(hidden)]
1283pub struct SinglePosFormat1FixedHeader {
1284 pub pos_format: BigEndian<u16>,
1285 pub coverage_offset: BigEndian<Offset16>,
1286 pub value_format: BigEndian<ValueFormat>,
1287}
1288
1289#[allow(clippy::absurd_extreme_comparisons)]
1290const _: () =
1291 assert!(std::mem::size_of::<SinglePosFormat1FixedHeader>() <= SinglePosFormat1::MIN_SIZE);
1292
1293#[derive(Clone)]
1295pub struct SinglePosFormat1<'a> {
1296 data: TableDataRef<'a, SinglePosFormat1FixedHeader>,
1297}
1298
1299#[allow(clippy::needless_lifetimes)]
1300impl<'a> SinglePosFormat1<'a> {
1301 pub const MIN_SIZE: usize =
1302 (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + ValueFormat::RAW_BYTE_LEN);
1303 basic_table_impls!(impl_the_methods);
1304
1305 pub fn pos_format(&self) -> u16 {
1307 self.data.header().pos_format.get()
1308 }
1309
1310 pub fn coverage_offset(&self) -> Offset16 {
1312 self.data.header().coverage_offset.get()
1313 }
1314
1315 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
1317 let data = self.offset_data();
1318 self.coverage_offset().resolve(data)
1319 }
1320
1321 pub fn value_format(&self) -> ValueFormat {
1323 self.data.header().value_format.get()
1324 }
1325
1326 pub fn value_record(&self) -> ValueRecord<'a> {
1329 let range = self.value_record_byte_range();
1330 ValueRecord::read_at(self.offset_data(), range.start, self.value_format())
1331 .unwrap_or_default()
1332 }
1333
1334 pub fn pos_format_byte_range(&self) -> Range<usize> {
1335 let start = 0;
1336 let end = start + u16::RAW_BYTE_LEN;
1337 start..end
1338 }
1339
1340 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
1341 let start = self.pos_format_byte_range().end;
1342 let end = start + Offset16::RAW_BYTE_LEN;
1343 start..end
1344 }
1345
1346 pub fn value_format_byte_range(&self) -> Range<usize> {
1347 let start = self.coverage_offset_byte_range().end;
1348 let end = start + ValueFormat::RAW_BYTE_LEN;
1349 start..end
1350 }
1351
1352 pub fn value_record_byte_range(&self) -> Range<usize> {
1353 let start = self.value_format_byte_range().end;
1354 let end =
1355 start + <ValueRecord as ComputeSize>::compute_size(self.value_format()).unwrap_or(0);
1356 start..end
1357 }
1358}
1359
1360const _: () = assert!(FontData::default_data_long_enough(
1361 SinglePosFormat1::MIN_SIZE
1362));
1363
1364impl Default for SinglePosFormat1<'_> {
1365 fn default() -> Self {
1366 Self {
1367 data: TableDataRef::new(FontData::default_format_1_u16_table_data().as_bytes())
1368 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1369 }
1370 }
1371}
1372
1373impl Format<u16> for SinglePosFormat2<'_> {
1374 const FORMAT: u16 = 2;
1375}
1376
1377impl<'a> MinByteRange<'a> for SinglePosFormat2<'a> {
1378 fn min_byte_range(&self) -> Range<usize> {
1379 0..self.value_records_byte_range().end
1380 }
1381 fn min_table_bytes(&self) -> &'a [u8] {
1382 let range = self.min_byte_range();
1383 self.offset_data().as_bytes().get(range).unwrap_or_default()
1384 }
1385}
1386
1387impl ReadArgs for SinglePosFormat2<'_> {
1388 type Args = ();
1389}
1390
1391impl<'a> FontRead<'a> for SinglePosFormat2<'a> {
1392 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1393 #[allow(clippy::absurd_extreme_comparisons)]
1394 if data.len() < Self::MIN_SIZE {
1395 return Err(ReadError::OutOfBounds);
1396 }
1397 let Some(data) = TableDataRef::new(data.as_bytes()) else {
1398 return Err(ReadError::OutOfBounds);
1399 };
1400 Ok(Self { data })
1401 }
1402}
1403
1404#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1406#[repr(C, packed)]
1407#[doc(hidden)]
1408pub struct SinglePosFormat2FixedHeader {
1409 pub pos_format: BigEndian<u16>,
1410 pub coverage_offset: BigEndian<Offset16>,
1411 pub value_format: BigEndian<ValueFormat>,
1412 pub value_count: BigEndian<u16>,
1413}
1414
1415#[allow(clippy::absurd_extreme_comparisons)]
1416const _: () =
1417 assert!(std::mem::size_of::<SinglePosFormat2FixedHeader>() <= SinglePosFormat2::MIN_SIZE);
1418
1419#[derive(Clone)]
1421pub struct SinglePosFormat2<'a> {
1422 data: TableDataRef<'a, SinglePosFormat2FixedHeader>,
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 self.data.header().pos_format.get()
1436 }
1437
1438 pub fn coverage_offset(&self) -> Offset16 {
1440 self.data.header().coverage_offset.get()
1441 }
1442
1443 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
1445 let data = self.offset_data();
1446 self.coverage_offset().resolve(data)
1447 }
1448
1449 pub fn value_format(&self) -> ValueFormat {
1451 self.data.header().value_format.get()
1452 }
1453
1454 pub fn value_count(&self) -> u16 {
1457 self.data.header().value_count.get()
1458 }
1459
1460 pub fn value_records(&self) -> ComputedArray<'a, ValueRecord<'a>> {
1462 let range = self.value_records_byte_range();
1463 ComputedArray::new(self.offset_data(), range, self.value_format()).unwrap_or_default()
1464 }
1465
1466 pub fn pos_format_byte_range(&self) -> Range<usize> {
1467 let start = 0;
1468 let end = start + u16::RAW_BYTE_LEN;
1469 start..end
1470 }
1471
1472 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
1473 let start = self.pos_format_byte_range().end;
1474 let end = start + Offset16::RAW_BYTE_LEN;
1475 start..end
1476 }
1477
1478 pub fn value_format_byte_range(&self) -> Range<usize> {
1479 let start = self.coverage_offset_byte_range().end;
1480 let end = start + ValueFormat::RAW_BYTE_LEN;
1481 start..end
1482 }
1483
1484 pub fn value_count_byte_range(&self) -> Range<usize> {
1485 let start = self.value_format_byte_range().end;
1486 let end = start + u16::RAW_BYTE_LEN;
1487 start..end
1488 }
1489
1490 pub fn value_records_byte_range(&self) -> Range<usize> {
1491 let value_count = self.value_count();
1492 let start = self.value_count_byte_range().end;
1493 let end = start
1494 + (transforms::to_usize(value_count)).saturating_mul(
1495 <ValueRecord as ComputeSize>::compute_size(self.value_format()).unwrap_or(0),
1496 );
1497 start..end
1498 }
1499}
1500
1501#[derive(Clone)]
1503pub enum PairPos<'a> {
1504 Format1(PairPosFormat1<'a>),
1505 Format2(PairPosFormat2<'a>),
1506 Format3(PairPosFormat3<'a>),
1507 Format4(PairPosFormat4<'a>),
1508}
1509
1510impl Default for PairPos<'_> {
1511 fn default() -> Self {
1512 Self::Format1(Default::default())
1513 }
1514}
1515
1516impl<'a> PairPos<'a> {
1517 pub fn offset_data(&self) -> FontData<'a> {
1519 match self {
1520 Self::Format1(item) => item.offset_data(),
1521 Self::Format2(item) => item.offset_data(),
1522 Self::Format3(item) => item.offset_data(),
1523 Self::Format4(item) => item.offset_data(),
1524 }
1525 }
1526
1527 pub fn pos_format(&self) -> u16 {
1529 match self {
1530 Self::Format1(item) => item.pos_format(),
1531 Self::Format2(item) => item.pos_format(),
1532 Self::Format3(item) => item.pos_format(),
1533 Self::Format4(item) => item.pos_format(),
1534 }
1535 }
1536
1537 pub fn value_format1(&self) -> ValueFormat {
1540 match self {
1541 Self::Format1(item) => item.value_format1(),
1542 Self::Format2(item) => item.value_format1(),
1543 Self::Format3(item) => item.value_format1(),
1544 Self::Format4(item) => item.value_format1(),
1545 }
1546 }
1547
1548 pub fn value_format2(&self) -> ValueFormat {
1551 match self {
1552 Self::Format1(item) => item.value_format2(),
1553 Self::Format2(item) => item.value_format2(),
1554 Self::Format3(item) => item.value_format2(),
1555 Self::Format4(item) => item.value_format2(),
1556 }
1557 }
1558}
1559
1560impl ReadArgs for PairPos<'_> {
1561 type Args = ();
1562}
1563
1564impl<'a> FontRead<'a> for PairPos<'a> {
1565 #[inline]
1566 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1567 let format: u16 = data.read_at(0usize)?;
1568 match format {
1569 PairPosFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
1570 PairPosFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
1571 PairPosFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
1572 PairPosFormat4::FORMAT => Ok(Self::Format4(FontRead::read(data)?)),
1573 other => Err(ReadError::InvalidFormat(other.into())),
1574 }
1575 }
1576}
1577
1578impl<'a> MinByteRange<'a> for PairPos<'a> {
1579 fn min_byte_range(&self) -> Range<usize> {
1580 match self {
1581 Self::Format1(item) => item.min_byte_range(),
1582 Self::Format2(item) => item.min_byte_range(),
1583 Self::Format3(item) => item.min_byte_range(),
1584 Self::Format4(item) => item.min_byte_range(),
1585 }
1586 }
1587 fn min_table_bytes(&self) -> &'a [u8] {
1588 match self {
1589 Self::Format1(item) => item.min_table_bytes(),
1590 Self::Format2(item) => item.min_table_bytes(),
1591 Self::Format3(item) => item.min_table_bytes(),
1592 Self::Format4(item) => item.min_table_bytes(),
1593 }
1594 }
1595}
1596
1597impl Format<u16> for PairPosFormat1<'_> {
1598 const FORMAT: u16 = 1;
1599}
1600
1601impl<'a> MinByteRange<'a> for PairPosFormat1<'a> {
1602 fn min_byte_range(&self) -> Range<usize> {
1603 0..self.pair_set_offsets_byte_range().end
1604 }
1605 fn min_table_bytes(&self) -> &'a [u8] {
1606 let range = self.min_byte_range();
1607 self.offset_data().as_bytes().get(range).unwrap_or_default()
1608 }
1609}
1610
1611impl ReadArgs for PairPosFormat1<'_> {
1612 type Args = ();
1613}
1614
1615impl<'a> FontRead<'a> for PairPosFormat1<'a> {
1616 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1617 #[allow(clippy::absurd_extreme_comparisons)]
1618 if data.len() < Self::MIN_SIZE {
1619 return Err(ReadError::OutOfBounds);
1620 }
1621 let Some(data) = TableDataRef::new(data.as_bytes()) else {
1622 return Err(ReadError::OutOfBounds);
1623 };
1624 Ok(Self { data })
1625 }
1626}
1627
1628#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1630#[repr(C, packed)]
1631#[doc(hidden)]
1632pub struct PairPosFormat1FixedHeader {
1633 pub pos_format: BigEndian<u16>,
1634 pub coverage_offset: BigEndian<Offset16>,
1635 pub value_format1: BigEndian<ValueFormat>,
1636 pub value_format2: BigEndian<ValueFormat>,
1637 pub pair_set_count: BigEndian<u16>,
1638}
1639
1640#[allow(clippy::absurd_extreme_comparisons)]
1641const _: () = assert!(std::mem::size_of::<PairPosFormat1FixedHeader>() <= PairPosFormat1::MIN_SIZE);
1642
1643#[derive(Clone)]
1645pub struct PairPosFormat1<'a> {
1646 data: TableDataRef<'a, PairPosFormat1FixedHeader>,
1647}
1648
1649#[allow(clippy::needless_lifetimes)]
1650impl<'a> PairPosFormat1<'a> {
1651 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1652 + Offset16::RAW_BYTE_LEN
1653 + ValueFormat::RAW_BYTE_LEN
1654 + ValueFormat::RAW_BYTE_LEN
1655 + u16::RAW_BYTE_LEN);
1656 basic_table_impls!(impl_the_methods);
1657
1658 pub fn pos_format(&self) -> u16 {
1660 self.data.header().pos_format.get()
1661 }
1662
1663 pub fn coverage_offset(&self) -> Offset16 {
1665 self.data.header().coverage_offset.get()
1666 }
1667
1668 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
1670 let data = self.offset_data();
1671 self.coverage_offset().resolve(data)
1672 }
1673
1674 pub fn value_format1(&self) -> ValueFormat {
1677 self.data.header().value_format1.get()
1678 }
1679
1680 pub fn value_format2(&self) -> ValueFormat {
1683 self.data.header().value_format2.get()
1684 }
1685
1686 pub fn pair_set_count(&self) -> u16 {
1688 self.data.header().pair_set_count.get()
1689 }
1690
1691 pub fn pair_set_offsets(&self) -> &'a [BigEndian<Offset16>] {
1694 let range = self.pair_set_offsets_byte_range();
1695 self.offset_data()
1696 .read_array(range)
1697 .ok()
1698 .unwrap_or_default()
1699 }
1700
1701 pub fn pair_sets(&self) -> ArrayOfOffsets<'a, PairSet<'a>, Offset16> {
1703 let data = self.offset_data();
1704 let offsets = self.pair_set_offsets();
1705 let args = (self.value_format1(), self.value_format2());
1706 ArrayOfOffsets::new(offsets, data, args)
1707 }
1708
1709 pub fn pos_format_byte_range(&self) -> Range<usize> {
1710 let start = 0;
1711 let end = start + u16::RAW_BYTE_LEN;
1712 start..end
1713 }
1714
1715 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
1716 let start = self.pos_format_byte_range().end;
1717 let end = start + Offset16::RAW_BYTE_LEN;
1718 start..end
1719 }
1720
1721 pub fn value_format1_byte_range(&self) -> Range<usize> {
1722 let start = self.coverage_offset_byte_range().end;
1723 let end = start + ValueFormat::RAW_BYTE_LEN;
1724 start..end
1725 }
1726
1727 pub fn value_format2_byte_range(&self) -> Range<usize> {
1728 let start = self.value_format1_byte_range().end;
1729 let end = start + ValueFormat::RAW_BYTE_LEN;
1730 start..end
1731 }
1732
1733 pub fn pair_set_count_byte_range(&self) -> Range<usize> {
1734 let start = self.value_format2_byte_range().end;
1735 let end = start + u16::RAW_BYTE_LEN;
1736 start..end
1737 }
1738
1739 pub fn pair_set_offsets_byte_range(&self) -> Range<usize> {
1740 let pair_set_count = self.pair_set_count();
1741 let start = self.pair_set_count_byte_range().end;
1742 let end =
1743 start + (transforms::to_usize(pair_set_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
1744 start..end
1745 }
1746}
1747
1748const _: () = assert!(FontData::default_data_long_enough(PairPosFormat1::MIN_SIZE));
1749
1750impl Default for PairPosFormat1<'_> {
1751 fn default() -> Self {
1752 Self {
1753 data: TableDataRef::new(FontData::default_format_1_u16_table_data().as_bytes())
1754 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1755 }
1756 }
1757}
1758
1759impl<'a> MinByteRange<'a> for PairSet<'a> {
1760 fn min_byte_range(&self) -> Range<usize> {
1761 0..self.pair_value_records_byte_range().end
1762 }
1763 fn min_table_bytes(&self) -> &'a [u8] {
1764 let range = self.min_byte_range();
1765 self.offset_data().as_bytes().get(range).unwrap_or_default()
1766 }
1767}
1768
1769impl ReadArgs for PairSet<'_> {
1770 type Args = (ValueFormat, ValueFormat);
1771}
1772
1773impl<'a> FontRead<'a> for PairSet<'a> {
1774 fn read_with_args(
1775 data: FontData<'a>,
1776 args: (ValueFormat, ValueFormat),
1777 ) -> Result<Self, ReadError> {
1778 let (value_format1, value_format2) = args;
1779
1780 #[allow(clippy::absurd_extreme_comparisons)]
1781 if data.len() < Self::MIN_SIZE {
1782 return Err(ReadError::OutOfBounds);
1783 }
1784 let Some(data) = TableDataRef::new(data.as_bytes()) else {
1785 return Err(ReadError::OutOfBounds);
1786 };
1787 Ok(Self {
1788 data,
1789 value_format1,
1790 value_format2,
1791 })
1792 }
1793}
1794
1795impl<'a> PairSet<'a> {
1796 pub fn read(
1801 data: FontData<'a>,
1802 value_format1: ValueFormat,
1803 value_format2: ValueFormat,
1804 ) -> Result<Self, ReadError> {
1805 let args = (value_format1, value_format2);
1806 Self::read_with_args(data, args)
1807 }
1808}
1809
1810#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1812#[repr(C, packed)]
1813#[doc(hidden)]
1814pub struct PairSetFixedHeader {
1815 pub pair_value_count: BigEndian<u16>,
1816}
1817
1818#[allow(clippy::absurd_extreme_comparisons)]
1819const _: () = assert!(std::mem::size_of::<PairSetFixedHeader>() <= PairSet::MIN_SIZE);
1820
1821#[derive(Clone)]
1823pub struct PairSet<'a> {
1824 data: TableDataRef<'a, PairSetFixedHeader>,
1825 value_format1: ValueFormat,
1826 value_format2: ValueFormat,
1827}
1828
1829#[allow(clippy::needless_lifetimes)]
1830impl<'a> PairSet<'a> {
1831 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
1832 basic_table_impls!(impl_the_methods);
1833
1834 pub fn pair_value_count(&self) -> u16 {
1836 self.data.header().pair_value_count.get()
1837 }
1838
1839 pub fn pair_value_records(&self) -> ComputedArray<'a, PairValueRecord<'a>> {
1842 let range = self.pair_value_records_byte_range();
1843 ComputedArray::new(
1844 self.offset_data(),
1845 range,
1846 (self.value_format1(), self.value_format2()),
1847 )
1848 .unwrap_or_default()
1849 }
1850
1851 pub(crate) fn value_format1(&self) -> ValueFormat {
1852 self.value_format1
1853 }
1854
1855 pub(crate) fn value_format2(&self) -> ValueFormat {
1856 self.value_format2
1857 }
1858
1859 pub fn pair_value_count_byte_range(&self) -> Range<usize> {
1860 let start = 0;
1861 let end = start + u16::RAW_BYTE_LEN;
1862 start..end
1863 }
1864
1865 pub fn pair_value_records_byte_range(&self) -> Range<usize> {
1866 let pair_value_count = self.pair_value_count();
1867 let start = self.pair_value_count_byte_range().end;
1868 let end = start
1869 + (transforms::to_usize(pair_value_count)).saturating_mul(
1870 <PairValueRecord as ComputeSize>::compute_size((
1871 self.value_format1(),
1872 self.value_format2(),
1873 ))
1874 .unwrap_or(0),
1875 );
1876 start..end
1877 }
1878}
1879
1880const _: () = assert!(FontData::default_data_long_enough(PairSet::MIN_SIZE));
1881
1882impl Default for PairSet<'_> {
1883 fn default() -> Self {
1884 Self {
1885 data: TableDataRef::new(FontData::default_table_data().as_bytes())
1886 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1887 value_format1: Default::default(),
1888 value_format2: Default::default(),
1889 }
1890 }
1891}
1892
1893#[derive(Clone, Debug)]
1895pub struct PairValueRecord<'a> {
1896 pub second_glyph: BigEndian<GlyphId16>,
1899 pub value_record1: ValueRecord<'a>,
1901 pub value_record2: ValueRecord<'a>,
1903}
1904
1905impl<'a> PairValueRecord<'a> {
1906 pub fn second_glyph(&self) -> GlyphId16 {
1909 self.second_glyph.get()
1910 }
1911
1912 pub fn value_record1(&self) -> &ValueRecord<'a> {
1914 &self.value_record1
1915 }
1916
1917 pub fn value_record2(&self) -> &ValueRecord<'a> {
1919 &self.value_record2
1920 }
1921}
1922
1923impl ReadArgs for PairValueRecord<'_> {
1924 type Args = (ValueFormat, ValueFormat);
1925}
1926
1927impl ComputeSize for PairValueRecord<'_> {
1928 #[allow(clippy::needless_question_mark)]
1929 fn compute_size(args: (ValueFormat, ValueFormat)) -> Result<usize, ReadError> {
1930 let (value_format1, value_format2) = args;
1931 let mut result = 0usize;
1932 result = result
1933 .checked_add(GlyphId16::RAW_BYTE_LEN)
1934 .ok_or(ReadError::OutOfBounds)?;
1935 result = result
1936 .checked_add(<ValueRecord as ComputeSize>::compute_size(value_format1).unwrap_or(0))
1937 .ok_or(ReadError::OutOfBounds)?;
1938 result = result
1939 .checked_add(<ValueRecord as ComputeSize>::compute_size(value_format2).unwrap_or(0))
1940 .ok_or(ReadError::OutOfBounds)?;
1941 Ok(result)
1942 }
1943}
1944
1945impl<'a> FontReadAt<'a> for PairValueRecord<'a> {
1946 fn read_at(
1947 data: FontData<'a>,
1948 offset: usize,
1949 args: (ValueFormat, ValueFormat),
1950 ) -> Result<Self, ReadError> {
1951 let mut cursor = data.cursor();
1952 cursor.advance_by(offset);
1953 let (value_format1, value_format2) = args;
1954 Ok(Self {
1955 second_glyph: cursor.read_be()?,
1956 value_record1: cursor.read_at_with_args(value_format1)?,
1957 value_record2: cursor.read_at_with_args(value_format2)?,
1958 })
1959 }
1960}
1961
1962#[allow(clippy::needless_lifetimes)]
1963impl<'a> PairValueRecord<'a> {
1964 pub fn read(
1969 data: FontData<'a>,
1970 offset: usize,
1971 value_format1: ValueFormat,
1972 value_format2: ValueFormat,
1973 ) -> Result<Self, ReadError> {
1974 let args = (value_format1, value_format2);
1975 Self::read_at(data, offset, args)
1976 }
1977}
1978
1979impl Format<u16> for PairPosFormat2<'_> {
1980 const FORMAT: u16 = 2;
1981}
1982
1983impl<'a> MinByteRange<'a> for PairPosFormat2<'a> {
1984 fn min_byte_range(&self) -> Range<usize> {
1985 0..self.class1_records_byte_range().end
1986 }
1987 fn min_table_bytes(&self) -> &'a [u8] {
1988 let range = self.min_byte_range();
1989 self.offset_data().as_bytes().get(range).unwrap_or_default()
1990 }
1991}
1992
1993impl ReadArgs for PairPosFormat2<'_> {
1994 type Args = ();
1995}
1996
1997impl<'a> FontRead<'a> for PairPosFormat2<'a> {
1998 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1999 #[allow(clippy::absurd_extreme_comparisons)]
2000 if data.len() < Self::MIN_SIZE {
2001 return Err(ReadError::OutOfBounds);
2002 }
2003 let Some(data) = TableDataRef::new(data.as_bytes()) else {
2004 return Err(ReadError::OutOfBounds);
2005 };
2006 Ok(Self { data })
2007 }
2008}
2009
2010#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
2012#[repr(C, packed)]
2013#[doc(hidden)]
2014pub struct PairPosFormat2FixedHeader {
2015 pub pos_format: BigEndian<u16>,
2016 pub coverage_offset: BigEndian<Offset16>,
2017 pub value_format1: BigEndian<ValueFormat>,
2018 pub value_format2: BigEndian<ValueFormat>,
2019 pub class_def1_offset: BigEndian<Offset16>,
2020 pub class_def2_offset: BigEndian<Offset16>,
2021 pub class1_count: BigEndian<u16>,
2022 pub class2_count: BigEndian<u16>,
2023}
2024
2025#[allow(clippy::absurd_extreme_comparisons)]
2026const _: () = assert!(std::mem::size_of::<PairPosFormat2FixedHeader>() <= PairPosFormat2::MIN_SIZE);
2027
2028#[derive(Clone)]
2030pub struct PairPosFormat2<'a> {
2031 data: TableDataRef<'a, PairPosFormat2FixedHeader>,
2032}
2033
2034#[allow(clippy::needless_lifetimes)]
2035impl<'a> PairPosFormat2<'a> {
2036 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
2037 + Offset16::RAW_BYTE_LEN
2038 + ValueFormat::RAW_BYTE_LEN
2039 + ValueFormat::RAW_BYTE_LEN
2040 + Offset16::RAW_BYTE_LEN
2041 + Offset16::RAW_BYTE_LEN
2042 + u16::RAW_BYTE_LEN
2043 + u16::RAW_BYTE_LEN);
2044 basic_table_impls!(impl_the_methods);
2045
2046 pub fn pos_format(&self) -> u16 {
2048 self.data.header().pos_format.get()
2049 }
2050
2051 pub fn coverage_offset(&self) -> Offset16 {
2053 self.data.header().coverage_offset.get()
2054 }
2055
2056 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2058 let data = self.offset_data();
2059 self.coverage_offset().resolve(data)
2060 }
2061
2062 pub fn value_format1(&self) -> ValueFormat {
2065 self.data.header().value_format1.get()
2066 }
2067
2068 pub fn value_format2(&self) -> ValueFormat {
2071 self.data.header().value_format2.get()
2072 }
2073
2074 pub fn class_def1_offset(&self) -> Offset16 {
2077 self.data.header().class_def1_offset.get()
2078 }
2079
2080 pub fn class_def1(&self) -> Result<ClassDef<'a>, ReadError> {
2082 let data = self.offset_data();
2083 self.class_def1_offset().resolve(data)
2084 }
2085
2086 pub fn class_def2_offset(&self) -> Offset16 {
2089 self.data.header().class_def2_offset.get()
2090 }
2091
2092 pub fn class_def2(&self) -> Result<ClassDef<'a>, ReadError> {
2094 let data = self.offset_data();
2095 self.class_def2_offset().resolve(data)
2096 }
2097
2098 pub fn class1_count(&self) -> u16 {
2100 self.data.header().class1_count.get()
2101 }
2102
2103 pub fn class2_count(&self) -> u16 {
2105 self.data.header().class2_count.get()
2106 }
2107
2108 pub fn class1_records(&self) -> ComputedArray<'a, Class1Record<'a>> {
2110 let range = self.class1_records_byte_range();
2111 ComputedArray::new(
2112 self.offset_data(),
2113 range,
2114 (
2115 self.class2_count(),
2116 self.value_format1(),
2117 self.value_format2(),
2118 ),
2119 )
2120 .unwrap_or_default()
2121 }
2122
2123 pub fn pos_format_byte_range(&self) -> Range<usize> {
2124 let start = 0;
2125 let end = start + u16::RAW_BYTE_LEN;
2126 start..end
2127 }
2128
2129 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
2130 let start = self.pos_format_byte_range().end;
2131 let end = start + Offset16::RAW_BYTE_LEN;
2132 start..end
2133 }
2134
2135 pub fn value_format1_byte_range(&self) -> Range<usize> {
2136 let start = self.coverage_offset_byte_range().end;
2137 let end = start + ValueFormat::RAW_BYTE_LEN;
2138 start..end
2139 }
2140
2141 pub fn value_format2_byte_range(&self) -> Range<usize> {
2142 let start = self.value_format1_byte_range().end;
2143 let end = start + ValueFormat::RAW_BYTE_LEN;
2144 start..end
2145 }
2146
2147 pub fn class_def1_offset_byte_range(&self) -> Range<usize> {
2148 let start = self.value_format2_byte_range().end;
2149 let end = start + Offset16::RAW_BYTE_LEN;
2150 start..end
2151 }
2152
2153 pub fn class_def2_offset_byte_range(&self) -> Range<usize> {
2154 let start = self.class_def1_offset_byte_range().end;
2155 let end = start + Offset16::RAW_BYTE_LEN;
2156 start..end
2157 }
2158
2159 pub fn class1_count_byte_range(&self) -> Range<usize> {
2160 let start = self.class_def2_offset_byte_range().end;
2161 let end = start + u16::RAW_BYTE_LEN;
2162 start..end
2163 }
2164
2165 pub fn class2_count_byte_range(&self) -> Range<usize> {
2166 let start = self.class1_count_byte_range().end;
2167 let end = start + u16::RAW_BYTE_LEN;
2168 start..end
2169 }
2170
2171 pub fn class1_records_byte_range(&self) -> Range<usize> {
2172 let class1_count = self.class1_count();
2173 let start = self.class2_count_byte_range().end;
2174 let end = start
2175 + (transforms::to_usize(class1_count)).saturating_mul(
2176 <Class1Record as ComputeSize>::compute_size((
2177 self.class2_count(),
2178 self.value_format1(),
2179 self.value_format2(),
2180 ))
2181 .unwrap_or(0),
2182 );
2183 start..end
2184 }
2185}
2186
2187#[derive(Clone, Debug)]
2189pub struct Class1Record<'a> {
2190 pub class2_records: ComputedArray<'a, Class2Record<'a>>,
2192}
2193
2194impl<'a> Class1Record<'a> {
2195 pub fn class2_records(&self) -> &ComputedArray<'a, Class2Record<'a>> {
2197 &self.class2_records
2198 }
2199}
2200
2201impl ReadArgs for Class1Record<'_> {
2202 type Args = (u16, ValueFormat, ValueFormat);
2203}
2204
2205impl ComputeSize for Class1Record<'_> {
2206 #[allow(clippy::needless_question_mark)]
2207 fn compute_size(args: (u16, ValueFormat, ValueFormat)) -> Result<usize, ReadError> {
2208 let (class2_count, value_format1, value_format2) = args;
2209 Ok((transforms::to_usize(class2_count)).saturating_mul(
2210 <Class2Record as ComputeSize>::compute_size((value_format1, value_format2))
2211 .unwrap_or(0),
2212 ))
2213 }
2214}
2215
2216impl<'a> FontReadAt<'a> for Class1Record<'a> {
2217 fn read_at(
2218 data: FontData<'a>,
2219 offset: usize,
2220 args: (u16, ValueFormat, ValueFormat),
2221 ) -> Result<Self, ReadError> {
2222 let mut cursor = data.cursor();
2223 cursor.advance_by(offset);
2224 let (class2_count, value_format1, value_format2) = args;
2225 Ok(Self {
2226 class2_records: cursor.read_computed_array(
2227 transforms::to_usize(class2_count),
2228 (value_format1, value_format2),
2229 )?,
2230 })
2231 }
2232}
2233
2234#[allow(clippy::needless_lifetimes)]
2235impl<'a> Class1Record<'a> {
2236 pub fn read(
2241 data: FontData<'a>,
2242 offset: usize,
2243 class2_count: u16,
2244 value_format1: ValueFormat,
2245 value_format2: ValueFormat,
2246 ) -> Result<Self, ReadError> {
2247 let args = (class2_count, value_format1, value_format2);
2248 Self::read_at(data, offset, args)
2249 }
2250}
2251
2252#[derive(Clone, Debug)]
2254pub struct Class2Record<'a> {
2255 pub value_record1: ValueRecord<'a>,
2257 pub value_record2: ValueRecord<'a>,
2259}
2260
2261impl<'a> Class2Record<'a> {
2262 pub fn value_record1(&self) -> &ValueRecord<'a> {
2264 &self.value_record1
2265 }
2266
2267 pub fn value_record2(&self) -> &ValueRecord<'a> {
2269 &self.value_record2
2270 }
2271}
2272
2273impl ReadArgs for Class2Record<'_> {
2274 type Args = (ValueFormat, ValueFormat);
2275}
2276
2277impl ComputeSize for Class2Record<'_> {
2278 #[allow(clippy::needless_question_mark)]
2279 fn compute_size(args: (ValueFormat, ValueFormat)) -> Result<usize, ReadError> {
2280 let (value_format1, value_format2) = args;
2281 let mut result = 0usize;
2282 result = result
2283 .checked_add(<ValueRecord as ComputeSize>::compute_size(value_format1).unwrap_or(0))
2284 .ok_or(ReadError::OutOfBounds)?;
2285 result = result
2286 .checked_add(<ValueRecord as ComputeSize>::compute_size(value_format2).unwrap_or(0))
2287 .ok_or(ReadError::OutOfBounds)?;
2288 Ok(result)
2289 }
2290}
2291
2292impl<'a> FontReadAt<'a> for Class2Record<'a> {
2293 fn read_at(
2294 data: FontData<'a>,
2295 offset: usize,
2296 args: (ValueFormat, ValueFormat),
2297 ) -> Result<Self, ReadError> {
2298 let mut cursor = data.cursor();
2299 cursor.advance_by(offset);
2300 let (value_format1, value_format2) = args;
2301 Ok(Self {
2302 value_record1: cursor.read_at_with_args(value_format1)?,
2303 value_record2: cursor.read_at_with_args(value_format2)?,
2304 })
2305 }
2306}
2307
2308#[allow(clippy::needless_lifetimes)]
2309impl<'a> Class2Record<'a> {
2310 pub fn read(
2315 data: FontData<'a>,
2316 offset: usize,
2317 value_format1: ValueFormat,
2318 value_format2: ValueFormat,
2319 ) -> Result<Self, ReadError> {
2320 let args = (value_format1, value_format2);
2321 Self::read_at(data, offset, args)
2322 }
2323}
2324
2325impl Format<u16> for CursivePosFormat1<'_> {
2326 const FORMAT: u16 = 1;
2327}
2328
2329impl<'a> MinByteRange<'a> for CursivePosFormat1<'a> {
2330 fn min_byte_range(&self) -> Range<usize> {
2331 0..self.entry_exit_record_byte_range().end
2332 }
2333 fn min_table_bytes(&self) -> &'a [u8] {
2334 let range = self.min_byte_range();
2335 self.offset_data().as_bytes().get(range).unwrap_or_default()
2336 }
2337}
2338
2339impl ReadArgs for CursivePosFormat1<'_> {
2340 type Args = ();
2341}
2342
2343impl<'a> FontRead<'a> for CursivePosFormat1<'a> {
2344 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2345 #[allow(clippy::absurd_extreme_comparisons)]
2346 if data.len() < Self::MIN_SIZE {
2347 return Err(ReadError::OutOfBounds);
2348 }
2349 let Some(data) = TableDataRef::new(data.as_bytes()) else {
2350 return Err(ReadError::OutOfBounds);
2351 };
2352 Ok(Self { data })
2353 }
2354}
2355
2356#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
2358#[repr(C, packed)]
2359#[doc(hidden)]
2360pub struct CursivePosFormat1FixedHeader {
2361 pub pos_format: BigEndian<u16>,
2362 pub coverage_offset: BigEndian<Offset16>,
2363 pub entry_exit_count: BigEndian<u16>,
2364}
2365
2366#[allow(clippy::absurd_extreme_comparisons)]
2367const _: () =
2368 assert!(std::mem::size_of::<CursivePosFormat1FixedHeader>() <= CursivePosFormat1::MIN_SIZE);
2369
2370#[derive(Clone)]
2372pub struct CursivePosFormat1<'a> {
2373 data: TableDataRef<'a, CursivePosFormat1FixedHeader>,
2374}
2375
2376#[allow(clippy::needless_lifetimes)]
2377impl<'a> CursivePosFormat1<'a> {
2378 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
2379 basic_table_impls!(impl_the_methods);
2380
2381 pub fn pos_format(&self) -> u16 {
2383 self.data.header().pos_format.get()
2384 }
2385
2386 pub fn coverage_offset(&self) -> Offset16 {
2388 self.data.header().coverage_offset.get()
2389 }
2390
2391 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2393 let data = self.offset_data();
2394 self.coverage_offset().resolve(data)
2395 }
2396
2397 pub fn entry_exit_count(&self) -> u16 {
2399 self.data.header().entry_exit_count.get()
2400 }
2401
2402 pub fn entry_exit_record(&self) -> &'a [EntryExitRecord] {
2404 let range = self.entry_exit_record_byte_range();
2405 self.offset_data()
2406 .read_array(range)
2407 .ok()
2408 .unwrap_or_default()
2409 }
2410
2411 pub fn pos_format_byte_range(&self) -> Range<usize> {
2412 let start = 0;
2413 let end = start + u16::RAW_BYTE_LEN;
2414 start..end
2415 }
2416
2417 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
2418 let start = self.pos_format_byte_range().end;
2419 let end = start + Offset16::RAW_BYTE_LEN;
2420 start..end
2421 }
2422
2423 pub fn entry_exit_count_byte_range(&self) -> Range<usize> {
2424 let start = self.coverage_offset_byte_range().end;
2425 let end = start + u16::RAW_BYTE_LEN;
2426 start..end
2427 }
2428
2429 pub fn entry_exit_record_byte_range(&self) -> Range<usize> {
2430 let entry_exit_count = self.entry_exit_count();
2431 let start = self.entry_exit_count_byte_range().end;
2432 let end = start
2433 + (transforms::to_usize(entry_exit_count))
2434 .saturating_mul(EntryExitRecord::RAW_BYTE_LEN);
2435 start..end
2436 }
2437}
2438
2439const _: () = assert!(FontData::default_data_long_enough(
2440 CursivePosFormat1::MIN_SIZE
2441));
2442
2443impl Default for CursivePosFormat1<'_> {
2444 fn default() -> Self {
2445 Self {
2446 data: TableDataRef::new(FontData::default_format_1_u16_table_data().as_bytes())
2447 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
2448 }
2449 }
2450}
2451
2452#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
2454#[repr(C)]
2455#[repr(packed)]
2456pub struct EntryExitRecord {
2457 pub entry_anchor_offset: BigEndian<Nullable<Offset16>>,
2460 pub exit_anchor_offset: BigEndian<Nullable<Offset16>>,
2463}
2464
2465impl EntryExitRecord {
2466 pub fn entry_anchor_offset(&self) -> Nullable<Offset16> {
2469 self.entry_anchor_offset.get()
2470 }
2471
2472 pub fn entry_anchor<'a>(
2478 &self,
2479 data: FontData<'a>,
2480 ) -> Option<Result<AnchorTable<'a>, ReadError>> {
2481 self.entry_anchor_offset().resolve(data)
2482 }
2483
2484 pub fn exit_anchor_offset(&self) -> Nullable<Offset16> {
2487 self.exit_anchor_offset.get()
2488 }
2489
2490 pub fn exit_anchor<'a>(
2496 &self,
2497 data: FontData<'a>,
2498 ) -> Option<Result<AnchorTable<'a>, ReadError>> {
2499 self.exit_anchor_offset().resolve(data)
2500 }
2501}
2502
2503impl FixedSize for EntryExitRecord {
2504 const RAW_BYTE_LEN: usize = Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
2505}
2506
2507impl Format<u16> for MarkBasePosFormat1<'_> {
2508 const FORMAT: u16 = 1;
2509}
2510
2511impl<'a> MinByteRange<'a> for MarkBasePosFormat1<'a> {
2512 fn min_byte_range(&self) -> Range<usize> {
2513 0..self.base_array_offset_byte_range().end
2514 }
2515 fn min_table_bytes(&self) -> &'a [u8] {
2516 let range = self.min_byte_range();
2517 self.offset_data().as_bytes().get(range).unwrap_or_default()
2518 }
2519}
2520
2521impl ReadArgs for MarkBasePosFormat1<'_> {
2522 type Args = ();
2523}
2524
2525impl<'a> FontRead<'a> for MarkBasePosFormat1<'a> {
2526 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2527 #[allow(clippy::absurd_extreme_comparisons)]
2528 if data.len() < Self::MIN_SIZE {
2529 return Err(ReadError::OutOfBounds);
2530 }
2531 let Some(data) = TableDataRef::new(data.as_bytes()) else {
2532 return Err(ReadError::OutOfBounds);
2533 };
2534 Ok(Self { data })
2535 }
2536}
2537
2538#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
2540#[repr(C, packed)]
2541#[doc(hidden)]
2542pub struct MarkBasePosFormat1FixedHeader {
2543 pub pos_format: BigEndian<u16>,
2544 pub mark_coverage_offset: BigEndian<Offset16>,
2545 pub base_coverage_offset: BigEndian<Offset16>,
2546 pub mark_class_count: BigEndian<u16>,
2547 pub mark_array_offset: BigEndian<Offset16>,
2548 pub base_array_offset: BigEndian<Offset16>,
2549}
2550
2551#[allow(clippy::absurd_extreme_comparisons)]
2552const _: () =
2553 assert!(std::mem::size_of::<MarkBasePosFormat1FixedHeader>() <= MarkBasePosFormat1::MIN_SIZE);
2554
2555#[derive(Clone)]
2557pub struct MarkBasePosFormat1<'a> {
2558 data: TableDataRef<'a, MarkBasePosFormat1FixedHeader>,
2559}
2560
2561#[allow(clippy::needless_lifetimes)]
2562impl<'a> MarkBasePosFormat1<'a> {
2563 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
2564 + Offset16::RAW_BYTE_LEN
2565 + Offset16::RAW_BYTE_LEN
2566 + u16::RAW_BYTE_LEN
2567 + Offset16::RAW_BYTE_LEN
2568 + Offset16::RAW_BYTE_LEN);
2569 basic_table_impls!(impl_the_methods);
2570
2571 pub fn pos_format(&self) -> u16 {
2573 self.data.header().pos_format.get()
2574 }
2575
2576 pub fn mark_coverage_offset(&self) -> Offset16 {
2579 self.data.header().mark_coverage_offset.get()
2580 }
2581
2582 pub fn mark_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2584 let data = self.offset_data();
2585 self.mark_coverage_offset().resolve(data)
2586 }
2587
2588 pub fn base_coverage_offset(&self) -> Offset16 {
2591 self.data.header().base_coverage_offset.get()
2592 }
2593
2594 pub fn base_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2596 let data = self.offset_data();
2597 self.base_coverage_offset().resolve(data)
2598 }
2599
2600 pub fn mark_class_count(&self) -> u16 {
2602 self.data.header().mark_class_count.get()
2603 }
2604
2605 pub fn mark_array_offset(&self) -> Offset16 {
2608 self.data.header().mark_array_offset.get()
2609 }
2610
2611 pub fn mark_array(&self) -> Result<MarkArray<'a>, ReadError> {
2613 let data = self.offset_data();
2614 self.mark_array_offset().resolve(data)
2615 }
2616
2617 pub fn base_array_offset(&self) -> Offset16 {
2620 self.data.header().base_array_offset.get()
2621 }
2622
2623 pub fn base_array(&self) -> Result<BaseArray<'a>, ReadError> {
2625 let data = self.offset_data();
2626 let args = self.mark_class_count();
2627 self.base_array_offset().resolve_with_args(data, args)
2628 }
2629
2630 pub fn pos_format_byte_range(&self) -> Range<usize> {
2631 let start = 0;
2632 let end = start + u16::RAW_BYTE_LEN;
2633 start..end
2634 }
2635
2636 pub fn mark_coverage_offset_byte_range(&self) -> Range<usize> {
2637 let start = self.pos_format_byte_range().end;
2638 let end = start + Offset16::RAW_BYTE_LEN;
2639 start..end
2640 }
2641
2642 pub fn base_coverage_offset_byte_range(&self) -> Range<usize> {
2643 let start = self.mark_coverage_offset_byte_range().end;
2644 let end = start + Offset16::RAW_BYTE_LEN;
2645 start..end
2646 }
2647
2648 pub fn mark_class_count_byte_range(&self) -> Range<usize> {
2649 let start = self.base_coverage_offset_byte_range().end;
2650 let end = start + u16::RAW_BYTE_LEN;
2651 start..end
2652 }
2653
2654 pub fn mark_array_offset_byte_range(&self) -> Range<usize> {
2655 let start = self.mark_class_count_byte_range().end;
2656 let end = start + Offset16::RAW_BYTE_LEN;
2657 start..end
2658 }
2659
2660 pub fn base_array_offset_byte_range(&self) -> Range<usize> {
2661 let start = self.mark_array_offset_byte_range().end;
2662 let end = start + Offset16::RAW_BYTE_LEN;
2663 start..end
2664 }
2665}
2666
2667const _: () = assert!(FontData::default_data_long_enough(
2668 MarkBasePosFormat1::MIN_SIZE
2669));
2670
2671impl Default for MarkBasePosFormat1<'_> {
2672 fn default() -> Self {
2673 Self {
2674 data: TableDataRef::new(FontData::default_format_1_u16_table_data().as_bytes())
2675 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
2676 }
2677 }
2678}
2679
2680impl<'a> MinByteRange<'a> for BaseArray<'a> {
2681 fn min_byte_range(&self) -> Range<usize> {
2682 0..self.base_records_byte_range().end
2683 }
2684 fn min_table_bytes(&self) -> &'a [u8] {
2685 let range = self.min_byte_range();
2686 self.offset_data().as_bytes().get(range).unwrap_or_default()
2687 }
2688}
2689
2690impl ReadArgs for BaseArray<'_> {
2691 type Args = u16;
2692}
2693
2694impl<'a> FontRead<'a> for BaseArray<'a> {
2695 fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
2696 let mark_class_count = args;
2697
2698 #[allow(clippy::absurd_extreme_comparisons)]
2699 if data.len() < Self::MIN_SIZE {
2700 return Err(ReadError::OutOfBounds);
2701 }
2702 let Some(data) = TableDataRef::new(data.as_bytes()) else {
2703 return Err(ReadError::OutOfBounds);
2704 };
2705 Ok(Self {
2706 data,
2707 mark_class_count,
2708 })
2709 }
2710}
2711
2712impl<'a> BaseArray<'a> {
2713 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
2718 let args = mark_class_count;
2719 Self::read_with_args(data, args)
2720 }
2721}
2722
2723#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
2725#[repr(C, packed)]
2726#[doc(hidden)]
2727pub struct BaseArrayFixedHeader {
2728 pub base_count: BigEndian<u16>,
2729}
2730
2731#[allow(clippy::absurd_extreme_comparisons)]
2732const _: () = assert!(std::mem::size_of::<BaseArrayFixedHeader>() <= BaseArray::MIN_SIZE);
2733
2734#[derive(Clone)]
2736pub struct BaseArray<'a> {
2737 data: TableDataRef<'a, BaseArrayFixedHeader>,
2738 mark_class_count: u16,
2739}
2740
2741#[allow(clippy::needless_lifetimes)]
2742impl<'a> BaseArray<'a> {
2743 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
2744 basic_table_impls!(impl_the_methods);
2745
2746 pub fn base_count(&self) -> u16 {
2748 self.data.header().base_count.get()
2749 }
2750
2751 pub fn base_records(&self) -> ComputedArray<'a, BaseRecord<'a>> {
2753 let range = self.base_records_byte_range();
2754 ComputedArray::new(self.offset_data(), range, self.mark_class_count()).unwrap_or_default()
2755 }
2756
2757 pub(crate) fn mark_class_count(&self) -> u16 {
2758 self.mark_class_count
2759 }
2760
2761 pub fn base_count_byte_range(&self) -> Range<usize> {
2762 let start = 0;
2763 let end = start + u16::RAW_BYTE_LEN;
2764 start..end
2765 }
2766
2767 pub fn base_records_byte_range(&self) -> Range<usize> {
2768 let base_count = self.base_count();
2769 let start = self.base_count_byte_range().end;
2770 let end = start
2771 + (transforms::to_usize(base_count)).saturating_mul(
2772 <BaseRecord as ComputeSize>::compute_size(self.mark_class_count()).unwrap_or(0),
2773 );
2774 start..end
2775 }
2776}
2777
2778const _: () = assert!(FontData::default_data_long_enough(BaseArray::MIN_SIZE));
2779
2780impl Default for BaseArray<'_> {
2781 fn default() -> Self {
2782 Self {
2783 data: TableDataRef::new(FontData::default_table_data().as_bytes())
2784 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
2785 mark_class_count: Default::default(),
2786 }
2787 }
2788}
2789
2790#[derive(Clone, Debug)]
2792pub struct BaseRecord<'a> {
2793 pub base_anchor_offsets: &'a [BigEndian<Nullable<Offset16>>],
2797}
2798
2799impl<'a> BaseRecord<'a> {
2800 pub fn base_anchor_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
2804 self.base_anchor_offsets
2805 }
2806
2807 pub fn base_anchors(
2814 &self,
2815 data: FontData<'a>,
2816 ) -> ArrayOfNullableOffsets<'a, AnchorTable<'a>, Offset16> {
2817 let offsets = self.base_anchor_offsets();
2818 ArrayOfNullableOffsets::new(offsets, data, ())
2819 }
2820}
2821
2822impl ReadArgs for BaseRecord<'_> {
2823 type Args = u16;
2824}
2825
2826impl ComputeSize for BaseRecord<'_> {
2827 #[allow(clippy::needless_question_mark)]
2828 fn compute_size(args: u16) -> Result<usize, ReadError> {
2829 let mark_class_count = args;
2830 Ok((transforms::to_usize(mark_class_count)).saturating_mul(Offset16::RAW_BYTE_LEN))
2831 }
2832}
2833
2834impl<'a> FontRead<'a> for BaseRecord<'a> {
2835 fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
2836 let mut cursor = data.cursor();
2837 let mark_class_count = args;
2838 Ok(Self {
2839 base_anchor_offsets: cursor.read_array(transforms::to_usize(mark_class_count))?,
2840 })
2841 }
2842}
2843
2844crate::impl_font_read_at!(BaseRecord<'a>);
2845
2846#[allow(clippy::needless_lifetimes)]
2847impl<'a> BaseRecord<'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
2858impl Format<u16> for MarkLigPosFormat1<'_> {
2859 const FORMAT: u16 = 1;
2860}
2861
2862impl<'a> MinByteRange<'a> for MarkLigPosFormat1<'a> {
2863 fn min_byte_range(&self) -> Range<usize> {
2864 0..self.ligature_array_offset_byte_range().end
2865 }
2866 fn min_table_bytes(&self) -> &'a [u8] {
2867 let range = self.min_byte_range();
2868 self.offset_data().as_bytes().get(range).unwrap_or_default()
2869 }
2870}
2871
2872impl ReadArgs for MarkLigPosFormat1<'_> {
2873 type Args = ();
2874}
2875
2876impl<'a> FontRead<'a> for MarkLigPosFormat1<'a> {
2877 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2878 #[allow(clippy::absurd_extreme_comparisons)]
2879 if data.len() < Self::MIN_SIZE {
2880 return Err(ReadError::OutOfBounds);
2881 }
2882 let Some(data) = TableDataRef::new(data.as_bytes()) else {
2883 return Err(ReadError::OutOfBounds);
2884 };
2885 Ok(Self { data })
2886 }
2887}
2888
2889#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
2891#[repr(C, packed)]
2892#[doc(hidden)]
2893pub struct MarkLigPosFormat1FixedHeader {
2894 pub pos_format: BigEndian<u16>,
2895 pub mark_coverage_offset: BigEndian<Offset16>,
2896 pub ligature_coverage_offset: BigEndian<Offset16>,
2897 pub mark_class_count: BigEndian<u16>,
2898 pub mark_array_offset: BigEndian<Offset16>,
2899 pub ligature_array_offset: BigEndian<Offset16>,
2900}
2901
2902#[allow(clippy::absurd_extreme_comparisons)]
2903const _: () =
2904 assert!(std::mem::size_of::<MarkLigPosFormat1FixedHeader>() <= MarkLigPosFormat1::MIN_SIZE);
2905
2906#[derive(Clone)]
2908pub struct MarkLigPosFormat1<'a> {
2909 data: TableDataRef<'a, MarkLigPosFormat1FixedHeader>,
2910}
2911
2912#[allow(clippy::needless_lifetimes)]
2913impl<'a> MarkLigPosFormat1<'a> {
2914 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
2915 + Offset16::RAW_BYTE_LEN
2916 + Offset16::RAW_BYTE_LEN
2917 + u16::RAW_BYTE_LEN
2918 + Offset16::RAW_BYTE_LEN
2919 + Offset16::RAW_BYTE_LEN);
2920 basic_table_impls!(impl_the_methods);
2921
2922 pub fn pos_format(&self) -> u16 {
2924 self.data.header().pos_format.get()
2925 }
2926
2927 pub fn mark_coverage_offset(&self) -> Offset16 {
2930 self.data.header().mark_coverage_offset.get()
2931 }
2932
2933 pub fn mark_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2935 let data = self.offset_data();
2936 self.mark_coverage_offset().resolve(data)
2937 }
2938
2939 pub fn ligature_coverage_offset(&self) -> Offset16 {
2942 self.data.header().ligature_coverage_offset.get()
2943 }
2944
2945 pub fn ligature_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2947 let data = self.offset_data();
2948 self.ligature_coverage_offset().resolve(data)
2949 }
2950
2951 pub fn mark_class_count(&self) -> u16 {
2953 self.data.header().mark_class_count.get()
2954 }
2955
2956 pub fn mark_array_offset(&self) -> Offset16 {
2959 self.data.header().mark_array_offset.get()
2960 }
2961
2962 pub fn mark_array(&self) -> Result<MarkArray<'a>, ReadError> {
2964 let data = self.offset_data();
2965 self.mark_array_offset().resolve(data)
2966 }
2967
2968 pub fn ligature_array_offset(&self) -> Offset16 {
2971 self.data.header().ligature_array_offset.get()
2972 }
2973
2974 pub fn ligature_array(&self) -> Result<LigatureArray<'a>, ReadError> {
2976 let data = self.offset_data();
2977 let args = self.mark_class_count();
2978 self.ligature_array_offset().resolve_with_args(data, args)
2979 }
2980
2981 pub fn pos_format_byte_range(&self) -> Range<usize> {
2982 let start = 0;
2983 let end = start + u16::RAW_BYTE_LEN;
2984 start..end
2985 }
2986
2987 pub fn mark_coverage_offset_byte_range(&self) -> Range<usize> {
2988 let start = self.pos_format_byte_range().end;
2989 let end = start + Offset16::RAW_BYTE_LEN;
2990 start..end
2991 }
2992
2993 pub fn ligature_coverage_offset_byte_range(&self) -> Range<usize> {
2994 let start = self.mark_coverage_offset_byte_range().end;
2995 let end = start + Offset16::RAW_BYTE_LEN;
2996 start..end
2997 }
2998
2999 pub fn mark_class_count_byte_range(&self) -> Range<usize> {
3000 let start = self.ligature_coverage_offset_byte_range().end;
3001 let end = start + u16::RAW_BYTE_LEN;
3002 start..end
3003 }
3004
3005 pub fn mark_array_offset_byte_range(&self) -> Range<usize> {
3006 let start = self.mark_class_count_byte_range().end;
3007 let end = start + Offset16::RAW_BYTE_LEN;
3008 start..end
3009 }
3010
3011 pub fn ligature_array_offset_byte_range(&self) -> Range<usize> {
3012 let start = self.mark_array_offset_byte_range().end;
3013 let end = start + Offset16::RAW_BYTE_LEN;
3014 start..end
3015 }
3016}
3017
3018const _: () = assert!(FontData::default_data_long_enough(
3019 MarkLigPosFormat1::MIN_SIZE
3020));
3021
3022impl Default for MarkLigPosFormat1<'_> {
3023 fn default() -> Self {
3024 Self {
3025 data: TableDataRef::new(FontData::default_format_1_u16_table_data().as_bytes())
3026 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
3027 }
3028 }
3029}
3030
3031impl<'a> MinByteRange<'a> for LigatureArray<'a> {
3032 fn min_byte_range(&self) -> Range<usize> {
3033 0..self.ligature_attach_offsets_byte_range().end
3034 }
3035 fn min_table_bytes(&self) -> &'a [u8] {
3036 let range = self.min_byte_range();
3037 self.offset_data().as_bytes().get(range).unwrap_or_default()
3038 }
3039}
3040
3041impl ReadArgs for LigatureArray<'_> {
3042 type Args = u16;
3043}
3044
3045impl<'a> FontRead<'a> for LigatureArray<'a> {
3046 fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
3047 let mark_class_count = args;
3048
3049 #[allow(clippy::absurd_extreme_comparisons)]
3050 if data.len() < Self::MIN_SIZE {
3051 return Err(ReadError::OutOfBounds);
3052 }
3053 let Some(data) = TableDataRef::new(data.as_bytes()) else {
3054 return Err(ReadError::OutOfBounds);
3055 };
3056 Ok(Self {
3057 data,
3058 mark_class_count,
3059 })
3060 }
3061}
3062
3063impl<'a> LigatureArray<'a> {
3064 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
3069 let args = mark_class_count;
3070 Self::read_with_args(data, args)
3071 }
3072}
3073
3074#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
3076#[repr(C, packed)]
3077#[doc(hidden)]
3078pub struct LigatureArrayFixedHeader {
3079 pub ligature_count: BigEndian<u16>,
3080}
3081
3082#[allow(clippy::absurd_extreme_comparisons)]
3083const _: () = assert!(std::mem::size_of::<LigatureArrayFixedHeader>() <= LigatureArray::MIN_SIZE);
3084
3085#[derive(Clone)]
3087pub struct LigatureArray<'a> {
3088 data: TableDataRef<'a, LigatureArrayFixedHeader>,
3089 mark_class_count: u16,
3090}
3091
3092#[allow(clippy::needless_lifetimes)]
3093impl<'a> LigatureArray<'a> {
3094 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
3095 basic_table_impls!(impl_the_methods);
3096
3097 pub fn ligature_count(&self) -> u16 {
3099 self.data.header().ligature_count.get()
3100 }
3101
3102 pub fn ligature_attach_offsets(&self) -> &'a [BigEndian<Offset16>] {
3106 let range = self.ligature_attach_offsets_byte_range();
3107 self.offset_data()
3108 .read_array(range)
3109 .ok()
3110 .unwrap_or_default()
3111 }
3112
3113 pub fn ligature_attaches(&self) -> ArrayOfOffsets<'a, LigatureAttach<'a>, Offset16> {
3115 let data = self.offset_data();
3116 let offsets = self.ligature_attach_offsets();
3117 let args = self.mark_class_count();
3118 ArrayOfOffsets::new(offsets, data, args)
3119 }
3120
3121 pub(crate) fn mark_class_count(&self) -> u16 {
3122 self.mark_class_count
3123 }
3124
3125 pub fn ligature_count_byte_range(&self) -> Range<usize> {
3126 let start = 0;
3127 let end = start + u16::RAW_BYTE_LEN;
3128 start..end
3129 }
3130
3131 pub fn ligature_attach_offsets_byte_range(&self) -> Range<usize> {
3132 let ligature_count = self.ligature_count();
3133 let start = self.ligature_count_byte_range().end;
3134 let end =
3135 start + (transforms::to_usize(ligature_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
3136 start..end
3137 }
3138}
3139
3140const _: () = assert!(FontData::default_data_long_enough(LigatureArray::MIN_SIZE));
3141
3142impl Default for LigatureArray<'_> {
3143 fn default() -> Self {
3144 Self {
3145 data: TableDataRef::new(FontData::default_table_data().as_bytes())
3146 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
3147 mark_class_count: Default::default(),
3148 }
3149 }
3150}
3151
3152impl<'a> MinByteRange<'a> for LigatureAttach<'a> {
3153 fn min_byte_range(&self) -> Range<usize> {
3154 0..self.component_records_byte_range().end
3155 }
3156 fn min_table_bytes(&self) -> &'a [u8] {
3157 let range = self.min_byte_range();
3158 self.offset_data().as_bytes().get(range).unwrap_or_default()
3159 }
3160}
3161
3162impl ReadArgs for LigatureAttach<'_> {
3163 type Args = u16;
3164}
3165
3166impl<'a> FontRead<'a> for LigatureAttach<'a> {
3167 fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
3168 let mark_class_count = args;
3169
3170 #[allow(clippy::absurd_extreme_comparisons)]
3171 if data.len() < Self::MIN_SIZE {
3172 return Err(ReadError::OutOfBounds);
3173 }
3174 let Some(data) = TableDataRef::new(data.as_bytes()) else {
3175 return Err(ReadError::OutOfBounds);
3176 };
3177 Ok(Self {
3178 data,
3179 mark_class_count,
3180 })
3181 }
3182}
3183
3184impl<'a> LigatureAttach<'a> {
3185 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
3190 let args = mark_class_count;
3191 Self::read_with_args(data, args)
3192 }
3193}
3194
3195#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
3197#[repr(C, packed)]
3198#[doc(hidden)]
3199pub struct LigatureAttachFixedHeader {
3200 pub component_count: BigEndian<u16>,
3201}
3202
3203#[allow(clippy::absurd_extreme_comparisons)]
3204const _: () = assert!(std::mem::size_of::<LigatureAttachFixedHeader>() <= LigatureAttach::MIN_SIZE);
3205
3206#[derive(Clone)]
3208pub struct LigatureAttach<'a> {
3209 data: TableDataRef<'a, LigatureAttachFixedHeader>,
3210 mark_class_count: u16,
3211}
3212
3213#[allow(clippy::needless_lifetimes)]
3214impl<'a> LigatureAttach<'a> {
3215 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
3216 basic_table_impls!(impl_the_methods);
3217
3218 pub fn component_count(&self) -> u16 {
3220 self.data.header().component_count.get()
3221 }
3222
3223 pub fn component_records(&self) -> ComputedArray<'a, ComponentRecord<'a>> {
3225 let range = self.component_records_byte_range();
3226 ComputedArray::new(self.offset_data(), range, self.mark_class_count()).unwrap_or_default()
3227 }
3228
3229 pub(crate) fn mark_class_count(&self) -> u16 {
3230 self.mark_class_count
3231 }
3232
3233 pub fn component_count_byte_range(&self) -> Range<usize> {
3234 let start = 0;
3235 let end = start + u16::RAW_BYTE_LEN;
3236 start..end
3237 }
3238
3239 pub fn component_records_byte_range(&self) -> Range<usize> {
3240 let component_count = self.component_count();
3241 let start = self.component_count_byte_range().end;
3242 let end = start
3243 + (transforms::to_usize(component_count)).saturating_mul(
3244 <ComponentRecord as ComputeSize>::compute_size(self.mark_class_count())
3245 .unwrap_or(0),
3246 );
3247 start..end
3248 }
3249}
3250
3251const _: () = assert!(FontData::default_data_long_enough(LigatureAttach::MIN_SIZE));
3252
3253impl Default for LigatureAttach<'_> {
3254 fn default() -> Self {
3255 Self {
3256 data: TableDataRef::new(FontData::default_table_data().as_bytes())
3257 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
3258 mark_class_count: Default::default(),
3259 }
3260 }
3261}
3262
3263#[derive(Clone, Debug)]
3265pub struct ComponentRecord<'a> {
3266 pub ligature_anchor_offsets: &'a [BigEndian<Nullable<Offset16>>],
3270}
3271
3272impl<'a> ComponentRecord<'a> {
3273 pub fn ligature_anchor_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
3277 self.ligature_anchor_offsets
3278 }
3279
3280 pub fn ligature_anchors(
3287 &self,
3288 data: FontData<'a>,
3289 ) -> ArrayOfNullableOffsets<'a, AnchorTable<'a>, Offset16> {
3290 let offsets = self.ligature_anchor_offsets();
3291 ArrayOfNullableOffsets::new(offsets, data, ())
3292 }
3293}
3294
3295impl ReadArgs for ComponentRecord<'_> {
3296 type Args = u16;
3297}
3298
3299impl ComputeSize for ComponentRecord<'_> {
3300 #[allow(clippy::needless_question_mark)]
3301 fn compute_size(args: u16) -> Result<usize, ReadError> {
3302 let mark_class_count = args;
3303 Ok((transforms::to_usize(mark_class_count)).saturating_mul(Offset16::RAW_BYTE_LEN))
3304 }
3305}
3306
3307impl<'a> FontRead<'a> for ComponentRecord<'a> {
3308 fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
3309 let mut cursor = data.cursor();
3310 let mark_class_count = args;
3311 Ok(Self {
3312 ligature_anchor_offsets: cursor.read_array(transforms::to_usize(mark_class_count))?,
3313 })
3314 }
3315}
3316
3317crate::impl_font_read_at!(ComponentRecord<'a>);
3318
3319#[allow(clippy::needless_lifetimes)]
3320impl<'a> ComponentRecord<'a> {
3321 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
3326 let args = mark_class_count;
3327 Self::read_with_args(data, args)
3328 }
3329}
3330
3331impl Format<u16> for MarkMarkPosFormat1<'_> {
3332 const FORMAT: u16 = 1;
3333}
3334
3335impl<'a> MinByteRange<'a> for MarkMarkPosFormat1<'a> {
3336 fn min_byte_range(&self) -> Range<usize> {
3337 0..self.mark2_array_offset_byte_range().end
3338 }
3339 fn min_table_bytes(&self) -> &'a [u8] {
3340 let range = self.min_byte_range();
3341 self.offset_data().as_bytes().get(range).unwrap_or_default()
3342 }
3343}
3344
3345impl ReadArgs for MarkMarkPosFormat1<'_> {
3346 type Args = ();
3347}
3348
3349impl<'a> FontRead<'a> for MarkMarkPosFormat1<'a> {
3350 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3351 #[allow(clippy::absurd_extreme_comparisons)]
3352 if data.len() < Self::MIN_SIZE {
3353 return Err(ReadError::OutOfBounds);
3354 }
3355 let Some(data) = TableDataRef::new(data.as_bytes()) else {
3356 return Err(ReadError::OutOfBounds);
3357 };
3358 Ok(Self { data })
3359 }
3360}
3361
3362#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
3364#[repr(C, packed)]
3365#[doc(hidden)]
3366pub struct MarkMarkPosFormat1FixedHeader {
3367 pub pos_format: BigEndian<u16>,
3368 pub mark1_coverage_offset: BigEndian<Offset16>,
3369 pub mark2_coverage_offset: BigEndian<Offset16>,
3370 pub mark_class_count: BigEndian<u16>,
3371 pub mark1_array_offset: BigEndian<Offset16>,
3372 pub mark2_array_offset: BigEndian<Offset16>,
3373}
3374
3375#[allow(clippy::absurd_extreme_comparisons)]
3376const _: () =
3377 assert!(std::mem::size_of::<MarkMarkPosFormat1FixedHeader>() <= MarkMarkPosFormat1::MIN_SIZE);
3378
3379#[derive(Clone)]
3381pub struct MarkMarkPosFormat1<'a> {
3382 data: TableDataRef<'a, MarkMarkPosFormat1FixedHeader>,
3383}
3384
3385#[allow(clippy::needless_lifetimes)]
3386impl<'a> MarkMarkPosFormat1<'a> {
3387 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
3388 + Offset16::RAW_BYTE_LEN
3389 + Offset16::RAW_BYTE_LEN
3390 + u16::RAW_BYTE_LEN
3391 + Offset16::RAW_BYTE_LEN
3392 + Offset16::RAW_BYTE_LEN);
3393 basic_table_impls!(impl_the_methods);
3394
3395 pub fn pos_format(&self) -> u16 {
3397 self.data.header().pos_format.get()
3398 }
3399
3400 pub fn mark1_coverage_offset(&self) -> Offset16 {
3403 self.data.header().mark1_coverage_offset.get()
3404 }
3405
3406 pub fn mark1_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
3408 let data = self.offset_data();
3409 self.mark1_coverage_offset().resolve(data)
3410 }
3411
3412 pub fn mark2_coverage_offset(&self) -> Offset16 {
3415 self.data.header().mark2_coverage_offset.get()
3416 }
3417
3418 pub fn mark2_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
3420 let data = self.offset_data();
3421 self.mark2_coverage_offset().resolve(data)
3422 }
3423
3424 pub fn mark_class_count(&self) -> u16 {
3426 self.data.header().mark_class_count.get()
3427 }
3428
3429 pub fn mark1_array_offset(&self) -> Offset16 {
3432 self.data.header().mark1_array_offset.get()
3433 }
3434
3435 pub fn mark1_array(&self) -> Result<MarkArray<'a>, ReadError> {
3437 let data = self.offset_data();
3438 self.mark1_array_offset().resolve(data)
3439 }
3440
3441 pub fn mark2_array_offset(&self) -> Offset16 {
3444 self.data.header().mark2_array_offset.get()
3445 }
3446
3447 pub fn mark2_array(&self) -> Result<Mark2Array<'a>, ReadError> {
3449 let data = self.offset_data();
3450 let args = self.mark_class_count();
3451 self.mark2_array_offset().resolve_with_args(data, args)
3452 }
3453
3454 pub fn pos_format_byte_range(&self) -> Range<usize> {
3455 let start = 0;
3456 let end = start + u16::RAW_BYTE_LEN;
3457 start..end
3458 }
3459
3460 pub fn mark1_coverage_offset_byte_range(&self) -> Range<usize> {
3461 let start = self.pos_format_byte_range().end;
3462 let end = start + Offset16::RAW_BYTE_LEN;
3463 start..end
3464 }
3465
3466 pub fn mark2_coverage_offset_byte_range(&self) -> Range<usize> {
3467 let start = self.mark1_coverage_offset_byte_range().end;
3468 let end = start + Offset16::RAW_BYTE_LEN;
3469 start..end
3470 }
3471
3472 pub fn mark_class_count_byte_range(&self) -> Range<usize> {
3473 let start = self.mark2_coverage_offset_byte_range().end;
3474 let end = start + u16::RAW_BYTE_LEN;
3475 start..end
3476 }
3477
3478 pub fn mark1_array_offset_byte_range(&self) -> Range<usize> {
3479 let start = self.mark_class_count_byte_range().end;
3480 let end = start + Offset16::RAW_BYTE_LEN;
3481 start..end
3482 }
3483
3484 pub fn mark2_array_offset_byte_range(&self) -> Range<usize> {
3485 let start = self.mark1_array_offset_byte_range().end;
3486 let end = start + Offset16::RAW_BYTE_LEN;
3487 start..end
3488 }
3489}
3490
3491const _: () = assert!(FontData::default_data_long_enough(
3492 MarkMarkPosFormat1::MIN_SIZE
3493));
3494
3495impl Default for MarkMarkPosFormat1<'_> {
3496 fn default() -> Self {
3497 Self {
3498 data: TableDataRef::new(FontData::default_format_1_u16_table_data().as_bytes())
3499 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
3500 }
3501 }
3502}
3503
3504impl<'a> MinByteRange<'a> for Mark2Array<'a> {
3505 fn min_byte_range(&self) -> Range<usize> {
3506 0..self.mark2_records_byte_range().end
3507 }
3508 fn min_table_bytes(&self) -> &'a [u8] {
3509 let range = self.min_byte_range();
3510 self.offset_data().as_bytes().get(range).unwrap_or_default()
3511 }
3512}
3513
3514impl ReadArgs for Mark2Array<'_> {
3515 type Args = u16;
3516}
3517
3518impl<'a> FontRead<'a> for Mark2Array<'a> {
3519 fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
3520 let mark_class_count = args;
3521
3522 #[allow(clippy::absurd_extreme_comparisons)]
3523 if data.len() < Self::MIN_SIZE {
3524 return Err(ReadError::OutOfBounds);
3525 }
3526 let Some(data) = TableDataRef::new(data.as_bytes()) else {
3527 return Err(ReadError::OutOfBounds);
3528 };
3529 Ok(Self {
3530 data,
3531 mark_class_count,
3532 })
3533 }
3534}
3535
3536impl<'a> Mark2Array<'a> {
3537 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
3542 let args = mark_class_count;
3543 Self::read_with_args(data, args)
3544 }
3545}
3546
3547#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
3549#[repr(C, packed)]
3550#[doc(hidden)]
3551pub struct Mark2ArrayFixedHeader {
3552 pub mark2_count: BigEndian<u16>,
3553}
3554
3555#[allow(clippy::absurd_extreme_comparisons)]
3556const _: () = assert!(std::mem::size_of::<Mark2ArrayFixedHeader>() <= Mark2Array::MIN_SIZE);
3557
3558#[derive(Clone)]
3560pub struct Mark2Array<'a> {
3561 data: TableDataRef<'a, Mark2ArrayFixedHeader>,
3562 mark_class_count: u16,
3563}
3564
3565#[allow(clippy::needless_lifetimes)]
3566impl<'a> Mark2Array<'a> {
3567 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
3568 basic_table_impls!(impl_the_methods);
3569
3570 pub fn mark2_count(&self) -> u16 {
3572 self.data.header().mark2_count.get()
3573 }
3574
3575 pub fn mark2_records(&self) -> ComputedArray<'a, Mark2Record<'a>> {
3577 let range = self.mark2_records_byte_range();
3578 ComputedArray::new(self.offset_data(), range, self.mark_class_count()).unwrap_or_default()
3579 }
3580
3581 pub(crate) fn mark_class_count(&self) -> u16 {
3582 self.mark_class_count
3583 }
3584
3585 pub fn mark2_count_byte_range(&self) -> Range<usize> {
3586 let start = 0;
3587 let end = start + u16::RAW_BYTE_LEN;
3588 start..end
3589 }
3590
3591 pub fn mark2_records_byte_range(&self) -> Range<usize> {
3592 let mark2_count = self.mark2_count();
3593 let start = self.mark2_count_byte_range().end;
3594 let end = start
3595 + (transforms::to_usize(mark2_count)).saturating_mul(
3596 <Mark2Record as ComputeSize>::compute_size(self.mark_class_count()).unwrap_or(0),
3597 );
3598 start..end
3599 }
3600}
3601
3602const _: () = assert!(FontData::default_data_long_enough(Mark2Array::MIN_SIZE));
3603
3604impl Default for Mark2Array<'_> {
3605 fn default() -> Self {
3606 Self {
3607 data: TableDataRef::new(FontData::default_table_data().as_bytes())
3608 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
3609 mark_class_count: Default::default(),
3610 }
3611 }
3612}
3613
3614#[derive(Clone, Debug)]
3616pub struct Mark2Record<'a> {
3617 pub mark2_anchor_offsets: &'a [BigEndian<Nullable<Offset16>>],
3621}
3622
3623impl<'a> Mark2Record<'a> {
3624 pub fn mark2_anchor_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
3628 self.mark2_anchor_offsets
3629 }
3630
3631 pub fn mark2_anchors(
3638 &self,
3639 data: FontData<'a>,
3640 ) -> ArrayOfNullableOffsets<'a, AnchorTable<'a>, Offset16> {
3641 let offsets = self.mark2_anchor_offsets();
3642 ArrayOfNullableOffsets::new(offsets, data, ())
3643 }
3644}
3645
3646impl ReadArgs for Mark2Record<'_> {
3647 type Args = u16;
3648}
3649
3650impl ComputeSize for Mark2Record<'_> {
3651 #[allow(clippy::needless_question_mark)]
3652 fn compute_size(args: u16) -> Result<usize, ReadError> {
3653 let mark_class_count = args;
3654 Ok((transforms::to_usize(mark_class_count)).saturating_mul(Offset16::RAW_BYTE_LEN))
3655 }
3656}
3657
3658impl<'a> FontRead<'a> for Mark2Record<'a> {
3659 fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
3660 let mut cursor = data.cursor();
3661 let mark_class_count = args;
3662 Ok(Self {
3663 mark2_anchor_offsets: cursor.read_array(transforms::to_usize(mark_class_count))?,
3664 })
3665 }
3666}
3667
3668crate::impl_font_read_at!(Mark2Record<'a>);
3669
3670#[allow(clippy::needless_lifetimes)]
3671impl<'a> Mark2Record<'a> {
3672 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
3677 let args = mark_class_count;
3678 Self::read_with_args(data, args)
3679 }
3680}
3681
3682impl Format<u16> for ExtensionPosFormat1<'_> {
3683 const FORMAT: u16 = 1;
3684}
3685
3686impl Discriminant for ExtensionPosFormat1<'_, ()> {
3687 fn read_discriminant(data: FontData<'_>) -> Result<u16, ReadError> {
3688 data.read_at(u16::RAW_BYTE_LEN)
3689 }
3690}
3691
3692impl<'a, T> MinByteRange<'a> for ExtensionPosFormat1<'a, T> {
3693 fn min_byte_range(&self) -> Range<usize> {
3694 0..self.extension_offset_byte_range().end
3695 }
3696 fn min_table_bytes(&self) -> &'a [u8] {
3697 let range = self.min_byte_range();
3698 self.offset_data().as_bytes().get(range).unwrap_or_default()
3699 }
3700}
3701
3702impl<T> ReadArgs for ExtensionPosFormat1<'_, T> {
3703 type Args = ();
3704}
3705
3706impl<'a, T> FontRead<'a> for ExtensionPosFormat1<'a, T> {
3707 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3708 #[allow(clippy::absurd_extreme_comparisons)]
3709 if data.len() < Self::MIN_SIZE {
3710 return Err(ReadError::OutOfBounds);
3711 }
3712 let Some(data) = TableDataRef::new(data.as_bytes()) else {
3713 return Err(ReadError::OutOfBounds);
3714 };
3715 Ok(Self {
3716 data,
3717 offset_type: std::marker::PhantomData,
3718 })
3719 }
3720}
3721
3722impl<'a, T> ExtensionPosFormat1<'a, T> {
3723 #[allow(dead_code)]
3724 pub(crate) fn of_unit_type(&self) -> ExtensionPosFormat1<'a, ()> {
3726 ExtensionPosFormat1 {
3727 data: self.data,
3728 offset_type: std::marker::PhantomData,
3729 }
3730 }
3731}
3732
3733#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
3735#[repr(C, packed)]
3736#[doc(hidden)]
3737pub struct ExtensionPosFormat1FixedHeader {
3738 pub pos_format: BigEndian<u16>,
3739 pub extension_lookup_type: BigEndian<u16>,
3740 pub extension_offset: BigEndian<Offset32>,
3741}
3742
3743#[allow(clippy::absurd_extreme_comparisons)]
3744const _: () = assert!(
3745 std::mem::size_of::<ExtensionPosFormat1FixedHeader>() <= ExtensionPosFormat1::<()>::MIN_SIZE
3746);
3747
3748#[derive(Clone)]
3750pub struct ExtensionPosFormat1<'a, T = ()> {
3751 data: TableDataRef<'a, ExtensionPosFormat1FixedHeader>,
3752 offset_type: std::marker::PhantomData<*const T>,
3753}
3754
3755#[allow(clippy::needless_lifetimes)]
3756impl<'a, T> ExtensionPosFormat1<'a, T> {
3757 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN);
3758 basic_table_impls!(impl_the_methods);
3759
3760 pub fn pos_format(&self) -> u16 {
3762 self.data.header().pos_format.get()
3763 }
3764
3765 pub fn extension_lookup_type(&self) -> u16 {
3768 self.data.header().extension_lookup_type.get()
3769 }
3770
3771 pub fn extension_offset(&self) -> Offset32 {
3775 self.data.header().extension_offset.get()
3776 }
3777
3778 pub fn extension(&self) -> Result<T, ReadError>
3780 where
3781 T: FontRead<'a, Args = ()>,
3782 {
3783 let data = self.offset_data();
3784 self.extension_offset().resolve(data)
3785 }
3786
3787 pub fn pos_format_byte_range(&self) -> Range<usize> {
3788 let start = 0;
3789 let end = start + u16::RAW_BYTE_LEN;
3790 start..end
3791 }
3792
3793 pub fn extension_lookup_type_byte_range(&self) -> Range<usize> {
3794 let start = self.pos_format_byte_range().end;
3795 let end = start + u16::RAW_BYTE_LEN;
3796 start..end
3797 }
3798
3799 pub fn extension_offset_byte_range(&self) -> Range<usize> {
3800 let start = self.extension_lookup_type_byte_range().end;
3801 let end = start + Offset32::RAW_BYTE_LEN;
3802 start..end
3803 }
3804}
3805
3806const _: () = assert!(FontData::default_data_long_enough(
3807 ExtensionPosFormat1::<()>::MIN_SIZE
3808));
3809
3810impl<T> Default for ExtensionPosFormat1<'_, T> {
3811 fn default() -> Self {
3812 Self {
3813 data: TableDataRef::new(FontData::default_format_1_u16_table_data().as_bytes())
3814 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
3815 offset_type: std::marker::PhantomData,
3816 }
3817 }
3818}
3819
3820pub enum ExtensionSubtable<'a> {
3822 Single(ExtensionPosFormat1<'a, SinglePos<'a>>),
3823 Pair(ExtensionPosFormat1<'a, PairPos<'a>>),
3824 Cursive(ExtensionPosFormat1<'a, CursivePos<'a>>),
3825 MarkToBase(ExtensionPosFormat1<'a, MarkBasePos<'a>>),
3826 MarkToLig(ExtensionPosFormat1<'a, MarkLigPos<'a>>),
3827 MarkToMark(ExtensionPosFormat1<'a, MarkMarkPos<'a>>),
3828 Contextual(ExtensionPosFormat1<'a, PositionSequenceContext<'a>>),
3829 ChainContextual(ExtensionPosFormat1<'a, PositionChainContext<'a>>),
3830}
3831
3832impl Default for ExtensionSubtable<'_> {
3833 fn default() -> Self {
3834 Self::Single(Default::default())
3835 }
3836}
3837
3838impl ReadArgs for ExtensionSubtable<'_> {
3839 type Args = ();
3840}
3841
3842impl<'a> FontRead<'a> for ExtensionSubtable<'a> {
3843 fn read_with_args(bytes: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3844 let discriminant = ExtensionPosFormat1::read_discriminant(bytes)?;
3845 match discriminant {
3846 1 => Ok(ExtensionSubtable::Single(FontRead::read(bytes)?)),
3847 2 => Ok(ExtensionSubtable::Pair(FontRead::read(bytes)?)),
3848 3 => Ok(ExtensionSubtable::Cursive(FontRead::read(bytes)?)),
3849 4 => Ok(ExtensionSubtable::MarkToBase(FontRead::read(bytes)?)),
3850 5 => Ok(ExtensionSubtable::MarkToLig(FontRead::read(bytes)?)),
3851 6 => Ok(ExtensionSubtable::MarkToMark(FontRead::read(bytes)?)),
3852 7 => Ok(ExtensionSubtable::Contextual(FontRead::read(bytes)?)),
3853 8 => Ok(ExtensionSubtable::ChainContextual(FontRead::read(bytes)?)),
3854 other => Err(ReadError::InvalidFormat(other.into())),
3855 }
3856 }
3857}
3858
3859impl<'a> ExtensionSubtable<'a> {
3860 #[allow(dead_code)]
3861 pub(crate) fn of_unit_type(&self) -> ExtensionPosFormat1<'a, ()> {
3865 match self {
3866 ExtensionSubtable::Single(inner) => inner.of_unit_type(),
3867 ExtensionSubtable::Pair(inner) => inner.of_unit_type(),
3868 ExtensionSubtable::Cursive(inner) => inner.of_unit_type(),
3869 ExtensionSubtable::MarkToBase(inner) => inner.of_unit_type(),
3870 ExtensionSubtable::MarkToLig(inner) => inner.of_unit_type(),
3871 ExtensionSubtable::MarkToMark(inner) => inner.of_unit_type(),
3872 ExtensionSubtable::Contextual(inner) => inner.of_unit_type(),
3873 ExtensionSubtable::ChainContextual(inner) => inner.of_unit_type(),
3874 }
3875 }
3876}
3877
3878impl Format<u16> for SinglePosFormat3<'_> {
3879 const FORMAT: u16 = 3;
3880}
3881
3882impl<'a> MinByteRange<'a> for SinglePosFormat3<'a> {
3883 fn min_byte_range(&self) -> Range<usize> {
3884 0..self.value_record_byte_range().end
3885 }
3886 fn min_table_bytes(&self) -> &'a [u8] {
3887 let range = self.min_byte_range();
3888 self.offset_data().as_bytes().get(range).unwrap_or_default()
3889 }
3890}
3891
3892impl ReadArgs for SinglePosFormat3<'_> {
3893 type Args = ();
3894}
3895
3896impl<'a> FontRead<'a> for SinglePosFormat3<'a> {
3897 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3898 #[allow(clippy::absurd_extreme_comparisons)]
3899 if data.len() < Self::MIN_SIZE {
3900 return Err(ReadError::OutOfBounds);
3901 }
3902 let Some(data) = TableDataRef::new(data.as_bytes()) else {
3903 return Err(ReadError::OutOfBounds);
3904 };
3905 Ok(Self { data })
3906 }
3907}
3908
3909#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
3911#[repr(C, packed)]
3912#[doc(hidden)]
3913pub struct SinglePosFormat3FixedHeader {
3914 pub pos_format: BigEndian<u16>,
3915 pub coverage_offset: BigEndian<Offset32>,
3916 pub value_format: BigEndian<ValueFormat>,
3917}
3918
3919#[allow(clippy::absurd_extreme_comparisons)]
3920const _: () =
3921 assert!(std::mem::size_of::<SinglePosFormat3FixedHeader>() <= SinglePosFormat3::MIN_SIZE);
3922
3923#[derive(Clone)]
3925pub struct SinglePosFormat3<'a> {
3926 data: TableDataRef<'a, SinglePosFormat3FixedHeader>,
3927}
3928
3929#[allow(clippy::needless_lifetimes)]
3930impl<'a> SinglePosFormat3<'a> {
3931 pub const MIN_SIZE: usize =
3932 (u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN + ValueFormat::RAW_BYTE_LEN);
3933 basic_table_impls!(impl_the_methods);
3934
3935 pub fn pos_format(&self) -> u16 {
3937 self.data.header().pos_format.get()
3938 }
3939
3940 pub fn coverage_offset(&self) -> Offset32 {
3942 self.data.header().coverage_offset.get()
3943 }
3944
3945 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
3947 let data = self.offset_data();
3948 self.coverage_offset().resolve(data)
3949 }
3950
3951 pub fn value_format(&self) -> ValueFormat {
3953 self.data.header().value_format.get()
3954 }
3955
3956 pub fn value_record(&self) -> ValueRecord<'a> {
3959 let range = self.value_record_byte_range();
3960 ValueRecord::read_at(self.offset_data(), range.start, self.value_format())
3961 .unwrap_or_default()
3962 }
3963
3964 pub fn pos_format_byte_range(&self) -> Range<usize> {
3965 let start = 0;
3966 let end = start + u16::RAW_BYTE_LEN;
3967 start..end
3968 }
3969
3970 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
3971 let start = self.pos_format_byte_range().end;
3972 let end = start + Offset32::RAW_BYTE_LEN;
3973 start..end
3974 }
3975
3976 pub fn value_format_byte_range(&self) -> Range<usize> {
3977 let start = self.coverage_offset_byte_range().end;
3978 let end = start + ValueFormat::RAW_BYTE_LEN;
3979 start..end
3980 }
3981
3982 pub fn value_record_byte_range(&self) -> Range<usize> {
3983 let start = self.value_format_byte_range().end;
3984 let end =
3985 start + <ValueRecord as ComputeSize>::compute_size(self.value_format()).unwrap_or(0);
3986 start..end
3987 }
3988}
3989
3990impl Format<u16> for SinglePosFormat4<'_> {
3991 const FORMAT: u16 = 4;
3992}
3993
3994impl<'a> MinByteRange<'a> for SinglePosFormat4<'a> {
3995 fn min_byte_range(&self) -> Range<usize> {
3996 0..self.value_records_byte_range().end
3997 }
3998 fn min_table_bytes(&self) -> &'a [u8] {
3999 let range = self.min_byte_range();
4000 self.offset_data().as_bytes().get(range).unwrap_or_default()
4001 }
4002}
4003
4004impl ReadArgs for SinglePosFormat4<'_> {
4005 type Args = ();
4006}
4007
4008impl<'a> FontRead<'a> for SinglePosFormat4<'a> {
4009 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
4010 #[allow(clippy::absurd_extreme_comparisons)]
4011 if data.len() < Self::MIN_SIZE {
4012 return Err(ReadError::OutOfBounds);
4013 }
4014 let Some(data) = TableDataRef::new(data.as_bytes()) else {
4015 return Err(ReadError::OutOfBounds);
4016 };
4017 Ok(Self { data })
4018 }
4019}
4020
4021#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
4023#[repr(C, packed)]
4024#[doc(hidden)]
4025pub struct SinglePosFormat4FixedHeader {
4026 pub pos_format: BigEndian<u16>,
4027 pub coverage_offset: BigEndian<Offset32>,
4028 pub value_format: BigEndian<ValueFormat>,
4029 pub value_count: BigEndian<Uint24>,
4030}
4031
4032#[allow(clippy::absurd_extreme_comparisons)]
4033const _: () =
4034 assert!(std::mem::size_of::<SinglePosFormat4FixedHeader>() <= SinglePosFormat4::MIN_SIZE);
4035
4036#[derive(Clone)]
4038pub struct SinglePosFormat4<'a> {
4039 data: TableDataRef<'a, SinglePosFormat4FixedHeader>,
4040}
4041
4042#[allow(clippy::needless_lifetimes)]
4043impl<'a> SinglePosFormat4<'a> {
4044 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
4045 + Offset32::RAW_BYTE_LEN
4046 + ValueFormat::RAW_BYTE_LEN
4047 + Uint24::RAW_BYTE_LEN);
4048 basic_table_impls!(impl_the_methods);
4049
4050 pub fn pos_format(&self) -> u16 {
4052 self.data.header().pos_format.get()
4053 }
4054
4055 pub fn coverage_offset(&self) -> Offset32 {
4057 self.data.header().coverage_offset.get()
4058 }
4059
4060 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
4062 let data = self.offset_data();
4063 self.coverage_offset().resolve(data)
4064 }
4065
4066 pub fn value_format(&self) -> ValueFormat {
4068 self.data.header().value_format.get()
4069 }
4070
4071 pub fn value_count(&self) -> Uint24 {
4074 self.data.header().value_count.get()
4075 }
4076
4077 pub fn value_records(&self) -> ComputedArray<'a, ValueRecord<'a>> {
4079 let range = self.value_records_byte_range();
4080 ComputedArray::new(self.offset_data(), range, self.value_format()).unwrap_or_default()
4081 }
4082
4083 pub fn pos_format_byte_range(&self) -> Range<usize> {
4084 let start = 0;
4085 let end = start + u16::RAW_BYTE_LEN;
4086 start..end
4087 }
4088
4089 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
4090 let start = self.pos_format_byte_range().end;
4091 let end = start + Offset32::RAW_BYTE_LEN;
4092 start..end
4093 }
4094
4095 pub fn value_format_byte_range(&self) -> Range<usize> {
4096 let start = self.coverage_offset_byte_range().end;
4097 let end = start + ValueFormat::RAW_BYTE_LEN;
4098 start..end
4099 }
4100
4101 pub fn value_count_byte_range(&self) -> Range<usize> {
4102 let start = self.value_format_byte_range().end;
4103 let end = start + Uint24::RAW_BYTE_LEN;
4104 start..end
4105 }
4106
4107 pub fn value_records_byte_range(&self) -> Range<usize> {
4108 let value_count = self.value_count();
4109 let start = self.value_count_byte_range().end;
4110 let end = start
4111 + (transforms::to_usize(value_count)).saturating_mul(
4112 <ValueRecord as ComputeSize>::compute_size(self.value_format()).unwrap_or(0),
4113 );
4114 start..end
4115 }
4116}
4117
4118impl Format<u16> for PairPosFormat3<'_> {
4119 const FORMAT: u16 = 3;
4120}
4121
4122impl<'a> MinByteRange<'a> for PairPosFormat3<'a> {
4123 fn min_byte_range(&self) -> Range<usize> {
4124 0..self.pair_set_offsets_byte_range().end
4125 }
4126 fn min_table_bytes(&self) -> &'a [u8] {
4127 let range = self.min_byte_range();
4128 self.offset_data().as_bytes().get(range).unwrap_or_default()
4129 }
4130}
4131
4132impl ReadArgs for PairPosFormat3<'_> {
4133 type Args = ();
4134}
4135
4136impl<'a> FontRead<'a> for PairPosFormat3<'a> {
4137 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
4138 #[allow(clippy::absurd_extreme_comparisons)]
4139 if data.len() < Self::MIN_SIZE {
4140 return Err(ReadError::OutOfBounds);
4141 }
4142 let Some(data) = TableDataRef::new(data.as_bytes()) else {
4143 return Err(ReadError::OutOfBounds);
4144 };
4145 Ok(Self { data })
4146 }
4147}
4148
4149#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
4151#[repr(C, packed)]
4152#[doc(hidden)]
4153pub struct PairPosFormat3FixedHeader {
4154 pub pos_format: BigEndian<u16>,
4155 pub coverage_offset: BigEndian<Offset32>,
4156 pub value_format1: BigEndian<ValueFormat>,
4157 pub value_format2: BigEndian<ValueFormat>,
4158 pub pair_set_count: BigEndian<Uint24>,
4159}
4160
4161#[allow(clippy::absurd_extreme_comparisons)]
4162const _: () = assert!(std::mem::size_of::<PairPosFormat3FixedHeader>() <= PairPosFormat3::MIN_SIZE);
4163
4164#[derive(Clone)]
4166pub struct PairPosFormat3<'a> {
4167 data: TableDataRef<'a, PairPosFormat3FixedHeader>,
4168}
4169
4170#[allow(clippy::needless_lifetimes)]
4171impl<'a> PairPosFormat3<'a> {
4172 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
4173 + Offset32::RAW_BYTE_LEN
4174 + ValueFormat::RAW_BYTE_LEN
4175 + ValueFormat::RAW_BYTE_LEN
4176 + Uint24::RAW_BYTE_LEN);
4177 basic_table_impls!(impl_the_methods);
4178
4179 pub fn pos_format(&self) -> u16 {
4181 self.data.header().pos_format.get()
4182 }
4183
4184 pub fn coverage_offset(&self) -> Offset32 {
4186 self.data.header().coverage_offset.get()
4187 }
4188
4189 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
4191 let data = self.offset_data();
4192 self.coverage_offset().resolve(data)
4193 }
4194
4195 pub fn value_format1(&self) -> ValueFormat {
4198 self.data.header().value_format1.get()
4199 }
4200
4201 pub fn value_format2(&self) -> ValueFormat {
4204 self.data.header().value_format2.get()
4205 }
4206
4207 pub fn pair_set_count(&self) -> Uint24 {
4209 self.data.header().pair_set_count.get()
4210 }
4211
4212 pub fn pair_set_offsets(&self) -> &'a [BigEndian<Offset24>] {
4215 let range = self.pair_set_offsets_byte_range();
4216 self.offset_data()
4217 .read_array(range)
4218 .ok()
4219 .unwrap_or_default()
4220 }
4221
4222 pub fn pair_sets(&self) -> ArrayOfOffsets<'a, PairSet2<'a>, Offset24> {
4224 let data = self.offset_data();
4225 let offsets = self.pair_set_offsets();
4226 let args = (self.value_format1(), self.value_format2());
4227 ArrayOfOffsets::new(offsets, data, args)
4228 }
4229
4230 pub fn pos_format_byte_range(&self) -> Range<usize> {
4231 let start = 0;
4232 let end = start + u16::RAW_BYTE_LEN;
4233 start..end
4234 }
4235
4236 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
4237 let start = self.pos_format_byte_range().end;
4238 let end = start + Offset32::RAW_BYTE_LEN;
4239 start..end
4240 }
4241
4242 pub fn value_format1_byte_range(&self) -> Range<usize> {
4243 let start = self.coverage_offset_byte_range().end;
4244 let end = start + ValueFormat::RAW_BYTE_LEN;
4245 start..end
4246 }
4247
4248 pub fn value_format2_byte_range(&self) -> Range<usize> {
4249 let start = self.value_format1_byte_range().end;
4250 let end = start + ValueFormat::RAW_BYTE_LEN;
4251 start..end
4252 }
4253
4254 pub fn pair_set_count_byte_range(&self) -> Range<usize> {
4255 let start = self.value_format2_byte_range().end;
4256 let end = start + Uint24::RAW_BYTE_LEN;
4257 start..end
4258 }
4259
4260 pub fn pair_set_offsets_byte_range(&self) -> Range<usize> {
4261 let pair_set_count = self.pair_set_count();
4262 let start = self.pair_set_count_byte_range().end;
4263 let end =
4264 start + (transforms::to_usize(pair_set_count)).saturating_mul(Offset24::RAW_BYTE_LEN);
4265 start..end
4266 }
4267}
4268
4269impl<'a> MinByteRange<'a> for PairSet2<'a> {
4270 fn min_byte_range(&self) -> Range<usize> {
4271 0..self.pair_value_records_byte_range().end
4272 }
4273 fn min_table_bytes(&self) -> &'a [u8] {
4274 let range = self.min_byte_range();
4275 self.offset_data().as_bytes().get(range).unwrap_or_default()
4276 }
4277}
4278
4279impl ReadArgs for PairSet2<'_> {
4280 type Args = (ValueFormat, ValueFormat);
4281}
4282
4283impl<'a> FontRead<'a> for PairSet2<'a> {
4284 fn read_with_args(
4285 data: FontData<'a>,
4286 args: (ValueFormat, ValueFormat),
4287 ) -> Result<Self, ReadError> {
4288 let (value_format1, value_format2) = args;
4289
4290 #[allow(clippy::absurd_extreme_comparisons)]
4291 if data.len() < Self::MIN_SIZE {
4292 return Err(ReadError::OutOfBounds);
4293 }
4294 let Some(data) = TableDataRef::new(data.as_bytes()) else {
4295 return Err(ReadError::OutOfBounds);
4296 };
4297 Ok(Self {
4298 data,
4299 value_format1,
4300 value_format2,
4301 })
4302 }
4303}
4304
4305impl<'a> PairSet2<'a> {
4306 pub fn read(
4311 data: FontData<'a>,
4312 value_format1: ValueFormat,
4313 value_format2: ValueFormat,
4314 ) -> Result<Self, ReadError> {
4315 let args = (value_format1, value_format2);
4316 Self::read_with_args(data, args)
4317 }
4318}
4319
4320#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
4322#[repr(C, packed)]
4323#[doc(hidden)]
4324pub struct PairSet2FixedHeader {
4325 pub pair_value_count: BigEndian<Uint24>,
4326}
4327
4328#[allow(clippy::absurd_extreme_comparisons)]
4329const _: () = assert!(std::mem::size_of::<PairSet2FixedHeader>() <= PairSet2::MIN_SIZE);
4330
4331#[derive(Clone)]
4333pub struct PairSet2<'a> {
4334 data: TableDataRef<'a, PairSet2FixedHeader>,
4335 value_format1: ValueFormat,
4336 value_format2: ValueFormat,
4337}
4338
4339#[allow(clippy::needless_lifetimes)]
4340impl<'a> PairSet2<'a> {
4341 pub const MIN_SIZE: usize = Uint24::RAW_BYTE_LEN;
4342 basic_table_impls!(impl_the_methods);
4343
4344 pub fn pair_value_count(&self) -> Uint24 {
4346 self.data.header().pair_value_count.get()
4347 }
4348
4349 pub fn pair_value_records(&self) -> ComputedArray<'a, PairValueRecord2<'a>> {
4352 let range = self.pair_value_records_byte_range();
4353 ComputedArray::new(
4354 self.offset_data(),
4355 range,
4356 (self.value_format1(), self.value_format2()),
4357 )
4358 .unwrap_or_default()
4359 }
4360
4361 pub(crate) fn value_format1(&self) -> ValueFormat {
4362 self.value_format1
4363 }
4364
4365 pub(crate) fn value_format2(&self) -> ValueFormat {
4366 self.value_format2
4367 }
4368
4369 pub fn pair_value_count_byte_range(&self) -> Range<usize> {
4370 let start = 0;
4371 let end = start + Uint24::RAW_BYTE_LEN;
4372 start..end
4373 }
4374
4375 pub fn pair_value_records_byte_range(&self) -> Range<usize> {
4376 let pair_value_count = self.pair_value_count();
4377 let start = self.pair_value_count_byte_range().end;
4378 let end = start
4379 + (transforms::to_usize(pair_value_count)).saturating_mul(
4380 <PairValueRecord2 as ComputeSize>::compute_size((
4381 self.value_format1(),
4382 self.value_format2(),
4383 ))
4384 .unwrap_or(0),
4385 );
4386 start..end
4387 }
4388}
4389
4390const _: () = assert!(FontData::default_data_long_enough(PairSet2::MIN_SIZE));
4391
4392impl Default for PairSet2<'_> {
4393 fn default() -> Self {
4394 Self {
4395 data: TableDataRef::new(FontData::default_table_data().as_bytes())
4396 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
4397 value_format1: Default::default(),
4398 value_format2: Default::default(),
4399 }
4400 }
4401}
4402
4403#[derive(Clone, Debug)]
4405pub struct PairValueRecord2<'a> {
4406 pub second_glyph: BigEndian<GlyphId24>,
4409 pub value_record1: ValueRecord<'a>,
4411 pub value_record2: ValueRecord<'a>,
4413}
4414
4415impl<'a> PairValueRecord2<'a> {
4416 pub fn second_glyph(&self) -> GlyphId24 {
4419 self.second_glyph.get()
4420 }
4421
4422 pub fn value_record1(&self) -> &ValueRecord<'a> {
4424 &self.value_record1
4425 }
4426
4427 pub fn value_record2(&self) -> &ValueRecord<'a> {
4429 &self.value_record2
4430 }
4431}
4432
4433impl ReadArgs for PairValueRecord2<'_> {
4434 type Args = (ValueFormat, ValueFormat);
4435}
4436
4437impl ComputeSize for PairValueRecord2<'_> {
4438 #[allow(clippy::needless_question_mark)]
4439 fn compute_size(args: (ValueFormat, ValueFormat)) -> Result<usize, ReadError> {
4440 let (value_format1, value_format2) = args;
4441 let mut result = 0usize;
4442 result = result
4443 .checked_add(GlyphId24::RAW_BYTE_LEN)
4444 .ok_or(ReadError::OutOfBounds)?;
4445 result = result
4446 .checked_add(<ValueRecord as ComputeSize>::compute_size(value_format1).unwrap_or(0))
4447 .ok_or(ReadError::OutOfBounds)?;
4448 result = result
4449 .checked_add(<ValueRecord as ComputeSize>::compute_size(value_format2).unwrap_or(0))
4450 .ok_or(ReadError::OutOfBounds)?;
4451 Ok(result)
4452 }
4453}
4454
4455impl<'a> FontReadAt<'a> for PairValueRecord2<'a> {
4456 fn read_at(
4457 data: FontData<'a>,
4458 offset: usize,
4459 args: (ValueFormat, ValueFormat),
4460 ) -> Result<Self, ReadError> {
4461 let mut cursor = data.cursor();
4462 cursor.advance_by(offset);
4463 let (value_format1, value_format2) = args;
4464 Ok(Self {
4465 second_glyph: cursor.read_be()?,
4466 value_record1: cursor.read_at_with_args(value_format1)?,
4467 value_record2: cursor.read_at_with_args(value_format2)?,
4468 })
4469 }
4470}
4471
4472#[allow(clippy::needless_lifetimes)]
4473impl<'a> PairValueRecord2<'a> {
4474 pub fn read(
4479 data: FontData<'a>,
4480 offset: usize,
4481 value_format1: ValueFormat,
4482 value_format2: ValueFormat,
4483 ) -> Result<Self, ReadError> {
4484 let args = (value_format1, value_format2);
4485 Self::read_at(data, offset, args)
4486 }
4487}
4488
4489impl Format<u16> for PairPosFormat4<'_> {
4490 const FORMAT: u16 = 4;
4491}
4492
4493impl<'a> MinByteRange<'a> for PairPosFormat4<'a> {
4494 fn min_byte_range(&self) -> Range<usize> {
4495 0..self.class1_records_byte_range().end
4496 }
4497 fn min_table_bytes(&self) -> &'a [u8] {
4498 let range = self.min_byte_range();
4499 self.offset_data().as_bytes().get(range).unwrap_or_default()
4500 }
4501}
4502
4503impl ReadArgs for PairPosFormat4<'_> {
4504 type Args = ();
4505}
4506
4507impl<'a> FontRead<'a> for PairPosFormat4<'a> {
4508 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
4509 #[allow(clippy::absurd_extreme_comparisons)]
4510 if data.len() < Self::MIN_SIZE {
4511 return Err(ReadError::OutOfBounds);
4512 }
4513 let Some(data) = TableDataRef::new(data.as_bytes()) else {
4514 return Err(ReadError::OutOfBounds);
4515 };
4516 Ok(Self { data })
4517 }
4518}
4519
4520#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
4522#[repr(C, packed)]
4523#[doc(hidden)]
4524pub struct PairPosFormat4FixedHeader {
4525 pub pos_format: BigEndian<u16>,
4526 pub coverage_offset: BigEndian<Offset32>,
4527 pub value_format1: BigEndian<ValueFormat>,
4528 pub value_format2: BigEndian<ValueFormat>,
4529 pub class_def1_offset: BigEndian<Offset32>,
4530 pub class_def2_offset: BigEndian<Offset32>,
4531 pub class1_count: BigEndian<u16>,
4532 pub class2_count: BigEndian<u16>,
4533}
4534
4535#[allow(clippy::absurd_extreme_comparisons)]
4536const _: () = assert!(std::mem::size_of::<PairPosFormat4FixedHeader>() <= PairPosFormat4::MIN_SIZE);
4537
4538#[derive(Clone)]
4540pub struct PairPosFormat4<'a> {
4541 data: TableDataRef<'a, PairPosFormat4FixedHeader>,
4542}
4543
4544#[allow(clippy::needless_lifetimes)]
4545impl<'a> PairPosFormat4<'a> {
4546 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
4547 + Offset32::RAW_BYTE_LEN
4548 + ValueFormat::RAW_BYTE_LEN
4549 + ValueFormat::RAW_BYTE_LEN
4550 + Offset32::RAW_BYTE_LEN
4551 + Offset32::RAW_BYTE_LEN
4552 + u16::RAW_BYTE_LEN
4553 + u16::RAW_BYTE_LEN);
4554 basic_table_impls!(impl_the_methods);
4555
4556 pub fn pos_format(&self) -> u16 {
4558 self.data.header().pos_format.get()
4559 }
4560
4561 pub fn coverage_offset(&self) -> Offset32 {
4563 self.data.header().coverage_offset.get()
4564 }
4565
4566 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
4568 let data = self.offset_data();
4569 self.coverage_offset().resolve(data)
4570 }
4571
4572 pub fn value_format1(&self) -> ValueFormat {
4575 self.data.header().value_format1.get()
4576 }
4577
4578 pub fn value_format2(&self) -> ValueFormat {
4581 self.data.header().value_format2.get()
4582 }
4583
4584 pub fn class_def1_offset(&self) -> Offset32 {
4587 self.data.header().class_def1_offset.get()
4588 }
4589
4590 pub fn class_def1(&self) -> Result<ClassDef<'a>, ReadError> {
4592 let data = self.offset_data();
4593 self.class_def1_offset().resolve(data)
4594 }
4595
4596 pub fn class_def2_offset(&self) -> Offset32 {
4599 self.data.header().class_def2_offset.get()
4600 }
4601
4602 pub fn class_def2(&self) -> Result<ClassDef<'a>, ReadError> {
4604 let data = self.offset_data();
4605 self.class_def2_offset().resolve(data)
4606 }
4607
4608 pub fn class1_count(&self) -> u16 {
4610 self.data.header().class1_count.get()
4611 }
4612
4613 pub fn class2_count(&self) -> u16 {
4615 self.data.header().class2_count.get()
4616 }
4617
4618 pub fn class1_records(&self) -> ComputedArray<'a, Class1Record<'a>> {
4620 let range = self.class1_records_byte_range();
4621 ComputedArray::new(
4622 self.offset_data(),
4623 range,
4624 (
4625 self.class2_count(),
4626 self.value_format1(),
4627 self.value_format2(),
4628 ),
4629 )
4630 .unwrap_or_default()
4631 }
4632
4633 pub fn pos_format_byte_range(&self) -> Range<usize> {
4634 let start = 0;
4635 let end = start + u16::RAW_BYTE_LEN;
4636 start..end
4637 }
4638
4639 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
4640 let start = self.pos_format_byte_range().end;
4641 let end = start + Offset32::RAW_BYTE_LEN;
4642 start..end
4643 }
4644
4645 pub fn value_format1_byte_range(&self) -> Range<usize> {
4646 let start = self.coverage_offset_byte_range().end;
4647 let end = start + ValueFormat::RAW_BYTE_LEN;
4648 start..end
4649 }
4650
4651 pub fn value_format2_byte_range(&self) -> Range<usize> {
4652 let start = self.value_format1_byte_range().end;
4653 let end = start + ValueFormat::RAW_BYTE_LEN;
4654 start..end
4655 }
4656
4657 pub fn class_def1_offset_byte_range(&self) -> Range<usize> {
4658 let start = self.value_format2_byte_range().end;
4659 let end = start + Offset32::RAW_BYTE_LEN;
4660 start..end
4661 }
4662
4663 pub fn class_def2_offset_byte_range(&self) -> Range<usize> {
4664 let start = self.class_def1_offset_byte_range().end;
4665 let end = start + Offset32::RAW_BYTE_LEN;
4666 start..end
4667 }
4668
4669 pub fn class1_count_byte_range(&self) -> Range<usize> {
4670 let start = self.class_def2_offset_byte_range().end;
4671 let end = start + u16::RAW_BYTE_LEN;
4672 start..end
4673 }
4674
4675 pub fn class2_count_byte_range(&self) -> Range<usize> {
4676 let start = self.class1_count_byte_range().end;
4677 let end = start + u16::RAW_BYTE_LEN;
4678 start..end
4679 }
4680
4681 pub fn class1_records_byte_range(&self) -> Range<usize> {
4682 let class1_count = self.class1_count();
4683 let start = self.class2_count_byte_range().end;
4684 let end = start
4685 + (transforms::to_usize(class1_count)).saturating_mul(
4686 <Class1Record as ComputeSize>::compute_size((
4687 self.class2_count(),
4688 self.value_format1(),
4689 self.value_format2(),
4690 ))
4691 .unwrap_or(0),
4692 );
4693 start..end
4694 }
4695}
4696
4697impl Format<u16> for CursivePosFormat2<'_> {
4698 const FORMAT: u16 = 2;
4699}
4700
4701impl<'a> MinByteRange<'a> for CursivePosFormat2<'a> {
4702 fn min_byte_range(&self) -> Range<usize> {
4703 0..self.entry_exit_record_byte_range().end
4704 }
4705 fn min_table_bytes(&self) -> &'a [u8] {
4706 let range = self.min_byte_range();
4707 self.offset_data().as_bytes().get(range).unwrap_or_default()
4708 }
4709}
4710
4711impl ReadArgs for CursivePosFormat2<'_> {
4712 type Args = ();
4713}
4714
4715impl<'a> FontRead<'a> for CursivePosFormat2<'a> {
4716 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
4717 #[allow(clippy::absurd_extreme_comparisons)]
4718 if data.len() < Self::MIN_SIZE {
4719 return Err(ReadError::OutOfBounds);
4720 }
4721 let Some(data) = TableDataRef::new(data.as_bytes()) else {
4722 return Err(ReadError::OutOfBounds);
4723 };
4724 Ok(Self { data })
4725 }
4726}
4727
4728#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
4730#[repr(C, packed)]
4731#[doc(hidden)]
4732pub struct CursivePosFormat2FixedHeader {
4733 pub pos_format: BigEndian<u16>,
4734 pub coverage_offset: BigEndian<Offset32>,
4735 pub entry_exit_count: BigEndian<Uint24>,
4736}
4737
4738#[allow(clippy::absurd_extreme_comparisons)]
4739const _: () =
4740 assert!(std::mem::size_of::<CursivePosFormat2FixedHeader>() <= CursivePosFormat2::MIN_SIZE);
4741
4742#[derive(Clone)]
4744pub struct CursivePosFormat2<'a> {
4745 data: TableDataRef<'a, CursivePosFormat2FixedHeader>,
4746}
4747
4748#[allow(clippy::needless_lifetimes)]
4749impl<'a> CursivePosFormat2<'a> {
4750 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN + Uint24::RAW_BYTE_LEN);
4751 basic_table_impls!(impl_the_methods);
4752
4753 pub fn pos_format(&self) -> u16 {
4755 self.data.header().pos_format.get()
4756 }
4757
4758 pub fn coverage_offset(&self) -> Offset32 {
4760 self.data.header().coverage_offset.get()
4761 }
4762
4763 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
4765 let data = self.offset_data();
4766 self.coverage_offset().resolve(data)
4767 }
4768
4769 pub fn entry_exit_count(&self) -> Uint24 {
4771 self.data.header().entry_exit_count.get()
4772 }
4773
4774 pub fn entry_exit_record(&self) -> &'a [EntryExitRecord2] {
4776 let range = self.entry_exit_record_byte_range();
4777 self.offset_data()
4778 .read_array(range)
4779 .ok()
4780 .unwrap_or_default()
4781 }
4782
4783 pub fn pos_format_byte_range(&self) -> Range<usize> {
4784 let start = 0;
4785 let end = start + u16::RAW_BYTE_LEN;
4786 start..end
4787 }
4788
4789 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
4790 let start = self.pos_format_byte_range().end;
4791 let end = start + Offset32::RAW_BYTE_LEN;
4792 start..end
4793 }
4794
4795 pub fn entry_exit_count_byte_range(&self) -> Range<usize> {
4796 let start = self.coverage_offset_byte_range().end;
4797 let end = start + Uint24::RAW_BYTE_LEN;
4798 start..end
4799 }
4800
4801 pub fn entry_exit_record_byte_range(&self) -> Range<usize> {
4802 let entry_exit_count = self.entry_exit_count();
4803 let start = self.entry_exit_count_byte_range().end;
4804 let end = start
4805 + (transforms::to_usize(entry_exit_count))
4806 .saturating_mul(EntryExitRecord2::RAW_BYTE_LEN);
4807 start..end
4808 }
4809}
4810
4811#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
4813#[repr(C)]
4814#[repr(packed)]
4815pub struct EntryExitRecord2 {
4816 pub entry_anchor_offset: BigEndian<Nullable<Offset24>>,
4819 pub exit_anchor_offset: BigEndian<Nullable<Offset24>>,
4822}
4823
4824impl EntryExitRecord2 {
4825 pub fn entry_anchor_offset(&self) -> Nullable<Offset24> {
4828 self.entry_anchor_offset.get()
4829 }
4830
4831 pub fn entry_anchor<'a>(
4837 &self,
4838 data: FontData<'a>,
4839 ) -> Option<Result<AnchorTable<'a>, ReadError>> {
4840 self.entry_anchor_offset().resolve(data)
4841 }
4842
4843 pub fn exit_anchor_offset(&self) -> Nullable<Offset24> {
4846 self.exit_anchor_offset.get()
4847 }
4848
4849 pub fn exit_anchor<'a>(
4855 &self,
4856 data: FontData<'a>,
4857 ) -> Option<Result<AnchorTable<'a>, ReadError>> {
4858 self.exit_anchor_offset().resolve(data)
4859 }
4860}
4861
4862impl FixedSize for EntryExitRecord2 {
4863 const RAW_BYTE_LEN: usize = Offset24::RAW_BYTE_LEN + Offset24::RAW_BYTE_LEN;
4864}
4865
4866impl Format<u16> for MarkBasePosFormat2<'_> {
4867 const FORMAT: u16 = 2;
4868}
4869
4870impl<'a> MinByteRange<'a> for MarkBasePosFormat2<'a> {
4871 fn min_byte_range(&self) -> Range<usize> {
4872 0..self.base_array_offset_byte_range().end
4873 }
4874 fn min_table_bytes(&self) -> &'a [u8] {
4875 let range = self.min_byte_range();
4876 self.offset_data().as_bytes().get(range).unwrap_or_default()
4877 }
4878}
4879
4880impl ReadArgs for MarkBasePosFormat2<'_> {
4881 type Args = ();
4882}
4883
4884impl<'a> FontRead<'a> for MarkBasePosFormat2<'a> {
4885 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
4886 #[allow(clippy::absurd_extreme_comparisons)]
4887 if data.len() < Self::MIN_SIZE {
4888 return Err(ReadError::OutOfBounds);
4889 }
4890 let Some(data) = TableDataRef::new(data.as_bytes()) else {
4891 return Err(ReadError::OutOfBounds);
4892 };
4893 Ok(Self { data })
4894 }
4895}
4896
4897#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
4899#[repr(C, packed)]
4900#[doc(hidden)]
4901pub struct MarkBasePosFormat2FixedHeader {
4902 pub pos_format: BigEndian<u16>,
4903 pub mark_coverage_offset: BigEndian<Offset32>,
4904 pub base_coverage_offset: BigEndian<Offset32>,
4905 pub mark_class_count: BigEndian<u16>,
4906 pub mark_array_offset: BigEndian<Offset32>,
4907 pub base_array_offset: BigEndian<Offset32>,
4908}
4909
4910#[allow(clippy::absurd_extreme_comparisons)]
4911const _: () =
4912 assert!(std::mem::size_of::<MarkBasePosFormat2FixedHeader>() <= MarkBasePosFormat2::MIN_SIZE);
4913
4914#[derive(Clone)]
4916pub struct MarkBasePosFormat2<'a> {
4917 data: TableDataRef<'a, MarkBasePosFormat2FixedHeader>,
4918}
4919
4920#[allow(clippy::needless_lifetimes)]
4921impl<'a> MarkBasePosFormat2<'a> {
4922 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
4923 + Offset32::RAW_BYTE_LEN
4924 + Offset32::RAW_BYTE_LEN
4925 + u16::RAW_BYTE_LEN
4926 + Offset32::RAW_BYTE_LEN
4927 + Offset32::RAW_BYTE_LEN);
4928 basic_table_impls!(impl_the_methods);
4929
4930 pub fn pos_format(&self) -> u16 {
4932 self.data.header().pos_format.get()
4933 }
4934
4935 pub fn mark_coverage_offset(&self) -> Offset32 {
4938 self.data.header().mark_coverage_offset.get()
4939 }
4940
4941 pub fn mark_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
4943 let data = self.offset_data();
4944 self.mark_coverage_offset().resolve(data)
4945 }
4946
4947 pub fn base_coverage_offset(&self) -> Offset32 {
4950 self.data.header().base_coverage_offset.get()
4951 }
4952
4953 pub fn base_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
4955 let data = self.offset_data();
4956 self.base_coverage_offset().resolve(data)
4957 }
4958
4959 pub fn mark_class_count(&self) -> u16 {
4961 self.data.header().mark_class_count.get()
4962 }
4963
4964 pub fn mark_array_offset(&self) -> Offset32 {
4967 self.data.header().mark_array_offset.get()
4968 }
4969
4970 pub fn mark_array(&self) -> Result<MarkArray2<'a>, ReadError> {
4972 let data = self.offset_data();
4973 self.mark_array_offset().resolve(data)
4974 }
4975
4976 pub fn base_array_offset(&self) -> Offset32 {
4979 self.data.header().base_array_offset.get()
4980 }
4981
4982 pub fn base_array(&self) -> Result<BaseArray2<'a>, ReadError> {
4984 let data = self.offset_data();
4985 let args = self.mark_class_count();
4986 self.base_array_offset().resolve_with_args(data, args)
4987 }
4988
4989 pub fn pos_format_byte_range(&self) -> Range<usize> {
4990 let start = 0;
4991 let end = start + u16::RAW_BYTE_LEN;
4992 start..end
4993 }
4994
4995 pub fn mark_coverage_offset_byte_range(&self) -> Range<usize> {
4996 let start = self.pos_format_byte_range().end;
4997 let end = start + Offset32::RAW_BYTE_LEN;
4998 start..end
4999 }
5000
5001 pub fn base_coverage_offset_byte_range(&self) -> Range<usize> {
5002 let start = self.mark_coverage_offset_byte_range().end;
5003 let end = start + Offset32::RAW_BYTE_LEN;
5004 start..end
5005 }
5006
5007 pub fn mark_class_count_byte_range(&self) -> Range<usize> {
5008 let start = self.base_coverage_offset_byte_range().end;
5009 let end = start + u16::RAW_BYTE_LEN;
5010 start..end
5011 }
5012
5013 pub fn mark_array_offset_byte_range(&self) -> Range<usize> {
5014 let start = self.mark_class_count_byte_range().end;
5015 let end = start + Offset32::RAW_BYTE_LEN;
5016 start..end
5017 }
5018
5019 pub fn base_array_offset_byte_range(&self) -> Range<usize> {
5020 let start = self.mark_array_offset_byte_range().end;
5021 let end = start + Offset32::RAW_BYTE_LEN;
5022 start..end
5023 }
5024}
5025
5026impl<'a> MinByteRange<'a> for BaseArray2<'a> {
5027 fn min_byte_range(&self) -> Range<usize> {
5028 0..self.base_records_byte_range().end
5029 }
5030 fn min_table_bytes(&self) -> &'a [u8] {
5031 let range = self.min_byte_range();
5032 self.offset_data().as_bytes().get(range).unwrap_or_default()
5033 }
5034}
5035
5036impl ReadArgs for BaseArray2<'_> {
5037 type Args = u16;
5038}
5039
5040impl<'a> FontRead<'a> for BaseArray2<'a> {
5041 fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
5042 let mark_class_count = args;
5043
5044 #[allow(clippy::absurd_extreme_comparisons)]
5045 if data.len() < Self::MIN_SIZE {
5046 return Err(ReadError::OutOfBounds);
5047 }
5048 let Some(data) = TableDataRef::new(data.as_bytes()) else {
5049 return Err(ReadError::OutOfBounds);
5050 };
5051 Ok(Self {
5052 data,
5053 mark_class_count,
5054 })
5055 }
5056}
5057
5058impl<'a> BaseArray2<'a> {
5059 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
5064 let args = mark_class_count;
5065 Self::read_with_args(data, args)
5066 }
5067}
5068
5069#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
5071#[repr(C, packed)]
5072#[doc(hidden)]
5073pub struct BaseArray2FixedHeader {
5074 pub base_count: BigEndian<Uint24>,
5075}
5076
5077#[allow(clippy::absurd_extreme_comparisons)]
5078const _: () = assert!(std::mem::size_of::<BaseArray2FixedHeader>() <= BaseArray2::MIN_SIZE);
5079
5080#[derive(Clone)]
5082pub struct BaseArray2<'a> {
5083 data: TableDataRef<'a, BaseArray2FixedHeader>,
5084 mark_class_count: u16,
5085}
5086
5087#[allow(clippy::needless_lifetimes)]
5088impl<'a> BaseArray2<'a> {
5089 pub const MIN_SIZE: usize = Uint24::RAW_BYTE_LEN;
5090 basic_table_impls!(impl_the_methods);
5091
5092 pub fn base_count(&self) -> Uint24 {
5094 self.data.header().base_count.get()
5095 }
5096
5097 pub fn base_records(&self) -> ComputedArray<'a, BaseRecord2<'a>> {
5099 let range = self.base_records_byte_range();
5100 ComputedArray::new(self.offset_data(), range, self.mark_class_count()).unwrap_or_default()
5101 }
5102
5103 pub(crate) fn mark_class_count(&self) -> u16 {
5104 self.mark_class_count
5105 }
5106
5107 pub fn base_count_byte_range(&self) -> Range<usize> {
5108 let start = 0;
5109 let end = start + Uint24::RAW_BYTE_LEN;
5110 start..end
5111 }
5112
5113 pub fn base_records_byte_range(&self) -> Range<usize> {
5114 let base_count = self.base_count();
5115 let start = self.base_count_byte_range().end;
5116 let end = start
5117 + (transforms::to_usize(base_count)).saturating_mul(
5118 <BaseRecord2 as ComputeSize>::compute_size(self.mark_class_count()).unwrap_or(0),
5119 );
5120 start..end
5121 }
5122}
5123
5124const _: () = assert!(FontData::default_data_long_enough(BaseArray2::MIN_SIZE));
5125
5126impl Default for BaseArray2<'_> {
5127 fn default() -> Self {
5128 Self {
5129 data: TableDataRef::new(FontData::default_table_data().as_bytes())
5130 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
5131 mark_class_count: Default::default(),
5132 }
5133 }
5134}
5135
5136#[derive(Clone, Debug)]
5138pub struct BaseRecord2<'a> {
5139 pub base_anchor_offsets: &'a [BigEndian<Nullable<Offset24>>],
5143}
5144
5145impl<'a> BaseRecord2<'a> {
5146 pub fn base_anchor_offsets(&self) -> &'a [BigEndian<Nullable<Offset24>>] {
5150 self.base_anchor_offsets
5151 }
5152
5153 pub fn base_anchors(
5160 &self,
5161 data: FontData<'a>,
5162 ) -> ArrayOfNullableOffsets<'a, AnchorTable<'a>, Offset24> {
5163 let offsets = self.base_anchor_offsets();
5164 ArrayOfNullableOffsets::new(offsets, data, ())
5165 }
5166}
5167
5168impl ReadArgs for BaseRecord2<'_> {
5169 type Args = u16;
5170}
5171
5172impl ComputeSize for BaseRecord2<'_> {
5173 #[allow(clippy::needless_question_mark)]
5174 fn compute_size(args: u16) -> Result<usize, ReadError> {
5175 let mark_class_count = args;
5176 Ok((transforms::to_usize(mark_class_count)).saturating_mul(Offset24::RAW_BYTE_LEN))
5177 }
5178}
5179
5180impl<'a> FontRead<'a> for BaseRecord2<'a> {
5181 fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
5182 let mut cursor = data.cursor();
5183 let mark_class_count = args;
5184 Ok(Self {
5185 base_anchor_offsets: cursor.read_array(transforms::to_usize(mark_class_count))?,
5186 })
5187 }
5188}
5189
5190crate::impl_font_read_at!(BaseRecord2<'a>);
5191
5192#[allow(clippy::needless_lifetimes)]
5193impl<'a> BaseRecord2<'a> {
5194 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
5199 let args = mark_class_count;
5200 Self::read_with_args(data, args)
5201 }
5202}
5203
5204impl Format<u16> for MarkLigPosFormat2<'_> {
5205 const FORMAT: u16 = 2;
5206}
5207
5208impl<'a> MinByteRange<'a> for MarkLigPosFormat2<'a> {
5209 fn min_byte_range(&self) -> Range<usize> {
5210 0..self.ligature_array_offset_byte_range().end
5211 }
5212 fn min_table_bytes(&self) -> &'a [u8] {
5213 let range = self.min_byte_range();
5214 self.offset_data().as_bytes().get(range).unwrap_or_default()
5215 }
5216}
5217
5218impl ReadArgs for MarkLigPosFormat2<'_> {
5219 type Args = ();
5220}
5221
5222impl<'a> FontRead<'a> for MarkLigPosFormat2<'a> {
5223 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
5224 #[allow(clippy::absurd_extreme_comparisons)]
5225 if data.len() < Self::MIN_SIZE {
5226 return Err(ReadError::OutOfBounds);
5227 }
5228 let Some(data) = TableDataRef::new(data.as_bytes()) else {
5229 return Err(ReadError::OutOfBounds);
5230 };
5231 Ok(Self { data })
5232 }
5233}
5234
5235#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
5237#[repr(C, packed)]
5238#[doc(hidden)]
5239pub struct MarkLigPosFormat2FixedHeader {
5240 pub pos_format: BigEndian<u16>,
5241 pub mark_coverage_offset: BigEndian<Offset32>,
5242 pub ligature_coverage_offset: BigEndian<Offset32>,
5243 pub mark_class_count: BigEndian<u16>,
5244 pub mark_array_offset: BigEndian<Offset32>,
5245 pub ligature_array_offset: BigEndian<Offset32>,
5246}
5247
5248#[allow(clippy::absurd_extreme_comparisons)]
5249const _: () =
5250 assert!(std::mem::size_of::<MarkLigPosFormat2FixedHeader>() <= MarkLigPosFormat2::MIN_SIZE);
5251
5252#[derive(Clone)]
5254pub struct MarkLigPosFormat2<'a> {
5255 data: TableDataRef<'a, MarkLigPosFormat2FixedHeader>,
5256}
5257
5258#[allow(clippy::needless_lifetimes)]
5259impl<'a> MarkLigPosFormat2<'a> {
5260 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
5261 + Offset32::RAW_BYTE_LEN
5262 + Offset32::RAW_BYTE_LEN
5263 + u16::RAW_BYTE_LEN
5264 + Offset32::RAW_BYTE_LEN
5265 + Offset32::RAW_BYTE_LEN);
5266 basic_table_impls!(impl_the_methods);
5267
5268 pub fn pos_format(&self) -> u16 {
5270 self.data.header().pos_format.get()
5271 }
5272
5273 pub fn mark_coverage_offset(&self) -> Offset32 {
5276 self.data.header().mark_coverage_offset.get()
5277 }
5278
5279 pub fn mark_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
5281 let data = self.offset_data();
5282 self.mark_coverage_offset().resolve(data)
5283 }
5284
5285 pub fn ligature_coverage_offset(&self) -> Offset32 {
5288 self.data.header().ligature_coverage_offset.get()
5289 }
5290
5291 pub fn ligature_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
5293 let data = self.offset_data();
5294 self.ligature_coverage_offset().resolve(data)
5295 }
5296
5297 pub fn mark_class_count(&self) -> u16 {
5299 self.data.header().mark_class_count.get()
5300 }
5301
5302 pub fn mark_array_offset(&self) -> Offset32 {
5305 self.data.header().mark_array_offset.get()
5306 }
5307
5308 pub fn mark_array(&self) -> Result<MarkArray2<'a>, ReadError> {
5310 let data = self.offset_data();
5311 self.mark_array_offset().resolve(data)
5312 }
5313
5314 pub fn ligature_array_offset(&self) -> Offset32 {
5317 self.data.header().ligature_array_offset.get()
5318 }
5319
5320 pub fn ligature_array(&self) -> Result<LigatureArray2<'a>, ReadError> {
5322 let data = self.offset_data();
5323 let args = self.mark_class_count();
5324 self.ligature_array_offset().resolve_with_args(data, args)
5325 }
5326
5327 pub fn pos_format_byte_range(&self) -> Range<usize> {
5328 let start = 0;
5329 let end = start + u16::RAW_BYTE_LEN;
5330 start..end
5331 }
5332
5333 pub fn mark_coverage_offset_byte_range(&self) -> Range<usize> {
5334 let start = self.pos_format_byte_range().end;
5335 let end = start + Offset32::RAW_BYTE_LEN;
5336 start..end
5337 }
5338
5339 pub fn ligature_coverage_offset_byte_range(&self) -> Range<usize> {
5340 let start = self.mark_coverage_offset_byte_range().end;
5341 let end = start + Offset32::RAW_BYTE_LEN;
5342 start..end
5343 }
5344
5345 pub fn mark_class_count_byte_range(&self) -> Range<usize> {
5346 let start = self.ligature_coverage_offset_byte_range().end;
5347 let end = start + u16::RAW_BYTE_LEN;
5348 start..end
5349 }
5350
5351 pub fn mark_array_offset_byte_range(&self) -> Range<usize> {
5352 let start = self.mark_class_count_byte_range().end;
5353 let end = start + Offset32::RAW_BYTE_LEN;
5354 start..end
5355 }
5356
5357 pub fn ligature_array_offset_byte_range(&self) -> Range<usize> {
5358 let start = self.mark_array_offset_byte_range().end;
5359 let end = start + Offset32::RAW_BYTE_LEN;
5360 start..end
5361 }
5362}
5363
5364impl<'a> MinByteRange<'a> for LigatureArray2<'a> {
5365 fn min_byte_range(&self) -> Range<usize> {
5366 0..self.ligature_attach_offsets_byte_range().end
5367 }
5368 fn min_table_bytes(&self) -> &'a [u8] {
5369 let range = self.min_byte_range();
5370 self.offset_data().as_bytes().get(range).unwrap_or_default()
5371 }
5372}
5373
5374impl ReadArgs for LigatureArray2<'_> {
5375 type Args = u16;
5376}
5377
5378impl<'a> FontRead<'a> for LigatureArray2<'a> {
5379 fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
5380 let mark_class_count = args;
5381
5382 #[allow(clippy::absurd_extreme_comparisons)]
5383 if data.len() < Self::MIN_SIZE {
5384 return Err(ReadError::OutOfBounds);
5385 }
5386 let Some(data) = TableDataRef::new(data.as_bytes()) else {
5387 return Err(ReadError::OutOfBounds);
5388 };
5389 Ok(Self {
5390 data,
5391 mark_class_count,
5392 })
5393 }
5394}
5395
5396impl<'a> LigatureArray2<'a> {
5397 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
5402 let args = mark_class_count;
5403 Self::read_with_args(data, args)
5404 }
5405}
5406
5407#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
5409#[repr(C, packed)]
5410#[doc(hidden)]
5411pub struct LigatureArray2FixedHeader {
5412 pub ligature_count: BigEndian<Uint24>,
5413}
5414
5415#[allow(clippy::absurd_extreme_comparisons)]
5416const _: () = assert!(std::mem::size_of::<LigatureArray2FixedHeader>() <= LigatureArray2::MIN_SIZE);
5417
5418#[derive(Clone)]
5420pub struct LigatureArray2<'a> {
5421 data: TableDataRef<'a, LigatureArray2FixedHeader>,
5422 mark_class_count: u16,
5423}
5424
5425#[allow(clippy::needless_lifetimes)]
5426impl<'a> LigatureArray2<'a> {
5427 pub const MIN_SIZE: usize = Uint24::RAW_BYTE_LEN;
5428 basic_table_impls!(impl_the_methods);
5429
5430 pub fn ligature_count(&self) -> Uint24 {
5432 self.data.header().ligature_count.get()
5433 }
5434
5435 pub fn ligature_attach_offsets(&self) -> &'a [BigEndian<Offset24>] {
5439 let range = self.ligature_attach_offsets_byte_range();
5440 self.offset_data()
5441 .read_array(range)
5442 .ok()
5443 .unwrap_or_default()
5444 }
5445
5446 pub fn ligature_attaches(&self) -> ArrayOfOffsets<'a, LigatureAttach2<'a>, Offset24> {
5448 let data = self.offset_data();
5449 let offsets = self.ligature_attach_offsets();
5450 let args = self.mark_class_count();
5451 ArrayOfOffsets::new(offsets, data, args)
5452 }
5453
5454 pub(crate) fn mark_class_count(&self) -> u16 {
5455 self.mark_class_count
5456 }
5457
5458 pub fn ligature_count_byte_range(&self) -> Range<usize> {
5459 let start = 0;
5460 let end = start + Uint24::RAW_BYTE_LEN;
5461 start..end
5462 }
5463
5464 pub fn ligature_attach_offsets_byte_range(&self) -> Range<usize> {
5465 let ligature_count = self.ligature_count();
5466 let start = self.ligature_count_byte_range().end;
5467 let end =
5468 start + (transforms::to_usize(ligature_count)).saturating_mul(Offset24::RAW_BYTE_LEN);
5469 start..end
5470 }
5471}
5472
5473const _: () = assert!(FontData::default_data_long_enough(LigatureArray2::MIN_SIZE));
5474
5475impl Default for LigatureArray2<'_> {
5476 fn default() -> Self {
5477 Self {
5478 data: TableDataRef::new(FontData::default_table_data().as_bytes())
5479 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
5480 mark_class_count: Default::default(),
5481 }
5482 }
5483}
5484
5485impl<'a> MinByteRange<'a> for LigatureAttach2<'a> {
5486 fn min_byte_range(&self) -> Range<usize> {
5487 0..self.component_records_byte_range().end
5488 }
5489 fn min_table_bytes(&self) -> &'a [u8] {
5490 let range = self.min_byte_range();
5491 self.offset_data().as_bytes().get(range).unwrap_or_default()
5492 }
5493}
5494
5495impl ReadArgs for LigatureAttach2<'_> {
5496 type Args = u16;
5497}
5498
5499impl<'a> FontRead<'a> for LigatureAttach2<'a> {
5500 fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
5501 let mark_class_count = args;
5502
5503 #[allow(clippy::absurd_extreme_comparisons)]
5504 if data.len() < Self::MIN_SIZE {
5505 return Err(ReadError::OutOfBounds);
5506 }
5507 let Some(data) = TableDataRef::new(data.as_bytes()) else {
5508 return Err(ReadError::OutOfBounds);
5509 };
5510 Ok(Self {
5511 data,
5512 mark_class_count,
5513 })
5514 }
5515}
5516
5517impl<'a> LigatureAttach2<'a> {
5518 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
5523 let args = mark_class_count;
5524 Self::read_with_args(data, args)
5525 }
5526}
5527
5528#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
5530#[repr(C, packed)]
5531#[doc(hidden)]
5532pub struct LigatureAttach2FixedHeader {
5533 pub component_count: BigEndian<u16>,
5534}
5535
5536#[allow(clippy::absurd_extreme_comparisons)]
5537const _: () =
5538 assert!(std::mem::size_of::<LigatureAttach2FixedHeader>() <= LigatureAttach2::MIN_SIZE);
5539
5540#[derive(Clone)]
5542pub struct LigatureAttach2<'a> {
5543 data: TableDataRef<'a, LigatureAttach2FixedHeader>,
5544 mark_class_count: u16,
5545}
5546
5547#[allow(clippy::needless_lifetimes)]
5548impl<'a> LigatureAttach2<'a> {
5549 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
5550 basic_table_impls!(impl_the_methods);
5551
5552 pub fn component_count(&self) -> u16 {
5554 self.data.header().component_count.get()
5555 }
5556
5557 pub fn component_records(&self) -> ComputedArray<'a, ComponentRecord2<'a>> {
5559 let range = self.component_records_byte_range();
5560 ComputedArray::new(self.offset_data(), range, self.mark_class_count()).unwrap_or_default()
5561 }
5562
5563 pub(crate) fn mark_class_count(&self) -> u16 {
5564 self.mark_class_count
5565 }
5566
5567 pub fn component_count_byte_range(&self) -> Range<usize> {
5568 let start = 0;
5569 let end = start + u16::RAW_BYTE_LEN;
5570 start..end
5571 }
5572
5573 pub fn component_records_byte_range(&self) -> Range<usize> {
5574 let component_count = self.component_count();
5575 let start = self.component_count_byte_range().end;
5576 let end = start
5577 + (transforms::to_usize(component_count)).saturating_mul(
5578 <ComponentRecord2 as ComputeSize>::compute_size(self.mark_class_count())
5579 .unwrap_or(0),
5580 );
5581 start..end
5582 }
5583}
5584
5585const _: () = assert!(FontData::default_data_long_enough(
5586 LigatureAttach2::MIN_SIZE
5587));
5588
5589impl Default for LigatureAttach2<'_> {
5590 fn default() -> Self {
5591 Self {
5592 data: TableDataRef::new(FontData::default_table_data().as_bytes())
5593 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
5594 mark_class_count: Default::default(),
5595 }
5596 }
5597}
5598
5599#[derive(Clone, Debug)]
5601pub struct ComponentRecord2<'a> {
5602 pub ligature_anchor_offsets: &'a [BigEndian<Nullable<Offset24>>],
5606}
5607
5608impl<'a> ComponentRecord2<'a> {
5609 pub fn ligature_anchor_offsets(&self) -> &'a [BigEndian<Nullable<Offset24>>] {
5613 self.ligature_anchor_offsets
5614 }
5615
5616 pub fn ligature_anchors(
5623 &self,
5624 data: FontData<'a>,
5625 ) -> ArrayOfNullableOffsets<'a, AnchorTable<'a>, Offset24> {
5626 let offsets = self.ligature_anchor_offsets();
5627 ArrayOfNullableOffsets::new(offsets, data, ())
5628 }
5629}
5630
5631impl ReadArgs for ComponentRecord2<'_> {
5632 type Args = u16;
5633}
5634
5635impl ComputeSize for ComponentRecord2<'_> {
5636 #[allow(clippy::needless_question_mark)]
5637 fn compute_size(args: u16) -> Result<usize, ReadError> {
5638 let mark_class_count = args;
5639 Ok((transforms::to_usize(mark_class_count)).saturating_mul(Offset24::RAW_BYTE_LEN))
5640 }
5641}
5642
5643impl<'a> FontRead<'a> for ComponentRecord2<'a> {
5644 fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
5645 let mut cursor = data.cursor();
5646 let mark_class_count = args;
5647 Ok(Self {
5648 ligature_anchor_offsets: cursor.read_array(transforms::to_usize(mark_class_count))?,
5649 })
5650 }
5651}
5652
5653crate::impl_font_read_at!(ComponentRecord2<'a>);
5654
5655#[allow(clippy::needless_lifetimes)]
5656impl<'a> ComponentRecord2<'a> {
5657 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
5662 let args = mark_class_count;
5663 Self::read_with_args(data, args)
5664 }
5665}
5666
5667impl Format<u16> for MarkMarkPosFormat2<'_> {
5668 const FORMAT: u16 = 2;
5669}
5670
5671impl<'a> MinByteRange<'a> for MarkMarkPosFormat2<'a> {
5672 fn min_byte_range(&self) -> Range<usize> {
5673 0..self.mark2_array_offset_byte_range().end
5674 }
5675 fn min_table_bytes(&self) -> &'a [u8] {
5676 let range = self.min_byte_range();
5677 self.offset_data().as_bytes().get(range).unwrap_or_default()
5678 }
5679}
5680
5681impl ReadArgs for MarkMarkPosFormat2<'_> {
5682 type Args = ();
5683}
5684
5685impl<'a> FontRead<'a> for MarkMarkPosFormat2<'a> {
5686 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
5687 #[allow(clippy::absurd_extreme_comparisons)]
5688 if data.len() < Self::MIN_SIZE {
5689 return Err(ReadError::OutOfBounds);
5690 }
5691 let Some(data) = TableDataRef::new(data.as_bytes()) else {
5692 return Err(ReadError::OutOfBounds);
5693 };
5694 Ok(Self { data })
5695 }
5696}
5697
5698#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
5700#[repr(C, packed)]
5701#[doc(hidden)]
5702pub struct MarkMarkPosFormat2FixedHeader {
5703 pub pos_format: BigEndian<u16>,
5704 pub mark1_coverage_offset: BigEndian<Offset32>,
5705 pub mark2_coverage_offset: BigEndian<Offset32>,
5706 pub mark_class_count: BigEndian<u16>,
5707 pub mark1_array_offset: BigEndian<Offset32>,
5708 pub mark2_array_offset: BigEndian<Offset32>,
5709}
5710
5711#[allow(clippy::absurd_extreme_comparisons)]
5712const _: () =
5713 assert!(std::mem::size_of::<MarkMarkPosFormat2FixedHeader>() <= MarkMarkPosFormat2::MIN_SIZE);
5714
5715#[derive(Clone)]
5717pub struct MarkMarkPosFormat2<'a> {
5718 data: TableDataRef<'a, MarkMarkPosFormat2FixedHeader>,
5719}
5720
5721#[allow(clippy::needless_lifetimes)]
5722impl<'a> MarkMarkPosFormat2<'a> {
5723 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
5724 + Offset32::RAW_BYTE_LEN
5725 + Offset32::RAW_BYTE_LEN
5726 + u16::RAW_BYTE_LEN
5727 + Offset32::RAW_BYTE_LEN
5728 + Offset32::RAW_BYTE_LEN);
5729 basic_table_impls!(impl_the_methods);
5730
5731 pub fn pos_format(&self) -> u16 {
5733 self.data.header().pos_format.get()
5734 }
5735
5736 pub fn mark1_coverage_offset(&self) -> Offset32 {
5739 self.data.header().mark1_coverage_offset.get()
5740 }
5741
5742 pub fn mark1_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
5744 let data = self.offset_data();
5745 self.mark1_coverage_offset().resolve(data)
5746 }
5747
5748 pub fn mark2_coverage_offset(&self) -> Offset32 {
5751 self.data.header().mark2_coverage_offset.get()
5752 }
5753
5754 pub fn mark2_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
5756 let data = self.offset_data();
5757 self.mark2_coverage_offset().resolve(data)
5758 }
5759
5760 pub fn mark_class_count(&self) -> u16 {
5762 self.data.header().mark_class_count.get()
5763 }
5764
5765 pub fn mark1_array_offset(&self) -> Offset32 {
5768 self.data.header().mark1_array_offset.get()
5769 }
5770
5771 pub fn mark1_array(&self) -> Result<MarkArray2<'a>, ReadError> {
5773 let data = self.offset_data();
5774 self.mark1_array_offset().resolve(data)
5775 }
5776
5777 pub fn mark2_array_offset(&self) -> Offset32 {
5780 self.data.header().mark2_array_offset.get()
5781 }
5782
5783 pub fn mark2_array(&self) -> Result<Mark2Array2<'a>, ReadError> {
5785 let data = self.offset_data();
5786 let args = self.mark_class_count();
5787 self.mark2_array_offset().resolve_with_args(data, args)
5788 }
5789
5790 pub fn pos_format_byte_range(&self) -> Range<usize> {
5791 let start = 0;
5792 let end = start + u16::RAW_BYTE_LEN;
5793 start..end
5794 }
5795
5796 pub fn mark1_coverage_offset_byte_range(&self) -> Range<usize> {
5797 let start = self.pos_format_byte_range().end;
5798 let end = start + Offset32::RAW_BYTE_LEN;
5799 start..end
5800 }
5801
5802 pub fn mark2_coverage_offset_byte_range(&self) -> Range<usize> {
5803 let start = self.mark1_coverage_offset_byte_range().end;
5804 let end = start + Offset32::RAW_BYTE_LEN;
5805 start..end
5806 }
5807
5808 pub fn mark_class_count_byte_range(&self) -> Range<usize> {
5809 let start = self.mark2_coverage_offset_byte_range().end;
5810 let end = start + u16::RAW_BYTE_LEN;
5811 start..end
5812 }
5813
5814 pub fn mark1_array_offset_byte_range(&self) -> Range<usize> {
5815 let start = self.mark_class_count_byte_range().end;
5816 let end = start + Offset32::RAW_BYTE_LEN;
5817 start..end
5818 }
5819
5820 pub fn mark2_array_offset_byte_range(&self) -> Range<usize> {
5821 let start = self.mark1_array_offset_byte_range().end;
5822 let end = start + Offset32::RAW_BYTE_LEN;
5823 start..end
5824 }
5825}
5826
5827impl<'a> MinByteRange<'a> for Mark2Array2<'a> {
5828 fn min_byte_range(&self) -> Range<usize> {
5829 0..self.mark2_records_byte_range().end
5830 }
5831 fn min_table_bytes(&self) -> &'a [u8] {
5832 let range = self.min_byte_range();
5833 self.offset_data().as_bytes().get(range).unwrap_or_default()
5834 }
5835}
5836
5837impl ReadArgs for Mark2Array2<'_> {
5838 type Args = u16;
5839}
5840
5841impl<'a> FontRead<'a> for Mark2Array2<'a> {
5842 fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
5843 let mark_class_count = args;
5844
5845 #[allow(clippy::absurd_extreme_comparisons)]
5846 if data.len() < Self::MIN_SIZE {
5847 return Err(ReadError::OutOfBounds);
5848 }
5849 let Some(data) = TableDataRef::new(data.as_bytes()) else {
5850 return Err(ReadError::OutOfBounds);
5851 };
5852 Ok(Self {
5853 data,
5854 mark_class_count,
5855 })
5856 }
5857}
5858
5859impl<'a> Mark2Array2<'a> {
5860 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
5865 let args = mark_class_count;
5866 Self::read_with_args(data, args)
5867 }
5868}
5869
5870#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
5872#[repr(C, packed)]
5873#[doc(hidden)]
5874pub struct Mark2Array2FixedHeader {
5875 pub mark2_count: BigEndian<u16>,
5876}
5877
5878#[allow(clippy::absurd_extreme_comparisons)]
5879const _: () = assert!(std::mem::size_of::<Mark2Array2FixedHeader>() <= Mark2Array2::MIN_SIZE);
5880
5881#[derive(Clone)]
5883pub struct Mark2Array2<'a> {
5884 data: TableDataRef<'a, Mark2Array2FixedHeader>,
5885 mark_class_count: u16,
5886}
5887
5888#[allow(clippy::needless_lifetimes)]
5889impl<'a> Mark2Array2<'a> {
5890 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
5891 basic_table_impls!(impl_the_methods);
5892
5893 pub fn mark2_count(&self) -> u16 {
5895 self.data.header().mark2_count.get()
5896 }
5897
5898 pub fn mark2_records(&self) -> ComputedArray<'a, Mark2Record2<'a>> {
5900 let range = self.mark2_records_byte_range();
5901 ComputedArray::new(self.offset_data(), range, self.mark_class_count()).unwrap_or_default()
5902 }
5903
5904 pub(crate) fn mark_class_count(&self) -> u16 {
5905 self.mark_class_count
5906 }
5907
5908 pub fn mark2_count_byte_range(&self) -> Range<usize> {
5909 let start = 0;
5910 let end = start + u16::RAW_BYTE_LEN;
5911 start..end
5912 }
5913
5914 pub fn mark2_records_byte_range(&self) -> Range<usize> {
5915 let mark2_count = self.mark2_count();
5916 let start = self.mark2_count_byte_range().end;
5917 let end = start
5918 + (transforms::to_usize(mark2_count)).saturating_mul(
5919 <Mark2Record2 as ComputeSize>::compute_size(self.mark_class_count()).unwrap_or(0),
5920 );
5921 start..end
5922 }
5923}
5924
5925const _: () = assert!(FontData::default_data_long_enough(Mark2Array2::MIN_SIZE));
5926
5927impl Default for Mark2Array2<'_> {
5928 fn default() -> Self {
5929 Self {
5930 data: TableDataRef::new(FontData::default_table_data().as_bytes())
5931 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
5932 mark_class_count: Default::default(),
5933 }
5934 }
5935}
5936
5937#[derive(Clone, Debug)]
5939pub struct Mark2Record2<'a> {
5940 pub mark2_anchor_offsets: &'a [BigEndian<Nullable<Offset24>>],
5944}
5945
5946impl<'a> Mark2Record2<'a> {
5947 pub fn mark2_anchor_offsets(&self) -> &'a [BigEndian<Nullable<Offset24>>] {
5951 self.mark2_anchor_offsets
5952 }
5953
5954 pub fn mark2_anchors(
5961 &self,
5962 data: FontData<'a>,
5963 ) -> ArrayOfNullableOffsets<'a, AnchorTable<'a>, Offset24> {
5964 let offsets = self.mark2_anchor_offsets();
5965 ArrayOfNullableOffsets::new(offsets, data, ())
5966 }
5967}
5968
5969impl ReadArgs for Mark2Record2<'_> {
5970 type Args = u16;
5971}
5972
5973impl ComputeSize for Mark2Record2<'_> {
5974 #[allow(clippy::needless_question_mark)]
5975 fn compute_size(args: u16) -> Result<usize, ReadError> {
5976 let mark_class_count = args;
5977 Ok((transforms::to_usize(mark_class_count)).saturating_mul(Offset24::RAW_BYTE_LEN))
5978 }
5979}
5980
5981impl<'a> FontRead<'a> for Mark2Record2<'a> {
5982 fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
5983 let mut cursor = data.cursor();
5984 let mark_class_count = args;
5985 Ok(Self {
5986 mark2_anchor_offsets: cursor.read_array(transforms::to_usize(mark_class_count))?,
5987 })
5988 }
5989}
5990
5991crate::impl_font_read_at!(Mark2Record2<'a>);
5992
5993#[allow(clippy::needless_lifetimes)]
5994impl<'a> Mark2Record2<'a> {
5995 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
6000 let args = mark_class_count;
6001 Self::read_with_args(data, args)
6002 }
6003}
6004
6005impl<'a> MinByteRange<'a> for MarkArray2<'a> {
6006 fn min_byte_range(&self) -> Range<usize> {
6007 0..self.mark_records_byte_range().end
6008 }
6009 fn min_table_bytes(&self) -> &'a [u8] {
6010 let range = self.min_byte_range();
6011 self.offset_data().as_bytes().get(range).unwrap_or_default()
6012 }
6013}
6014
6015impl ReadArgs for MarkArray2<'_> {
6016 type Args = ();
6017}
6018
6019impl<'a> FontRead<'a> for MarkArray2<'a> {
6020 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
6021 #[allow(clippy::absurd_extreme_comparisons)]
6022 if data.len() < Self::MIN_SIZE {
6023 return Err(ReadError::OutOfBounds);
6024 }
6025 let Some(data) = TableDataRef::new(data.as_bytes()) else {
6026 return Err(ReadError::OutOfBounds);
6027 };
6028 Ok(Self { data })
6029 }
6030}
6031
6032#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
6034#[repr(C, packed)]
6035#[doc(hidden)]
6036pub struct MarkArray2FixedHeader {
6037 pub mark_count: BigEndian<Uint24>,
6038}
6039
6040#[allow(clippy::absurd_extreme_comparisons)]
6041const _: () = assert!(std::mem::size_of::<MarkArray2FixedHeader>() <= MarkArray2::MIN_SIZE);
6042
6043#[derive(Clone)]
6045pub struct MarkArray2<'a> {
6046 data: TableDataRef<'a, MarkArray2FixedHeader>,
6047}
6048
6049#[allow(clippy::needless_lifetimes)]
6050impl<'a> MarkArray2<'a> {
6051 pub const MIN_SIZE: usize = Uint24::RAW_BYTE_LEN;
6052 basic_table_impls!(impl_the_methods);
6053
6054 pub fn mark_count(&self) -> Uint24 {
6056 self.data.header().mark_count.get()
6057 }
6058
6059 pub fn mark_records(&self) -> &'a [MarkRecord2] {
6062 let range = self.mark_records_byte_range();
6063 self.offset_data()
6064 .read_array(range)
6065 .ok()
6066 .unwrap_or_default()
6067 }
6068
6069 pub fn mark_count_byte_range(&self) -> Range<usize> {
6070 let start = 0;
6071 let end = start + Uint24::RAW_BYTE_LEN;
6072 start..end
6073 }
6074
6075 pub fn mark_records_byte_range(&self) -> Range<usize> {
6076 let mark_count = self.mark_count();
6077 let start = self.mark_count_byte_range().end;
6078 let end =
6079 start + (transforms::to_usize(mark_count)).saturating_mul(MarkRecord2::RAW_BYTE_LEN);
6080 start..end
6081 }
6082}
6083
6084const _: () = assert!(FontData::default_data_long_enough(MarkArray2::MIN_SIZE));
6085
6086impl Default for MarkArray2<'_> {
6087 fn default() -> Self {
6088 Self {
6089 data: TableDataRef::new(FontData::default_table_data().as_bytes())
6090 .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
6091 }
6092 }
6093}
6094
6095#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
6097#[repr(C)]
6098#[repr(packed)]
6099pub struct MarkRecord2 {
6100 pub mark_class: BigEndian<u16>,
6102 pub mark_anchor_offset: BigEndian<Offset24>,
6104}
6105
6106impl MarkRecord2 {
6107 pub fn mark_class(&self) -> u16 {
6109 self.mark_class.get()
6110 }
6111
6112 pub fn mark_anchor_offset(&self) -> Offset24 {
6114 self.mark_anchor_offset.get()
6115 }
6116
6117 pub fn mark_anchor<'a>(&self, data: FontData<'a>) -> Result<AnchorTable<'a>, ReadError> {
6122 self.mark_anchor_offset().resolve(data)
6123 }
6124}
6125
6126impl FixedSize for MarkRecord2 {
6127 const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + Offset24::RAW_BYTE_LEN;
6128}
6129
6130#[derive(Clone)]
6132pub enum CursivePos<'a> {
6133 Format1(CursivePosFormat1<'a>),
6134 Format2(CursivePosFormat2<'a>),
6135}
6136
6137impl Default for CursivePos<'_> {
6138 fn default() -> Self {
6139 Self::Format1(Default::default())
6140 }
6141}
6142
6143impl<'a> CursivePos<'a> {
6144 pub fn offset_data(&self) -> FontData<'a> {
6146 match self {
6147 Self::Format1(item) => item.offset_data(),
6148 Self::Format2(item) => item.offset_data(),
6149 }
6150 }
6151
6152 pub fn pos_format(&self) -> u16 {
6154 match self {
6155 Self::Format1(item) => item.pos_format(),
6156 Self::Format2(item) => item.pos_format(),
6157 }
6158 }
6159}
6160
6161impl ReadArgs for CursivePos<'_> {
6162 type Args = ();
6163}
6164
6165impl<'a> FontRead<'a> for CursivePos<'a> {
6166 #[inline]
6167 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
6168 let format: u16 = data.read_at(0usize)?;
6169 match format {
6170 CursivePosFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
6171 CursivePosFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
6172 other => Err(ReadError::InvalidFormat(other.into())),
6173 }
6174 }
6175}
6176
6177impl<'a> MinByteRange<'a> for CursivePos<'a> {
6178 fn min_byte_range(&self) -> Range<usize> {
6179 match self {
6180 Self::Format1(item) => item.min_byte_range(),
6181 Self::Format2(item) => item.min_byte_range(),
6182 }
6183 }
6184 fn min_table_bytes(&self) -> &'a [u8] {
6185 match self {
6186 Self::Format1(item) => item.min_table_bytes(),
6187 Self::Format2(item) => item.min_table_bytes(),
6188 }
6189 }
6190}
6191
6192#[derive(Clone)]
6194pub enum MarkBasePos<'a> {
6195 Format1(MarkBasePosFormat1<'a>),
6196 Format2(MarkBasePosFormat2<'a>),
6197}
6198
6199impl Default for MarkBasePos<'_> {
6200 fn default() -> Self {
6201 Self::Format1(Default::default())
6202 }
6203}
6204
6205impl<'a> MarkBasePos<'a> {
6206 pub fn offset_data(&self) -> FontData<'a> {
6208 match self {
6209 Self::Format1(item) => item.offset_data(),
6210 Self::Format2(item) => item.offset_data(),
6211 }
6212 }
6213
6214 pub fn pos_format(&self) -> u16 {
6216 match self {
6217 Self::Format1(item) => item.pos_format(),
6218 Self::Format2(item) => item.pos_format(),
6219 }
6220 }
6221
6222 pub fn mark_class_count(&self) -> u16 {
6224 match self {
6225 Self::Format1(item) => item.mark_class_count(),
6226 Self::Format2(item) => item.mark_class_count(),
6227 }
6228 }
6229}
6230
6231impl ReadArgs for MarkBasePos<'_> {
6232 type Args = ();
6233}
6234
6235impl<'a> FontRead<'a> for MarkBasePos<'a> {
6236 #[inline]
6237 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
6238 let format: u16 = data.read_at(0usize)?;
6239 match format {
6240 MarkBasePosFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
6241 MarkBasePosFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
6242 other => Err(ReadError::InvalidFormat(other.into())),
6243 }
6244 }
6245}
6246
6247impl<'a> MinByteRange<'a> for MarkBasePos<'a> {
6248 fn min_byte_range(&self) -> Range<usize> {
6249 match self {
6250 Self::Format1(item) => item.min_byte_range(),
6251 Self::Format2(item) => item.min_byte_range(),
6252 }
6253 }
6254 fn min_table_bytes(&self) -> &'a [u8] {
6255 match self {
6256 Self::Format1(item) => item.min_table_bytes(),
6257 Self::Format2(item) => item.min_table_bytes(),
6258 }
6259 }
6260}
6261
6262#[derive(Clone)]
6264pub enum MarkLigPos<'a> {
6265 Format1(MarkLigPosFormat1<'a>),
6266 Format2(MarkLigPosFormat2<'a>),
6267}
6268
6269impl Default for MarkLigPos<'_> {
6270 fn default() -> Self {
6271 Self::Format1(Default::default())
6272 }
6273}
6274
6275impl<'a> MarkLigPos<'a> {
6276 pub fn offset_data(&self) -> FontData<'a> {
6278 match self {
6279 Self::Format1(item) => item.offset_data(),
6280 Self::Format2(item) => item.offset_data(),
6281 }
6282 }
6283
6284 pub fn pos_format(&self) -> u16 {
6286 match self {
6287 Self::Format1(item) => item.pos_format(),
6288 Self::Format2(item) => item.pos_format(),
6289 }
6290 }
6291
6292 pub fn mark_class_count(&self) -> u16 {
6294 match self {
6295 Self::Format1(item) => item.mark_class_count(),
6296 Self::Format2(item) => item.mark_class_count(),
6297 }
6298 }
6299}
6300
6301impl ReadArgs for MarkLigPos<'_> {
6302 type Args = ();
6303}
6304
6305impl<'a> FontRead<'a> for MarkLigPos<'a> {
6306 #[inline]
6307 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
6308 let format: u16 = data.read_at(0usize)?;
6309 match format {
6310 MarkLigPosFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
6311 MarkLigPosFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
6312 other => Err(ReadError::InvalidFormat(other.into())),
6313 }
6314 }
6315}
6316
6317impl<'a> MinByteRange<'a> for MarkLigPos<'a> {
6318 fn min_byte_range(&self) -> Range<usize> {
6319 match self {
6320 Self::Format1(item) => item.min_byte_range(),
6321 Self::Format2(item) => item.min_byte_range(),
6322 }
6323 }
6324 fn min_table_bytes(&self) -> &'a [u8] {
6325 match self {
6326 Self::Format1(item) => item.min_table_bytes(),
6327 Self::Format2(item) => item.min_table_bytes(),
6328 }
6329 }
6330}
6331
6332#[derive(Clone)]
6334pub enum MarkMarkPos<'a> {
6335 Format1(MarkMarkPosFormat1<'a>),
6336 Format2(MarkMarkPosFormat2<'a>),
6337}
6338
6339impl Default for MarkMarkPos<'_> {
6340 fn default() -> Self {
6341 Self::Format1(Default::default())
6342 }
6343}
6344
6345impl<'a> MarkMarkPos<'a> {
6346 pub fn offset_data(&self) -> FontData<'a> {
6348 match self {
6349 Self::Format1(item) => item.offset_data(),
6350 Self::Format2(item) => item.offset_data(),
6351 }
6352 }
6353
6354 pub fn pos_format(&self) -> u16 {
6356 match self {
6357 Self::Format1(item) => item.pos_format(),
6358 Self::Format2(item) => item.pos_format(),
6359 }
6360 }
6361
6362 pub fn mark_class_count(&self) -> u16 {
6364 match self {
6365 Self::Format1(item) => item.mark_class_count(),
6366 Self::Format2(item) => item.mark_class_count(),
6367 }
6368 }
6369}
6370
6371impl ReadArgs for MarkMarkPos<'_> {
6372 type Args = ();
6373}
6374
6375impl<'a> FontRead<'a> for MarkMarkPos<'a> {
6376 #[inline]
6377 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
6378 let format: u16 = data.read_at(0usize)?;
6379 match format {
6380 MarkMarkPosFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
6381 MarkMarkPosFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
6382 other => Err(ReadError::InvalidFormat(other.into())),
6383 }
6384 }
6385}
6386
6387impl<'a> MinByteRange<'a> for MarkMarkPos<'a> {
6388 fn min_byte_range(&self) -> Range<usize> {
6389 match self {
6390 Self::Format1(item) => item.min_byte_range(),
6391 Self::Format2(item) => item.min_byte_range(),
6392 }
6393 }
6394 fn min_table_bytes(&self) -> &'a [u8] {
6395 match self {
6396 Self::Format1(item) => item.min_table_bytes(),
6397 Self::Format2(item) => item.min_table_bytes(),
6398 }
6399 }
6400}