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 + (number_of_index_subtables as usize)
810 .saturating_mul(IndexSubtableRecord::RAW_BYTE_LEN)
811 }
812}
813
814#[cfg(feature = "experimental_traverse")]
815impl<'a> SomeTable<'a> for IndexSubtableList<'a> {
816 fn type_name(&self) -> &str {
817 "IndexSubtableList"
818 }
819 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
820 match idx {
821 0usize => Some(Field::new(
822 "index_subtable_records",
823 traversal::FieldType::array_of_records(
824 stringify!(IndexSubtableRecord),
825 self.index_subtable_records(),
826 self.offset_data(),
827 ),
828 )),
829 _ => None,
830 }
831 }
832}
833
834#[cfg(feature = "experimental_traverse")]
835#[allow(clippy::needless_lifetimes)]
836impl<'a> std::fmt::Debug for IndexSubtableList<'a> {
837 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
838 (self as &dyn SomeTable<'a>).fmt(f)
839 }
840}
841
842#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
843#[repr(C)]
844#[repr(packed)]
845pub struct IndexSubtableRecord {
846 pub first_glyph_index: BigEndian<GlyphId16>,
848 pub last_glyph_index: BigEndian<GlyphId16>,
850 pub index_subtable_offset: BigEndian<Offset32>,
852}
853
854impl IndexSubtableRecord {
855 pub fn first_glyph_index(&self) -> GlyphId16 {
857 self.first_glyph_index.get()
858 }
859
860 pub fn last_glyph_index(&self) -> GlyphId16 {
862 self.last_glyph_index.get()
863 }
864
865 pub fn index_subtable_offset(&self) -> Offset32 {
867 self.index_subtable_offset.get()
868 }
869
870 pub fn index_subtable<'a>(&self, data: FontData<'a>) -> Result<IndexSubtable<'a>, ReadError> {
875 let args = (self.last_glyph_index(), self.first_glyph_index());
876 self.index_subtable_offset().resolve_with_args(data, &args)
877 }
878}
879
880impl FixedSize for IndexSubtableRecord {
881 const RAW_BYTE_LEN: usize =
882 GlyphId16::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
883}
884
885#[cfg(feature = "experimental_traverse")]
886impl<'a> SomeRecord<'a> for IndexSubtableRecord {
887 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
888 RecordResolver {
889 name: "IndexSubtableRecord",
890 get_field: Box::new(move |idx, _data| match idx {
891 0usize => Some(Field::new("first_glyph_index", self.first_glyph_index())),
892 1usize => Some(Field::new("last_glyph_index", self.last_glyph_index())),
893 2usize => Some(Field::new(
894 "index_subtable_offset",
895 FieldType::offset(self.index_subtable_offset(), self.index_subtable(_data)),
896 )),
897 _ => None,
898 }),
899 data,
900 }
901 }
902}
903
904impl Format<u16> for IndexSubtable1<'_> {
905 const FORMAT: u16 = 1;
906}
907
908impl<'a> MinByteRange<'a> for IndexSubtable1<'a> {
909 fn min_byte_range(&self) -> Range<usize> {
910 0..self.sbit_offsets_byte_range().end
911 }
912 fn min_table_bytes(&self) -> &'a [u8] {
913 let range = self.min_byte_range();
914 self.data.as_bytes().get(range).unwrap_or_default()
915 }
916}
917
918impl ReadArgs for IndexSubtable1<'_> {
919 type Args = (GlyphId16, GlyphId16);
920}
921
922impl<'a> FontReadWithArgs<'a> for IndexSubtable1<'a> {
923 fn read_with_args(
924 data: FontData<'a>,
925 args: &(GlyphId16, GlyphId16),
926 ) -> Result<Self, ReadError> {
927 let (last_glyph_index, first_glyph_index) = *args;
928
929 #[allow(clippy::absurd_extreme_comparisons)]
930 if data.len() < Self::MIN_SIZE {
931 return Err(ReadError::OutOfBounds);
932 }
933 Ok(Self {
934 data,
935 last_glyph_index,
936 first_glyph_index,
937 })
938 }
939}
940
941impl<'a> IndexSubtable1<'a> {
942 pub fn read(
947 data: FontData<'a>,
948 last_glyph_index: GlyphId16,
949 first_glyph_index: GlyphId16,
950 ) -> Result<Self, ReadError> {
951 let args = (last_glyph_index, first_glyph_index);
952 Self::read_with_args(data, &args)
953 }
954}
955
956#[derive(Clone)]
958pub struct IndexSubtable1<'a> {
959 data: FontData<'a>,
960 last_glyph_index: GlyphId16,
961 first_glyph_index: GlyphId16,
962}
963
964#[allow(clippy::needless_lifetimes)]
965impl<'a> IndexSubtable1<'a> {
966 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
967 basic_table_impls!(impl_the_methods);
968
969 pub fn index_format(&self) -> u16 {
971 let range = self.index_format_byte_range();
972 self.data.read_at(range.start).ok().unwrap()
973 }
974
975 pub fn image_format(&self) -> u16 {
977 let range = self.image_format_byte_range();
978 self.data.read_at(range.start).ok().unwrap()
979 }
980
981 pub fn image_data_offset(&self) -> u32 {
983 let range = self.image_data_offset_byte_range();
984 self.data.read_at(range.start).ok().unwrap()
985 }
986
987 pub fn sbit_offsets(&self) -> &'a [BigEndian<u32>] {
988 let range = self.sbit_offsets_byte_range();
989 self.data.read_array(range).ok().unwrap_or_default()
990 }
991
992 pub(crate) fn last_glyph_index(&self) -> GlyphId16 {
993 self.last_glyph_index
994 }
995
996 pub(crate) fn first_glyph_index(&self) -> GlyphId16 {
997 self.first_glyph_index
998 }
999
1000 pub fn index_format_byte_range(&self) -> Range<usize> {
1001 let start = 0;
1002 start..start + u16::RAW_BYTE_LEN
1003 }
1004
1005 pub fn image_format_byte_range(&self) -> Range<usize> {
1006 let start = self.index_format_byte_range().end;
1007 start..start + u16::RAW_BYTE_LEN
1008 }
1009
1010 pub fn image_data_offset_byte_range(&self) -> Range<usize> {
1011 let start = self.image_format_byte_range().end;
1012 start..start + u32::RAW_BYTE_LEN
1013 }
1014
1015 pub fn sbit_offsets_byte_range(&self) -> Range<usize> {
1016 let last_glyph_index = self.last_glyph_index();
1017 let first_glyph_index = self.first_glyph_index();
1018 let start = self.image_data_offset_byte_range().end;
1019 start
1020 ..start
1021 + (transforms::subtract_add_two(last_glyph_index, first_glyph_index))
1022 .saturating_mul(u32::RAW_BYTE_LEN)
1023 }
1024}
1025
1026#[cfg(feature = "experimental_traverse")]
1027impl<'a> SomeTable<'a> for IndexSubtable1<'a> {
1028 fn type_name(&self) -> &str {
1029 "IndexSubtable1"
1030 }
1031 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1032 match idx {
1033 0usize => Some(Field::new("index_format", self.index_format())),
1034 1usize => Some(Field::new("image_format", self.image_format())),
1035 2usize => Some(Field::new("image_data_offset", self.image_data_offset())),
1036 3usize => Some(Field::new("sbit_offsets", self.sbit_offsets())),
1037 _ => None,
1038 }
1039 }
1040}
1041
1042#[cfg(feature = "experimental_traverse")]
1043#[allow(clippy::needless_lifetimes)]
1044impl<'a> std::fmt::Debug for IndexSubtable1<'a> {
1045 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1046 (self as &dyn SomeTable<'a>).fmt(f)
1047 }
1048}
1049
1050impl Format<u16> for IndexSubtable2<'_> {
1051 const FORMAT: u16 = 2;
1052}
1053
1054impl<'a> MinByteRange<'a> for IndexSubtable2<'a> {
1055 fn min_byte_range(&self) -> Range<usize> {
1056 0..self.big_metrics_byte_range().end
1057 }
1058 fn min_table_bytes(&self) -> &'a [u8] {
1059 let range = self.min_byte_range();
1060 self.data.as_bytes().get(range).unwrap_or_default()
1061 }
1062}
1063
1064impl<'a> FontRead<'a> for IndexSubtable2<'a> {
1065 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1066 #[allow(clippy::absurd_extreme_comparisons)]
1067 if data.len() < Self::MIN_SIZE {
1068 return Err(ReadError::OutOfBounds);
1069 }
1070 Ok(Self { data })
1071 }
1072}
1073
1074#[derive(Clone)]
1076pub struct IndexSubtable2<'a> {
1077 data: FontData<'a>,
1078}
1079
1080#[allow(clippy::needless_lifetimes)]
1081impl<'a> IndexSubtable2<'a> {
1082 pub const MIN_SIZE: usize =
1083 (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
1084 basic_table_impls!(impl_the_methods);
1085
1086 pub fn index_format(&self) -> u16 {
1088 let range = self.index_format_byte_range();
1089 self.data.read_at(range.start).ok().unwrap()
1090 }
1091
1092 pub fn image_format(&self) -> u16 {
1094 let range = self.image_format_byte_range();
1095 self.data.read_at(range.start).ok().unwrap()
1096 }
1097
1098 pub fn image_data_offset(&self) -> u32 {
1100 let range = self.image_data_offset_byte_range();
1101 self.data.read_at(range.start).ok().unwrap()
1102 }
1103
1104 pub fn image_size(&self) -> u32 {
1106 let range = self.image_size_byte_range();
1107 self.data.read_at(range.start).ok().unwrap()
1108 }
1109
1110 pub fn big_metrics(&self) -> &'a [BigGlyphMetrics] {
1112 let range = self.big_metrics_byte_range();
1113 self.data.read_array(range).ok().unwrap_or_default()
1114 }
1115
1116 pub fn index_format_byte_range(&self) -> Range<usize> {
1117 let start = 0;
1118 start..start + u16::RAW_BYTE_LEN
1119 }
1120
1121 pub fn image_format_byte_range(&self) -> Range<usize> {
1122 let start = self.index_format_byte_range().end;
1123 start..start + u16::RAW_BYTE_LEN
1124 }
1125
1126 pub fn image_data_offset_byte_range(&self) -> Range<usize> {
1127 let start = self.image_format_byte_range().end;
1128 start..start + u32::RAW_BYTE_LEN
1129 }
1130
1131 pub fn image_size_byte_range(&self) -> Range<usize> {
1132 let start = self.image_data_offset_byte_range().end;
1133 start..start + u32::RAW_BYTE_LEN
1134 }
1135
1136 pub fn big_metrics_byte_range(&self) -> Range<usize> {
1137 let start = self.image_size_byte_range().end;
1138 start..start + BigGlyphMetrics::RAW_BYTE_LEN
1139 }
1140}
1141
1142#[cfg(feature = "experimental_traverse")]
1143impl<'a> SomeTable<'a> for IndexSubtable2<'a> {
1144 fn type_name(&self) -> &str {
1145 "IndexSubtable2"
1146 }
1147 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1148 match idx {
1149 0usize => Some(Field::new("index_format", self.index_format())),
1150 1usize => Some(Field::new("image_format", self.image_format())),
1151 2usize => Some(Field::new("image_data_offset", self.image_data_offset())),
1152 3usize => Some(Field::new("image_size", self.image_size())),
1153 4usize => Some(Field::new(
1154 "big_metrics",
1155 traversal::FieldType::array_of_records(
1156 stringify!(BigGlyphMetrics),
1157 self.big_metrics(),
1158 self.offset_data(),
1159 ),
1160 )),
1161 _ => None,
1162 }
1163 }
1164}
1165
1166#[cfg(feature = "experimental_traverse")]
1167#[allow(clippy::needless_lifetimes)]
1168impl<'a> std::fmt::Debug for IndexSubtable2<'a> {
1169 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1170 (self as &dyn SomeTable<'a>).fmt(f)
1171 }
1172}
1173
1174impl Format<u16> for IndexSubtable3<'_> {
1175 const FORMAT: u16 = 3;
1176}
1177
1178impl<'a> MinByteRange<'a> for IndexSubtable3<'a> {
1179 fn min_byte_range(&self) -> Range<usize> {
1180 0..self.sbit_offsets_byte_range().end
1181 }
1182 fn min_table_bytes(&self) -> &'a [u8] {
1183 let range = self.min_byte_range();
1184 self.data.as_bytes().get(range).unwrap_or_default()
1185 }
1186}
1187
1188impl ReadArgs for IndexSubtable3<'_> {
1189 type Args = (GlyphId16, GlyphId16);
1190}
1191
1192impl<'a> FontReadWithArgs<'a> for IndexSubtable3<'a> {
1193 fn read_with_args(
1194 data: FontData<'a>,
1195 args: &(GlyphId16, GlyphId16),
1196 ) -> Result<Self, ReadError> {
1197 let (last_glyph_index, first_glyph_index) = *args;
1198
1199 #[allow(clippy::absurd_extreme_comparisons)]
1200 if data.len() < Self::MIN_SIZE {
1201 return Err(ReadError::OutOfBounds);
1202 }
1203 Ok(Self {
1204 data,
1205 last_glyph_index,
1206 first_glyph_index,
1207 })
1208 }
1209}
1210
1211impl<'a> IndexSubtable3<'a> {
1212 pub fn read(
1217 data: FontData<'a>,
1218 last_glyph_index: GlyphId16,
1219 first_glyph_index: GlyphId16,
1220 ) -> Result<Self, ReadError> {
1221 let args = (last_glyph_index, first_glyph_index);
1222 Self::read_with_args(data, &args)
1223 }
1224}
1225
1226#[derive(Clone)]
1228pub struct IndexSubtable3<'a> {
1229 data: FontData<'a>,
1230 last_glyph_index: GlyphId16,
1231 first_glyph_index: GlyphId16,
1232}
1233
1234#[allow(clippy::needless_lifetimes)]
1235impl<'a> IndexSubtable3<'a> {
1236 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
1237 basic_table_impls!(impl_the_methods);
1238
1239 pub fn index_format(&self) -> u16 {
1241 let range = self.index_format_byte_range();
1242 self.data.read_at(range.start).ok().unwrap()
1243 }
1244
1245 pub fn image_format(&self) -> u16 {
1247 let range = self.image_format_byte_range();
1248 self.data.read_at(range.start).ok().unwrap()
1249 }
1250
1251 pub fn image_data_offset(&self) -> u32 {
1253 let range = self.image_data_offset_byte_range();
1254 self.data.read_at(range.start).ok().unwrap()
1255 }
1256
1257 pub fn sbit_offsets(&self) -> &'a [BigEndian<u16>] {
1258 let range = self.sbit_offsets_byte_range();
1259 self.data.read_array(range).ok().unwrap_or_default()
1260 }
1261
1262 pub(crate) fn last_glyph_index(&self) -> GlyphId16 {
1263 self.last_glyph_index
1264 }
1265
1266 pub(crate) fn first_glyph_index(&self) -> GlyphId16 {
1267 self.first_glyph_index
1268 }
1269
1270 pub fn index_format_byte_range(&self) -> Range<usize> {
1271 let start = 0;
1272 start..start + u16::RAW_BYTE_LEN
1273 }
1274
1275 pub fn image_format_byte_range(&self) -> Range<usize> {
1276 let start = self.index_format_byte_range().end;
1277 start..start + u16::RAW_BYTE_LEN
1278 }
1279
1280 pub fn image_data_offset_byte_range(&self) -> Range<usize> {
1281 let start = self.image_format_byte_range().end;
1282 start..start + u32::RAW_BYTE_LEN
1283 }
1284
1285 pub fn sbit_offsets_byte_range(&self) -> Range<usize> {
1286 let last_glyph_index = self.last_glyph_index();
1287 let first_glyph_index = self.first_glyph_index();
1288 let start = self.image_data_offset_byte_range().end;
1289 start
1290 ..start
1291 + (transforms::subtract_add_two(last_glyph_index, first_glyph_index))
1292 .saturating_mul(u16::RAW_BYTE_LEN)
1293 }
1294}
1295
1296#[cfg(feature = "experimental_traverse")]
1297impl<'a> SomeTable<'a> for IndexSubtable3<'a> {
1298 fn type_name(&self) -> &str {
1299 "IndexSubtable3"
1300 }
1301 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1302 match idx {
1303 0usize => Some(Field::new("index_format", self.index_format())),
1304 1usize => Some(Field::new("image_format", self.image_format())),
1305 2usize => Some(Field::new("image_data_offset", self.image_data_offset())),
1306 3usize => Some(Field::new("sbit_offsets", self.sbit_offsets())),
1307 _ => None,
1308 }
1309 }
1310}
1311
1312#[cfg(feature = "experimental_traverse")]
1313#[allow(clippy::needless_lifetimes)]
1314impl<'a> std::fmt::Debug for IndexSubtable3<'a> {
1315 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1316 (self as &dyn SomeTable<'a>).fmt(f)
1317 }
1318}
1319
1320impl Format<u16> for IndexSubtable4<'_> {
1321 const FORMAT: u16 = 4;
1322}
1323
1324impl<'a> MinByteRange<'a> for IndexSubtable4<'a> {
1325 fn min_byte_range(&self) -> Range<usize> {
1326 0..self.glyph_array_byte_range().end
1327 }
1328 fn min_table_bytes(&self) -> &'a [u8] {
1329 let range = self.min_byte_range();
1330 self.data.as_bytes().get(range).unwrap_or_default()
1331 }
1332}
1333
1334impl<'a> FontRead<'a> for IndexSubtable4<'a> {
1335 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1336 #[allow(clippy::absurd_extreme_comparisons)]
1337 if data.len() < Self::MIN_SIZE {
1338 return Err(ReadError::OutOfBounds);
1339 }
1340 Ok(Self { data })
1341 }
1342}
1343
1344#[derive(Clone)]
1346pub struct IndexSubtable4<'a> {
1347 data: FontData<'a>,
1348}
1349
1350#[allow(clippy::needless_lifetimes)]
1351impl<'a> IndexSubtable4<'a> {
1352 pub const MIN_SIZE: usize =
1353 (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
1354 basic_table_impls!(impl_the_methods);
1355
1356 pub fn index_format(&self) -> u16 {
1358 let range = self.index_format_byte_range();
1359 self.data.read_at(range.start).ok().unwrap()
1360 }
1361
1362 pub fn image_format(&self) -> u16 {
1364 let range = self.image_format_byte_range();
1365 self.data.read_at(range.start).ok().unwrap()
1366 }
1367
1368 pub fn image_data_offset(&self) -> u32 {
1370 let range = self.image_data_offset_byte_range();
1371 self.data.read_at(range.start).ok().unwrap()
1372 }
1373
1374 pub fn num_glyphs(&self) -> u32 {
1376 let range = self.num_glyphs_byte_range();
1377 self.data.read_at(range.start).ok().unwrap()
1378 }
1379
1380 pub fn glyph_array(&self) -> &'a [GlyphIdOffsetPair] {
1382 let range = self.glyph_array_byte_range();
1383 self.data.read_array(range).ok().unwrap_or_default()
1384 }
1385
1386 pub fn index_format_byte_range(&self) -> Range<usize> {
1387 let start = 0;
1388 start..start + u16::RAW_BYTE_LEN
1389 }
1390
1391 pub fn image_format_byte_range(&self) -> Range<usize> {
1392 let start = self.index_format_byte_range().end;
1393 start..start + u16::RAW_BYTE_LEN
1394 }
1395
1396 pub fn image_data_offset_byte_range(&self) -> Range<usize> {
1397 let start = self.image_format_byte_range().end;
1398 start..start + u32::RAW_BYTE_LEN
1399 }
1400
1401 pub fn num_glyphs_byte_range(&self) -> Range<usize> {
1402 let start = self.image_data_offset_byte_range().end;
1403 start..start + u32::RAW_BYTE_LEN
1404 }
1405
1406 pub fn glyph_array_byte_range(&self) -> Range<usize> {
1407 let num_glyphs = self.num_glyphs();
1408 let start = self.num_glyphs_byte_range().end;
1409 start
1410 ..start
1411 + (transforms::add(num_glyphs, 1_usize))
1412 .saturating_mul(GlyphIdOffsetPair::RAW_BYTE_LEN)
1413 }
1414}
1415
1416#[cfg(feature = "experimental_traverse")]
1417impl<'a> SomeTable<'a> for IndexSubtable4<'a> {
1418 fn type_name(&self) -> &str {
1419 "IndexSubtable4"
1420 }
1421 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1422 match idx {
1423 0usize => Some(Field::new("index_format", self.index_format())),
1424 1usize => Some(Field::new("image_format", self.image_format())),
1425 2usize => Some(Field::new("image_data_offset", self.image_data_offset())),
1426 3usize => Some(Field::new("num_glyphs", self.num_glyphs())),
1427 4usize => Some(Field::new(
1428 "glyph_array",
1429 traversal::FieldType::array_of_records(
1430 stringify!(GlyphIdOffsetPair),
1431 self.glyph_array(),
1432 self.offset_data(),
1433 ),
1434 )),
1435 _ => None,
1436 }
1437 }
1438}
1439
1440#[cfg(feature = "experimental_traverse")]
1441#[allow(clippy::needless_lifetimes)]
1442impl<'a> std::fmt::Debug for IndexSubtable4<'a> {
1443 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1444 (self as &dyn SomeTable<'a>).fmt(f)
1445 }
1446}
1447
1448#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1450#[repr(C)]
1451#[repr(packed)]
1452pub struct GlyphIdOffsetPair {
1453 pub glyph_id: BigEndian<GlyphId16>,
1455 pub sbit_offset: BigEndian<u16>,
1457}
1458
1459impl GlyphIdOffsetPair {
1460 pub fn glyph_id(&self) -> GlyphId16 {
1462 self.glyph_id.get()
1463 }
1464
1465 pub fn sbit_offset(&self) -> u16 {
1467 self.sbit_offset.get()
1468 }
1469}
1470
1471impl FixedSize for GlyphIdOffsetPair {
1472 const RAW_BYTE_LEN: usize = GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
1473}
1474
1475#[cfg(feature = "experimental_traverse")]
1476impl<'a> SomeRecord<'a> for GlyphIdOffsetPair {
1477 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1478 RecordResolver {
1479 name: "GlyphIdOffsetPair",
1480 get_field: Box::new(move |idx, _data| match idx {
1481 0usize => Some(Field::new("glyph_id", self.glyph_id())),
1482 1usize => Some(Field::new("sbit_offset", self.sbit_offset())),
1483 _ => None,
1484 }),
1485 data,
1486 }
1487 }
1488}
1489
1490impl Format<u16> for IndexSubtable5<'_> {
1491 const FORMAT: u16 = 5;
1492}
1493
1494impl<'a> MinByteRange<'a> for IndexSubtable5<'a> {
1495 fn min_byte_range(&self) -> Range<usize> {
1496 0..self.glyph_array_byte_range().end
1497 }
1498 fn min_table_bytes(&self) -> &'a [u8] {
1499 let range = self.min_byte_range();
1500 self.data.as_bytes().get(range).unwrap_or_default()
1501 }
1502}
1503
1504impl<'a> FontRead<'a> for IndexSubtable5<'a> {
1505 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1506 #[allow(clippy::absurd_extreme_comparisons)]
1507 if data.len() < Self::MIN_SIZE {
1508 return Err(ReadError::OutOfBounds);
1509 }
1510 Ok(Self { data })
1511 }
1512}
1513
1514#[derive(Clone)]
1516pub struct IndexSubtable5<'a> {
1517 data: FontData<'a>,
1518}
1519
1520#[allow(clippy::needless_lifetimes)]
1521impl<'a> IndexSubtable5<'a> {
1522 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1523 + u16::RAW_BYTE_LEN
1524 + u32::RAW_BYTE_LEN
1525 + u32::RAW_BYTE_LEN
1526 + u32::RAW_BYTE_LEN);
1527 basic_table_impls!(impl_the_methods);
1528
1529 pub fn index_format(&self) -> u16 {
1531 let range = self.index_format_byte_range();
1532 self.data.read_at(range.start).ok().unwrap()
1533 }
1534
1535 pub fn image_format(&self) -> u16 {
1537 let range = self.image_format_byte_range();
1538 self.data.read_at(range.start).ok().unwrap()
1539 }
1540
1541 pub fn image_data_offset(&self) -> u32 {
1543 let range = self.image_data_offset_byte_range();
1544 self.data.read_at(range.start).ok().unwrap()
1545 }
1546
1547 pub fn image_size(&self) -> u32 {
1549 let range = self.image_size_byte_range();
1550 self.data.read_at(range.start).ok().unwrap()
1551 }
1552
1553 pub fn big_metrics(&self) -> &'a [BigGlyphMetrics] {
1555 let range = self.big_metrics_byte_range();
1556 self.data.read_array(range).ok().unwrap_or_default()
1557 }
1558
1559 pub fn num_glyphs(&self) -> u32 {
1561 let range = self.num_glyphs_byte_range();
1562 self.data.read_at(range.start).ok().unwrap_or_default()
1563 }
1564
1565 pub fn glyph_array(&self) -> &'a [BigEndian<GlyphId16>] {
1567 let range = self.glyph_array_byte_range();
1568 self.data.read_array(range).ok().unwrap_or_default()
1569 }
1570
1571 pub fn index_format_byte_range(&self) -> Range<usize> {
1572 let start = 0;
1573 start..start + u16::RAW_BYTE_LEN
1574 }
1575
1576 pub fn image_format_byte_range(&self) -> Range<usize> {
1577 let start = self.index_format_byte_range().end;
1578 start..start + u16::RAW_BYTE_LEN
1579 }
1580
1581 pub fn image_data_offset_byte_range(&self) -> Range<usize> {
1582 let start = self.image_format_byte_range().end;
1583 start..start + u32::RAW_BYTE_LEN
1584 }
1585
1586 pub fn image_size_byte_range(&self) -> Range<usize> {
1587 let start = self.image_data_offset_byte_range().end;
1588 start..start + u32::RAW_BYTE_LEN
1589 }
1590
1591 pub fn big_metrics_byte_range(&self) -> Range<usize> {
1592 let start = self.image_size_byte_range().end;
1593 start..start + BigGlyphMetrics::RAW_BYTE_LEN
1594 }
1595
1596 pub fn num_glyphs_byte_range(&self) -> Range<usize> {
1597 let start = self.big_metrics_byte_range().end;
1598 start..start + u32::RAW_BYTE_LEN
1599 }
1600
1601 pub fn glyph_array_byte_range(&self) -> Range<usize> {
1602 let num_glyphs = self.num_glyphs();
1603 let start = self.num_glyphs_byte_range().end;
1604 start..start + (num_glyphs as usize).saturating_mul(GlyphId16::RAW_BYTE_LEN)
1605 }
1606}
1607
1608#[cfg(feature = "experimental_traverse")]
1609impl<'a> SomeTable<'a> for IndexSubtable5<'a> {
1610 fn type_name(&self) -> &str {
1611 "IndexSubtable5"
1612 }
1613 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1614 match idx {
1615 0usize => Some(Field::new("index_format", self.index_format())),
1616 1usize => Some(Field::new("image_format", self.image_format())),
1617 2usize => Some(Field::new("image_data_offset", self.image_data_offset())),
1618 3usize => Some(Field::new("image_size", self.image_size())),
1619 4usize => Some(Field::new(
1620 "big_metrics",
1621 traversal::FieldType::array_of_records(
1622 stringify!(BigGlyphMetrics),
1623 self.big_metrics(),
1624 self.offset_data(),
1625 ),
1626 )),
1627 5usize => Some(Field::new("num_glyphs", self.num_glyphs())),
1628 6usize => Some(Field::new("glyph_array", self.glyph_array())),
1629 _ => None,
1630 }
1631 }
1632}
1633
1634#[cfg(feature = "experimental_traverse")]
1635#[allow(clippy::needless_lifetimes)]
1636impl<'a> std::fmt::Debug for IndexSubtable5<'a> {
1637 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1638 (self as &dyn SomeTable<'a>).fmt(f)
1639 }
1640}
1641
1642#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1644#[repr(C)]
1645#[repr(packed)]
1646pub struct BdtComponent {
1647 pub glyph_id: BigEndian<GlyphId16>,
1649 pub x_offset: BigEndian<i8>,
1651 pub y_offset: BigEndian<i8>,
1653}
1654
1655impl BdtComponent {
1656 pub fn glyph_id(&self) -> GlyphId16 {
1658 self.glyph_id.get()
1659 }
1660
1661 pub fn x_offset(&self) -> i8 {
1663 self.x_offset.get()
1664 }
1665
1666 pub fn y_offset(&self) -> i8 {
1668 self.y_offset.get()
1669 }
1670}
1671
1672impl FixedSize for BdtComponent {
1673 const RAW_BYTE_LEN: usize = GlyphId16::RAW_BYTE_LEN + i8::RAW_BYTE_LEN + i8::RAW_BYTE_LEN;
1674}
1675
1676#[cfg(feature = "experimental_traverse")]
1677impl<'a> SomeRecord<'a> for BdtComponent {
1678 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1679 RecordResolver {
1680 name: "BdtComponent",
1681 get_field: Box::new(move |idx, _data| match idx {
1682 0usize => Some(Field::new("glyph_id", self.glyph_id())),
1683 1usize => Some(Field::new("x_offset", self.x_offset())),
1684 2usize => Some(Field::new("y_offset", self.y_offset())),
1685 _ => None,
1686 }),
1687 data,
1688 }
1689 }
1690}