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> FontRead<'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 let end = start
808 + (transforms::to_usize(number_of_index_subtables))
809 .saturating_mul(IndexSubtableRecord::RAW_BYTE_LEN);
810 start..end
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> FontRead<'a> for IndexSubtable1<'a> {
937 fn read_with_args(data: FontData<'a>, args: (GlyphId16, GlyphId16)) -> Result<Self, ReadError> {
938 let (last_glyph_index, first_glyph_index) = args;
939
940 #[allow(clippy::absurd_extreme_comparisons)]
941 if data.len() < Self::MIN_SIZE {
942 return Err(ReadError::OutOfBounds);
943 }
944 Ok(Self {
945 data,
946 last_glyph_index,
947 first_glyph_index,
948 })
949 }
950}
951
952impl<'a> IndexSubtable1<'a> {
953 pub fn read(
958 data: FontData<'a>,
959 last_glyph_index: GlyphId16,
960 first_glyph_index: GlyphId16,
961 ) -> Result<Self, ReadError> {
962 let args = (last_glyph_index, first_glyph_index);
963 Self::read_with_args(data, args)
964 }
965}
966
967#[derive(Clone)]
969pub struct IndexSubtable1<'a> {
970 data: FontData<'a>,
971 last_glyph_index: GlyphId16,
972 first_glyph_index: GlyphId16,
973}
974
975#[allow(clippy::needless_lifetimes)]
976impl<'a> IndexSubtable1<'a> {
977 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
978 basic_table_impls!(impl_the_methods);
979
980 pub fn index_format(&self) -> u16 {
982 let range = self.index_format_byte_range();
983 self.data.read_at(range.start).ok().unwrap()
984 }
985
986 pub fn image_format(&self) -> u16 {
988 let range = self.image_format_byte_range();
989 self.data.read_at(range.start).ok().unwrap()
990 }
991
992 pub fn image_data_offset(&self) -> u32 {
994 let range = self.image_data_offset_byte_range();
995 self.data.read_at(range.start).ok().unwrap()
996 }
997
998 pub fn sbit_offsets(&self) -> &'a [BigEndian<u32>] {
999 let range = self.sbit_offsets_byte_range();
1000 self.data.read_array(range).ok().unwrap_or_default()
1001 }
1002
1003 pub(crate) fn last_glyph_index(&self) -> GlyphId16 {
1004 self.last_glyph_index
1005 }
1006
1007 pub(crate) fn first_glyph_index(&self) -> GlyphId16 {
1008 self.first_glyph_index
1009 }
1010
1011 pub fn index_format_byte_range(&self) -> Range<usize> {
1012 let start = 0;
1013 let end = start + u16::RAW_BYTE_LEN;
1014 start..end
1015 }
1016
1017 pub fn image_format_byte_range(&self) -> Range<usize> {
1018 let start = self.index_format_byte_range().end;
1019 let end = start + u16::RAW_BYTE_LEN;
1020 start..end
1021 }
1022
1023 pub fn image_data_offset_byte_range(&self) -> Range<usize> {
1024 let start = self.image_format_byte_range().end;
1025 let end = start + u32::RAW_BYTE_LEN;
1026 start..end
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 let end = start
1034 + (transforms::subtract_add_two(last_glyph_index, first_glyph_index))
1035 .saturating_mul(u32::RAW_BYTE_LEN);
1036 start..end
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 ReadArgs for IndexSubtable2<'_> {
1091 type Args = ();
1092}
1093
1094impl<'a> FontRead<'a> for IndexSubtable2<'a> {
1095 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1096 #[allow(clippy::absurd_extreme_comparisons)]
1097 if data.len() < Self::MIN_SIZE {
1098 return Err(ReadError::OutOfBounds);
1099 }
1100 Ok(Self { data })
1101 }
1102}
1103
1104#[derive(Clone)]
1106pub struct IndexSubtable2<'a> {
1107 data: FontData<'a>,
1108}
1109
1110#[allow(clippy::needless_lifetimes)]
1111impl<'a> IndexSubtable2<'a> {
1112 pub const MIN_SIZE: usize =
1113 (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
1114 basic_table_impls!(impl_the_methods);
1115
1116 pub fn index_format(&self) -> u16 {
1118 let range = self.index_format_byte_range();
1119 self.data.read_at(range.start).ok().unwrap()
1120 }
1121
1122 pub fn image_format(&self) -> u16 {
1124 let range = self.image_format_byte_range();
1125 self.data.read_at(range.start).ok().unwrap()
1126 }
1127
1128 pub fn image_data_offset(&self) -> u32 {
1130 let range = self.image_data_offset_byte_range();
1131 self.data.read_at(range.start).ok().unwrap()
1132 }
1133
1134 pub fn image_size(&self) -> u32 {
1136 let range = self.image_size_byte_range();
1137 self.data.read_at(range.start).ok().unwrap()
1138 }
1139
1140 pub fn big_metrics(&self) -> &'a [BigGlyphMetrics] {
1142 let range = self.big_metrics_byte_range();
1143 self.data.read_array(range).ok().unwrap_or_default()
1144 }
1145
1146 pub fn index_format_byte_range(&self) -> Range<usize> {
1147 let start = 0;
1148 let end = start + u16::RAW_BYTE_LEN;
1149 start..end
1150 }
1151
1152 pub fn image_format_byte_range(&self) -> Range<usize> {
1153 let start = self.index_format_byte_range().end;
1154 let end = start + u16::RAW_BYTE_LEN;
1155 start..end
1156 }
1157
1158 pub fn image_data_offset_byte_range(&self) -> Range<usize> {
1159 let start = self.image_format_byte_range().end;
1160 let end = start + u32::RAW_BYTE_LEN;
1161 start..end
1162 }
1163
1164 pub fn image_size_byte_range(&self) -> Range<usize> {
1165 let start = self.image_data_offset_byte_range().end;
1166 let end = start + u32::RAW_BYTE_LEN;
1167 start..end
1168 }
1169
1170 pub fn big_metrics_byte_range(&self) -> Range<usize> {
1171 let start = self.image_size_byte_range().end;
1172 let end = start + BigGlyphMetrics::RAW_BYTE_LEN;
1173 start..end
1174 }
1175}
1176
1177#[cfg(feature = "experimental_traverse")]
1178impl<'a> SomeTable<'a> for IndexSubtable2<'a> {
1179 fn type_name(&self) -> &str {
1180 "IndexSubtable2"
1181 }
1182 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1183 match idx {
1184 0usize => Some(Field::new("index_format", self.index_format())),
1185 1usize => Some(Field::new("image_format", self.image_format())),
1186 2usize => Some(Field::new("image_data_offset", self.image_data_offset())),
1187 3usize => Some(Field::new("image_size", self.image_size())),
1188 4usize => Some(Field::new(
1189 "big_metrics",
1190 traversal::FieldType::array_of_records(
1191 stringify!(BigGlyphMetrics),
1192 self.big_metrics(),
1193 self.offset_data(),
1194 ),
1195 )),
1196 _ => None,
1197 }
1198 }
1199}
1200
1201#[cfg(feature = "experimental_traverse")]
1202#[allow(clippy::needless_lifetimes)]
1203impl<'a> std::fmt::Debug for IndexSubtable2<'a> {
1204 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1205 (self as &dyn SomeTable<'a>).fmt(f)
1206 }
1207}
1208
1209impl Format<u16> for IndexSubtable3<'_> {
1210 const FORMAT: u16 = 3;
1211}
1212
1213impl<'a> MinByteRange<'a> for IndexSubtable3<'a> {
1214 fn min_byte_range(&self) -> Range<usize> {
1215 0..self.sbit_offsets_byte_range().end
1216 }
1217 fn min_table_bytes(&self) -> &'a [u8] {
1218 let range = self.min_byte_range();
1219 self.data.as_bytes().get(range).unwrap_or_default()
1220 }
1221}
1222
1223impl ReadArgs for IndexSubtable3<'_> {
1224 type Args = (GlyphId16, GlyphId16);
1225}
1226
1227impl<'a> FontRead<'a> for IndexSubtable3<'a> {
1228 fn read_with_args(data: FontData<'a>, args: (GlyphId16, GlyphId16)) -> Result<Self, ReadError> {
1229 let (last_glyph_index, first_glyph_index) = args;
1230
1231 #[allow(clippy::absurd_extreme_comparisons)]
1232 if data.len() < Self::MIN_SIZE {
1233 return Err(ReadError::OutOfBounds);
1234 }
1235 Ok(Self {
1236 data,
1237 last_glyph_index,
1238 first_glyph_index,
1239 })
1240 }
1241}
1242
1243impl<'a> IndexSubtable3<'a> {
1244 pub fn read(
1249 data: FontData<'a>,
1250 last_glyph_index: GlyphId16,
1251 first_glyph_index: GlyphId16,
1252 ) -> Result<Self, ReadError> {
1253 let args = (last_glyph_index, first_glyph_index);
1254 Self::read_with_args(data, args)
1255 }
1256}
1257
1258#[derive(Clone)]
1260pub struct IndexSubtable3<'a> {
1261 data: FontData<'a>,
1262 last_glyph_index: GlyphId16,
1263 first_glyph_index: GlyphId16,
1264}
1265
1266#[allow(clippy::needless_lifetimes)]
1267impl<'a> IndexSubtable3<'a> {
1268 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
1269 basic_table_impls!(impl_the_methods);
1270
1271 pub fn index_format(&self) -> u16 {
1273 let range = self.index_format_byte_range();
1274 self.data.read_at(range.start).ok().unwrap()
1275 }
1276
1277 pub fn image_format(&self) -> u16 {
1279 let range = self.image_format_byte_range();
1280 self.data.read_at(range.start).ok().unwrap()
1281 }
1282
1283 pub fn image_data_offset(&self) -> u32 {
1285 let range = self.image_data_offset_byte_range();
1286 self.data.read_at(range.start).ok().unwrap()
1287 }
1288
1289 pub fn sbit_offsets(&self) -> &'a [BigEndian<u16>] {
1290 let range = self.sbit_offsets_byte_range();
1291 self.data.read_array(range).ok().unwrap_or_default()
1292 }
1293
1294 pub(crate) fn last_glyph_index(&self) -> GlyphId16 {
1295 self.last_glyph_index
1296 }
1297
1298 pub(crate) fn first_glyph_index(&self) -> GlyphId16 {
1299 self.first_glyph_index
1300 }
1301
1302 pub fn index_format_byte_range(&self) -> Range<usize> {
1303 let start = 0;
1304 let end = start + u16::RAW_BYTE_LEN;
1305 start..end
1306 }
1307
1308 pub fn image_format_byte_range(&self) -> Range<usize> {
1309 let start = self.index_format_byte_range().end;
1310 let end = start + u16::RAW_BYTE_LEN;
1311 start..end
1312 }
1313
1314 pub fn image_data_offset_byte_range(&self) -> Range<usize> {
1315 let start = self.image_format_byte_range().end;
1316 let end = start + u32::RAW_BYTE_LEN;
1317 start..end
1318 }
1319
1320 pub fn sbit_offsets_byte_range(&self) -> Range<usize> {
1321 let last_glyph_index = self.last_glyph_index();
1322 let first_glyph_index = self.first_glyph_index();
1323 let start = self.image_data_offset_byte_range().end;
1324 let end = start
1325 + (transforms::subtract_add_two(last_glyph_index, first_glyph_index))
1326 .saturating_mul(u16::RAW_BYTE_LEN);
1327 start..end
1328 }
1329}
1330
1331#[cfg(feature = "experimental_traverse")]
1332impl<'a> SomeTable<'a> for IndexSubtable3<'a> {
1333 fn type_name(&self) -> &str {
1334 "IndexSubtable3"
1335 }
1336 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1337 match idx {
1338 0usize => Some(Field::new("index_format", self.index_format())),
1339 1usize => Some(Field::new("image_format", self.image_format())),
1340 2usize => Some(Field::new("image_data_offset", self.image_data_offset())),
1341 3usize => Some(Field::new("sbit_offsets", self.sbit_offsets())),
1342 _ => None,
1343 }
1344 }
1345}
1346
1347#[cfg(feature = "experimental_traverse")]
1348#[allow(clippy::needless_lifetimes)]
1349impl<'a> std::fmt::Debug for IndexSubtable3<'a> {
1350 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1351 (self as &dyn SomeTable<'a>).fmt(f)
1352 }
1353}
1354
1355impl Format<u16> for IndexSubtable4<'_> {
1356 const FORMAT: u16 = 4;
1357}
1358
1359impl<'a> MinByteRange<'a> for IndexSubtable4<'a> {
1360 fn min_byte_range(&self) -> Range<usize> {
1361 0..self.glyph_array_byte_range().end
1362 }
1363 fn min_table_bytes(&self) -> &'a [u8] {
1364 let range = self.min_byte_range();
1365 self.data.as_bytes().get(range).unwrap_or_default()
1366 }
1367}
1368
1369impl ReadArgs for IndexSubtable4<'_> {
1370 type Args = ();
1371}
1372
1373impl<'a> FontRead<'a> for IndexSubtable4<'a> {
1374 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1375 #[allow(clippy::absurd_extreme_comparisons)]
1376 if data.len() < Self::MIN_SIZE {
1377 return Err(ReadError::OutOfBounds);
1378 }
1379 Ok(Self { data })
1380 }
1381}
1382
1383#[derive(Clone)]
1385pub struct IndexSubtable4<'a> {
1386 data: FontData<'a>,
1387}
1388
1389#[allow(clippy::needless_lifetimes)]
1390impl<'a> IndexSubtable4<'a> {
1391 pub const MIN_SIZE: usize =
1392 (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
1393 basic_table_impls!(impl_the_methods);
1394
1395 pub fn index_format(&self) -> u16 {
1397 let range = self.index_format_byte_range();
1398 self.data.read_at(range.start).ok().unwrap()
1399 }
1400
1401 pub fn image_format(&self) -> u16 {
1403 let range = self.image_format_byte_range();
1404 self.data.read_at(range.start).ok().unwrap()
1405 }
1406
1407 pub fn image_data_offset(&self) -> u32 {
1409 let range = self.image_data_offset_byte_range();
1410 self.data.read_at(range.start).ok().unwrap()
1411 }
1412
1413 pub fn num_glyphs(&self) -> u32 {
1415 let range = self.num_glyphs_byte_range();
1416 self.data.read_at(range.start).ok().unwrap()
1417 }
1418
1419 pub fn glyph_array(&self) -> &'a [GlyphIdOffsetPair] {
1421 let range = self.glyph_array_byte_range();
1422 self.data.read_array(range).ok().unwrap_or_default()
1423 }
1424
1425 pub fn index_format_byte_range(&self) -> Range<usize> {
1426 let start = 0;
1427 let end = start + u16::RAW_BYTE_LEN;
1428 start..end
1429 }
1430
1431 pub fn image_format_byte_range(&self) -> Range<usize> {
1432 let start = self.index_format_byte_range().end;
1433 let end = start + u16::RAW_BYTE_LEN;
1434 start..end
1435 }
1436
1437 pub fn image_data_offset_byte_range(&self) -> Range<usize> {
1438 let start = self.image_format_byte_range().end;
1439 let end = start + u32::RAW_BYTE_LEN;
1440 start..end
1441 }
1442
1443 pub fn num_glyphs_byte_range(&self) -> Range<usize> {
1444 let start = self.image_data_offset_byte_range().end;
1445 let end = start + u32::RAW_BYTE_LEN;
1446 start..end
1447 }
1448
1449 pub fn glyph_array_byte_range(&self) -> Range<usize> {
1450 let num_glyphs = self.num_glyphs();
1451 let start = self.num_glyphs_byte_range().end;
1452 let end = start
1453 + (transforms::add(num_glyphs, 1_usize))
1454 .saturating_mul(GlyphIdOffsetPair::RAW_BYTE_LEN);
1455 start..end
1456 }
1457}
1458
1459#[cfg(feature = "experimental_traverse")]
1460impl<'a> SomeTable<'a> for IndexSubtable4<'a> {
1461 fn type_name(&self) -> &str {
1462 "IndexSubtable4"
1463 }
1464 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1465 match idx {
1466 0usize => Some(Field::new("index_format", self.index_format())),
1467 1usize => Some(Field::new("image_format", self.image_format())),
1468 2usize => Some(Field::new("image_data_offset", self.image_data_offset())),
1469 3usize => Some(Field::new("num_glyphs", self.num_glyphs())),
1470 4usize => Some(Field::new(
1471 "glyph_array",
1472 traversal::FieldType::array_of_records(
1473 stringify!(GlyphIdOffsetPair),
1474 self.glyph_array(),
1475 self.offset_data(),
1476 ),
1477 )),
1478 _ => None,
1479 }
1480 }
1481}
1482
1483#[cfg(feature = "experimental_traverse")]
1484#[allow(clippy::needless_lifetimes)]
1485impl<'a> std::fmt::Debug for IndexSubtable4<'a> {
1486 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1487 (self as &dyn SomeTable<'a>).fmt(f)
1488 }
1489}
1490
1491#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1493#[repr(C)]
1494#[repr(packed)]
1495pub struct GlyphIdOffsetPair {
1496 pub glyph_id: BigEndian<GlyphId16>,
1498 pub sbit_offset: BigEndian<u16>,
1500}
1501
1502impl GlyphIdOffsetPair {
1503 pub fn glyph_id(&self) -> GlyphId16 {
1505 self.glyph_id.get()
1506 }
1507
1508 pub fn sbit_offset(&self) -> u16 {
1510 self.sbit_offset.get()
1511 }
1512}
1513
1514impl FixedSize for GlyphIdOffsetPair {
1515 const RAW_BYTE_LEN: usize = GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
1516}
1517
1518#[cfg(feature = "experimental_traverse")]
1519impl<'a> SomeRecord<'a> for GlyphIdOffsetPair {
1520 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1521 RecordResolver {
1522 name: "GlyphIdOffsetPair",
1523 get_field: Box::new(move |idx, _data| match idx {
1524 0usize => Some(Field::new("glyph_id", self.glyph_id())),
1525 1usize => Some(Field::new("sbit_offset", self.sbit_offset())),
1526 _ => None,
1527 }),
1528 data,
1529 }
1530 }
1531}
1532
1533impl Format<u16> for IndexSubtable5<'_> {
1534 const FORMAT: u16 = 5;
1535}
1536
1537impl<'a> MinByteRange<'a> for IndexSubtable5<'a> {
1538 fn min_byte_range(&self) -> Range<usize> {
1539 0..self.glyph_array_byte_range().end
1540 }
1541 fn min_table_bytes(&self) -> &'a [u8] {
1542 let range = self.min_byte_range();
1543 self.data.as_bytes().get(range).unwrap_or_default()
1544 }
1545}
1546
1547impl ReadArgs for IndexSubtable5<'_> {
1548 type Args = ();
1549}
1550
1551impl<'a> FontRead<'a> for IndexSubtable5<'a> {
1552 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1553 #[allow(clippy::absurd_extreme_comparisons)]
1554 if data.len() < Self::MIN_SIZE {
1555 return Err(ReadError::OutOfBounds);
1556 }
1557 Ok(Self { data })
1558 }
1559}
1560
1561#[derive(Clone)]
1563pub struct IndexSubtable5<'a> {
1564 data: FontData<'a>,
1565}
1566
1567#[allow(clippy::needless_lifetimes)]
1568impl<'a> IndexSubtable5<'a> {
1569 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1570 + u16::RAW_BYTE_LEN
1571 + u32::RAW_BYTE_LEN
1572 + u32::RAW_BYTE_LEN
1573 + u32::RAW_BYTE_LEN);
1574 basic_table_impls!(impl_the_methods);
1575
1576 pub fn index_format(&self) -> u16 {
1578 let range = self.index_format_byte_range();
1579 self.data.read_at(range.start).ok().unwrap()
1580 }
1581
1582 pub fn image_format(&self) -> u16 {
1584 let range = self.image_format_byte_range();
1585 self.data.read_at(range.start).ok().unwrap()
1586 }
1587
1588 pub fn image_data_offset(&self) -> u32 {
1590 let range = self.image_data_offset_byte_range();
1591 self.data.read_at(range.start).ok().unwrap()
1592 }
1593
1594 pub fn image_size(&self) -> u32 {
1596 let range = self.image_size_byte_range();
1597 self.data.read_at(range.start).ok().unwrap()
1598 }
1599
1600 pub fn big_metrics(&self) -> &'a [BigGlyphMetrics] {
1602 let range = self.big_metrics_byte_range();
1603 self.data.read_array(range).ok().unwrap_or_default()
1604 }
1605
1606 pub fn num_glyphs(&self) -> u32 {
1608 let range = self.num_glyphs_byte_range();
1609 self.data.read_at(range.start).ok().unwrap_or_default()
1610 }
1611
1612 pub fn glyph_array(&self) -> &'a [BigEndian<GlyphId16>] {
1614 let range = self.glyph_array_byte_range();
1615 self.data.read_array(range).ok().unwrap_or_default()
1616 }
1617
1618 pub fn index_format_byte_range(&self) -> Range<usize> {
1619 let start = 0;
1620 let end = start + u16::RAW_BYTE_LEN;
1621 start..end
1622 }
1623
1624 pub fn image_format_byte_range(&self) -> Range<usize> {
1625 let start = self.index_format_byte_range().end;
1626 let end = start + u16::RAW_BYTE_LEN;
1627 start..end
1628 }
1629
1630 pub fn image_data_offset_byte_range(&self) -> Range<usize> {
1631 let start = self.image_format_byte_range().end;
1632 let end = start + u32::RAW_BYTE_LEN;
1633 start..end
1634 }
1635
1636 pub fn image_size_byte_range(&self) -> Range<usize> {
1637 let start = self.image_data_offset_byte_range().end;
1638 let end = start + u32::RAW_BYTE_LEN;
1639 start..end
1640 }
1641
1642 pub fn big_metrics_byte_range(&self) -> Range<usize> {
1643 let start = self.image_size_byte_range().end;
1644 let end = start + BigGlyphMetrics::RAW_BYTE_LEN;
1645 start..end
1646 }
1647
1648 pub fn num_glyphs_byte_range(&self) -> Range<usize> {
1649 let start = self.big_metrics_byte_range().end;
1650 let end = start + u32::RAW_BYTE_LEN;
1651 start..end
1652 }
1653
1654 pub fn glyph_array_byte_range(&self) -> Range<usize> {
1655 let num_glyphs = self.num_glyphs();
1656 let start = self.num_glyphs_byte_range().end;
1657 let end =
1658 start + (transforms::to_usize(num_glyphs)).saturating_mul(GlyphId16::RAW_BYTE_LEN);
1659 start..end
1660 }
1661}
1662
1663#[cfg(feature = "experimental_traverse")]
1664impl<'a> SomeTable<'a> for IndexSubtable5<'a> {
1665 fn type_name(&self) -> &str {
1666 "IndexSubtable5"
1667 }
1668 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1669 match idx {
1670 0usize => Some(Field::new("index_format", self.index_format())),
1671 1usize => Some(Field::new("image_format", self.image_format())),
1672 2usize => Some(Field::new("image_data_offset", self.image_data_offset())),
1673 3usize => Some(Field::new("image_size", self.image_size())),
1674 4usize => Some(Field::new(
1675 "big_metrics",
1676 traversal::FieldType::array_of_records(
1677 stringify!(BigGlyphMetrics),
1678 self.big_metrics(),
1679 self.offset_data(),
1680 ),
1681 )),
1682 5usize => Some(Field::new("num_glyphs", self.num_glyphs())),
1683 6usize => Some(Field::new("glyph_array", self.glyph_array())),
1684 _ => None,
1685 }
1686 }
1687}
1688
1689#[cfg(feature = "experimental_traverse")]
1690#[allow(clippy::needless_lifetimes)]
1691impl<'a> std::fmt::Debug for IndexSubtable5<'a> {
1692 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1693 (self as &dyn SomeTable<'a>).fmt(f)
1694 }
1695}
1696
1697#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1699#[repr(C)]
1700#[repr(packed)]
1701pub struct BdtComponent {
1702 pub glyph_id: BigEndian<GlyphId16>,
1704 pub x_offset: BigEndian<i8>,
1706 pub y_offset: BigEndian<i8>,
1708}
1709
1710impl BdtComponent {
1711 pub fn glyph_id(&self) -> GlyphId16 {
1713 self.glyph_id.get()
1714 }
1715
1716 pub fn x_offset(&self) -> i8 {
1718 self.x_offset.get()
1719 }
1720
1721 pub fn y_offset(&self) -> i8 {
1723 self.y_offset.get()
1724 }
1725}
1726
1727impl FixedSize for BdtComponent {
1728 const RAW_BYTE_LEN: usize = GlyphId16::RAW_BYTE_LEN + i8::RAW_BYTE_LEN + i8::RAW_BYTE_LEN;
1729}
1730
1731#[cfg(feature = "experimental_traverse")]
1732impl<'a> SomeRecord<'a> for BdtComponent {
1733 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1734 RecordResolver {
1735 name: "BdtComponent",
1736 get_field: Box::new(move |idx, _data| match idx {
1737 0usize => Some(Field::new("glyph_id", self.glyph_id())),
1738 1usize => Some(Field::new("x_offset", self.x_offset())),
1739 2usize => Some(Field::new("y_offset", self.y_offset())),
1740 _ => None,
1741 }),
1742 data,
1743 }
1744 }
1745}