1#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8impl<'a> MinByteRange<'a> for OtKern<'a> {
9 fn min_byte_range(&self) -> Range<usize> {
10 0..self.subtable_data_byte_range().end
11 }
12 fn min_table_bytes(&self) -> &'a [u8] {
13 let range = self.min_byte_range();
14 self.data.as_bytes().get(range).unwrap_or_default()
15 }
16}
17
18impl<'a> FontRead<'a> for OtKern<'a> {
19 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
20 #[allow(clippy::absurd_extreme_comparisons)]
21 if data.len() < Self::MIN_SIZE {
22 return Err(ReadError::OutOfBounds);
23 }
24 Ok(Self { data })
25 }
26}
27
28#[derive(Clone)]
30pub struct OtKern<'a> {
31 data: FontData<'a>,
32}
33
34#[allow(clippy::needless_lifetimes)]
35impl<'a> OtKern<'a> {
36 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
37 basic_table_impls!(impl_the_methods);
38
39 pub fn version(&self) -> u16 {
41 let range = self.version_byte_range();
42 self.data.read_at(range.start).ok().unwrap()
43 }
44
45 pub fn n_tables(&self) -> u16 {
47 let range = self.n_tables_byte_range();
48 self.data.read_at(range.start).ok().unwrap()
49 }
50
51 pub fn subtable_data(&self) -> &'a [u8] {
53 let range = self.subtable_data_byte_range();
54 self.data.read_array(range).ok().unwrap_or_default()
55 }
56
57 pub fn version_byte_range(&self) -> Range<usize> {
58 let start = 0;
59 start..start + u16::RAW_BYTE_LEN
60 }
61
62 pub fn n_tables_byte_range(&self) -> Range<usize> {
63 let start = self.version_byte_range().end;
64 start..start + u16::RAW_BYTE_LEN
65 }
66
67 pub fn subtable_data_byte_range(&self) -> Range<usize> {
68 let start = self.n_tables_byte_range().end;
69 start..start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN
70 }
71}
72
73#[cfg(feature = "experimental_traverse")]
74impl<'a> SomeTable<'a> for OtKern<'a> {
75 fn type_name(&self) -> &str {
76 "OtKern"
77 }
78 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
79 match idx {
80 0usize => Some(Field::new("version", self.version())),
81 1usize => Some(Field::new("n_tables", self.n_tables())),
82 2usize => Some(Field::new("subtable_data", self.subtable_data())),
83 _ => None,
84 }
85 }
86}
87
88#[cfg(feature = "experimental_traverse")]
89#[allow(clippy::needless_lifetimes)]
90impl<'a> std::fmt::Debug for OtKern<'a> {
91 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92 (self as &dyn SomeTable<'a>).fmt(f)
93 }
94}
95
96impl<'a> MinByteRange<'a> for AatKern<'a> {
97 fn min_byte_range(&self) -> Range<usize> {
98 0..self.subtable_data_byte_range().end
99 }
100 fn min_table_bytes(&self) -> &'a [u8] {
101 let range = self.min_byte_range();
102 self.data.as_bytes().get(range).unwrap_or_default()
103 }
104}
105
106impl<'a> FontRead<'a> for AatKern<'a> {
107 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
108 #[allow(clippy::absurd_extreme_comparisons)]
109 if data.len() < Self::MIN_SIZE {
110 return Err(ReadError::OutOfBounds);
111 }
112 Ok(Self { data })
113 }
114}
115
116#[derive(Clone)]
118pub struct AatKern<'a> {
119 data: FontData<'a>,
120}
121
122#[allow(clippy::needless_lifetimes)]
123impl<'a> AatKern<'a> {
124 pub const MIN_SIZE: usize = (MajorMinor::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
125 basic_table_impls!(impl_the_methods);
126
127 pub fn version(&self) -> MajorMinor {
129 let range = self.version_byte_range();
130 self.data.read_at(range.start).ok().unwrap()
131 }
132
133 pub fn n_tables(&self) -> u32 {
135 let range = self.n_tables_byte_range();
136 self.data.read_at(range.start).ok().unwrap()
137 }
138
139 pub fn subtable_data(&self) -> &'a [u8] {
141 let range = self.subtable_data_byte_range();
142 self.data.read_array(range).ok().unwrap_or_default()
143 }
144
145 pub fn version_byte_range(&self) -> Range<usize> {
146 let start = 0;
147 start..start + MajorMinor::RAW_BYTE_LEN
148 }
149
150 pub fn n_tables_byte_range(&self) -> Range<usize> {
151 let start = self.version_byte_range().end;
152 start..start + u32::RAW_BYTE_LEN
153 }
154
155 pub fn subtable_data_byte_range(&self) -> Range<usize> {
156 let start = self.n_tables_byte_range().end;
157 start..start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN
158 }
159}
160
161#[cfg(feature = "experimental_traverse")]
162impl<'a> SomeTable<'a> for AatKern<'a> {
163 fn type_name(&self) -> &str {
164 "AatKern"
165 }
166 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
167 match idx {
168 0usize => Some(Field::new("version", self.version())),
169 1usize => Some(Field::new("n_tables", self.n_tables())),
170 2usize => Some(Field::new("subtable_data", self.subtable_data())),
171 _ => None,
172 }
173 }
174}
175
176#[cfg(feature = "experimental_traverse")]
177#[allow(clippy::needless_lifetimes)]
178impl<'a> std::fmt::Debug for AatKern<'a> {
179 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
180 (self as &dyn SomeTable<'a>).fmt(f)
181 }
182}
183
184impl<'a> MinByteRange<'a> for OtSubtable<'a> {
185 fn min_byte_range(&self) -> Range<usize> {
186 0..self.data_byte_range().end
187 }
188 fn min_table_bytes(&self) -> &'a [u8] {
189 let range = self.min_byte_range();
190 self.data.as_bytes().get(range).unwrap_or_default()
191 }
192}
193
194impl<'a> FontRead<'a> for OtSubtable<'a> {
195 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
196 #[allow(clippy::absurd_extreme_comparisons)]
197 if data.len() < Self::MIN_SIZE {
198 return Err(ReadError::OutOfBounds);
199 }
200 Ok(Self { data })
201 }
202}
203
204#[derive(Clone)]
206pub struct OtSubtable<'a> {
207 data: FontData<'a>,
208}
209
210#[allow(clippy::needless_lifetimes)]
211impl<'a> OtSubtable<'a> {
212 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
213 basic_table_impls!(impl_the_methods);
214
215 pub fn version(&self) -> u16 {
217 let range = self.version_byte_range();
218 self.data.read_at(range.start).ok().unwrap()
219 }
220
221 pub fn length(&self) -> u16 {
223 let range = self.length_byte_range();
224 self.data.read_at(range.start).ok().unwrap()
225 }
226
227 pub fn coverage(&self) -> u16 {
229 let range = self.coverage_byte_range();
230 self.data.read_at(range.start).ok().unwrap()
231 }
232
233 pub fn data(&self) -> &'a [u8] {
235 let range = self.data_byte_range();
236 self.data.read_array(range).ok().unwrap_or_default()
237 }
238
239 pub fn version_byte_range(&self) -> Range<usize> {
240 let start = 0;
241 start..start + u16::RAW_BYTE_LEN
242 }
243
244 pub fn length_byte_range(&self) -> Range<usize> {
245 let start = self.version_byte_range().end;
246 start..start + u16::RAW_BYTE_LEN
247 }
248
249 pub fn coverage_byte_range(&self) -> Range<usize> {
250 let start = self.length_byte_range().end;
251 start..start + u16::RAW_BYTE_LEN
252 }
253
254 pub fn data_byte_range(&self) -> Range<usize> {
255 let start = self.coverage_byte_range().end;
256 start..start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN
257 }
258}
259
260#[cfg(feature = "experimental_traverse")]
261impl<'a> SomeTable<'a> for OtSubtable<'a> {
262 fn type_name(&self) -> &str {
263 "OtSubtable"
264 }
265 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
266 match idx {
267 0usize => Some(Field::new("version", self.version())),
268 1usize => Some(Field::new("length", self.length())),
269 2usize => Some(Field::new("coverage", self.coverage())),
270 3usize => Some(Field::new("data", self.data())),
271 _ => None,
272 }
273 }
274}
275
276#[cfg(feature = "experimental_traverse")]
277#[allow(clippy::needless_lifetimes)]
278impl<'a> std::fmt::Debug for OtSubtable<'a> {
279 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
280 (self as &dyn SomeTable<'a>).fmt(f)
281 }
282}
283
284impl<'a> MinByteRange<'a> for AatSubtable<'a> {
285 fn min_byte_range(&self) -> Range<usize> {
286 0..self.data_byte_range().end
287 }
288 fn min_table_bytes(&self) -> &'a [u8] {
289 let range = self.min_byte_range();
290 self.data.as_bytes().get(range).unwrap_or_default()
291 }
292}
293
294impl<'a> FontRead<'a> for AatSubtable<'a> {
295 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
296 #[allow(clippy::absurd_extreme_comparisons)]
297 if data.len() < Self::MIN_SIZE {
298 return Err(ReadError::OutOfBounds);
299 }
300 Ok(Self { data })
301 }
302}
303
304#[derive(Clone)]
306pub struct AatSubtable<'a> {
307 data: FontData<'a>,
308}
309
310#[allow(clippy::needless_lifetimes)]
311impl<'a> AatSubtable<'a> {
312 pub const MIN_SIZE: usize = (u32::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
313 basic_table_impls!(impl_the_methods);
314
315 pub fn length(&self) -> u32 {
317 let range = self.length_byte_range();
318 self.data.read_at(range.start).ok().unwrap()
319 }
320
321 pub fn coverage(&self) -> u16 {
323 let range = self.coverage_byte_range();
324 self.data.read_at(range.start).ok().unwrap()
325 }
326
327 pub fn tuple_index(&self) -> u16 {
329 let range = self.tuple_index_byte_range();
330 self.data.read_at(range.start).ok().unwrap()
331 }
332
333 pub fn data(&self) -> &'a [u8] {
335 let range = self.data_byte_range();
336 self.data.read_array(range).ok().unwrap_or_default()
337 }
338
339 pub fn length_byte_range(&self) -> Range<usize> {
340 let start = 0;
341 start..start + u32::RAW_BYTE_LEN
342 }
343
344 pub fn coverage_byte_range(&self) -> Range<usize> {
345 let start = self.length_byte_range().end;
346 start..start + u16::RAW_BYTE_LEN
347 }
348
349 pub fn tuple_index_byte_range(&self) -> Range<usize> {
350 let start = self.coverage_byte_range().end;
351 start..start + u16::RAW_BYTE_LEN
352 }
353
354 pub fn data_byte_range(&self) -> Range<usize> {
355 let start = self.tuple_index_byte_range().end;
356 start..start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN
357 }
358}
359
360#[cfg(feature = "experimental_traverse")]
361impl<'a> SomeTable<'a> for AatSubtable<'a> {
362 fn type_name(&self) -> &str {
363 "AatSubtable"
364 }
365 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
366 match idx {
367 0usize => Some(Field::new("length", self.length())),
368 1usize => Some(Field::new("coverage", self.coverage())),
369 2usize => Some(Field::new("tuple_index", self.tuple_index())),
370 3usize => Some(Field::new("data", self.data())),
371 _ => None,
372 }
373 }
374}
375
376#[cfg(feature = "experimental_traverse")]
377#[allow(clippy::needless_lifetimes)]
378impl<'a> std::fmt::Debug for AatSubtable<'a> {
379 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
380 (self as &dyn SomeTable<'a>).fmt(f)
381 }
382}
383
384impl<'a> MinByteRange<'a> for Subtable0<'a> {
385 fn min_byte_range(&self) -> Range<usize> {
386 0..self.pairs_byte_range().end
387 }
388 fn min_table_bytes(&self) -> &'a [u8] {
389 let range = self.min_byte_range();
390 self.data.as_bytes().get(range).unwrap_or_default()
391 }
392}
393
394impl<'a> FontRead<'a> for Subtable0<'a> {
395 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
396 #[allow(clippy::absurd_extreme_comparisons)]
397 if data.len() < Self::MIN_SIZE {
398 return Err(ReadError::OutOfBounds);
399 }
400 Ok(Self { data })
401 }
402}
403
404#[derive(Clone)]
406pub struct Subtable0<'a> {
407 data: FontData<'a>,
408}
409
410#[allow(clippy::needless_lifetimes)]
411impl<'a> Subtable0<'a> {
412 pub const MIN_SIZE: usize =
413 (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
414 basic_table_impls!(impl_the_methods);
415
416 pub fn n_pairs(&self) -> u16 {
418 let range = self.n_pairs_byte_range();
419 self.data.read_at(range.start).ok().unwrap()
420 }
421
422 pub fn search_range(&self) -> u16 {
424 let range = self.search_range_byte_range();
425 self.data.read_at(range.start).ok().unwrap()
426 }
427
428 pub fn entry_selector(&self) -> u16 {
430 let range = self.entry_selector_byte_range();
431 self.data.read_at(range.start).ok().unwrap()
432 }
433
434 pub fn range_shift(&self) -> u16 {
436 let range = self.range_shift_byte_range();
437 self.data.read_at(range.start).ok().unwrap()
438 }
439
440 pub fn pairs(&self) -> &'a [Subtable0Pair] {
442 let range = self.pairs_byte_range();
443 self.data.read_array(range).ok().unwrap_or_default()
444 }
445
446 pub fn n_pairs_byte_range(&self) -> Range<usize> {
447 let start = 0;
448 start..start + u16::RAW_BYTE_LEN
449 }
450
451 pub fn search_range_byte_range(&self) -> Range<usize> {
452 let start = self.n_pairs_byte_range().end;
453 start..start + u16::RAW_BYTE_LEN
454 }
455
456 pub fn entry_selector_byte_range(&self) -> Range<usize> {
457 let start = self.search_range_byte_range().end;
458 start..start + u16::RAW_BYTE_LEN
459 }
460
461 pub fn range_shift_byte_range(&self) -> Range<usize> {
462 let start = self.entry_selector_byte_range().end;
463 start..start + u16::RAW_BYTE_LEN
464 }
465
466 pub fn pairs_byte_range(&self) -> Range<usize> {
467 let n_pairs = self.n_pairs();
468 let start = self.range_shift_byte_range().end;
469 start..start + (n_pairs as usize).saturating_mul(Subtable0Pair::RAW_BYTE_LEN)
470 }
471}
472
473#[cfg(feature = "experimental_traverse")]
474impl<'a> SomeTable<'a> for Subtable0<'a> {
475 fn type_name(&self) -> &str {
476 "Subtable0"
477 }
478 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
479 match idx {
480 0usize => Some(Field::new("n_pairs", self.n_pairs())),
481 1usize => Some(Field::new("search_range", self.search_range())),
482 2usize => Some(Field::new("entry_selector", self.entry_selector())),
483 3usize => Some(Field::new("range_shift", self.range_shift())),
484 4usize => Some(Field::new(
485 "pairs",
486 traversal::FieldType::array_of_records(
487 stringify!(Subtable0Pair),
488 self.pairs(),
489 self.offset_data(),
490 ),
491 )),
492 _ => None,
493 }
494 }
495}
496
497#[cfg(feature = "experimental_traverse")]
498#[allow(clippy::needless_lifetimes)]
499impl<'a> std::fmt::Debug for Subtable0<'a> {
500 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
501 (self as &dyn SomeTable<'a>).fmt(f)
502 }
503}
504
505impl<'a> MinByteRange<'a> for Subtable2ClassTable<'a> {
506 fn min_byte_range(&self) -> Range<usize> {
507 0..self.offsets_byte_range().end
508 }
509 fn min_table_bytes(&self) -> &'a [u8] {
510 let range = self.min_byte_range();
511 self.data.as_bytes().get(range).unwrap_or_default()
512 }
513}
514
515impl<'a> FontRead<'a> for Subtable2ClassTable<'a> {
516 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
517 #[allow(clippy::absurd_extreme_comparisons)]
518 if data.len() < Self::MIN_SIZE {
519 return Err(ReadError::OutOfBounds);
520 }
521 Ok(Self { data })
522 }
523}
524
525#[derive(Clone)]
527pub struct Subtable2ClassTable<'a> {
528 data: FontData<'a>,
529}
530
531#[allow(clippy::needless_lifetimes)]
532impl<'a> Subtable2ClassTable<'a> {
533 pub const MIN_SIZE: usize = (GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
534 basic_table_impls!(impl_the_methods);
535
536 pub fn first_glyph(&self) -> GlyphId16 {
538 let range = self.first_glyph_byte_range();
539 self.data.read_at(range.start).ok().unwrap()
540 }
541
542 pub fn n_glyphs(&self) -> u16 {
544 let range = self.n_glyphs_byte_range();
545 self.data.read_at(range.start).ok().unwrap()
546 }
547
548 pub fn offsets(&self) -> &'a [BigEndian<u16>] {
550 let range = self.offsets_byte_range();
551 self.data.read_array(range).ok().unwrap_or_default()
552 }
553
554 pub fn first_glyph_byte_range(&self) -> Range<usize> {
555 let start = 0;
556 start..start + GlyphId16::RAW_BYTE_LEN
557 }
558
559 pub fn n_glyphs_byte_range(&self) -> Range<usize> {
560 let start = self.first_glyph_byte_range().end;
561 start..start + u16::RAW_BYTE_LEN
562 }
563
564 pub fn offsets_byte_range(&self) -> Range<usize> {
565 let n_glyphs = self.n_glyphs();
566 let start = self.n_glyphs_byte_range().end;
567 start..start + (n_glyphs as usize).saturating_mul(u16::RAW_BYTE_LEN)
568 }
569}
570
571#[cfg(feature = "experimental_traverse")]
572impl<'a> SomeTable<'a> for Subtable2ClassTable<'a> {
573 fn type_name(&self) -> &str {
574 "Subtable2ClassTable"
575 }
576 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
577 match idx {
578 0usize => Some(Field::new("first_glyph", self.first_glyph())),
579 1usize => Some(Field::new("n_glyphs", self.n_glyphs())),
580 2usize => Some(Field::new("offsets", self.offsets())),
581 _ => None,
582 }
583 }
584}
585
586#[cfg(feature = "experimental_traverse")]
587#[allow(clippy::needless_lifetimes)]
588impl<'a> std::fmt::Debug for Subtable2ClassTable<'a> {
589 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
590 (self as &dyn SomeTable<'a>).fmt(f)
591 }
592}
593
594impl<'a> MinByteRange<'a> for Subtable3<'a> {
595 fn min_byte_range(&self) -> Range<usize> {
596 0..self.kern_index_byte_range().end
597 }
598 fn min_table_bytes(&self) -> &'a [u8] {
599 let range = self.min_byte_range();
600 self.data.as_bytes().get(range).unwrap_or_default()
601 }
602}
603
604impl<'a> FontRead<'a> for Subtable3<'a> {
605 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
606 #[allow(clippy::absurd_extreme_comparisons)]
607 if data.len() < Self::MIN_SIZE {
608 return Err(ReadError::OutOfBounds);
609 }
610 Ok(Self { data })
611 }
612}
613
614#[derive(Clone)]
616pub struct Subtable3<'a> {
617 data: FontData<'a>,
618}
619
620#[allow(clippy::needless_lifetimes)]
621impl<'a> Subtable3<'a> {
622 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
623 + u8::RAW_BYTE_LEN
624 + u8::RAW_BYTE_LEN
625 + u8::RAW_BYTE_LEN
626 + u8::RAW_BYTE_LEN);
627 basic_table_impls!(impl_the_methods);
628
629 pub fn glyph_count(&self) -> u16 {
631 let range = self.glyph_count_byte_range();
632 self.data.read_at(range.start).ok().unwrap()
633 }
634
635 pub fn kern_value_count(&self) -> u8 {
637 let range = self.kern_value_count_byte_range();
638 self.data.read_at(range.start).ok().unwrap()
639 }
640
641 pub fn left_class_count(&self) -> u8 {
643 let range = self.left_class_count_byte_range();
644 self.data.read_at(range.start).ok().unwrap()
645 }
646
647 pub fn right_class_count(&self) -> u8 {
649 let range = self.right_class_count_byte_range();
650 self.data.read_at(range.start).ok().unwrap()
651 }
652
653 pub fn flags(&self) -> u8 {
655 let range = self.flags_byte_range();
656 self.data.read_at(range.start).ok().unwrap()
657 }
658
659 pub fn kern_value(&self) -> &'a [BigEndian<i16>] {
661 let range = self.kern_value_byte_range();
662 self.data.read_array(range).ok().unwrap_or_default()
663 }
664
665 pub fn left_class(&self) -> &'a [u8] {
667 let range = self.left_class_byte_range();
668 self.data.read_array(range).ok().unwrap_or_default()
669 }
670
671 pub fn right_class(&self) -> &'a [u8] {
673 let range = self.right_class_byte_range();
674 self.data.read_array(range).ok().unwrap_or_default()
675 }
676
677 pub fn kern_index(&self) -> &'a [u8] {
679 let range = self.kern_index_byte_range();
680 self.data.read_array(range).ok().unwrap_or_default()
681 }
682
683 pub fn glyph_count_byte_range(&self) -> Range<usize> {
684 let start = 0;
685 start..start + u16::RAW_BYTE_LEN
686 }
687
688 pub fn kern_value_count_byte_range(&self) -> Range<usize> {
689 let start = self.glyph_count_byte_range().end;
690 start..start + u8::RAW_BYTE_LEN
691 }
692
693 pub fn left_class_count_byte_range(&self) -> Range<usize> {
694 let start = self.kern_value_count_byte_range().end;
695 start..start + u8::RAW_BYTE_LEN
696 }
697
698 pub fn right_class_count_byte_range(&self) -> Range<usize> {
699 let start = self.left_class_count_byte_range().end;
700 start..start + u8::RAW_BYTE_LEN
701 }
702
703 pub fn flags_byte_range(&self) -> Range<usize> {
704 let start = self.right_class_count_byte_range().end;
705 start..start + u8::RAW_BYTE_LEN
706 }
707
708 pub fn kern_value_byte_range(&self) -> Range<usize> {
709 let kern_value_count = self.kern_value_count();
710 let start = self.flags_byte_range().end;
711 start..start + (kern_value_count as usize).saturating_mul(i16::RAW_BYTE_LEN)
712 }
713
714 pub fn left_class_byte_range(&self) -> Range<usize> {
715 let glyph_count = self.glyph_count();
716 let start = self.kern_value_byte_range().end;
717 start..start + (glyph_count as usize).saturating_mul(u8::RAW_BYTE_LEN)
718 }
719
720 pub fn right_class_byte_range(&self) -> Range<usize> {
721 let glyph_count = self.glyph_count();
722 let start = self.left_class_byte_range().end;
723 start..start + (glyph_count as usize).saturating_mul(u8::RAW_BYTE_LEN)
724 }
725
726 pub fn kern_index_byte_range(&self) -> Range<usize> {
727 let left_class_count = self.left_class_count();
728 let right_class_count = self.right_class_count();
729 let start = self.right_class_byte_range().end;
730 start
731 ..start
732 + (transforms::add_multiply(left_class_count, 0_usize, right_class_count))
733 .saturating_mul(u8::RAW_BYTE_LEN)
734 }
735}
736
737#[cfg(feature = "experimental_traverse")]
738impl<'a> SomeTable<'a> for Subtable3<'a> {
739 fn type_name(&self) -> &str {
740 "Subtable3"
741 }
742 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
743 match idx {
744 0usize => Some(Field::new("glyph_count", self.glyph_count())),
745 1usize => Some(Field::new("kern_value_count", self.kern_value_count())),
746 2usize => Some(Field::new("left_class_count", self.left_class_count())),
747 3usize => Some(Field::new("right_class_count", self.right_class_count())),
748 4usize => Some(Field::new("flags", self.flags())),
749 5usize => Some(Field::new("kern_value", self.kern_value())),
750 6usize => Some(Field::new("left_class", self.left_class())),
751 7usize => Some(Field::new("right_class", self.right_class())),
752 8usize => Some(Field::new("kern_index", self.kern_index())),
753 _ => None,
754 }
755 }
756}
757
758#[cfg(feature = "experimental_traverse")]
759#[allow(clippy::needless_lifetimes)]
760impl<'a> std::fmt::Debug for Subtable3<'a> {
761 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
762 (self as &dyn SomeTable<'a>).fmt(f)
763 }
764}