1#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
10#[repr(C)]
11#[repr(packed)]
12pub struct BitmapSize {
13 pub index_subtable_list_offset: BigEndian<u32>,
15 pub index_subtable_list_size: BigEndian<u32>,
17 pub number_of_index_subtables: BigEndian<u32>,
19 pub color_ref: BigEndian<u32>,
21 pub hori: SbitLineMetrics,
23 pub vert: SbitLineMetrics,
25 pub start_glyph_index: BigEndian<GlyphId16>,
27 pub end_glyph_index: BigEndian<GlyphId16>,
29 pub ppem_x: u8,
31 pub ppem_y: u8,
33 pub bit_depth: u8,
36 pub flags: BigEndian<BitmapFlags>,
38}
39
40impl BitmapSize {
41 pub fn index_subtable_list_offset(&self) -> u32 {
43 self.index_subtable_list_offset.get()
44 }
45
46 pub fn index_subtable_list_size(&self) -> u32 {
48 self.index_subtable_list_size.get()
49 }
50
51 pub fn number_of_index_subtables(&self) -> u32 {
53 self.number_of_index_subtables.get()
54 }
55
56 pub fn color_ref(&self) -> u32 {
58 self.color_ref.get()
59 }
60
61 pub fn hori(&self) -> &SbitLineMetrics {
63 &self.hori
64 }
65
66 pub fn vert(&self) -> &SbitLineMetrics {
68 &self.vert
69 }
70
71 pub fn start_glyph_index(&self) -> GlyphId16 {
73 self.start_glyph_index.get()
74 }
75
76 pub fn end_glyph_index(&self) -> GlyphId16 {
78 self.end_glyph_index.get()
79 }
80
81 pub fn ppem_x(&self) -> u8 {
83 self.ppem_x
84 }
85
86 pub fn ppem_y(&self) -> u8 {
88 self.ppem_y
89 }
90
91 pub fn bit_depth(&self) -> u8 {
94 self.bit_depth
95 }
96
97 pub fn flags(&self) -> BitmapFlags {
99 self.flags.get()
100 }
101}
102
103impl FixedSize for BitmapSize {
104 const RAW_BYTE_LEN: usize = u32::RAW_BYTE_LEN
105 + u32::RAW_BYTE_LEN
106 + u32::RAW_BYTE_LEN
107 + u32::RAW_BYTE_LEN
108 + SbitLineMetrics::RAW_BYTE_LEN
109 + SbitLineMetrics::RAW_BYTE_LEN
110 + GlyphId16::RAW_BYTE_LEN
111 + GlyphId16::RAW_BYTE_LEN
112 + u8::RAW_BYTE_LEN
113 + u8::RAW_BYTE_LEN
114 + u8::RAW_BYTE_LEN
115 + BitmapFlags::RAW_BYTE_LEN;
116}
117
118#[cfg(feature = "experimental_traverse")]
119impl<'a> SomeRecord<'a> for BitmapSize {
120 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
121 RecordResolver {
122 name: "BitmapSize",
123 get_field: Box::new(move |idx, _data| match idx {
124 0usize => Some(Field::new(
125 "index_subtable_list_offset",
126 self.index_subtable_list_offset(),
127 )),
128 1usize => Some(Field::new(
129 "index_subtable_list_size",
130 self.index_subtable_list_size(),
131 )),
132 2usize => Some(Field::new(
133 "number_of_index_subtables",
134 self.number_of_index_subtables(),
135 )),
136 3usize => Some(Field::new("color_ref", self.color_ref())),
137 4usize => Some(Field::new("hori", self.hori().traversal_type(_data))),
138 5usize => Some(Field::new("vert", self.vert().traversal_type(_data))),
139 6usize => Some(Field::new("start_glyph_index", self.start_glyph_index())),
140 7usize => Some(Field::new("end_glyph_index", self.end_glyph_index())),
141 8usize => Some(Field::new("ppem_x", self.ppem_x())),
142 9usize => Some(Field::new("ppem_y", self.ppem_y())),
143 10usize => Some(Field::new("bit_depth", self.bit_depth())),
144 11usize => Some(Field::new("flags", self.flags())),
145 _ => None,
146 }),
147 data,
148 }
149 }
150}
151
152#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
154#[repr(C)]
155#[repr(packed)]
156pub struct SbitLineMetrics {
157 pub ascender: BigEndian<i8>,
158 pub descender: BigEndian<i8>,
159 pub width_max: u8,
160 pub caret_slope_numerator: BigEndian<i8>,
161 pub caret_slope_denominator: u8,
162 pub caret_offset: BigEndian<i8>,
163 pub min_origin_sb: BigEndian<i8>,
164 pub min_advance_sb: BigEndian<i8>,
165 pub max_before_bl: BigEndian<i8>,
166 pub min_after_bl: BigEndian<i8>,
167 pub pad1: BigEndian<i8>,
168 pub pad2: BigEndian<i8>,
169}
170
171impl SbitLineMetrics {
172 pub fn ascender(&self) -> i8 {
173 self.ascender.get()
174 }
175
176 pub fn descender(&self) -> i8 {
177 self.descender.get()
178 }
179
180 pub fn width_max(&self) -> u8 {
181 self.width_max
182 }
183
184 pub fn caret_slope_numerator(&self) -> i8 {
185 self.caret_slope_numerator.get()
186 }
187
188 pub fn caret_slope_denominator(&self) -> u8 {
189 self.caret_slope_denominator
190 }
191
192 pub fn caret_offset(&self) -> i8 {
193 self.caret_offset.get()
194 }
195
196 pub fn min_origin_sb(&self) -> i8 {
197 self.min_origin_sb.get()
198 }
199
200 pub fn min_advance_sb(&self) -> i8 {
201 self.min_advance_sb.get()
202 }
203
204 pub fn max_before_bl(&self) -> i8 {
205 self.max_before_bl.get()
206 }
207
208 pub fn min_after_bl(&self) -> i8 {
209 self.min_after_bl.get()
210 }
211
212 pub fn pad1(&self) -> i8 {
213 self.pad1.get()
214 }
215
216 pub fn pad2(&self) -> i8 {
217 self.pad2.get()
218 }
219}
220
221impl FixedSize for SbitLineMetrics {
222 const RAW_BYTE_LEN: usize = i8::RAW_BYTE_LEN
223 + i8::RAW_BYTE_LEN
224 + u8::RAW_BYTE_LEN
225 + i8::RAW_BYTE_LEN
226 + u8::RAW_BYTE_LEN
227 + i8::RAW_BYTE_LEN
228 + i8::RAW_BYTE_LEN
229 + i8::RAW_BYTE_LEN
230 + i8::RAW_BYTE_LEN
231 + i8::RAW_BYTE_LEN
232 + i8::RAW_BYTE_LEN
233 + i8::RAW_BYTE_LEN;
234}
235
236#[cfg(feature = "experimental_traverse")]
237impl<'a> SomeRecord<'a> for SbitLineMetrics {
238 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
239 RecordResolver {
240 name: "SbitLineMetrics",
241 get_field: Box::new(move |idx, _data| match idx {
242 0usize => Some(Field::new("ascender", self.ascender())),
243 1usize => Some(Field::new("descender", self.descender())),
244 2usize => Some(Field::new("width_max", self.width_max())),
245 3usize => Some(Field::new(
246 "caret_slope_numerator",
247 self.caret_slope_numerator(),
248 )),
249 4usize => Some(Field::new(
250 "caret_slope_denominator",
251 self.caret_slope_denominator(),
252 )),
253 5usize => Some(Field::new("caret_offset", self.caret_offset())),
254 6usize => Some(Field::new("min_origin_sb", self.min_origin_sb())),
255 7usize => Some(Field::new("min_advance_sb", self.min_advance_sb())),
256 8usize => Some(Field::new("max_before_bl", self.max_before_bl())),
257 9usize => Some(Field::new("min_after_bl", self.min_after_bl())),
258 10usize => Some(Field::new("pad1", self.pad1())),
259 11usize => Some(Field::new("pad2", self.pad2())),
260 _ => None,
261 }),
262 data,
263 }
264 }
265}
266
267#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, bytemuck :: AnyBitPattern)]
269#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
270#[repr(transparent)]
271pub struct BitmapFlags {
272 bits: u8,
273}
274
275impl BitmapFlags {
276 pub const HORIZONTAL_METRICS: Self = Self { bits: 0x01 };
278
279 pub const VERTICAL_METRICS: Self = Self { bits: 0x02 };
281}
282
283impl BitmapFlags {
284 #[inline]
286 pub const fn empty() -> Self {
287 Self { bits: 0 }
288 }
289
290 #[inline]
292 pub const fn all() -> Self {
293 Self {
294 bits: Self::HORIZONTAL_METRICS.bits | Self::VERTICAL_METRICS.bits,
295 }
296 }
297
298 #[inline]
300 pub const fn bits(&self) -> u8 {
301 self.bits
302 }
303
304 #[inline]
307 pub const fn from_bits(bits: u8) -> Option<Self> {
308 if (bits & !Self::all().bits()) == 0 {
309 Some(Self { bits })
310 } else {
311 None
312 }
313 }
314
315 #[inline]
318 pub const fn from_bits_truncate(bits: u8) -> Self {
319 Self {
320 bits: bits & Self::all().bits,
321 }
322 }
323
324 #[inline]
326 pub const fn is_empty(&self) -> bool {
327 self.bits() == Self::empty().bits()
328 }
329
330 #[inline]
332 pub const fn intersects(&self, other: Self) -> bool {
333 !(Self {
334 bits: self.bits & other.bits,
335 })
336 .is_empty()
337 }
338
339 #[inline]
341 pub const fn contains(&self, other: Self) -> bool {
342 (self.bits & other.bits) == other.bits
343 }
344
345 #[inline]
347 pub fn insert(&mut self, other: Self) {
348 self.bits |= other.bits;
349 }
350
351 #[inline]
353 pub fn remove(&mut self, other: Self) {
354 self.bits &= !other.bits;
355 }
356
357 #[inline]
359 pub fn toggle(&mut self, other: Self) {
360 self.bits ^= other.bits;
361 }
362
363 #[inline]
374 #[must_use]
375 pub const fn intersection(self, other: Self) -> Self {
376 Self {
377 bits: self.bits & other.bits,
378 }
379 }
380
381 #[inline]
392 #[must_use]
393 pub const fn union(self, other: Self) -> Self {
394 Self {
395 bits: self.bits | other.bits,
396 }
397 }
398
399 #[inline]
412 #[must_use]
413 pub const fn difference(self, other: Self) -> Self {
414 Self {
415 bits: self.bits & !other.bits,
416 }
417 }
418}
419
420impl std::ops::BitOr for BitmapFlags {
421 type Output = Self;
422
423 #[inline]
425 fn bitor(self, other: BitmapFlags) -> Self {
426 Self {
427 bits: self.bits | other.bits,
428 }
429 }
430}
431
432impl std::ops::BitOrAssign for BitmapFlags {
433 #[inline]
435 fn bitor_assign(&mut self, other: Self) {
436 self.bits |= other.bits;
437 }
438}
439
440impl std::ops::BitXor for BitmapFlags {
441 type Output = Self;
442
443 #[inline]
445 fn bitxor(self, other: Self) -> Self {
446 Self {
447 bits: self.bits ^ other.bits,
448 }
449 }
450}
451
452impl std::ops::BitXorAssign for BitmapFlags {
453 #[inline]
455 fn bitxor_assign(&mut self, other: Self) {
456 self.bits ^= other.bits;
457 }
458}
459
460impl std::ops::BitAnd for BitmapFlags {
461 type Output = Self;
462
463 #[inline]
465 fn bitand(self, other: Self) -> Self {
466 Self {
467 bits: self.bits & other.bits,
468 }
469 }
470}
471
472impl std::ops::BitAndAssign for BitmapFlags {
473 #[inline]
475 fn bitand_assign(&mut self, other: Self) {
476 self.bits &= other.bits;
477 }
478}
479
480impl std::ops::Sub for BitmapFlags {
481 type Output = Self;
482
483 #[inline]
485 fn sub(self, other: Self) -> Self {
486 Self {
487 bits: self.bits & !other.bits,
488 }
489 }
490}
491
492impl std::ops::SubAssign for BitmapFlags {
493 #[inline]
495 fn sub_assign(&mut self, other: Self) {
496 self.bits &= !other.bits;
497 }
498}
499
500impl std::ops::Not for BitmapFlags {
501 type Output = Self;
502
503 #[inline]
505 fn not(self) -> Self {
506 Self { bits: !self.bits } & Self::all()
507 }
508}
509
510impl std::fmt::Debug for BitmapFlags {
511 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
512 let members: &[(&str, Self)] = &[
513 ("HORIZONTAL_METRICS", Self::HORIZONTAL_METRICS),
514 ("VERTICAL_METRICS", Self::VERTICAL_METRICS),
515 ];
516 let mut first = true;
517 for (name, value) in members {
518 if self.contains(*value) {
519 if !first {
520 f.write_str(" | ")?;
521 }
522 first = false;
523 f.write_str(name)?;
524 }
525 }
526 if first {
527 f.write_str("(empty)")?;
528 }
529 Ok(())
530 }
531}
532
533impl std::fmt::Binary for BitmapFlags {
534 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
535 std::fmt::Binary::fmt(&self.bits, f)
536 }
537}
538
539impl std::fmt::Octal for BitmapFlags {
540 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
541 std::fmt::Octal::fmt(&self.bits, f)
542 }
543}
544
545impl std::fmt::LowerHex for BitmapFlags {
546 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
547 std::fmt::LowerHex::fmt(&self.bits, f)
548 }
549}
550
551impl std::fmt::UpperHex for BitmapFlags {
552 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
553 std::fmt::UpperHex::fmt(&self.bits, f)
554 }
555}
556
557impl font_types::Scalar for BitmapFlags {
558 type Raw = <u8 as font_types::Scalar>::Raw;
559 fn to_raw(self) -> Self::Raw {
560 self.bits().to_raw()
561 }
562 fn from_raw(raw: Self::Raw) -> Self {
563 let t = <u8>::from_raw(raw);
564 Self::from_bits_truncate(t)
565 }
566}
567
568#[cfg(feature = "experimental_traverse")]
569impl<'a> From<BitmapFlags> for FieldType<'a> {
570 fn from(src: BitmapFlags) -> FieldType<'a> {
571 src.bits().into()
572 }
573}
574
575#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
577#[repr(C)]
578#[repr(packed)]
579pub struct BigGlyphMetrics {
580 pub height: u8,
582 pub width: u8,
584 pub hori_bearing_x: BigEndian<i8>,
586 pub hori_bearing_y: BigEndian<i8>,
588 pub hori_advance: u8,
590 pub vert_bearing_x: BigEndian<i8>,
592 pub vert_bearing_y: BigEndian<i8>,
594 pub vert_advance: u8,
596}
597
598impl BigGlyphMetrics {
599 pub fn height(&self) -> u8 {
601 self.height
602 }
603
604 pub fn width(&self) -> u8 {
606 self.width
607 }
608
609 pub fn hori_bearing_x(&self) -> i8 {
611 self.hori_bearing_x.get()
612 }
613
614 pub fn hori_bearing_y(&self) -> i8 {
616 self.hori_bearing_y.get()
617 }
618
619 pub fn hori_advance(&self) -> u8 {
621 self.hori_advance
622 }
623
624 pub fn vert_bearing_x(&self) -> i8 {
626 self.vert_bearing_x.get()
627 }
628
629 pub fn vert_bearing_y(&self) -> i8 {
631 self.vert_bearing_y.get()
632 }
633
634 pub fn vert_advance(&self) -> u8 {
636 self.vert_advance
637 }
638}
639
640impl FixedSize for BigGlyphMetrics {
641 const RAW_BYTE_LEN: usize = u8::RAW_BYTE_LEN
642 + u8::RAW_BYTE_LEN
643 + i8::RAW_BYTE_LEN
644 + i8::RAW_BYTE_LEN
645 + u8::RAW_BYTE_LEN
646 + i8::RAW_BYTE_LEN
647 + i8::RAW_BYTE_LEN
648 + u8::RAW_BYTE_LEN;
649}
650
651#[cfg(feature = "experimental_traverse")]
652impl<'a> SomeRecord<'a> for BigGlyphMetrics {
653 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
654 RecordResolver {
655 name: "BigGlyphMetrics",
656 get_field: Box::new(move |idx, _data| match idx {
657 0usize => Some(Field::new("height", self.height())),
658 1usize => Some(Field::new("width", self.width())),
659 2usize => Some(Field::new("hori_bearing_x", self.hori_bearing_x())),
660 3usize => Some(Field::new("hori_bearing_y", self.hori_bearing_y())),
661 4usize => Some(Field::new("hori_advance", self.hori_advance())),
662 5usize => Some(Field::new("vert_bearing_x", self.vert_bearing_x())),
663 6usize => Some(Field::new("vert_bearing_y", self.vert_bearing_y())),
664 7usize => Some(Field::new("vert_advance", self.vert_advance())),
665 _ => None,
666 }),
667 data,
668 }
669 }
670}
671
672#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
674#[repr(C)]
675#[repr(packed)]
676pub struct SmallGlyphMetrics {
677 pub height: u8,
679 pub width: u8,
681 pub bearing_x: BigEndian<i8>,
683 pub bearing_y: BigEndian<i8>,
685 pub advance: u8,
687}
688
689impl SmallGlyphMetrics {
690 pub fn height(&self) -> u8 {
692 self.height
693 }
694
695 pub fn width(&self) -> u8 {
697 self.width
698 }
699
700 pub fn bearing_x(&self) -> i8 {
702 self.bearing_x.get()
703 }
704
705 pub fn bearing_y(&self) -> i8 {
707 self.bearing_y.get()
708 }
709
710 pub fn advance(&self) -> u8 {
712 self.advance
713 }
714}
715
716impl FixedSize for SmallGlyphMetrics {
717 const RAW_BYTE_LEN: usize = u8::RAW_BYTE_LEN
718 + u8::RAW_BYTE_LEN
719 + i8::RAW_BYTE_LEN
720 + i8::RAW_BYTE_LEN
721 + u8::RAW_BYTE_LEN;
722}
723
724#[cfg(feature = "experimental_traverse")]
725impl<'a> SomeRecord<'a> for SmallGlyphMetrics {
726 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
727 RecordResolver {
728 name: "SmallGlyphMetrics",
729 get_field: Box::new(move |idx, _data| match idx {
730 0usize => Some(Field::new("height", self.height())),
731 1usize => Some(Field::new("width", self.width())),
732 2usize => Some(Field::new("bearing_x", self.bearing_x())),
733 3usize => Some(Field::new("bearing_y", self.bearing_y())),
734 4usize => Some(Field::new("advance", self.advance())),
735 _ => None,
736 }),
737 data,
738 }
739 }
740}
741
742impl<'a> MinByteRange<'a> for IndexSubtableList<'a> {
743 fn min_byte_range(&self) -> Range<usize> {
744 0..self.index_subtable_records_byte_range().end
745 }
746 fn min_table_bytes(&self) -> &'a [u8] {
747 let range = self.min_byte_range();
748 self.data.as_bytes().get(range).unwrap_or_default()
749 }
750}
751
752impl ReadArgs for IndexSubtableList<'_> {
753 type Args = u32;
754}
755
756impl<'a> FontReadWithArgs<'a> for IndexSubtableList<'a> {
757 fn read_with_args(data: FontData<'a>, args: &u32) -> Result<Self, ReadError> {
758 let number_of_index_subtables = *args;
759
760 #[allow(clippy::absurd_extreme_comparisons)]
761 if data.len() < Self::MIN_SIZE {
762 return Err(ReadError::OutOfBounds);
763 }
764 Ok(Self {
765 data,
766 number_of_index_subtables,
767 })
768 }
769}
770
771impl<'a> IndexSubtableList<'a> {
772 pub fn read(data: FontData<'a>, number_of_index_subtables: u32) -> Result<Self, ReadError> {
777 let args = number_of_index_subtables;
778 Self::read_with_args(data, &args)
779 }
780}
781
782#[derive(Clone)]
784pub struct IndexSubtableList<'a> {
785 data: FontData<'a>,
786 number_of_index_subtables: u32,
787}
788
789#[allow(clippy::needless_lifetimes)]
790impl<'a> IndexSubtableList<'a> {
791 pub const MIN_SIZE: usize = 0;
792 basic_table_impls!(impl_the_methods);
793
794 pub fn index_subtable_records(&self) -> &'a [IndexSubtableRecord] {
796 let range = self.index_subtable_records_byte_range();
797 self.data.read_array(range).ok().unwrap_or_default()
798 }
799
800 pub(crate) fn number_of_index_subtables(&self) -> u32 {
801 self.number_of_index_subtables
802 }
803
804 pub fn index_subtable_records_byte_range(&self) -> Range<usize> {
805 let number_of_index_subtables = self.number_of_index_subtables();
806 let start = 0;
807 start
808 ..start
809 + (transforms::to_usize(number_of_index_subtables))
810 .saturating_mul(IndexSubtableRecord::RAW_BYTE_LEN)
811 }
812}
813
814#[allow(clippy::absurd_extreme_comparisons)]
815const _: () = assert!(FontData::default_data_long_enough(
816 IndexSubtableList::MIN_SIZE
817));
818
819impl Default for IndexSubtableList<'_> {
820 fn default() -> Self {
821 Self {
822 data: FontData::default_table_data(),
823 number_of_index_subtables: Default::default(),
824 }
825 }
826}
827
828#[cfg(feature = "experimental_traverse")]
829impl<'a> SomeTable<'a> for IndexSubtableList<'a> {
830 fn type_name(&self) -> &str {
831 "IndexSubtableList"
832 }
833 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
834 match idx {
835 0usize => Some(Field::new(
836 "index_subtable_records",
837 traversal::FieldType::array_of_records(
838 stringify!(IndexSubtableRecord),
839 self.index_subtable_records(),
840 self.offset_data(),
841 ),
842 )),
843 _ => None,
844 }
845 }
846}
847
848#[cfg(feature = "experimental_traverse")]
849#[allow(clippy::needless_lifetimes)]
850impl<'a> std::fmt::Debug for IndexSubtableList<'a> {
851 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
852 (self as &dyn SomeTable<'a>).fmt(f)
853 }
854}
855
856#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
857#[repr(C)]
858#[repr(packed)]
859pub struct IndexSubtableRecord {
860 pub first_glyph_index: BigEndian<GlyphId16>,
862 pub last_glyph_index: BigEndian<GlyphId16>,
864 pub index_subtable_offset: BigEndian<Offset32>,
866}
867
868impl IndexSubtableRecord {
869 pub fn first_glyph_index(&self) -> GlyphId16 {
871 self.first_glyph_index.get()
872 }
873
874 pub fn last_glyph_index(&self) -> GlyphId16 {
876 self.last_glyph_index.get()
877 }
878
879 pub fn index_subtable_offset(&self) -> Offset32 {
881 self.index_subtable_offset.get()
882 }
883
884 pub fn index_subtable<'a>(&self, data: FontData<'a>) -> Result<IndexSubtable<'a>, ReadError> {
889 let args = (self.last_glyph_index(), self.first_glyph_index());
890 self.index_subtable_offset().resolve_with_args(data, &args)
891 }
892}
893
894impl FixedSize for IndexSubtableRecord {
895 const RAW_BYTE_LEN: usize =
896 GlyphId16::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
897}
898
899#[cfg(feature = "experimental_traverse")]
900impl<'a> SomeRecord<'a> for IndexSubtableRecord {
901 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
902 RecordResolver {
903 name: "IndexSubtableRecord",
904 get_field: Box::new(move |idx, _data| match idx {
905 0usize => Some(Field::new("first_glyph_index", self.first_glyph_index())),
906 1usize => Some(Field::new("last_glyph_index", self.last_glyph_index())),
907 2usize => Some(Field::new(
908 "index_subtable_offset",
909 FieldType::offset(self.index_subtable_offset(), self.index_subtable(_data)),
910 )),
911 _ => None,
912 }),
913 data,
914 }
915 }
916}
917
918impl Format<u16> for IndexSubtable1<'_> {
919 const FORMAT: u16 = 1;
920}
921
922impl<'a> MinByteRange<'a> for IndexSubtable1<'a> {
923 fn min_byte_range(&self) -> Range<usize> {
924 0..self.sbit_offsets_byte_range().end
925 }
926 fn min_table_bytes(&self) -> &'a [u8] {
927 let range = self.min_byte_range();
928 self.data.as_bytes().get(range).unwrap_or_default()
929 }
930}
931
932impl ReadArgs for IndexSubtable1<'_> {
933 type Args = (GlyphId16, GlyphId16);
934}
935
936impl<'a> FontReadWithArgs<'a> for IndexSubtable1<'a> {
937 fn read_with_args(
938 data: FontData<'a>,
939 args: &(GlyphId16, GlyphId16),
940 ) -> Result<Self, ReadError> {
941 let (last_glyph_index, first_glyph_index) = *args;
942
943 #[allow(clippy::absurd_extreme_comparisons)]
944 if data.len() < Self::MIN_SIZE {
945 return Err(ReadError::OutOfBounds);
946 }
947 Ok(Self {
948 data,
949 last_glyph_index,
950 first_glyph_index,
951 })
952 }
953}
954
955impl<'a> IndexSubtable1<'a> {
956 pub fn read(
961 data: FontData<'a>,
962 last_glyph_index: GlyphId16,
963 first_glyph_index: GlyphId16,
964 ) -> Result<Self, ReadError> {
965 let args = (last_glyph_index, first_glyph_index);
966 Self::read_with_args(data, &args)
967 }
968}
969
970#[derive(Clone)]
972pub struct IndexSubtable1<'a> {
973 data: FontData<'a>,
974 last_glyph_index: GlyphId16,
975 first_glyph_index: GlyphId16,
976}
977
978#[allow(clippy::needless_lifetimes)]
979impl<'a> IndexSubtable1<'a> {
980 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
981 basic_table_impls!(impl_the_methods);
982
983 pub fn index_format(&self) -> u16 {
985 let range = self.index_format_byte_range();
986 self.data.read_at(range.start).ok().unwrap()
987 }
988
989 pub fn image_format(&self) -> u16 {
991 let range = self.image_format_byte_range();
992 self.data.read_at(range.start).ok().unwrap()
993 }
994
995 pub fn image_data_offset(&self) -> u32 {
997 let range = self.image_data_offset_byte_range();
998 self.data.read_at(range.start).ok().unwrap()
999 }
1000
1001 pub fn sbit_offsets(&self) -> &'a [BigEndian<u32>] {
1002 let range = self.sbit_offsets_byte_range();
1003 self.data.read_array(range).ok().unwrap_or_default()
1004 }
1005
1006 pub(crate) fn last_glyph_index(&self) -> GlyphId16 {
1007 self.last_glyph_index
1008 }
1009
1010 pub(crate) fn first_glyph_index(&self) -> GlyphId16 {
1011 self.first_glyph_index
1012 }
1013
1014 pub fn index_format_byte_range(&self) -> Range<usize> {
1015 let start = 0;
1016 start..start + u16::RAW_BYTE_LEN
1017 }
1018
1019 pub fn image_format_byte_range(&self) -> Range<usize> {
1020 let start = self.index_format_byte_range().end;
1021 start..start + u16::RAW_BYTE_LEN
1022 }
1023
1024 pub fn image_data_offset_byte_range(&self) -> Range<usize> {
1025 let start = self.image_format_byte_range().end;
1026 start..start + u32::RAW_BYTE_LEN
1027 }
1028
1029 pub fn sbit_offsets_byte_range(&self) -> Range<usize> {
1030 let last_glyph_index = self.last_glyph_index();
1031 let first_glyph_index = self.first_glyph_index();
1032 let start = self.image_data_offset_byte_range().end;
1033 start
1034 ..start
1035 + (transforms::subtract_add_two(last_glyph_index, first_glyph_index))
1036 .saturating_mul(u32::RAW_BYTE_LEN)
1037 }
1038}
1039
1040const _: () = assert!(FontData::default_data_long_enough(IndexSubtable1::MIN_SIZE));
1041
1042impl Default for IndexSubtable1<'_> {
1043 fn default() -> Self {
1044 Self {
1045 data: FontData::default_format_1_u16_table_data(),
1046 last_glyph_index: Default::default(),
1047 first_glyph_index: Default::default(),
1048 }
1049 }
1050}
1051
1052#[cfg(feature = "experimental_traverse")]
1053impl<'a> SomeTable<'a> for IndexSubtable1<'a> {
1054 fn type_name(&self) -> &str {
1055 "IndexSubtable1"
1056 }
1057 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1058 match idx {
1059 0usize => Some(Field::new("index_format", self.index_format())),
1060 1usize => Some(Field::new("image_format", self.image_format())),
1061 2usize => Some(Field::new("image_data_offset", self.image_data_offset())),
1062 3usize => Some(Field::new("sbit_offsets", self.sbit_offsets())),
1063 _ => None,
1064 }
1065 }
1066}
1067
1068#[cfg(feature = "experimental_traverse")]
1069#[allow(clippy::needless_lifetimes)]
1070impl<'a> std::fmt::Debug for IndexSubtable1<'a> {
1071 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1072 (self as &dyn SomeTable<'a>).fmt(f)
1073 }
1074}
1075
1076impl Format<u16> for IndexSubtable2<'_> {
1077 const FORMAT: u16 = 2;
1078}
1079
1080impl<'a> MinByteRange<'a> for IndexSubtable2<'a> {
1081 fn min_byte_range(&self) -> Range<usize> {
1082 0..self.big_metrics_byte_range().end
1083 }
1084 fn min_table_bytes(&self) -> &'a [u8] {
1085 let range = self.min_byte_range();
1086 self.data.as_bytes().get(range).unwrap_or_default()
1087 }
1088}
1089
1090impl<'a> FontRead<'a> for IndexSubtable2<'a> {
1091 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1092 #[allow(clippy::absurd_extreme_comparisons)]
1093 if data.len() < Self::MIN_SIZE {
1094 return Err(ReadError::OutOfBounds);
1095 }
1096 Ok(Self { data })
1097 }
1098}
1099
1100#[derive(Clone)]
1102pub struct IndexSubtable2<'a> {
1103 data: FontData<'a>,
1104}
1105
1106#[allow(clippy::needless_lifetimes)]
1107impl<'a> IndexSubtable2<'a> {
1108 pub const MIN_SIZE: usize =
1109 (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
1110 basic_table_impls!(impl_the_methods);
1111
1112 pub fn index_format(&self) -> u16 {
1114 let range = self.index_format_byte_range();
1115 self.data.read_at(range.start).ok().unwrap()
1116 }
1117
1118 pub fn image_format(&self) -> u16 {
1120 let range = self.image_format_byte_range();
1121 self.data.read_at(range.start).ok().unwrap()
1122 }
1123
1124 pub fn image_data_offset(&self) -> u32 {
1126 let range = self.image_data_offset_byte_range();
1127 self.data.read_at(range.start).ok().unwrap()
1128 }
1129
1130 pub fn image_size(&self) -> u32 {
1132 let range = self.image_size_byte_range();
1133 self.data.read_at(range.start).ok().unwrap()
1134 }
1135
1136 pub fn big_metrics(&self) -> &'a [BigGlyphMetrics] {
1138 let range = self.big_metrics_byte_range();
1139 self.data.read_array(range).ok().unwrap_or_default()
1140 }
1141
1142 pub fn index_format_byte_range(&self) -> Range<usize> {
1143 let start = 0;
1144 start..start + u16::RAW_BYTE_LEN
1145 }
1146
1147 pub fn image_format_byte_range(&self) -> Range<usize> {
1148 let start = self.index_format_byte_range().end;
1149 start..start + u16::RAW_BYTE_LEN
1150 }
1151
1152 pub fn image_data_offset_byte_range(&self) -> Range<usize> {
1153 let start = self.image_format_byte_range().end;
1154 start..start + u32::RAW_BYTE_LEN
1155 }
1156
1157 pub fn image_size_byte_range(&self) -> Range<usize> {
1158 let start = self.image_data_offset_byte_range().end;
1159 start..start + u32::RAW_BYTE_LEN
1160 }
1161
1162 pub fn big_metrics_byte_range(&self) -> Range<usize> {
1163 let start = self.image_size_byte_range().end;
1164 start..start + BigGlyphMetrics::RAW_BYTE_LEN
1165 }
1166}
1167
1168#[cfg(feature = "experimental_traverse")]
1169impl<'a> SomeTable<'a> for IndexSubtable2<'a> {
1170 fn type_name(&self) -> &str {
1171 "IndexSubtable2"
1172 }
1173 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1174 match idx {
1175 0usize => Some(Field::new("index_format", self.index_format())),
1176 1usize => Some(Field::new("image_format", self.image_format())),
1177 2usize => Some(Field::new("image_data_offset", self.image_data_offset())),
1178 3usize => Some(Field::new("image_size", self.image_size())),
1179 4usize => Some(Field::new(
1180 "big_metrics",
1181 traversal::FieldType::array_of_records(
1182 stringify!(BigGlyphMetrics),
1183 self.big_metrics(),
1184 self.offset_data(),
1185 ),
1186 )),
1187 _ => None,
1188 }
1189 }
1190}
1191
1192#[cfg(feature = "experimental_traverse")]
1193#[allow(clippy::needless_lifetimes)]
1194impl<'a> std::fmt::Debug for IndexSubtable2<'a> {
1195 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1196 (self as &dyn SomeTable<'a>).fmt(f)
1197 }
1198}
1199
1200impl Format<u16> for IndexSubtable3<'_> {
1201 const FORMAT: u16 = 3;
1202}
1203
1204impl<'a> MinByteRange<'a> for IndexSubtable3<'a> {
1205 fn min_byte_range(&self) -> Range<usize> {
1206 0..self.sbit_offsets_byte_range().end
1207 }
1208 fn min_table_bytes(&self) -> &'a [u8] {
1209 let range = self.min_byte_range();
1210 self.data.as_bytes().get(range).unwrap_or_default()
1211 }
1212}
1213
1214impl ReadArgs for IndexSubtable3<'_> {
1215 type Args = (GlyphId16, GlyphId16);
1216}
1217
1218impl<'a> FontReadWithArgs<'a> for IndexSubtable3<'a> {
1219 fn read_with_args(
1220 data: FontData<'a>,
1221 args: &(GlyphId16, GlyphId16),
1222 ) -> Result<Self, ReadError> {
1223 let (last_glyph_index, first_glyph_index) = *args;
1224
1225 #[allow(clippy::absurd_extreme_comparisons)]
1226 if data.len() < Self::MIN_SIZE {
1227 return Err(ReadError::OutOfBounds);
1228 }
1229 Ok(Self {
1230 data,
1231 last_glyph_index,
1232 first_glyph_index,
1233 })
1234 }
1235}
1236
1237impl<'a> IndexSubtable3<'a> {
1238 pub fn read(
1243 data: FontData<'a>,
1244 last_glyph_index: GlyphId16,
1245 first_glyph_index: GlyphId16,
1246 ) -> Result<Self, ReadError> {
1247 let args = (last_glyph_index, first_glyph_index);
1248 Self::read_with_args(data, &args)
1249 }
1250}
1251
1252#[derive(Clone)]
1254pub struct IndexSubtable3<'a> {
1255 data: FontData<'a>,
1256 last_glyph_index: GlyphId16,
1257 first_glyph_index: GlyphId16,
1258}
1259
1260#[allow(clippy::needless_lifetimes)]
1261impl<'a> IndexSubtable3<'a> {
1262 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
1263 basic_table_impls!(impl_the_methods);
1264
1265 pub fn index_format(&self) -> u16 {
1267 let range = self.index_format_byte_range();
1268 self.data.read_at(range.start).ok().unwrap()
1269 }
1270
1271 pub fn image_format(&self) -> u16 {
1273 let range = self.image_format_byte_range();
1274 self.data.read_at(range.start).ok().unwrap()
1275 }
1276
1277 pub fn image_data_offset(&self) -> u32 {
1279 let range = self.image_data_offset_byte_range();
1280 self.data.read_at(range.start).ok().unwrap()
1281 }
1282
1283 pub fn sbit_offsets(&self) -> &'a [BigEndian<u16>] {
1284 let range = self.sbit_offsets_byte_range();
1285 self.data.read_array(range).ok().unwrap_or_default()
1286 }
1287
1288 pub(crate) fn last_glyph_index(&self) -> GlyphId16 {
1289 self.last_glyph_index
1290 }
1291
1292 pub(crate) fn first_glyph_index(&self) -> GlyphId16 {
1293 self.first_glyph_index
1294 }
1295
1296 pub fn index_format_byte_range(&self) -> Range<usize> {
1297 let start = 0;
1298 start..start + u16::RAW_BYTE_LEN
1299 }
1300
1301 pub fn image_format_byte_range(&self) -> Range<usize> {
1302 let start = self.index_format_byte_range().end;
1303 start..start + u16::RAW_BYTE_LEN
1304 }
1305
1306 pub fn image_data_offset_byte_range(&self) -> Range<usize> {
1307 let start = self.image_format_byte_range().end;
1308 start..start + u32::RAW_BYTE_LEN
1309 }
1310
1311 pub fn sbit_offsets_byte_range(&self) -> Range<usize> {
1312 let last_glyph_index = self.last_glyph_index();
1313 let first_glyph_index = self.first_glyph_index();
1314 let start = self.image_data_offset_byte_range().end;
1315 start
1316 ..start
1317 + (transforms::subtract_add_two(last_glyph_index, first_glyph_index))
1318 .saturating_mul(u16::RAW_BYTE_LEN)
1319 }
1320}
1321
1322#[cfg(feature = "experimental_traverse")]
1323impl<'a> SomeTable<'a> for IndexSubtable3<'a> {
1324 fn type_name(&self) -> &str {
1325 "IndexSubtable3"
1326 }
1327 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1328 match idx {
1329 0usize => Some(Field::new("index_format", self.index_format())),
1330 1usize => Some(Field::new("image_format", self.image_format())),
1331 2usize => Some(Field::new("image_data_offset", self.image_data_offset())),
1332 3usize => Some(Field::new("sbit_offsets", self.sbit_offsets())),
1333 _ => None,
1334 }
1335 }
1336}
1337
1338#[cfg(feature = "experimental_traverse")]
1339#[allow(clippy::needless_lifetimes)]
1340impl<'a> std::fmt::Debug for IndexSubtable3<'a> {
1341 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1342 (self as &dyn SomeTable<'a>).fmt(f)
1343 }
1344}
1345
1346impl Format<u16> for IndexSubtable4<'_> {
1347 const FORMAT: u16 = 4;
1348}
1349
1350impl<'a> MinByteRange<'a> for IndexSubtable4<'a> {
1351 fn min_byte_range(&self) -> Range<usize> {
1352 0..self.glyph_array_byte_range().end
1353 }
1354 fn min_table_bytes(&self) -> &'a [u8] {
1355 let range = self.min_byte_range();
1356 self.data.as_bytes().get(range).unwrap_or_default()
1357 }
1358}
1359
1360impl<'a> FontRead<'a> for IndexSubtable4<'a> {
1361 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1362 #[allow(clippy::absurd_extreme_comparisons)]
1363 if data.len() < Self::MIN_SIZE {
1364 return Err(ReadError::OutOfBounds);
1365 }
1366 Ok(Self { data })
1367 }
1368}
1369
1370#[derive(Clone)]
1372pub struct IndexSubtable4<'a> {
1373 data: FontData<'a>,
1374}
1375
1376#[allow(clippy::needless_lifetimes)]
1377impl<'a> IndexSubtable4<'a> {
1378 pub const MIN_SIZE: usize =
1379 (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
1380 basic_table_impls!(impl_the_methods);
1381
1382 pub fn index_format(&self) -> u16 {
1384 let range = self.index_format_byte_range();
1385 self.data.read_at(range.start).ok().unwrap()
1386 }
1387
1388 pub fn image_format(&self) -> u16 {
1390 let range = self.image_format_byte_range();
1391 self.data.read_at(range.start).ok().unwrap()
1392 }
1393
1394 pub fn image_data_offset(&self) -> u32 {
1396 let range = self.image_data_offset_byte_range();
1397 self.data.read_at(range.start).ok().unwrap()
1398 }
1399
1400 pub fn num_glyphs(&self) -> u32 {
1402 let range = self.num_glyphs_byte_range();
1403 self.data.read_at(range.start).ok().unwrap()
1404 }
1405
1406 pub fn glyph_array(&self) -> &'a [GlyphIdOffsetPair] {
1408 let range = self.glyph_array_byte_range();
1409 self.data.read_array(range).ok().unwrap_or_default()
1410 }
1411
1412 pub fn index_format_byte_range(&self) -> Range<usize> {
1413 let start = 0;
1414 start..start + u16::RAW_BYTE_LEN
1415 }
1416
1417 pub fn image_format_byte_range(&self) -> Range<usize> {
1418 let start = self.index_format_byte_range().end;
1419 start..start + u16::RAW_BYTE_LEN
1420 }
1421
1422 pub fn image_data_offset_byte_range(&self) -> Range<usize> {
1423 let start = self.image_format_byte_range().end;
1424 start..start + u32::RAW_BYTE_LEN
1425 }
1426
1427 pub fn num_glyphs_byte_range(&self) -> Range<usize> {
1428 let start = self.image_data_offset_byte_range().end;
1429 start..start + u32::RAW_BYTE_LEN
1430 }
1431
1432 pub fn glyph_array_byte_range(&self) -> Range<usize> {
1433 let num_glyphs = self.num_glyphs();
1434 let start = self.num_glyphs_byte_range().end;
1435 start
1436 ..start
1437 + (transforms::add(num_glyphs, 1_usize))
1438 .saturating_mul(GlyphIdOffsetPair::RAW_BYTE_LEN)
1439 }
1440}
1441
1442#[cfg(feature = "experimental_traverse")]
1443impl<'a> SomeTable<'a> for IndexSubtable4<'a> {
1444 fn type_name(&self) -> &str {
1445 "IndexSubtable4"
1446 }
1447 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1448 match idx {
1449 0usize => Some(Field::new("index_format", self.index_format())),
1450 1usize => Some(Field::new("image_format", self.image_format())),
1451 2usize => Some(Field::new("image_data_offset", self.image_data_offset())),
1452 3usize => Some(Field::new("num_glyphs", self.num_glyphs())),
1453 4usize => Some(Field::new(
1454 "glyph_array",
1455 traversal::FieldType::array_of_records(
1456 stringify!(GlyphIdOffsetPair),
1457 self.glyph_array(),
1458 self.offset_data(),
1459 ),
1460 )),
1461 _ => None,
1462 }
1463 }
1464}
1465
1466#[cfg(feature = "experimental_traverse")]
1467#[allow(clippy::needless_lifetimes)]
1468impl<'a> std::fmt::Debug for IndexSubtable4<'a> {
1469 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1470 (self as &dyn SomeTable<'a>).fmt(f)
1471 }
1472}
1473
1474#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1476#[repr(C)]
1477#[repr(packed)]
1478pub struct GlyphIdOffsetPair {
1479 pub glyph_id: BigEndian<GlyphId16>,
1481 pub sbit_offset: BigEndian<u16>,
1483}
1484
1485impl GlyphIdOffsetPair {
1486 pub fn glyph_id(&self) -> GlyphId16 {
1488 self.glyph_id.get()
1489 }
1490
1491 pub fn sbit_offset(&self) -> u16 {
1493 self.sbit_offset.get()
1494 }
1495}
1496
1497impl FixedSize for GlyphIdOffsetPair {
1498 const RAW_BYTE_LEN: usize = GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
1499}
1500
1501#[cfg(feature = "experimental_traverse")]
1502impl<'a> SomeRecord<'a> for GlyphIdOffsetPair {
1503 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1504 RecordResolver {
1505 name: "GlyphIdOffsetPair",
1506 get_field: Box::new(move |idx, _data| match idx {
1507 0usize => Some(Field::new("glyph_id", self.glyph_id())),
1508 1usize => Some(Field::new("sbit_offset", self.sbit_offset())),
1509 _ => None,
1510 }),
1511 data,
1512 }
1513 }
1514}
1515
1516impl Format<u16> for IndexSubtable5<'_> {
1517 const FORMAT: u16 = 5;
1518}
1519
1520impl<'a> MinByteRange<'a> for IndexSubtable5<'a> {
1521 fn min_byte_range(&self) -> Range<usize> {
1522 0..self.glyph_array_byte_range().end
1523 }
1524 fn min_table_bytes(&self) -> &'a [u8] {
1525 let range = self.min_byte_range();
1526 self.data.as_bytes().get(range).unwrap_or_default()
1527 }
1528}
1529
1530impl<'a> FontRead<'a> for IndexSubtable5<'a> {
1531 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1532 #[allow(clippy::absurd_extreme_comparisons)]
1533 if data.len() < Self::MIN_SIZE {
1534 return Err(ReadError::OutOfBounds);
1535 }
1536 Ok(Self { data })
1537 }
1538}
1539
1540#[derive(Clone)]
1542pub struct IndexSubtable5<'a> {
1543 data: FontData<'a>,
1544}
1545
1546#[allow(clippy::needless_lifetimes)]
1547impl<'a> IndexSubtable5<'a> {
1548 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1549 + u16::RAW_BYTE_LEN
1550 + u32::RAW_BYTE_LEN
1551 + u32::RAW_BYTE_LEN
1552 + u32::RAW_BYTE_LEN);
1553 basic_table_impls!(impl_the_methods);
1554
1555 pub fn index_format(&self) -> u16 {
1557 let range = self.index_format_byte_range();
1558 self.data.read_at(range.start).ok().unwrap()
1559 }
1560
1561 pub fn image_format(&self) -> u16 {
1563 let range = self.image_format_byte_range();
1564 self.data.read_at(range.start).ok().unwrap()
1565 }
1566
1567 pub fn image_data_offset(&self) -> u32 {
1569 let range = self.image_data_offset_byte_range();
1570 self.data.read_at(range.start).ok().unwrap()
1571 }
1572
1573 pub fn image_size(&self) -> u32 {
1575 let range = self.image_size_byte_range();
1576 self.data.read_at(range.start).ok().unwrap()
1577 }
1578
1579 pub fn big_metrics(&self) -> &'a [BigGlyphMetrics] {
1581 let range = self.big_metrics_byte_range();
1582 self.data.read_array(range).ok().unwrap_or_default()
1583 }
1584
1585 pub fn num_glyphs(&self) -> u32 {
1587 let range = self.num_glyphs_byte_range();
1588 self.data.read_at(range.start).ok().unwrap_or_default()
1589 }
1590
1591 pub fn glyph_array(&self) -> &'a [BigEndian<GlyphId16>] {
1593 let range = self.glyph_array_byte_range();
1594 self.data.read_array(range).ok().unwrap_or_default()
1595 }
1596
1597 pub fn index_format_byte_range(&self) -> Range<usize> {
1598 let start = 0;
1599 start..start + u16::RAW_BYTE_LEN
1600 }
1601
1602 pub fn image_format_byte_range(&self) -> Range<usize> {
1603 let start = self.index_format_byte_range().end;
1604 start..start + u16::RAW_BYTE_LEN
1605 }
1606
1607 pub fn image_data_offset_byte_range(&self) -> Range<usize> {
1608 let start = self.image_format_byte_range().end;
1609 start..start + u32::RAW_BYTE_LEN
1610 }
1611
1612 pub fn image_size_byte_range(&self) -> Range<usize> {
1613 let start = self.image_data_offset_byte_range().end;
1614 start..start + u32::RAW_BYTE_LEN
1615 }
1616
1617 pub fn big_metrics_byte_range(&self) -> Range<usize> {
1618 let start = self.image_size_byte_range().end;
1619 start..start + BigGlyphMetrics::RAW_BYTE_LEN
1620 }
1621
1622 pub fn num_glyphs_byte_range(&self) -> Range<usize> {
1623 let start = self.big_metrics_byte_range().end;
1624 start..start + u32::RAW_BYTE_LEN
1625 }
1626
1627 pub fn glyph_array_byte_range(&self) -> Range<usize> {
1628 let num_glyphs = self.num_glyphs();
1629 let start = self.num_glyphs_byte_range().end;
1630 start..start + (transforms::to_usize(num_glyphs)).saturating_mul(GlyphId16::RAW_BYTE_LEN)
1631 }
1632}
1633
1634#[cfg(feature = "experimental_traverse")]
1635impl<'a> SomeTable<'a> for IndexSubtable5<'a> {
1636 fn type_name(&self) -> &str {
1637 "IndexSubtable5"
1638 }
1639 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1640 match idx {
1641 0usize => Some(Field::new("index_format", self.index_format())),
1642 1usize => Some(Field::new("image_format", self.image_format())),
1643 2usize => Some(Field::new("image_data_offset", self.image_data_offset())),
1644 3usize => Some(Field::new("image_size", self.image_size())),
1645 4usize => Some(Field::new(
1646 "big_metrics",
1647 traversal::FieldType::array_of_records(
1648 stringify!(BigGlyphMetrics),
1649 self.big_metrics(),
1650 self.offset_data(),
1651 ),
1652 )),
1653 5usize => Some(Field::new("num_glyphs", self.num_glyphs())),
1654 6usize => Some(Field::new("glyph_array", self.glyph_array())),
1655 _ => None,
1656 }
1657 }
1658}
1659
1660#[cfg(feature = "experimental_traverse")]
1661#[allow(clippy::needless_lifetimes)]
1662impl<'a> std::fmt::Debug for IndexSubtable5<'a> {
1663 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1664 (self as &dyn SomeTable<'a>).fmt(f)
1665 }
1666}
1667
1668#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1670#[repr(C)]
1671#[repr(packed)]
1672pub struct BdtComponent {
1673 pub glyph_id: BigEndian<GlyphId16>,
1675 pub x_offset: BigEndian<i8>,
1677 pub y_offset: BigEndian<i8>,
1679}
1680
1681impl BdtComponent {
1682 pub fn glyph_id(&self) -> GlyphId16 {
1684 self.glyph_id.get()
1685 }
1686
1687 pub fn x_offset(&self) -> i8 {
1689 self.x_offset.get()
1690 }
1691
1692 pub fn y_offset(&self) -> i8 {
1694 self.y_offset.get()
1695 }
1696}
1697
1698impl FixedSize for BdtComponent {
1699 const RAW_BYTE_LEN: usize = GlyphId16::RAW_BYTE_LEN + i8::RAW_BYTE_LEN + i8::RAW_BYTE_LEN;
1700}
1701
1702#[cfg(feature = "experimental_traverse")]
1703impl<'a> SomeRecord<'a> for BdtComponent {
1704 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1705 RecordResolver {
1706 name: "BdtComponent",
1707 get_field: Box::new(move |idx, _data| match idx {
1708 0usize => Some(Field::new("glyph_id", self.glyph_id())),
1709 1usize => Some(Field::new("x_offset", self.x_offset())),
1710 2usize => Some(Field::new("y_offset", self.y_offset())),
1711 _ => None,
1712 }),
1713 data,
1714 }
1715 }
1716}