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