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
73const _: () = assert!(FontData::default_data_long_enough(OtKern::MIN_SIZE));
74
75impl Default for OtKern<'_> {
76 fn default() -> Self {
77 Self {
78 data: FontData::default_table_data(),
79 }
80 }
81}
82
83#[cfg(feature = "experimental_traverse")]
84impl<'a> SomeTable<'a> for OtKern<'a> {
85 fn type_name(&self) -> &str {
86 "OtKern"
87 }
88 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
89 match idx {
90 0usize => Some(Field::new("version", self.version())),
91 1usize => Some(Field::new("n_tables", self.n_tables())),
92 2usize => Some(Field::new("subtable_data", self.subtable_data())),
93 _ => None,
94 }
95 }
96}
97
98#[cfg(feature = "experimental_traverse")]
99#[allow(clippy::needless_lifetimes)]
100impl<'a> std::fmt::Debug for OtKern<'a> {
101 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102 (self as &dyn SomeTable<'a>).fmt(f)
103 }
104}
105
106impl<'a> MinByteRange<'a> for AatKern<'a> {
107 fn min_byte_range(&self) -> Range<usize> {
108 0..self.subtable_data_byte_range().end
109 }
110 fn min_table_bytes(&self) -> &'a [u8] {
111 let range = self.min_byte_range();
112 self.data.as_bytes().get(range).unwrap_or_default()
113 }
114}
115
116impl<'a> FontRead<'a> for AatKern<'a> {
117 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
118 #[allow(clippy::absurd_extreme_comparisons)]
119 if data.len() < Self::MIN_SIZE {
120 return Err(ReadError::OutOfBounds);
121 }
122 Ok(Self { data })
123 }
124}
125
126#[derive(Clone)]
128pub struct AatKern<'a> {
129 data: FontData<'a>,
130}
131
132#[allow(clippy::needless_lifetimes)]
133impl<'a> AatKern<'a> {
134 pub const MIN_SIZE: usize = (MajorMinor::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
135 basic_table_impls!(impl_the_methods);
136
137 pub fn version(&self) -> MajorMinor {
139 let range = self.version_byte_range();
140 self.data.read_at(range.start).ok().unwrap()
141 }
142
143 pub fn n_tables(&self) -> u32 {
145 let range = self.n_tables_byte_range();
146 self.data.read_at(range.start).ok().unwrap()
147 }
148
149 pub fn subtable_data(&self) -> &'a [u8] {
151 let range = self.subtable_data_byte_range();
152 self.data.read_array(range).ok().unwrap_or_default()
153 }
154
155 pub fn version_byte_range(&self) -> Range<usize> {
156 let start = 0;
157 start..start + MajorMinor::RAW_BYTE_LEN
158 }
159
160 pub fn n_tables_byte_range(&self) -> Range<usize> {
161 let start = self.version_byte_range().end;
162 start..start + u32::RAW_BYTE_LEN
163 }
164
165 pub fn subtable_data_byte_range(&self) -> Range<usize> {
166 let start = self.n_tables_byte_range().end;
167 start..start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN
168 }
169}
170
171const _: () = assert!(FontData::default_data_long_enough(AatKern::MIN_SIZE));
172
173impl Default for AatKern<'_> {
174 fn default() -> Self {
175 Self {
176 data: FontData::default_table_data(),
177 }
178 }
179}
180
181#[cfg(feature = "experimental_traverse")]
182impl<'a> SomeTable<'a> for AatKern<'a> {
183 fn type_name(&self) -> &str {
184 "AatKern"
185 }
186 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
187 match idx {
188 0usize => Some(Field::new("version", self.version())),
189 1usize => Some(Field::new("n_tables", self.n_tables())),
190 2usize => Some(Field::new("subtable_data", self.subtable_data())),
191 _ => None,
192 }
193 }
194}
195
196#[cfg(feature = "experimental_traverse")]
197#[allow(clippy::needless_lifetimes)]
198impl<'a> std::fmt::Debug for AatKern<'a> {
199 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
200 (self as &dyn SomeTable<'a>).fmt(f)
201 }
202}
203
204impl<'a> MinByteRange<'a> for OtSubtable<'a> {
205 fn min_byte_range(&self) -> Range<usize> {
206 0..self.data_byte_range().end
207 }
208 fn min_table_bytes(&self) -> &'a [u8] {
209 let range = self.min_byte_range();
210 self.data.as_bytes().get(range).unwrap_or_default()
211 }
212}
213
214impl<'a> FontRead<'a> for OtSubtable<'a> {
215 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
216 #[allow(clippy::absurd_extreme_comparisons)]
217 if data.len() < Self::MIN_SIZE {
218 return Err(ReadError::OutOfBounds);
219 }
220 Ok(Self { data })
221 }
222}
223
224#[derive(Clone)]
226pub struct OtSubtable<'a> {
227 data: FontData<'a>,
228}
229
230#[allow(clippy::needless_lifetimes)]
231impl<'a> OtSubtable<'a> {
232 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
233 basic_table_impls!(impl_the_methods);
234
235 pub fn version(&self) -> u16 {
237 let range = self.version_byte_range();
238 self.data.read_at(range.start).ok().unwrap()
239 }
240
241 pub fn length(&self) -> u16 {
243 let range = self.length_byte_range();
244 self.data.read_at(range.start).ok().unwrap()
245 }
246
247 pub fn coverage(&self) -> u16 {
249 let range = self.coverage_byte_range();
250 self.data.read_at(range.start).ok().unwrap()
251 }
252
253 pub fn data(&self) -> &'a [u8] {
255 let range = self.data_byte_range();
256 self.data.read_array(range).ok().unwrap_or_default()
257 }
258
259 pub fn version_byte_range(&self) -> Range<usize> {
260 let start = 0;
261 start..start + u16::RAW_BYTE_LEN
262 }
263
264 pub fn length_byte_range(&self) -> Range<usize> {
265 let start = self.version_byte_range().end;
266 start..start + u16::RAW_BYTE_LEN
267 }
268
269 pub fn coverage_byte_range(&self) -> Range<usize> {
270 let start = self.length_byte_range().end;
271 start..start + u16::RAW_BYTE_LEN
272 }
273
274 pub fn data_byte_range(&self) -> Range<usize> {
275 let start = self.coverage_byte_range().end;
276 start..start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN
277 }
278}
279
280const _: () = assert!(FontData::default_data_long_enough(OtSubtable::MIN_SIZE));
281
282impl Default for OtSubtable<'_> {
283 fn default() -> Self {
284 Self {
285 data: FontData::default_table_data(),
286 }
287 }
288}
289
290#[cfg(feature = "experimental_traverse")]
291impl<'a> SomeTable<'a> for OtSubtable<'a> {
292 fn type_name(&self) -> &str {
293 "OtSubtable"
294 }
295 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
296 match idx {
297 0usize => Some(Field::new("version", self.version())),
298 1usize => Some(Field::new("length", self.length())),
299 2usize => Some(Field::new("coverage", self.coverage())),
300 3usize => Some(Field::new("data", self.data())),
301 _ => None,
302 }
303 }
304}
305
306#[cfg(feature = "experimental_traverse")]
307#[allow(clippy::needless_lifetimes)]
308impl<'a> std::fmt::Debug for OtSubtable<'a> {
309 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
310 (self as &dyn SomeTable<'a>).fmt(f)
311 }
312}
313
314impl<'a> MinByteRange<'a> for AatSubtable<'a> {
315 fn min_byte_range(&self) -> Range<usize> {
316 0..self.data_byte_range().end
317 }
318 fn min_table_bytes(&self) -> &'a [u8] {
319 let range = self.min_byte_range();
320 self.data.as_bytes().get(range).unwrap_or_default()
321 }
322}
323
324impl<'a> FontRead<'a> for AatSubtable<'a> {
325 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
326 #[allow(clippy::absurd_extreme_comparisons)]
327 if data.len() < Self::MIN_SIZE {
328 return Err(ReadError::OutOfBounds);
329 }
330 Ok(Self { data })
331 }
332}
333
334#[derive(Clone)]
336pub struct AatSubtable<'a> {
337 data: FontData<'a>,
338}
339
340#[allow(clippy::needless_lifetimes)]
341impl<'a> AatSubtable<'a> {
342 pub const MIN_SIZE: usize = (u32::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
343 basic_table_impls!(impl_the_methods);
344
345 pub fn length(&self) -> u32 {
347 let range = self.length_byte_range();
348 self.data.read_at(range.start).ok().unwrap()
349 }
350
351 pub fn coverage(&self) -> u16 {
353 let range = self.coverage_byte_range();
354 self.data.read_at(range.start).ok().unwrap()
355 }
356
357 pub fn tuple_index(&self) -> u16 {
359 let range = self.tuple_index_byte_range();
360 self.data.read_at(range.start).ok().unwrap()
361 }
362
363 pub fn data(&self) -> &'a [u8] {
365 let range = self.data_byte_range();
366 self.data.read_array(range).ok().unwrap_or_default()
367 }
368
369 pub fn length_byte_range(&self) -> Range<usize> {
370 let start = 0;
371 start..start + u32::RAW_BYTE_LEN
372 }
373
374 pub fn coverage_byte_range(&self) -> Range<usize> {
375 let start = self.length_byte_range().end;
376 start..start + u16::RAW_BYTE_LEN
377 }
378
379 pub fn tuple_index_byte_range(&self) -> Range<usize> {
380 let start = self.coverage_byte_range().end;
381 start..start + u16::RAW_BYTE_LEN
382 }
383
384 pub fn data_byte_range(&self) -> Range<usize> {
385 let start = self.tuple_index_byte_range().end;
386 start..start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN
387 }
388}
389
390const _: () = assert!(FontData::default_data_long_enough(AatSubtable::MIN_SIZE));
391
392impl Default for AatSubtable<'_> {
393 fn default() -> Self {
394 Self {
395 data: FontData::default_table_data(),
396 }
397 }
398}
399
400#[cfg(feature = "experimental_traverse")]
401impl<'a> SomeTable<'a> for AatSubtable<'a> {
402 fn type_name(&self) -> &str {
403 "AatSubtable"
404 }
405 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
406 match idx {
407 0usize => Some(Field::new("length", self.length())),
408 1usize => Some(Field::new("coverage", self.coverage())),
409 2usize => Some(Field::new("tuple_index", self.tuple_index())),
410 3usize => Some(Field::new("data", self.data())),
411 _ => None,
412 }
413 }
414}
415
416#[cfg(feature = "experimental_traverse")]
417#[allow(clippy::needless_lifetimes)]
418impl<'a> std::fmt::Debug for AatSubtable<'a> {
419 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
420 (self as &dyn SomeTable<'a>).fmt(f)
421 }
422}
423
424impl<'a> MinByteRange<'a> for Subtable0<'a> {
425 fn min_byte_range(&self) -> Range<usize> {
426 0..self.pairs_byte_range().end
427 }
428 fn min_table_bytes(&self) -> &'a [u8] {
429 let range = self.min_byte_range();
430 self.data.as_bytes().get(range).unwrap_or_default()
431 }
432}
433
434impl<'a> FontRead<'a> for Subtable0<'a> {
435 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
436 #[allow(clippy::absurd_extreme_comparisons)]
437 if data.len() < Self::MIN_SIZE {
438 return Err(ReadError::OutOfBounds);
439 }
440 Ok(Self { data })
441 }
442}
443
444#[derive(Clone)]
446pub struct Subtable0<'a> {
447 data: FontData<'a>,
448}
449
450#[allow(clippy::needless_lifetimes)]
451impl<'a> Subtable0<'a> {
452 pub const MIN_SIZE: usize =
453 (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
454 basic_table_impls!(impl_the_methods);
455
456 pub fn n_pairs(&self) -> u16 {
458 let range = self.n_pairs_byte_range();
459 self.data.read_at(range.start).ok().unwrap()
460 }
461
462 pub fn search_range(&self) -> u16 {
464 let range = self.search_range_byte_range();
465 self.data.read_at(range.start).ok().unwrap()
466 }
467
468 pub fn entry_selector(&self) -> u16 {
470 let range = self.entry_selector_byte_range();
471 self.data.read_at(range.start).ok().unwrap()
472 }
473
474 pub fn range_shift(&self) -> u16 {
476 let range = self.range_shift_byte_range();
477 self.data.read_at(range.start).ok().unwrap()
478 }
479
480 pub fn pairs(&self) -> &'a [Subtable0Pair] {
482 let range = self.pairs_byte_range();
483 self.data.read_array(range).ok().unwrap_or_default()
484 }
485
486 pub fn n_pairs_byte_range(&self) -> Range<usize> {
487 let start = 0;
488 start..start + u16::RAW_BYTE_LEN
489 }
490
491 pub fn search_range_byte_range(&self) -> Range<usize> {
492 let start = self.n_pairs_byte_range().end;
493 start..start + u16::RAW_BYTE_LEN
494 }
495
496 pub fn entry_selector_byte_range(&self) -> Range<usize> {
497 let start = self.search_range_byte_range().end;
498 start..start + u16::RAW_BYTE_LEN
499 }
500
501 pub fn range_shift_byte_range(&self) -> Range<usize> {
502 let start = self.entry_selector_byte_range().end;
503 start..start + u16::RAW_BYTE_LEN
504 }
505
506 pub fn pairs_byte_range(&self) -> Range<usize> {
507 let n_pairs = self.n_pairs();
508 let start = self.range_shift_byte_range().end;
509 start..start + (transforms::to_usize(n_pairs)).saturating_mul(Subtable0Pair::RAW_BYTE_LEN)
510 }
511}
512
513const _: () = assert!(FontData::default_data_long_enough(Subtable0::MIN_SIZE));
514
515impl Default for Subtable0<'_> {
516 fn default() -> Self {
517 Self {
518 data: FontData::default_table_data(),
519 }
520 }
521}
522
523#[cfg(feature = "experimental_traverse")]
524impl<'a> SomeTable<'a> for Subtable0<'a> {
525 fn type_name(&self) -> &str {
526 "Subtable0"
527 }
528 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
529 match idx {
530 0usize => Some(Field::new("n_pairs", self.n_pairs())),
531 1usize => Some(Field::new("search_range", self.search_range())),
532 2usize => Some(Field::new("entry_selector", self.entry_selector())),
533 3usize => Some(Field::new("range_shift", self.range_shift())),
534 4usize => Some(Field::new(
535 "pairs",
536 traversal::FieldType::array_of_records(
537 stringify!(Subtable0Pair),
538 self.pairs(),
539 self.offset_data(),
540 ),
541 )),
542 _ => None,
543 }
544 }
545}
546
547#[cfg(feature = "experimental_traverse")]
548#[allow(clippy::needless_lifetimes)]
549impl<'a> std::fmt::Debug for Subtable0<'a> {
550 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
551 (self as &dyn SomeTable<'a>).fmt(f)
552 }
553}
554
555impl<'a> MinByteRange<'a> for Subtable2ClassTable<'a> {
556 fn min_byte_range(&self) -> Range<usize> {
557 0..self.offsets_byte_range().end
558 }
559 fn min_table_bytes(&self) -> &'a [u8] {
560 let range = self.min_byte_range();
561 self.data.as_bytes().get(range).unwrap_or_default()
562 }
563}
564
565impl<'a> FontRead<'a> for Subtable2ClassTable<'a> {
566 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
567 #[allow(clippy::absurd_extreme_comparisons)]
568 if data.len() < Self::MIN_SIZE {
569 return Err(ReadError::OutOfBounds);
570 }
571 Ok(Self { data })
572 }
573}
574
575#[derive(Clone)]
577pub struct Subtable2ClassTable<'a> {
578 data: FontData<'a>,
579}
580
581#[allow(clippy::needless_lifetimes)]
582impl<'a> Subtable2ClassTable<'a> {
583 pub const MIN_SIZE: usize = (GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
584 basic_table_impls!(impl_the_methods);
585
586 pub fn first_glyph(&self) -> GlyphId16 {
588 let range = self.first_glyph_byte_range();
589 self.data.read_at(range.start).ok().unwrap()
590 }
591
592 pub fn n_glyphs(&self) -> u16 {
594 let range = self.n_glyphs_byte_range();
595 self.data.read_at(range.start).ok().unwrap()
596 }
597
598 pub fn offsets(&self) -> &'a [BigEndian<u16>] {
600 let range = self.offsets_byte_range();
601 self.data.read_array(range).ok().unwrap_or_default()
602 }
603
604 pub fn first_glyph_byte_range(&self) -> Range<usize> {
605 let start = 0;
606 start..start + GlyphId16::RAW_BYTE_LEN
607 }
608
609 pub fn n_glyphs_byte_range(&self) -> Range<usize> {
610 let start = self.first_glyph_byte_range().end;
611 start..start + u16::RAW_BYTE_LEN
612 }
613
614 pub fn offsets_byte_range(&self) -> Range<usize> {
615 let n_glyphs = self.n_glyphs();
616 let start = self.n_glyphs_byte_range().end;
617 start..start + (transforms::to_usize(n_glyphs)).saturating_mul(u16::RAW_BYTE_LEN)
618 }
619}
620
621const _: () = assert!(FontData::default_data_long_enough(
622 Subtable2ClassTable::MIN_SIZE
623));
624
625impl Default for Subtable2ClassTable<'_> {
626 fn default() -> Self {
627 Self {
628 data: FontData::default_table_data(),
629 }
630 }
631}
632
633#[cfg(feature = "experimental_traverse")]
634impl<'a> SomeTable<'a> for Subtable2ClassTable<'a> {
635 fn type_name(&self) -> &str {
636 "Subtable2ClassTable"
637 }
638 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
639 match idx {
640 0usize => Some(Field::new("first_glyph", self.first_glyph())),
641 1usize => Some(Field::new("n_glyphs", self.n_glyphs())),
642 2usize => Some(Field::new("offsets", self.offsets())),
643 _ => None,
644 }
645 }
646}
647
648#[cfg(feature = "experimental_traverse")]
649#[allow(clippy::needless_lifetimes)]
650impl<'a> std::fmt::Debug for Subtable2ClassTable<'a> {
651 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
652 (self as &dyn SomeTable<'a>).fmt(f)
653 }
654}
655
656impl<'a> MinByteRange<'a> for Subtable3<'a> {
657 fn min_byte_range(&self) -> Range<usize> {
658 0..self.kern_index_byte_range().end
659 }
660 fn min_table_bytes(&self) -> &'a [u8] {
661 let range = self.min_byte_range();
662 self.data.as_bytes().get(range).unwrap_or_default()
663 }
664}
665
666impl<'a> FontRead<'a> for Subtable3<'a> {
667 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
668 #[allow(clippy::absurd_extreme_comparisons)]
669 if data.len() < Self::MIN_SIZE {
670 return Err(ReadError::OutOfBounds);
671 }
672 Ok(Self { data })
673 }
674}
675
676#[derive(Clone)]
678pub struct Subtable3<'a> {
679 data: FontData<'a>,
680}
681
682#[allow(clippy::needless_lifetimes)]
683impl<'a> Subtable3<'a> {
684 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
685 + u8::RAW_BYTE_LEN
686 + u8::RAW_BYTE_LEN
687 + u8::RAW_BYTE_LEN
688 + u8::RAW_BYTE_LEN);
689 basic_table_impls!(impl_the_methods);
690
691 pub fn glyph_count(&self) -> u16 {
693 let range = self.glyph_count_byte_range();
694 self.data.read_at(range.start).ok().unwrap()
695 }
696
697 pub fn kern_value_count(&self) -> u8 {
699 let range = self.kern_value_count_byte_range();
700 self.data.read_at(range.start).ok().unwrap()
701 }
702
703 pub fn left_class_count(&self) -> u8 {
705 let range = self.left_class_count_byte_range();
706 self.data.read_at(range.start).ok().unwrap()
707 }
708
709 pub fn right_class_count(&self) -> u8 {
711 let range = self.right_class_count_byte_range();
712 self.data.read_at(range.start).ok().unwrap()
713 }
714
715 pub fn flags(&self) -> u8 {
717 let range = self.flags_byte_range();
718 self.data.read_at(range.start).ok().unwrap()
719 }
720
721 pub fn kern_value(&self) -> &'a [BigEndian<i16>] {
723 let range = self.kern_value_byte_range();
724 self.data.read_array(range).ok().unwrap_or_default()
725 }
726
727 pub fn left_class(&self) -> &'a [u8] {
729 let range = self.left_class_byte_range();
730 self.data.read_array(range).ok().unwrap_or_default()
731 }
732
733 pub fn right_class(&self) -> &'a [u8] {
735 let range = self.right_class_byte_range();
736 self.data.read_array(range).ok().unwrap_or_default()
737 }
738
739 pub fn kern_index(&self) -> &'a [u8] {
741 let range = self.kern_index_byte_range();
742 self.data.read_array(range).ok().unwrap_or_default()
743 }
744
745 pub fn glyph_count_byte_range(&self) -> Range<usize> {
746 let start = 0;
747 start..start + u16::RAW_BYTE_LEN
748 }
749
750 pub fn kern_value_count_byte_range(&self) -> Range<usize> {
751 let start = self.glyph_count_byte_range().end;
752 start..start + u8::RAW_BYTE_LEN
753 }
754
755 pub fn left_class_count_byte_range(&self) -> Range<usize> {
756 let start = self.kern_value_count_byte_range().end;
757 start..start + u8::RAW_BYTE_LEN
758 }
759
760 pub fn right_class_count_byte_range(&self) -> Range<usize> {
761 let start = self.left_class_count_byte_range().end;
762 start..start + u8::RAW_BYTE_LEN
763 }
764
765 pub fn flags_byte_range(&self) -> Range<usize> {
766 let start = self.right_class_count_byte_range().end;
767 start..start + u8::RAW_BYTE_LEN
768 }
769
770 pub fn kern_value_byte_range(&self) -> Range<usize> {
771 let kern_value_count = self.kern_value_count();
772 let start = self.flags_byte_range().end;
773 start..start + (transforms::to_usize(kern_value_count)).saturating_mul(i16::RAW_BYTE_LEN)
774 }
775
776 pub fn left_class_byte_range(&self) -> Range<usize> {
777 let glyph_count = self.glyph_count();
778 let start = self.kern_value_byte_range().end;
779 start..start + (transforms::to_usize(glyph_count)).saturating_mul(u8::RAW_BYTE_LEN)
780 }
781
782 pub fn right_class_byte_range(&self) -> Range<usize> {
783 let glyph_count = self.glyph_count();
784 let start = self.left_class_byte_range().end;
785 start..start + (transforms::to_usize(glyph_count)).saturating_mul(u8::RAW_BYTE_LEN)
786 }
787
788 pub fn kern_index_byte_range(&self) -> Range<usize> {
789 let left_class_count = self.left_class_count();
790 let right_class_count = self.right_class_count();
791 let start = self.right_class_byte_range().end;
792 start
793 ..start
794 + (transforms::add_multiply(left_class_count, 0_usize, right_class_count))
795 .saturating_mul(u8::RAW_BYTE_LEN)
796 }
797}
798
799const _: () = assert!(FontData::default_data_long_enough(Subtable3::MIN_SIZE));
800
801impl Default for Subtable3<'_> {
802 fn default() -> Self {
803 Self {
804 data: FontData::default_table_data(),
805 }
806 }
807}
808
809#[cfg(feature = "experimental_traverse")]
810impl<'a> SomeTable<'a> for Subtable3<'a> {
811 fn type_name(&self) -> &str {
812 "Subtable3"
813 }
814 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
815 match idx {
816 0usize => Some(Field::new("glyph_count", self.glyph_count())),
817 1usize => Some(Field::new("kern_value_count", self.kern_value_count())),
818 2usize => Some(Field::new("left_class_count", self.left_class_count())),
819 3usize => Some(Field::new("right_class_count", self.right_class_count())),
820 4usize => Some(Field::new("flags", self.flags())),
821 5usize => Some(Field::new("kern_value", self.kern_value())),
822 6usize => Some(Field::new("left_class", self.left_class())),
823 7usize => Some(Field::new("right_class", self.right_class())),
824 8usize => Some(Field::new("kern_index", self.kern_index())),
825 _ => None,
826 }
827 }
828}
829
830#[cfg(feature = "experimental_traverse")]
831#[allow(clippy::needless_lifetimes)]
832impl<'a> std::fmt::Debug for Subtable3<'a> {
833 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
834 (self as &dyn SomeTable<'a>).fmt(f)
835 }
836}