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 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> 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 let end = start + u16::RAW_BYTE_LEN;
1017 start..end
1018 }
1019
1020 pub fn image_format_byte_range(&self) -> Range<usize> {
1021 let start = self.index_format_byte_range().end;
1022 let end = start + u16::RAW_BYTE_LEN;
1023 start..end
1024 }
1025
1026 pub fn image_data_offset_byte_range(&self) -> Range<usize> {
1027 let start = self.image_format_byte_range().end;
1028 let end = start + u32::RAW_BYTE_LEN;
1029 start..end
1030 }
1031
1032 pub fn sbit_offsets_byte_range(&self) -> Range<usize> {
1033 let last_glyph_index = self.last_glyph_index();
1034 let first_glyph_index = self.first_glyph_index();
1035 let start = self.image_data_offset_byte_range().end;
1036 let end = start
1037 + (transforms::subtract_add_two(last_glyph_index, first_glyph_index))
1038 .saturating_mul(u32::RAW_BYTE_LEN);
1039 start..end
1040 }
1041}
1042
1043const _: () = assert!(FontData::default_data_long_enough(IndexSubtable1::MIN_SIZE));
1044
1045impl Default for IndexSubtable1<'_> {
1046 fn default() -> Self {
1047 Self {
1048 data: FontData::default_format_1_u16_table_data(),
1049 last_glyph_index: Default::default(),
1050 first_glyph_index: Default::default(),
1051 }
1052 }
1053}
1054
1055#[cfg(feature = "experimental_traverse")]
1056impl<'a> SomeTable<'a> for IndexSubtable1<'a> {
1057 fn type_name(&self) -> &str {
1058 "IndexSubtable1"
1059 }
1060 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1061 match idx {
1062 0usize => Some(Field::new("index_format", self.index_format())),
1063 1usize => Some(Field::new("image_format", self.image_format())),
1064 2usize => Some(Field::new("image_data_offset", self.image_data_offset())),
1065 3usize => Some(Field::new("sbit_offsets", self.sbit_offsets())),
1066 _ => None,
1067 }
1068 }
1069}
1070
1071#[cfg(feature = "experimental_traverse")]
1072#[allow(clippy::needless_lifetimes)]
1073impl<'a> std::fmt::Debug for IndexSubtable1<'a> {
1074 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1075 (self as &dyn SomeTable<'a>).fmt(f)
1076 }
1077}
1078
1079impl Format<u16> for IndexSubtable2<'_> {
1080 const FORMAT: u16 = 2;
1081}
1082
1083impl<'a> MinByteRange<'a> for IndexSubtable2<'a> {
1084 fn min_byte_range(&self) -> Range<usize> {
1085 0..self.big_metrics_byte_range().end
1086 }
1087 fn min_table_bytes(&self) -> &'a [u8] {
1088 let range = self.min_byte_range();
1089 self.data.as_bytes().get(range).unwrap_or_default()
1090 }
1091}
1092
1093impl<'a> FontRead<'a> for IndexSubtable2<'a> {
1094 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1095 #[allow(clippy::absurd_extreme_comparisons)]
1096 if data.len() < Self::MIN_SIZE {
1097 return Err(ReadError::OutOfBounds);
1098 }
1099 Ok(Self { data })
1100 }
1101}
1102
1103#[derive(Clone)]
1105pub struct IndexSubtable2<'a> {
1106 data: FontData<'a>,
1107}
1108
1109#[allow(clippy::needless_lifetimes)]
1110impl<'a> IndexSubtable2<'a> {
1111 pub const MIN_SIZE: usize =
1112 (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
1113 basic_table_impls!(impl_the_methods);
1114
1115 pub fn index_format(&self) -> u16 {
1117 let range = self.index_format_byte_range();
1118 self.data.read_at(range.start).ok().unwrap()
1119 }
1120
1121 pub fn image_format(&self) -> u16 {
1123 let range = self.image_format_byte_range();
1124 self.data.read_at(range.start).ok().unwrap()
1125 }
1126
1127 pub fn image_data_offset(&self) -> u32 {
1129 let range = self.image_data_offset_byte_range();
1130 self.data.read_at(range.start).ok().unwrap()
1131 }
1132
1133 pub fn image_size(&self) -> u32 {
1135 let range = self.image_size_byte_range();
1136 self.data.read_at(range.start).ok().unwrap()
1137 }
1138
1139 pub fn big_metrics(&self) -> &'a [BigGlyphMetrics] {
1141 let range = self.big_metrics_byte_range();
1142 self.data.read_array(range).ok().unwrap_or_default()
1143 }
1144
1145 pub fn index_format_byte_range(&self) -> Range<usize> {
1146 let start = 0;
1147 let end = start + u16::RAW_BYTE_LEN;
1148 start..end
1149 }
1150
1151 pub fn image_format_byte_range(&self) -> Range<usize> {
1152 let start = self.index_format_byte_range().end;
1153 let end = start + u16::RAW_BYTE_LEN;
1154 start..end
1155 }
1156
1157 pub fn image_data_offset_byte_range(&self) -> Range<usize> {
1158 let start = self.image_format_byte_range().end;
1159 let end = start + u32::RAW_BYTE_LEN;
1160 start..end
1161 }
1162
1163 pub fn image_size_byte_range(&self) -> Range<usize> {
1164 let start = self.image_data_offset_byte_range().end;
1165 let end = start + u32::RAW_BYTE_LEN;
1166 start..end
1167 }
1168
1169 pub fn big_metrics_byte_range(&self) -> Range<usize> {
1170 let start = self.image_size_byte_range().end;
1171 let end = start + BigGlyphMetrics::RAW_BYTE_LEN;
1172 start..end
1173 }
1174}
1175
1176#[cfg(feature = "experimental_traverse")]
1177impl<'a> SomeTable<'a> for IndexSubtable2<'a> {
1178 fn type_name(&self) -> &str {
1179 "IndexSubtable2"
1180 }
1181 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1182 match idx {
1183 0usize => Some(Field::new("index_format", self.index_format())),
1184 1usize => Some(Field::new("image_format", self.image_format())),
1185 2usize => Some(Field::new("image_data_offset", self.image_data_offset())),
1186 3usize => Some(Field::new("image_size", self.image_size())),
1187 4usize => Some(Field::new(
1188 "big_metrics",
1189 traversal::FieldType::array_of_records(
1190 stringify!(BigGlyphMetrics),
1191 self.big_metrics(),
1192 self.offset_data(),
1193 ),
1194 )),
1195 _ => None,
1196 }
1197 }
1198}
1199
1200#[cfg(feature = "experimental_traverse")]
1201#[allow(clippy::needless_lifetimes)]
1202impl<'a> std::fmt::Debug for IndexSubtable2<'a> {
1203 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1204 (self as &dyn SomeTable<'a>).fmt(f)
1205 }
1206}
1207
1208impl Format<u16> for IndexSubtable3<'_> {
1209 const FORMAT: u16 = 3;
1210}
1211
1212impl<'a> MinByteRange<'a> for IndexSubtable3<'a> {
1213 fn min_byte_range(&self) -> Range<usize> {
1214 0..self.sbit_offsets_byte_range().end
1215 }
1216 fn min_table_bytes(&self) -> &'a [u8] {
1217 let range = self.min_byte_range();
1218 self.data.as_bytes().get(range).unwrap_or_default()
1219 }
1220}
1221
1222impl ReadArgs for IndexSubtable3<'_> {
1223 type Args = (GlyphId16, GlyphId16);
1224}
1225
1226impl<'a> FontReadWithArgs<'a> for IndexSubtable3<'a> {
1227 fn read_with_args(
1228 data: FontData<'a>,
1229 args: &(GlyphId16, GlyphId16),
1230 ) -> Result<Self, ReadError> {
1231 let (last_glyph_index, first_glyph_index) = *args;
1232
1233 #[allow(clippy::absurd_extreme_comparisons)]
1234 if data.len() < Self::MIN_SIZE {
1235 return Err(ReadError::OutOfBounds);
1236 }
1237 Ok(Self {
1238 data,
1239 last_glyph_index,
1240 first_glyph_index,
1241 })
1242 }
1243}
1244
1245impl<'a> IndexSubtable3<'a> {
1246 pub fn read(
1251 data: FontData<'a>,
1252 last_glyph_index: GlyphId16,
1253 first_glyph_index: GlyphId16,
1254 ) -> Result<Self, ReadError> {
1255 let args = (last_glyph_index, first_glyph_index);
1256 Self::read_with_args(data, &args)
1257 }
1258}
1259
1260#[derive(Clone)]
1262pub struct IndexSubtable3<'a> {
1263 data: FontData<'a>,
1264 last_glyph_index: GlyphId16,
1265 first_glyph_index: GlyphId16,
1266}
1267
1268#[allow(clippy::needless_lifetimes)]
1269impl<'a> IndexSubtable3<'a> {
1270 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
1271 basic_table_impls!(impl_the_methods);
1272
1273 pub fn index_format(&self) -> u16 {
1275 let range = self.index_format_byte_range();
1276 self.data.read_at(range.start).ok().unwrap()
1277 }
1278
1279 pub fn image_format(&self) -> u16 {
1281 let range = self.image_format_byte_range();
1282 self.data.read_at(range.start).ok().unwrap()
1283 }
1284
1285 pub fn image_data_offset(&self) -> u32 {
1287 let range = self.image_data_offset_byte_range();
1288 self.data.read_at(range.start).ok().unwrap()
1289 }
1290
1291 pub fn sbit_offsets(&self) -> &'a [BigEndian<u16>] {
1292 let range = self.sbit_offsets_byte_range();
1293 self.data.read_array(range).ok().unwrap_or_default()
1294 }
1295
1296 pub(crate) fn last_glyph_index(&self) -> GlyphId16 {
1297 self.last_glyph_index
1298 }
1299
1300 pub(crate) fn first_glyph_index(&self) -> GlyphId16 {
1301 self.first_glyph_index
1302 }
1303
1304 pub fn index_format_byte_range(&self) -> Range<usize> {
1305 let start = 0;
1306 let end = start + u16::RAW_BYTE_LEN;
1307 start..end
1308 }
1309
1310 pub fn image_format_byte_range(&self) -> Range<usize> {
1311 let start = self.index_format_byte_range().end;
1312 let end = start + u16::RAW_BYTE_LEN;
1313 start..end
1314 }
1315
1316 pub fn image_data_offset_byte_range(&self) -> Range<usize> {
1317 let start = self.image_format_byte_range().end;
1318 let end = start + u32::RAW_BYTE_LEN;
1319 start..end
1320 }
1321
1322 pub fn sbit_offsets_byte_range(&self) -> Range<usize> {
1323 let last_glyph_index = self.last_glyph_index();
1324 let first_glyph_index = self.first_glyph_index();
1325 let start = self.image_data_offset_byte_range().end;
1326 let end = start
1327 + (transforms::subtract_add_two(last_glyph_index, first_glyph_index))
1328 .saturating_mul(u16::RAW_BYTE_LEN);
1329 start..end
1330 }
1331}
1332
1333#[cfg(feature = "experimental_traverse")]
1334impl<'a> SomeTable<'a> for IndexSubtable3<'a> {
1335 fn type_name(&self) -> &str {
1336 "IndexSubtable3"
1337 }
1338 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1339 match idx {
1340 0usize => Some(Field::new("index_format", self.index_format())),
1341 1usize => Some(Field::new("image_format", self.image_format())),
1342 2usize => Some(Field::new("image_data_offset", self.image_data_offset())),
1343 3usize => Some(Field::new("sbit_offsets", self.sbit_offsets())),
1344 _ => None,
1345 }
1346 }
1347}
1348
1349#[cfg(feature = "experimental_traverse")]
1350#[allow(clippy::needless_lifetimes)]
1351impl<'a> std::fmt::Debug for IndexSubtable3<'a> {
1352 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1353 (self as &dyn SomeTable<'a>).fmt(f)
1354 }
1355}
1356
1357impl Format<u16> for IndexSubtable4<'_> {
1358 const FORMAT: u16 = 4;
1359}
1360
1361impl<'a> MinByteRange<'a> for IndexSubtable4<'a> {
1362 fn min_byte_range(&self) -> Range<usize> {
1363 0..self.glyph_array_byte_range().end
1364 }
1365 fn min_table_bytes(&self) -> &'a [u8] {
1366 let range = self.min_byte_range();
1367 self.data.as_bytes().get(range).unwrap_or_default()
1368 }
1369}
1370
1371impl<'a> FontRead<'a> for IndexSubtable4<'a> {
1372 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1373 #[allow(clippy::absurd_extreme_comparisons)]
1374 if data.len() < Self::MIN_SIZE {
1375 return Err(ReadError::OutOfBounds);
1376 }
1377 Ok(Self { data })
1378 }
1379}
1380
1381#[derive(Clone)]
1383pub struct IndexSubtable4<'a> {
1384 data: FontData<'a>,
1385}
1386
1387#[allow(clippy::needless_lifetimes)]
1388impl<'a> IndexSubtable4<'a> {
1389 pub const MIN_SIZE: usize =
1390 (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
1391 basic_table_impls!(impl_the_methods);
1392
1393 pub fn index_format(&self) -> u16 {
1395 let range = self.index_format_byte_range();
1396 self.data.read_at(range.start).ok().unwrap()
1397 }
1398
1399 pub fn image_format(&self) -> u16 {
1401 let range = self.image_format_byte_range();
1402 self.data.read_at(range.start).ok().unwrap()
1403 }
1404
1405 pub fn image_data_offset(&self) -> u32 {
1407 let range = self.image_data_offset_byte_range();
1408 self.data.read_at(range.start).ok().unwrap()
1409 }
1410
1411 pub fn num_glyphs(&self) -> u32 {
1413 let range = self.num_glyphs_byte_range();
1414 self.data.read_at(range.start).ok().unwrap()
1415 }
1416
1417 pub fn glyph_array(&self) -> &'a [GlyphIdOffsetPair] {
1419 let range = self.glyph_array_byte_range();
1420 self.data.read_array(range).ok().unwrap_or_default()
1421 }
1422
1423 pub fn index_format_byte_range(&self) -> Range<usize> {
1424 let start = 0;
1425 let end = start + u16::RAW_BYTE_LEN;
1426 start..end
1427 }
1428
1429 pub fn image_format_byte_range(&self) -> Range<usize> {
1430 let start = self.index_format_byte_range().end;
1431 let end = start + u16::RAW_BYTE_LEN;
1432 start..end
1433 }
1434
1435 pub fn image_data_offset_byte_range(&self) -> Range<usize> {
1436 let start = self.image_format_byte_range().end;
1437 let end = start + u32::RAW_BYTE_LEN;
1438 start..end
1439 }
1440
1441 pub fn num_glyphs_byte_range(&self) -> Range<usize> {
1442 let start = self.image_data_offset_byte_range().end;
1443 let end = start + u32::RAW_BYTE_LEN;
1444 start..end
1445 }
1446
1447 pub fn glyph_array_byte_range(&self) -> Range<usize> {
1448 let num_glyphs = self.num_glyphs();
1449 let start = self.num_glyphs_byte_range().end;
1450 let end = start
1451 + (transforms::add(num_glyphs, 1_usize))
1452 .saturating_mul(GlyphIdOffsetPair::RAW_BYTE_LEN);
1453 start..end
1454 }
1455}
1456
1457#[cfg(feature = "experimental_traverse")]
1458impl<'a> SomeTable<'a> for IndexSubtable4<'a> {
1459 fn type_name(&self) -> &str {
1460 "IndexSubtable4"
1461 }
1462 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1463 match idx {
1464 0usize => Some(Field::new("index_format", self.index_format())),
1465 1usize => Some(Field::new("image_format", self.image_format())),
1466 2usize => Some(Field::new("image_data_offset", self.image_data_offset())),
1467 3usize => Some(Field::new("num_glyphs", self.num_glyphs())),
1468 4usize => Some(Field::new(
1469 "glyph_array",
1470 traversal::FieldType::array_of_records(
1471 stringify!(GlyphIdOffsetPair),
1472 self.glyph_array(),
1473 self.offset_data(),
1474 ),
1475 )),
1476 _ => None,
1477 }
1478 }
1479}
1480
1481#[cfg(feature = "experimental_traverse")]
1482#[allow(clippy::needless_lifetimes)]
1483impl<'a> std::fmt::Debug for IndexSubtable4<'a> {
1484 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1485 (self as &dyn SomeTable<'a>).fmt(f)
1486 }
1487}
1488
1489#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1491#[repr(C)]
1492#[repr(packed)]
1493pub struct GlyphIdOffsetPair {
1494 pub glyph_id: BigEndian<GlyphId16>,
1496 pub sbit_offset: BigEndian<u16>,
1498}
1499
1500impl GlyphIdOffsetPair {
1501 pub fn glyph_id(&self) -> GlyphId16 {
1503 self.glyph_id.get()
1504 }
1505
1506 pub fn sbit_offset(&self) -> u16 {
1508 self.sbit_offset.get()
1509 }
1510}
1511
1512impl FixedSize for GlyphIdOffsetPair {
1513 const RAW_BYTE_LEN: usize = GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
1514}
1515
1516#[cfg(feature = "experimental_traverse")]
1517impl<'a> SomeRecord<'a> for GlyphIdOffsetPair {
1518 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1519 RecordResolver {
1520 name: "GlyphIdOffsetPair",
1521 get_field: Box::new(move |idx, _data| match idx {
1522 0usize => Some(Field::new("glyph_id", self.glyph_id())),
1523 1usize => Some(Field::new("sbit_offset", self.sbit_offset())),
1524 _ => None,
1525 }),
1526 data,
1527 }
1528 }
1529}
1530
1531impl Format<u16> for IndexSubtable5<'_> {
1532 const FORMAT: u16 = 5;
1533}
1534
1535impl<'a> MinByteRange<'a> for IndexSubtable5<'a> {
1536 fn min_byte_range(&self) -> Range<usize> {
1537 0..self.glyph_array_byte_range().end
1538 }
1539 fn min_table_bytes(&self) -> &'a [u8] {
1540 let range = self.min_byte_range();
1541 self.data.as_bytes().get(range).unwrap_or_default()
1542 }
1543}
1544
1545impl<'a> FontRead<'a> for IndexSubtable5<'a> {
1546 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1547 #[allow(clippy::absurd_extreme_comparisons)]
1548 if data.len() < Self::MIN_SIZE {
1549 return Err(ReadError::OutOfBounds);
1550 }
1551 Ok(Self { data })
1552 }
1553}
1554
1555#[derive(Clone)]
1557pub struct IndexSubtable5<'a> {
1558 data: FontData<'a>,
1559}
1560
1561#[allow(clippy::needless_lifetimes)]
1562impl<'a> IndexSubtable5<'a> {
1563 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1564 + u16::RAW_BYTE_LEN
1565 + u32::RAW_BYTE_LEN
1566 + u32::RAW_BYTE_LEN
1567 + u32::RAW_BYTE_LEN);
1568 basic_table_impls!(impl_the_methods);
1569
1570 pub fn index_format(&self) -> u16 {
1572 let range = self.index_format_byte_range();
1573 self.data.read_at(range.start).ok().unwrap()
1574 }
1575
1576 pub fn image_format(&self) -> u16 {
1578 let range = self.image_format_byte_range();
1579 self.data.read_at(range.start).ok().unwrap()
1580 }
1581
1582 pub fn image_data_offset(&self) -> u32 {
1584 let range = self.image_data_offset_byte_range();
1585 self.data.read_at(range.start).ok().unwrap()
1586 }
1587
1588 pub fn image_size(&self) -> u32 {
1590 let range = self.image_size_byte_range();
1591 self.data.read_at(range.start).ok().unwrap()
1592 }
1593
1594 pub fn big_metrics(&self) -> &'a [BigGlyphMetrics] {
1596 let range = self.big_metrics_byte_range();
1597 self.data.read_array(range).ok().unwrap_or_default()
1598 }
1599
1600 pub fn num_glyphs(&self) -> u32 {
1602 let range = self.num_glyphs_byte_range();
1603 self.data.read_at(range.start).ok().unwrap_or_default()
1604 }
1605
1606 pub fn glyph_array(&self) -> &'a [BigEndian<GlyphId16>] {
1608 let range = self.glyph_array_byte_range();
1609 self.data.read_array(range).ok().unwrap_or_default()
1610 }
1611
1612 pub fn index_format_byte_range(&self) -> Range<usize> {
1613 let start = 0;
1614 let end = start + u16::RAW_BYTE_LEN;
1615 start..end
1616 }
1617
1618 pub fn image_format_byte_range(&self) -> Range<usize> {
1619 let start = self.index_format_byte_range().end;
1620 let end = start + u16::RAW_BYTE_LEN;
1621 start..end
1622 }
1623
1624 pub fn image_data_offset_byte_range(&self) -> Range<usize> {
1625 let start = self.image_format_byte_range().end;
1626 let end = start + u32::RAW_BYTE_LEN;
1627 start..end
1628 }
1629
1630 pub fn image_size_byte_range(&self) -> Range<usize> {
1631 let start = self.image_data_offset_byte_range().end;
1632 let end = start + u32::RAW_BYTE_LEN;
1633 start..end
1634 }
1635
1636 pub fn big_metrics_byte_range(&self) -> Range<usize> {
1637 let start = self.image_size_byte_range().end;
1638 let end = start + BigGlyphMetrics::RAW_BYTE_LEN;
1639 start..end
1640 }
1641
1642 pub fn num_glyphs_byte_range(&self) -> Range<usize> {
1643 let start = self.big_metrics_byte_range().end;
1644 let end = start + u32::RAW_BYTE_LEN;
1645 start..end
1646 }
1647
1648 pub fn glyph_array_byte_range(&self) -> Range<usize> {
1649 let num_glyphs = self.num_glyphs();
1650 let start = self.num_glyphs_byte_range().end;
1651 let end =
1652 start + (transforms::to_usize(num_glyphs)).saturating_mul(GlyphId16::RAW_BYTE_LEN);
1653 start..end
1654 }
1655}
1656
1657#[cfg(feature = "experimental_traverse")]
1658impl<'a> SomeTable<'a> for IndexSubtable5<'a> {
1659 fn type_name(&self) -> &str {
1660 "IndexSubtable5"
1661 }
1662 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1663 match idx {
1664 0usize => Some(Field::new("index_format", self.index_format())),
1665 1usize => Some(Field::new("image_format", self.image_format())),
1666 2usize => Some(Field::new("image_data_offset", self.image_data_offset())),
1667 3usize => Some(Field::new("image_size", self.image_size())),
1668 4usize => Some(Field::new(
1669 "big_metrics",
1670 traversal::FieldType::array_of_records(
1671 stringify!(BigGlyphMetrics),
1672 self.big_metrics(),
1673 self.offset_data(),
1674 ),
1675 )),
1676 5usize => Some(Field::new("num_glyphs", self.num_glyphs())),
1677 6usize => Some(Field::new("glyph_array", self.glyph_array())),
1678 _ => None,
1679 }
1680 }
1681}
1682
1683#[cfg(feature = "experimental_traverse")]
1684#[allow(clippy::needless_lifetimes)]
1685impl<'a> std::fmt::Debug for IndexSubtable5<'a> {
1686 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1687 (self as &dyn SomeTable<'a>).fmt(f)
1688 }
1689}
1690
1691#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1693#[repr(C)]
1694#[repr(packed)]
1695pub struct BdtComponent {
1696 pub glyph_id: BigEndian<GlyphId16>,
1698 pub x_offset: BigEndian<i8>,
1700 pub y_offset: BigEndian<i8>,
1702}
1703
1704impl BdtComponent {
1705 pub fn glyph_id(&self) -> GlyphId16 {
1707 self.glyph_id.get()
1708 }
1709
1710 pub fn x_offset(&self) -> i8 {
1712 self.x_offset.get()
1713 }
1714
1715 pub fn y_offset(&self) -> i8 {
1717 self.y_offset.get()
1718 }
1719}
1720
1721impl FixedSize for BdtComponent {
1722 const RAW_BYTE_LEN: usize = GlyphId16::RAW_BYTE_LEN + i8::RAW_BYTE_LEN + i8::RAW_BYTE_LEN;
1723}
1724
1725#[cfg(feature = "experimental_traverse")]
1726impl<'a> SomeRecord<'a> for BdtComponent {
1727 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1728 RecordResolver {
1729 name: "BdtComponent",
1730 get_field: Box::new(move |idx, _data| match idx {
1731 0usize => Some(Field::new("glyph_id", self.glyph_id())),
1732 1usize => Some(Field::new("x_offset", self.x_offset())),
1733 2usize => Some(Field::new("y_offset", self.y_offset())),
1734 _ => None,
1735 }),
1736 data,
1737 }
1738 }
1739}