1#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8impl<'a> MinByteRange<'a> for Gsub<'a> {
9 fn min_byte_range(&self) -> Range<usize> {
10 0..self.lookup_list_offset_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 TopLevelTable for Gsub<'_> {
19 const TAG: Tag = Tag::new(b"GSUB");
21}
22
23impl<'a> FontRead<'a> for Gsub<'a> {
24 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
25 #[allow(clippy::absurd_extreme_comparisons)]
26 if data.len() < Self::MIN_SIZE {
27 return Err(ReadError::OutOfBounds);
28 }
29 Ok(Self { data })
30 }
31}
32
33#[derive(Clone)]
35pub struct Gsub<'a> {
36 data: FontData<'a>,
37}
38
39#[allow(clippy::needless_lifetimes)]
40impl<'a> Gsub<'a> {
41 pub const MIN_SIZE: usize = (MajorMinor::RAW_BYTE_LEN
42 + Offset16::RAW_BYTE_LEN
43 + Offset16::RAW_BYTE_LEN
44 + Offset16::RAW_BYTE_LEN);
45 basic_table_impls!(impl_the_methods);
46
47 pub fn version(&self) -> MajorMinor {
49 let range = self.version_byte_range();
50 self.data.read_at(range.start).ok().unwrap()
51 }
52
53 pub fn script_list_offset(&self) -> Offset16 {
55 let range = self.script_list_offset_byte_range();
56 self.data.read_at(range.start).ok().unwrap()
57 }
58
59 pub fn script_list(&self) -> Result<ScriptList<'a>, ReadError> {
61 let data = self.data;
62 self.script_list_offset().resolve(data)
63 }
64
65 pub fn feature_list_offset(&self) -> Offset16 {
67 let range = self.feature_list_offset_byte_range();
68 self.data.read_at(range.start).ok().unwrap()
69 }
70
71 pub fn feature_list(&self) -> Result<FeatureList<'a>, ReadError> {
73 let data = self.data;
74 self.feature_list_offset().resolve(data)
75 }
76
77 pub fn lookup_list_offset(&self) -> Offset16 {
79 let range = self.lookup_list_offset_byte_range();
80 self.data.read_at(range.start).ok().unwrap()
81 }
82
83 pub fn lookup_list(&self) -> Result<SubstitutionLookupList<'a>, ReadError> {
85 let data = self.data;
86 self.lookup_list_offset().resolve(data)
87 }
88
89 pub fn feature_variations_offset(&self) -> Option<Nullable<Offset32>> {
92 let range = self.feature_variations_offset_byte_range();
93 (!range.is_empty())
94 .then(|| self.data.read_at(range.start).ok())
95 .flatten()
96 }
97
98 pub fn feature_variations(&self) -> Option<Result<FeatureVariations<'a>, ReadError>> {
100 let data = self.data;
101 self.feature_variations_offset().map(|x| x.resolve(data))?
102 }
103
104 pub fn version_byte_range(&self) -> Range<usize> {
105 let start = 0;
106 start..start + MajorMinor::RAW_BYTE_LEN
107 }
108
109 pub fn script_list_offset_byte_range(&self) -> Range<usize> {
110 let start = self.version_byte_range().end;
111 start..start + Offset16::RAW_BYTE_LEN
112 }
113
114 pub fn feature_list_offset_byte_range(&self) -> Range<usize> {
115 let start = self.script_list_offset_byte_range().end;
116 start..start + Offset16::RAW_BYTE_LEN
117 }
118
119 pub fn lookup_list_offset_byte_range(&self) -> Range<usize> {
120 let start = self.feature_list_offset_byte_range().end;
121 start..start + Offset16::RAW_BYTE_LEN
122 }
123
124 pub fn feature_variations_offset_byte_range(&self) -> Range<usize> {
125 let start = self.lookup_list_offset_byte_range().end;
126 start
127 ..(self.version().compatible((1u16, 1u16)))
128 .then(|| start + Offset32::RAW_BYTE_LEN)
129 .unwrap_or(start)
130 }
131}
132
133const _: () = assert!(FontData::default_data_long_enough(Gsub::MIN_SIZE));
134
135impl Default for Gsub<'_> {
136 fn default() -> Self {
137 Self {
138 data: FontData::default_table_data(),
139 }
140 }
141}
142
143#[cfg(feature = "experimental_traverse")]
144impl<'a> SomeTable<'a> for Gsub<'a> {
145 fn type_name(&self) -> &str {
146 "Gsub"
147 }
148 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
149 match idx {
150 0usize => Some(Field::new("version", self.version())),
151 1usize => Some(Field::new(
152 "script_list_offset",
153 FieldType::offset(self.script_list_offset(), self.script_list()),
154 )),
155 2usize => Some(Field::new(
156 "feature_list_offset",
157 FieldType::offset(self.feature_list_offset(), self.feature_list()),
158 )),
159 3usize => Some(Field::new(
160 "lookup_list_offset",
161 FieldType::offset(self.lookup_list_offset(), self.lookup_list()),
162 )),
163 4usize if self.version().compatible((1u16, 1u16)) => Some(Field::new(
164 "feature_variations_offset",
165 FieldType::offset(
166 self.feature_variations_offset().unwrap(),
167 self.feature_variations(),
168 ),
169 )),
170 _ => None,
171 }
172 }
173}
174
175#[cfg(feature = "experimental_traverse")]
176#[allow(clippy::needless_lifetimes)]
177impl<'a> std::fmt::Debug for Gsub<'a> {
178 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
179 (self as &dyn SomeTable<'a>).fmt(f)
180 }
181}
182
183pub enum SubstitutionLookup<'a> {
185 Single(Lookup<'a, SingleSubst<'a>>),
186 Multiple(Lookup<'a, MultipleSubstFormat1<'a>>),
187 Alternate(Lookup<'a, AlternateSubstFormat1<'a>>),
188 Ligature(Lookup<'a, LigatureSubstFormat1<'a>>),
189 Contextual(Lookup<'a, SubstitutionSequenceContext<'a>>),
190 ChainContextual(Lookup<'a, SubstitutionChainContext<'a>>),
191 Extension(Lookup<'a, ExtensionSubtable<'a>>),
192 Reverse(Lookup<'a, ReverseChainSingleSubstFormat1<'a>>),
193}
194
195impl Default for SubstitutionLookup<'_> {
196 fn default() -> Self {
197 Self::Single(Default::default())
198 }
199}
200
201impl<'a> FontRead<'a> for SubstitutionLookup<'a> {
202 fn read(bytes: FontData<'a>) -> Result<Self, ReadError> {
203 let discriminant = Lookup::read_discriminant(bytes)?;
204 match discriminant {
205 1 => Ok(SubstitutionLookup::Single(FontRead::read(bytes)?)),
206 2 => Ok(SubstitutionLookup::Multiple(FontRead::read(bytes)?)),
207 3 => Ok(SubstitutionLookup::Alternate(FontRead::read(bytes)?)),
208 4 => Ok(SubstitutionLookup::Ligature(FontRead::read(bytes)?)),
209 5 => Ok(SubstitutionLookup::Contextual(FontRead::read(bytes)?)),
210 6 => Ok(SubstitutionLookup::ChainContextual(FontRead::read(bytes)?)),
211 7 => Ok(SubstitutionLookup::Extension(FontRead::read(bytes)?)),
212 8 => Ok(SubstitutionLookup::Reverse(FontRead::read(bytes)?)),
213 other => Err(ReadError::InvalidFormat(other.into())),
214 }
215 }
216}
217
218impl<'a> SubstitutionLookup<'a> {
219 #[allow(dead_code)]
220 pub(crate) fn of_unit_type(&self) -> Lookup<'a, ()> {
224 match self {
225 SubstitutionLookup::Single(inner) => inner.of_unit_type(),
226 SubstitutionLookup::Multiple(inner) => inner.of_unit_type(),
227 SubstitutionLookup::Alternate(inner) => inner.of_unit_type(),
228 SubstitutionLookup::Ligature(inner) => inner.of_unit_type(),
229 SubstitutionLookup::Contextual(inner) => inner.of_unit_type(),
230 SubstitutionLookup::ChainContextual(inner) => inner.of_unit_type(),
231 SubstitutionLookup::Extension(inner) => inner.of_unit_type(),
232 SubstitutionLookup::Reverse(inner) => inner.of_unit_type(),
233 }
234 }
235}
236
237#[cfg(feature = "experimental_traverse")]
238impl<'a> SubstitutionLookup<'a> {
239 fn dyn_inner(&self) -> &(dyn SomeTable<'a> + 'a) {
240 match self {
241 SubstitutionLookup::Single(table) => table,
242 SubstitutionLookup::Multiple(table) => table,
243 SubstitutionLookup::Alternate(table) => table,
244 SubstitutionLookup::Ligature(table) => table,
245 SubstitutionLookup::Contextual(table) => table,
246 SubstitutionLookup::ChainContextual(table) => table,
247 SubstitutionLookup::Extension(table) => table,
248 SubstitutionLookup::Reverse(table) => table,
249 }
250 }
251}
252
253#[cfg(feature = "experimental_traverse")]
254impl<'a> SomeTable<'a> for SubstitutionLookup<'a> {
255 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
256 self.dyn_inner().get_field(idx)
257 }
258 fn type_name(&self) -> &str {
259 self.dyn_inner().type_name()
260 }
261}
262
263#[cfg(feature = "experimental_traverse")]
264impl std::fmt::Debug for SubstitutionLookup<'_> {
265 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
266 self.dyn_inner().fmt(f)
267 }
268}
269
270#[derive(Clone)]
272pub enum SingleSubst<'a> {
273 Format1(SingleSubstFormat1<'a>),
274 Format2(SingleSubstFormat2<'a>),
275}
276
277impl Default for SingleSubst<'_> {
278 fn default() -> Self {
279 Self::Format1(Default::default())
280 }
281}
282
283impl<'a> SingleSubst<'a> {
284 pub fn offset_data(&self) -> FontData<'a> {
286 match self {
287 Self::Format1(item) => item.offset_data(),
288 Self::Format2(item) => item.offset_data(),
289 }
290 }
291
292 pub fn subst_format(&self) -> u16 {
294 match self {
295 Self::Format1(item) => item.subst_format(),
296 Self::Format2(item) => item.subst_format(),
297 }
298 }
299
300 pub fn coverage_offset(&self) -> Offset16 {
303 match self {
304 Self::Format1(item) => item.coverage_offset(),
305 Self::Format2(item) => item.coverage_offset(),
306 }
307 }
308}
309
310impl<'a> FontRead<'a> for SingleSubst<'a> {
311 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
312 let format: u16 = data.read_at(0usize)?;
313 match format {
314 SingleSubstFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
315 SingleSubstFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
316 other => Err(ReadError::InvalidFormat(other.into())),
317 }
318 }
319}
320
321impl<'a> MinByteRange<'a> for SingleSubst<'a> {
322 fn min_byte_range(&self) -> Range<usize> {
323 match self {
324 Self::Format1(item) => item.min_byte_range(),
325 Self::Format2(item) => item.min_byte_range(),
326 }
327 }
328 fn min_table_bytes(&self) -> &'a [u8] {
329 match self {
330 Self::Format1(item) => item.min_table_bytes(),
331 Self::Format2(item) => item.min_table_bytes(),
332 }
333 }
334}
335
336#[cfg(feature = "experimental_traverse")]
337impl<'a> SingleSubst<'a> {
338 fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
339 match self {
340 Self::Format1(table) => table,
341 Self::Format2(table) => table,
342 }
343 }
344}
345
346#[cfg(feature = "experimental_traverse")]
347impl std::fmt::Debug for SingleSubst<'_> {
348 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
349 self.dyn_inner().fmt(f)
350 }
351}
352
353#[cfg(feature = "experimental_traverse")]
354impl<'a> SomeTable<'a> for SingleSubst<'a> {
355 fn type_name(&self) -> &str {
356 self.dyn_inner().type_name()
357 }
358 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
359 self.dyn_inner().get_field(idx)
360 }
361}
362
363impl Format<u16> for SingleSubstFormat1<'_> {
364 const FORMAT: u16 = 1;
365}
366
367impl<'a> MinByteRange<'a> for SingleSubstFormat1<'a> {
368 fn min_byte_range(&self) -> Range<usize> {
369 0..self.delta_glyph_id_byte_range().end
370 }
371 fn min_table_bytes(&self) -> &'a [u8] {
372 let range = self.min_byte_range();
373 self.data.as_bytes().get(range).unwrap_or_default()
374 }
375}
376
377impl<'a> FontRead<'a> for SingleSubstFormat1<'a> {
378 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
379 #[allow(clippy::absurd_extreme_comparisons)]
380 if data.len() < Self::MIN_SIZE {
381 return Err(ReadError::OutOfBounds);
382 }
383 Ok(Self { data })
384 }
385}
386
387#[derive(Clone)]
389pub struct SingleSubstFormat1<'a> {
390 data: FontData<'a>,
391}
392
393#[allow(clippy::needless_lifetimes)]
394impl<'a> SingleSubstFormat1<'a> {
395 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN);
396 basic_table_impls!(impl_the_methods);
397
398 pub fn subst_format(&self) -> u16 {
400 let range = self.subst_format_byte_range();
401 self.data.read_at(range.start).ok().unwrap()
402 }
403
404 pub fn coverage_offset(&self) -> Offset16 {
407 let range = self.coverage_offset_byte_range();
408 self.data.read_at(range.start).ok().unwrap()
409 }
410
411 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
413 let data = self.data;
414 self.coverage_offset().resolve(data)
415 }
416
417 pub fn delta_glyph_id(&self) -> i16 {
419 let range = self.delta_glyph_id_byte_range();
420 self.data.read_at(range.start).ok().unwrap()
421 }
422
423 pub fn subst_format_byte_range(&self) -> Range<usize> {
424 let start = 0;
425 start..start + u16::RAW_BYTE_LEN
426 }
427
428 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
429 let start = self.subst_format_byte_range().end;
430 start..start + Offset16::RAW_BYTE_LEN
431 }
432
433 pub fn delta_glyph_id_byte_range(&self) -> Range<usize> {
434 let start = self.coverage_offset_byte_range().end;
435 start..start + i16::RAW_BYTE_LEN
436 }
437}
438
439const _: () = assert!(FontData::default_data_long_enough(
440 SingleSubstFormat1::MIN_SIZE
441));
442
443impl Default for SingleSubstFormat1<'_> {
444 fn default() -> Self {
445 Self {
446 data: FontData::default_format_1_u16_table_data(),
447 }
448 }
449}
450
451#[cfg(feature = "experimental_traverse")]
452impl<'a> SomeTable<'a> for SingleSubstFormat1<'a> {
453 fn type_name(&self) -> &str {
454 "SingleSubstFormat1"
455 }
456 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
457 match idx {
458 0usize => Some(Field::new("subst_format", self.subst_format())),
459 1usize => Some(Field::new(
460 "coverage_offset",
461 FieldType::offset(self.coverage_offset(), self.coverage()),
462 )),
463 2usize => Some(Field::new("delta_glyph_id", self.delta_glyph_id())),
464 _ => None,
465 }
466 }
467}
468
469#[cfg(feature = "experimental_traverse")]
470#[allow(clippy::needless_lifetimes)]
471impl<'a> std::fmt::Debug for SingleSubstFormat1<'a> {
472 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
473 (self as &dyn SomeTable<'a>).fmt(f)
474 }
475}
476
477impl Format<u16> for SingleSubstFormat2<'_> {
478 const FORMAT: u16 = 2;
479}
480
481impl<'a> MinByteRange<'a> for SingleSubstFormat2<'a> {
482 fn min_byte_range(&self) -> Range<usize> {
483 0..self.substitute_glyph_ids_byte_range().end
484 }
485 fn min_table_bytes(&self) -> &'a [u8] {
486 let range = self.min_byte_range();
487 self.data.as_bytes().get(range).unwrap_or_default()
488 }
489}
490
491impl<'a> FontRead<'a> for SingleSubstFormat2<'a> {
492 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
493 #[allow(clippy::absurd_extreme_comparisons)]
494 if data.len() < Self::MIN_SIZE {
495 return Err(ReadError::OutOfBounds);
496 }
497 Ok(Self { data })
498 }
499}
500
501#[derive(Clone)]
503pub struct SingleSubstFormat2<'a> {
504 data: FontData<'a>,
505}
506
507#[allow(clippy::needless_lifetimes)]
508impl<'a> SingleSubstFormat2<'a> {
509 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
510 basic_table_impls!(impl_the_methods);
511
512 pub fn subst_format(&self) -> u16 {
514 let range = self.subst_format_byte_range();
515 self.data.read_at(range.start).ok().unwrap()
516 }
517
518 pub fn coverage_offset(&self) -> Offset16 {
521 let range = self.coverage_offset_byte_range();
522 self.data.read_at(range.start).ok().unwrap()
523 }
524
525 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
527 let data = self.data;
528 self.coverage_offset().resolve(data)
529 }
530
531 pub fn glyph_count(&self) -> u16 {
533 let range = self.glyph_count_byte_range();
534 self.data.read_at(range.start).ok().unwrap()
535 }
536
537 pub fn substitute_glyph_ids(&self) -> &'a [BigEndian<GlyphId16>] {
539 let range = self.substitute_glyph_ids_byte_range();
540 self.data.read_array(range).ok().unwrap_or_default()
541 }
542
543 pub fn subst_format_byte_range(&self) -> Range<usize> {
544 let start = 0;
545 start..start + u16::RAW_BYTE_LEN
546 }
547
548 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
549 let start = self.subst_format_byte_range().end;
550 start..start + Offset16::RAW_BYTE_LEN
551 }
552
553 pub fn glyph_count_byte_range(&self) -> Range<usize> {
554 let start = self.coverage_offset_byte_range().end;
555 start..start + u16::RAW_BYTE_LEN
556 }
557
558 pub fn substitute_glyph_ids_byte_range(&self) -> Range<usize> {
559 let glyph_count = self.glyph_count();
560 let start = self.glyph_count_byte_range().end;
561 start..start + (glyph_count as usize).saturating_mul(GlyphId16::RAW_BYTE_LEN)
562 }
563}
564
565#[cfg(feature = "experimental_traverse")]
566impl<'a> SomeTable<'a> for SingleSubstFormat2<'a> {
567 fn type_name(&self) -> &str {
568 "SingleSubstFormat2"
569 }
570 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
571 match idx {
572 0usize => Some(Field::new("subst_format", self.subst_format())),
573 1usize => Some(Field::new(
574 "coverage_offset",
575 FieldType::offset(self.coverage_offset(), self.coverage()),
576 )),
577 2usize => Some(Field::new("glyph_count", self.glyph_count())),
578 3usize => Some(Field::new(
579 "substitute_glyph_ids",
580 self.substitute_glyph_ids(),
581 )),
582 _ => None,
583 }
584 }
585}
586
587#[cfg(feature = "experimental_traverse")]
588#[allow(clippy::needless_lifetimes)]
589impl<'a> std::fmt::Debug for SingleSubstFormat2<'a> {
590 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
591 (self as &dyn SomeTable<'a>).fmt(f)
592 }
593}
594
595impl Format<u16> for MultipleSubstFormat1<'_> {
596 const FORMAT: u16 = 1;
597}
598
599impl<'a> MinByteRange<'a> for MultipleSubstFormat1<'a> {
600 fn min_byte_range(&self) -> Range<usize> {
601 0..self.sequence_offsets_byte_range().end
602 }
603 fn min_table_bytes(&self) -> &'a [u8] {
604 let range = self.min_byte_range();
605 self.data.as_bytes().get(range).unwrap_or_default()
606 }
607}
608
609impl<'a> FontRead<'a> for MultipleSubstFormat1<'a> {
610 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
611 #[allow(clippy::absurd_extreme_comparisons)]
612 if data.len() < Self::MIN_SIZE {
613 return Err(ReadError::OutOfBounds);
614 }
615 Ok(Self { data })
616 }
617}
618
619#[derive(Clone)]
621pub struct MultipleSubstFormat1<'a> {
622 data: FontData<'a>,
623}
624
625#[allow(clippy::needless_lifetimes)]
626impl<'a> MultipleSubstFormat1<'a> {
627 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
628 basic_table_impls!(impl_the_methods);
629
630 pub fn subst_format(&self) -> u16 {
632 let range = self.subst_format_byte_range();
633 self.data.read_at(range.start).ok().unwrap()
634 }
635
636 pub fn coverage_offset(&self) -> Offset16 {
639 let range = self.coverage_offset_byte_range();
640 self.data.read_at(range.start).ok().unwrap()
641 }
642
643 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
645 let data = self.data;
646 self.coverage_offset().resolve(data)
647 }
648
649 pub fn sequence_count(&self) -> u16 {
651 let range = self.sequence_count_byte_range();
652 self.data.read_at(range.start).ok().unwrap()
653 }
654
655 pub fn sequence_offsets(&self) -> &'a [BigEndian<Offset16>] {
658 let range = self.sequence_offsets_byte_range();
659 self.data.read_array(range).ok().unwrap_or_default()
660 }
661
662 pub fn sequences(&self) -> ArrayOfOffsets<'a, Sequence<'a>, Offset16> {
664 let data = self.data;
665 let offsets = self.sequence_offsets();
666 ArrayOfOffsets::new(offsets, data, ())
667 }
668
669 pub fn subst_format_byte_range(&self) -> Range<usize> {
670 let start = 0;
671 start..start + u16::RAW_BYTE_LEN
672 }
673
674 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
675 let start = self.subst_format_byte_range().end;
676 start..start + Offset16::RAW_BYTE_LEN
677 }
678
679 pub fn sequence_count_byte_range(&self) -> Range<usize> {
680 let start = self.coverage_offset_byte_range().end;
681 start..start + u16::RAW_BYTE_LEN
682 }
683
684 pub fn sequence_offsets_byte_range(&self) -> Range<usize> {
685 let sequence_count = self.sequence_count();
686 let start = self.sequence_count_byte_range().end;
687 start..start + (sequence_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
688 }
689}
690
691const _: () = assert!(FontData::default_data_long_enough(
692 MultipleSubstFormat1::MIN_SIZE
693));
694
695impl Default for MultipleSubstFormat1<'_> {
696 fn default() -> Self {
697 Self {
698 data: FontData::default_format_1_u16_table_data(),
699 }
700 }
701}
702
703#[cfg(feature = "experimental_traverse")]
704impl<'a> SomeTable<'a> for MultipleSubstFormat1<'a> {
705 fn type_name(&self) -> &str {
706 "MultipleSubstFormat1"
707 }
708 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
709 match idx {
710 0usize => Some(Field::new("subst_format", self.subst_format())),
711 1usize => Some(Field::new(
712 "coverage_offset",
713 FieldType::offset(self.coverage_offset(), self.coverage()),
714 )),
715 2usize => Some(Field::new("sequence_count", self.sequence_count())),
716 3usize => Some(Field::new(
717 "sequence_offsets",
718 FieldType::from(self.sequences()),
719 )),
720 _ => None,
721 }
722 }
723}
724
725#[cfg(feature = "experimental_traverse")]
726#[allow(clippy::needless_lifetimes)]
727impl<'a> std::fmt::Debug for MultipleSubstFormat1<'a> {
728 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
729 (self as &dyn SomeTable<'a>).fmt(f)
730 }
731}
732
733impl<'a> MinByteRange<'a> for Sequence<'a> {
734 fn min_byte_range(&self) -> Range<usize> {
735 0..self.substitute_glyph_ids_byte_range().end
736 }
737 fn min_table_bytes(&self) -> &'a [u8] {
738 let range = self.min_byte_range();
739 self.data.as_bytes().get(range).unwrap_or_default()
740 }
741}
742
743impl<'a> FontRead<'a> for Sequence<'a> {
744 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
745 #[allow(clippy::absurd_extreme_comparisons)]
746 if data.len() < Self::MIN_SIZE {
747 return Err(ReadError::OutOfBounds);
748 }
749 Ok(Self { data })
750 }
751}
752
753#[derive(Clone)]
755pub struct Sequence<'a> {
756 data: FontData<'a>,
757}
758
759#[allow(clippy::needless_lifetimes)]
760impl<'a> Sequence<'a> {
761 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
762 basic_table_impls!(impl_the_methods);
763
764 pub fn glyph_count(&self) -> u16 {
767 let range = self.glyph_count_byte_range();
768 self.data.read_at(range.start).ok().unwrap()
769 }
770
771 pub fn substitute_glyph_ids(&self) -> &'a [BigEndian<GlyphId16>] {
773 let range = self.substitute_glyph_ids_byte_range();
774 self.data.read_array(range).ok().unwrap_or_default()
775 }
776
777 pub fn glyph_count_byte_range(&self) -> Range<usize> {
778 let start = 0;
779 start..start + u16::RAW_BYTE_LEN
780 }
781
782 pub fn substitute_glyph_ids_byte_range(&self) -> Range<usize> {
783 let glyph_count = self.glyph_count();
784 let start = self.glyph_count_byte_range().end;
785 start..start + (glyph_count as usize).saturating_mul(GlyphId16::RAW_BYTE_LEN)
786 }
787}
788
789const _: () = assert!(FontData::default_data_long_enough(Sequence::MIN_SIZE));
790
791impl Default for Sequence<'_> {
792 fn default() -> Self {
793 Self {
794 data: FontData::default_table_data(),
795 }
796 }
797}
798
799#[cfg(feature = "experimental_traverse")]
800impl<'a> SomeTable<'a> for Sequence<'a> {
801 fn type_name(&self) -> &str {
802 "Sequence"
803 }
804 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
805 match idx {
806 0usize => Some(Field::new("glyph_count", self.glyph_count())),
807 1usize => Some(Field::new(
808 "substitute_glyph_ids",
809 self.substitute_glyph_ids(),
810 )),
811 _ => None,
812 }
813 }
814}
815
816#[cfg(feature = "experimental_traverse")]
817#[allow(clippy::needless_lifetimes)]
818impl<'a> std::fmt::Debug for Sequence<'a> {
819 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
820 (self as &dyn SomeTable<'a>).fmt(f)
821 }
822}
823
824impl Format<u16> for AlternateSubstFormat1<'_> {
825 const FORMAT: u16 = 1;
826}
827
828impl<'a> MinByteRange<'a> for AlternateSubstFormat1<'a> {
829 fn min_byte_range(&self) -> Range<usize> {
830 0..self.alternate_set_offsets_byte_range().end
831 }
832 fn min_table_bytes(&self) -> &'a [u8] {
833 let range = self.min_byte_range();
834 self.data.as_bytes().get(range).unwrap_or_default()
835 }
836}
837
838impl<'a> FontRead<'a> for AlternateSubstFormat1<'a> {
839 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
840 #[allow(clippy::absurd_extreme_comparisons)]
841 if data.len() < Self::MIN_SIZE {
842 return Err(ReadError::OutOfBounds);
843 }
844 Ok(Self { data })
845 }
846}
847
848#[derive(Clone)]
850pub struct AlternateSubstFormat1<'a> {
851 data: FontData<'a>,
852}
853
854#[allow(clippy::needless_lifetimes)]
855impl<'a> AlternateSubstFormat1<'a> {
856 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
857 basic_table_impls!(impl_the_methods);
858
859 pub fn subst_format(&self) -> u16 {
861 let range = self.subst_format_byte_range();
862 self.data.read_at(range.start).ok().unwrap()
863 }
864
865 pub fn coverage_offset(&self) -> Offset16 {
868 let range = self.coverage_offset_byte_range();
869 self.data.read_at(range.start).ok().unwrap()
870 }
871
872 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
874 let data = self.data;
875 self.coverage_offset().resolve(data)
876 }
877
878 pub fn alternate_set_count(&self) -> u16 {
880 let range = self.alternate_set_count_byte_range();
881 self.data.read_at(range.start).ok().unwrap()
882 }
883
884 pub fn alternate_set_offsets(&self) -> &'a [BigEndian<Offset16>] {
887 let range = self.alternate_set_offsets_byte_range();
888 self.data.read_array(range).ok().unwrap_or_default()
889 }
890
891 pub fn alternate_sets(&self) -> ArrayOfOffsets<'a, AlternateSet<'a>, Offset16> {
893 let data = self.data;
894 let offsets = self.alternate_set_offsets();
895 ArrayOfOffsets::new(offsets, data, ())
896 }
897
898 pub fn subst_format_byte_range(&self) -> Range<usize> {
899 let start = 0;
900 start..start + u16::RAW_BYTE_LEN
901 }
902
903 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
904 let start = self.subst_format_byte_range().end;
905 start..start + Offset16::RAW_BYTE_LEN
906 }
907
908 pub fn alternate_set_count_byte_range(&self) -> Range<usize> {
909 let start = self.coverage_offset_byte_range().end;
910 start..start + u16::RAW_BYTE_LEN
911 }
912
913 pub fn alternate_set_offsets_byte_range(&self) -> Range<usize> {
914 let alternate_set_count = self.alternate_set_count();
915 let start = self.alternate_set_count_byte_range().end;
916 start..start + (alternate_set_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
917 }
918}
919
920const _: () = assert!(FontData::default_data_long_enough(
921 AlternateSubstFormat1::MIN_SIZE
922));
923
924impl Default for AlternateSubstFormat1<'_> {
925 fn default() -> Self {
926 Self {
927 data: FontData::default_format_1_u16_table_data(),
928 }
929 }
930}
931
932#[cfg(feature = "experimental_traverse")]
933impl<'a> SomeTable<'a> for AlternateSubstFormat1<'a> {
934 fn type_name(&self) -> &str {
935 "AlternateSubstFormat1"
936 }
937 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
938 match idx {
939 0usize => Some(Field::new("subst_format", self.subst_format())),
940 1usize => Some(Field::new(
941 "coverage_offset",
942 FieldType::offset(self.coverage_offset(), self.coverage()),
943 )),
944 2usize => Some(Field::new(
945 "alternate_set_count",
946 self.alternate_set_count(),
947 )),
948 3usize => Some(Field::new(
949 "alternate_set_offsets",
950 FieldType::from(self.alternate_sets()),
951 )),
952 _ => None,
953 }
954 }
955}
956
957#[cfg(feature = "experimental_traverse")]
958#[allow(clippy::needless_lifetimes)]
959impl<'a> std::fmt::Debug for AlternateSubstFormat1<'a> {
960 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
961 (self as &dyn SomeTable<'a>).fmt(f)
962 }
963}
964
965impl<'a> MinByteRange<'a> for AlternateSet<'a> {
966 fn min_byte_range(&self) -> Range<usize> {
967 0..self.alternate_glyph_ids_byte_range().end
968 }
969 fn min_table_bytes(&self) -> &'a [u8] {
970 let range = self.min_byte_range();
971 self.data.as_bytes().get(range).unwrap_or_default()
972 }
973}
974
975impl<'a> FontRead<'a> for AlternateSet<'a> {
976 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
977 #[allow(clippy::absurd_extreme_comparisons)]
978 if data.len() < Self::MIN_SIZE {
979 return Err(ReadError::OutOfBounds);
980 }
981 Ok(Self { data })
982 }
983}
984
985#[derive(Clone)]
987pub struct AlternateSet<'a> {
988 data: FontData<'a>,
989}
990
991#[allow(clippy::needless_lifetimes)]
992impl<'a> AlternateSet<'a> {
993 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
994 basic_table_impls!(impl_the_methods);
995
996 pub fn glyph_count(&self) -> u16 {
998 let range = self.glyph_count_byte_range();
999 self.data.read_at(range.start).ok().unwrap()
1000 }
1001
1002 pub fn alternate_glyph_ids(&self) -> &'a [BigEndian<GlyphId16>] {
1004 let range = self.alternate_glyph_ids_byte_range();
1005 self.data.read_array(range).ok().unwrap_or_default()
1006 }
1007
1008 pub fn glyph_count_byte_range(&self) -> Range<usize> {
1009 let start = 0;
1010 start..start + u16::RAW_BYTE_LEN
1011 }
1012
1013 pub fn alternate_glyph_ids_byte_range(&self) -> Range<usize> {
1014 let glyph_count = self.glyph_count();
1015 let start = self.glyph_count_byte_range().end;
1016 start..start + (glyph_count as usize).saturating_mul(GlyphId16::RAW_BYTE_LEN)
1017 }
1018}
1019
1020const _: () = assert!(FontData::default_data_long_enough(AlternateSet::MIN_SIZE));
1021
1022impl Default for AlternateSet<'_> {
1023 fn default() -> Self {
1024 Self {
1025 data: FontData::default_table_data(),
1026 }
1027 }
1028}
1029
1030#[cfg(feature = "experimental_traverse")]
1031impl<'a> SomeTable<'a> for AlternateSet<'a> {
1032 fn type_name(&self) -> &str {
1033 "AlternateSet"
1034 }
1035 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1036 match idx {
1037 0usize => Some(Field::new("glyph_count", self.glyph_count())),
1038 1usize => Some(Field::new(
1039 "alternate_glyph_ids",
1040 self.alternate_glyph_ids(),
1041 )),
1042 _ => None,
1043 }
1044 }
1045}
1046
1047#[cfg(feature = "experimental_traverse")]
1048#[allow(clippy::needless_lifetimes)]
1049impl<'a> std::fmt::Debug for AlternateSet<'a> {
1050 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1051 (self as &dyn SomeTable<'a>).fmt(f)
1052 }
1053}
1054
1055impl Format<u16> for LigatureSubstFormat1<'_> {
1056 const FORMAT: u16 = 1;
1057}
1058
1059impl<'a> MinByteRange<'a> for LigatureSubstFormat1<'a> {
1060 fn min_byte_range(&self) -> Range<usize> {
1061 0..self.ligature_set_offsets_byte_range().end
1062 }
1063 fn min_table_bytes(&self) -> &'a [u8] {
1064 let range = self.min_byte_range();
1065 self.data.as_bytes().get(range).unwrap_or_default()
1066 }
1067}
1068
1069impl<'a> FontRead<'a> for LigatureSubstFormat1<'a> {
1070 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1071 #[allow(clippy::absurd_extreme_comparisons)]
1072 if data.len() < Self::MIN_SIZE {
1073 return Err(ReadError::OutOfBounds);
1074 }
1075 Ok(Self { data })
1076 }
1077}
1078
1079#[derive(Clone)]
1081pub struct LigatureSubstFormat1<'a> {
1082 data: FontData<'a>,
1083}
1084
1085#[allow(clippy::needless_lifetimes)]
1086impl<'a> LigatureSubstFormat1<'a> {
1087 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1088 basic_table_impls!(impl_the_methods);
1089
1090 pub fn subst_format(&self) -> u16 {
1092 let range = self.subst_format_byte_range();
1093 self.data.read_at(range.start).ok().unwrap()
1094 }
1095
1096 pub fn coverage_offset(&self) -> Offset16 {
1099 let range = self.coverage_offset_byte_range();
1100 self.data.read_at(range.start).ok().unwrap()
1101 }
1102
1103 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
1105 let data = self.data;
1106 self.coverage_offset().resolve(data)
1107 }
1108
1109 pub fn ligature_set_count(&self) -> u16 {
1111 let range = self.ligature_set_count_byte_range();
1112 self.data.read_at(range.start).ok().unwrap()
1113 }
1114
1115 pub fn ligature_set_offsets(&self) -> &'a [BigEndian<Offset16>] {
1118 let range = self.ligature_set_offsets_byte_range();
1119 self.data.read_array(range).ok().unwrap_or_default()
1120 }
1121
1122 pub fn ligature_sets(&self) -> ArrayOfOffsets<'a, LigatureSet<'a>, Offset16> {
1124 let data = self.data;
1125 let offsets = self.ligature_set_offsets();
1126 ArrayOfOffsets::new(offsets, data, ())
1127 }
1128
1129 pub fn subst_format_byte_range(&self) -> Range<usize> {
1130 let start = 0;
1131 start..start + u16::RAW_BYTE_LEN
1132 }
1133
1134 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
1135 let start = self.subst_format_byte_range().end;
1136 start..start + Offset16::RAW_BYTE_LEN
1137 }
1138
1139 pub fn ligature_set_count_byte_range(&self) -> Range<usize> {
1140 let start = self.coverage_offset_byte_range().end;
1141 start..start + u16::RAW_BYTE_LEN
1142 }
1143
1144 pub fn ligature_set_offsets_byte_range(&self) -> Range<usize> {
1145 let ligature_set_count = self.ligature_set_count();
1146 let start = self.ligature_set_count_byte_range().end;
1147 start..start + (ligature_set_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
1148 }
1149}
1150
1151const _: () = assert!(FontData::default_data_long_enough(
1152 LigatureSubstFormat1::MIN_SIZE
1153));
1154
1155impl Default for LigatureSubstFormat1<'_> {
1156 fn default() -> Self {
1157 Self {
1158 data: FontData::default_format_1_u16_table_data(),
1159 }
1160 }
1161}
1162
1163#[cfg(feature = "experimental_traverse")]
1164impl<'a> SomeTable<'a> for LigatureSubstFormat1<'a> {
1165 fn type_name(&self) -> &str {
1166 "LigatureSubstFormat1"
1167 }
1168 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1169 match idx {
1170 0usize => Some(Field::new("subst_format", self.subst_format())),
1171 1usize => Some(Field::new(
1172 "coverage_offset",
1173 FieldType::offset(self.coverage_offset(), self.coverage()),
1174 )),
1175 2usize => Some(Field::new("ligature_set_count", self.ligature_set_count())),
1176 3usize => Some(Field::new(
1177 "ligature_set_offsets",
1178 FieldType::from(self.ligature_sets()),
1179 )),
1180 _ => None,
1181 }
1182 }
1183}
1184
1185#[cfg(feature = "experimental_traverse")]
1186#[allow(clippy::needless_lifetimes)]
1187impl<'a> std::fmt::Debug for LigatureSubstFormat1<'a> {
1188 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1189 (self as &dyn SomeTable<'a>).fmt(f)
1190 }
1191}
1192
1193impl<'a> MinByteRange<'a> for LigatureSet<'a> {
1194 fn min_byte_range(&self) -> Range<usize> {
1195 0..self.ligature_offsets_byte_range().end
1196 }
1197 fn min_table_bytes(&self) -> &'a [u8] {
1198 let range = self.min_byte_range();
1199 self.data.as_bytes().get(range).unwrap_or_default()
1200 }
1201}
1202
1203impl<'a> FontRead<'a> for LigatureSet<'a> {
1204 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1205 #[allow(clippy::absurd_extreme_comparisons)]
1206 if data.len() < Self::MIN_SIZE {
1207 return Err(ReadError::OutOfBounds);
1208 }
1209 Ok(Self { data })
1210 }
1211}
1212
1213#[derive(Clone)]
1215pub struct LigatureSet<'a> {
1216 data: FontData<'a>,
1217}
1218
1219#[allow(clippy::needless_lifetimes)]
1220impl<'a> LigatureSet<'a> {
1221 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
1222 basic_table_impls!(impl_the_methods);
1223
1224 pub fn ligature_count(&self) -> u16 {
1226 let range = self.ligature_count_byte_range();
1227 self.data.read_at(range.start).ok().unwrap()
1228 }
1229
1230 pub fn ligature_offsets(&self) -> &'a [BigEndian<Offset16>] {
1233 let range = self.ligature_offsets_byte_range();
1234 self.data.read_array(range).ok().unwrap_or_default()
1235 }
1236
1237 pub fn ligatures(&self) -> ArrayOfOffsets<'a, Ligature<'a>, Offset16> {
1239 let data = self.data;
1240 let offsets = self.ligature_offsets();
1241 ArrayOfOffsets::new(offsets, data, ())
1242 }
1243
1244 pub fn ligature_count_byte_range(&self) -> Range<usize> {
1245 let start = 0;
1246 start..start + u16::RAW_BYTE_LEN
1247 }
1248
1249 pub fn ligature_offsets_byte_range(&self) -> Range<usize> {
1250 let ligature_count = self.ligature_count();
1251 let start = self.ligature_count_byte_range().end;
1252 start..start + (ligature_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
1253 }
1254}
1255
1256const _: () = assert!(FontData::default_data_long_enough(LigatureSet::MIN_SIZE));
1257
1258impl Default for LigatureSet<'_> {
1259 fn default() -> Self {
1260 Self {
1261 data: FontData::default_table_data(),
1262 }
1263 }
1264}
1265
1266#[cfg(feature = "experimental_traverse")]
1267impl<'a> SomeTable<'a> for LigatureSet<'a> {
1268 fn type_name(&self) -> &str {
1269 "LigatureSet"
1270 }
1271 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1272 match idx {
1273 0usize => Some(Field::new("ligature_count", self.ligature_count())),
1274 1usize => Some(Field::new(
1275 "ligature_offsets",
1276 FieldType::from(self.ligatures()),
1277 )),
1278 _ => None,
1279 }
1280 }
1281}
1282
1283#[cfg(feature = "experimental_traverse")]
1284#[allow(clippy::needless_lifetimes)]
1285impl<'a> std::fmt::Debug for LigatureSet<'a> {
1286 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1287 (self as &dyn SomeTable<'a>).fmt(f)
1288 }
1289}
1290
1291impl<'a> MinByteRange<'a> for Ligature<'a> {
1292 fn min_byte_range(&self) -> Range<usize> {
1293 0..self.component_glyph_ids_byte_range().end
1294 }
1295 fn min_table_bytes(&self) -> &'a [u8] {
1296 let range = self.min_byte_range();
1297 self.data.as_bytes().get(range).unwrap_or_default()
1298 }
1299}
1300
1301impl<'a> FontRead<'a> for Ligature<'a> {
1302 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1303 #[allow(clippy::absurd_extreme_comparisons)]
1304 if data.len() < Self::MIN_SIZE {
1305 return Err(ReadError::OutOfBounds);
1306 }
1307 Ok(Self { data })
1308 }
1309}
1310
1311#[derive(Clone)]
1313pub struct Ligature<'a> {
1314 data: FontData<'a>,
1315}
1316
1317#[allow(clippy::needless_lifetimes)]
1318impl<'a> Ligature<'a> {
1319 pub const MIN_SIZE: usize = (GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1320 basic_table_impls!(impl_the_methods);
1321
1322 pub fn ligature_glyph(&self) -> GlyphId16 {
1324 let range = self.ligature_glyph_byte_range();
1325 self.data.read_at(range.start).ok().unwrap()
1326 }
1327
1328 pub fn component_count(&self) -> u16 {
1330 let range = self.component_count_byte_range();
1331 self.data.read_at(range.start).ok().unwrap()
1332 }
1333
1334 pub fn component_glyph_ids(&self) -> &'a [BigEndian<GlyphId16>] {
1337 let range = self.component_glyph_ids_byte_range();
1338 self.data.read_array(range).ok().unwrap_or_default()
1339 }
1340
1341 pub fn ligature_glyph_byte_range(&self) -> Range<usize> {
1342 let start = 0;
1343 start..start + GlyphId16::RAW_BYTE_LEN
1344 }
1345
1346 pub fn component_count_byte_range(&self) -> Range<usize> {
1347 let start = self.ligature_glyph_byte_range().end;
1348 start..start + u16::RAW_BYTE_LEN
1349 }
1350
1351 pub fn component_glyph_ids_byte_range(&self) -> Range<usize> {
1352 let component_count = self.component_count();
1353 let start = self.component_count_byte_range().end;
1354 start
1355 ..start
1356 + (transforms::subtract(component_count, 1_usize))
1357 .saturating_mul(GlyphId16::RAW_BYTE_LEN)
1358 }
1359}
1360
1361const _: () = assert!(FontData::default_data_long_enough(Ligature::MIN_SIZE));
1362
1363impl Default for Ligature<'_> {
1364 fn default() -> Self {
1365 Self {
1366 data: FontData::default_table_data(),
1367 }
1368 }
1369}
1370
1371#[cfg(feature = "experimental_traverse")]
1372impl<'a> SomeTable<'a> for Ligature<'a> {
1373 fn type_name(&self) -> &str {
1374 "Ligature"
1375 }
1376 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1377 match idx {
1378 0usize => Some(Field::new("ligature_glyph", self.ligature_glyph())),
1379 1usize => Some(Field::new("component_count", self.component_count())),
1380 2usize => Some(Field::new(
1381 "component_glyph_ids",
1382 self.component_glyph_ids(),
1383 )),
1384 _ => None,
1385 }
1386 }
1387}
1388
1389#[cfg(feature = "experimental_traverse")]
1390#[allow(clippy::needless_lifetimes)]
1391impl<'a> std::fmt::Debug for Ligature<'a> {
1392 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1393 (self as &dyn SomeTable<'a>).fmt(f)
1394 }
1395}
1396
1397impl Format<u16> for ExtensionSubstFormat1<'_> {
1398 const FORMAT: u16 = 1;
1399}
1400
1401impl Discriminant for ExtensionSubstFormat1<'_, ()> {
1402 fn read_discriminant(data: FontData<'_>) -> Result<u16, ReadError> {
1403 data.read_at(u16::RAW_BYTE_LEN)
1404 }
1405}
1406
1407impl<'a, T> MinByteRange<'a> for ExtensionSubstFormat1<'a, T> {
1408 fn min_byte_range(&self) -> Range<usize> {
1409 0..self.extension_offset_byte_range().end
1410 }
1411 fn min_table_bytes(&self) -> &'a [u8] {
1412 let range = self.min_byte_range();
1413 self.data.as_bytes().get(range).unwrap_or_default()
1414 }
1415}
1416
1417impl<'a, T> FontRead<'a> for ExtensionSubstFormat1<'a, T> {
1418 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1419 #[allow(clippy::absurd_extreme_comparisons)]
1420 if data.len() < Self::MIN_SIZE {
1421 return Err(ReadError::OutOfBounds);
1422 }
1423 Ok(Self {
1424 data,
1425 offset_type: std::marker::PhantomData,
1426 })
1427 }
1428}
1429
1430impl<'a, T> ExtensionSubstFormat1<'a, T> {
1431 #[allow(dead_code)]
1432 pub(crate) fn of_unit_type(&self) -> ExtensionSubstFormat1<'a, ()> {
1434 ExtensionSubstFormat1 {
1435 data: self.data,
1436 offset_type: std::marker::PhantomData,
1437 }
1438 }
1439}
1440
1441#[derive(Clone)]
1443pub struct ExtensionSubstFormat1<'a, T = ()> {
1444 data: FontData<'a>,
1445 offset_type: std::marker::PhantomData<*const T>,
1446}
1447
1448#[allow(clippy::needless_lifetimes)]
1449impl<'a, T> ExtensionSubstFormat1<'a, T> {
1450 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN);
1451 basic_table_impls!(impl_the_methods);
1452
1453 pub fn subst_format(&self) -> u16 {
1455 let range = self.subst_format_byte_range();
1456 self.data.read_at(range.start).ok().unwrap()
1457 }
1458
1459 pub fn extension_lookup_type(&self) -> u16 {
1462 let range = self.extension_lookup_type_byte_range();
1463 self.data.read_at(range.start).ok().unwrap()
1464 }
1465
1466 pub fn extension_offset(&self) -> Offset32 {
1470 let range = self.extension_offset_byte_range();
1471 self.data.read_at(range.start).ok().unwrap()
1472 }
1473
1474 pub fn extension(&self) -> Result<T, ReadError>
1476 where
1477 T: FontRead<'a>,
1478 {
1479 let data = self.data;
1480 self.extension_offset().resolve(data)
1481 }
1482
1483 pub fn subst_format_byte_range(&self) -> Range<usize> {
1484 let start = 0;
1485 start..start + u16::RAW_BYTE_LEN
1486 }
1487
1488 pub fn extension_lookup_type_byte_range(&self) -> Range<usize> {
1489 let start = self.subst_format_byte_range().end;
1490 start..start + u16::RAW_BYTE_LEN
1491 }
1492
1493 pub fn extension_offset_byte_range(&self) -> Range<usize> {
1494 let start = self.extension_lookup_type_byte_range().end;
1495 start..start + Offset32::RAW_BYTE_LEN
1496 }
1497}
1498
1499const _: () = assert!(FontData::default_data_long_enough(
1500 ExtensionSubstFormat1::<()>::MIN_SIZE
1501));
1502
1503impl<T> Default for ExtensionSubstFormat1<'_, T> {
1504 fn default() -> Self {
1505 Self {
1506 data: FontData::default_format_1_u16_table_data(),
1507 offset_type: std::marker::PhantomData,
1508 }
1509 }
1510}
1511
1512#[cfg(feature = "experimental_traverse")]
1513impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> SomeTable<'a> for ExtensionSubstFormat1<'a, T> {
1514 fn type_name(&self) -> &str {
1515 "ExtensionSubstFormat1"
1516 }
1517 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1518 match idx {
1519 0usize => Some(Field::new("subst_format", self.subst_format())),
1520 1usize => Some(Field::new(
1521 "extension_lookup_type",
1522 self.extension_lookup_type(),
1523 )),
1524 2usize => Some(Field::new(
1525 "extension_offset",
1526 FieldType::offset(self.extension_offset(), self.extension()),
1527 )),
1528 _ => None,
1529 }
1530 }
1531}
1532
1533#[cfg(feature = "experimental_traverse")]
1534#[allow(clippy::needless_lifetimes)]
1535impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> std::fmt::Debug for ExtensionSubstFormat1<'a, T> {
1536 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1537 (self as &dyn SomeTable<'a>).fmt(f)
1538 }
1539}
1540
1541pub enum ExtensionSubtable<'a> {
1543 Single(ExtensionSubstFormat1<'a, SingleSubst<'a>>),
1544 Multiple(ExtensionSubstFormat1<'a, MultipleSubstFormat1<'a>>),
1545 Alternate(ExtensionSubstFormat1<'a, AlternateSubstFormat1<'a>>),
1546 Ligature(ExtensionSubstFormat1<'a, LigatureSubstFormat1<'a>>),
1547 Contextual(ExtensionSubstFormat1<'a, SubstitutionSequenceContext<'a>>),
1548 ChainContextual(ExtensionSubstFormat1<'a, SubstitutionChainContext<'a>>),
1549 Reverse(ExtensionSubstFormat1<'a, ReverseChainSingleSubstFormat1<'a>>),
1550}
1551
1552impl Default for ExtensionSubtable<'_> {
1553 fn default() -> Self {
1554 Self::Single(Default::default())
1555 }
1556}
1557
1558impl<'a> FontRead<'a> for ExtensionSubtable<'a> {
1559 fn read(bytes: FontData<'a>) -> Result<Self, ReadError> {
1560 let discriminant = ExtensionSubstFormat1::read_discriminant(bytes)?;
1561 match discriminant {
1562 1 => Ok(ExtensionSubtable::Single(FontRead::read(bytes)?)),
1563 2 => Ok(ExtensionSubtable::Multiple(FontRead::read(bytes)?)),
1564 3 => Ok(ExtensionSubtable::Alternate(FontRead::read(bytes)?)),
1565 4 => Ok(ExtensionSubtable::Ligature(FontRead::read(bytes)?)),
1566 5 => Ok(ExtensionSubtable::Contextual(FontRead::read(bytes)?)),
1567 6 => Ok(ExtensionSubtable::ChainContextual(FontRead::read(bytes)?)),
1568 8 => Ok(ExtensionSubtable::Reverse(FontRead::read(bytes)?)),
1569 other => Err(ReadError::InvalidFormat(other.into())),
1570 }
1571 }
1572}
1573
1574impl<'a> ExtensionSubtable<'a> {
1575 #[allow(dead_code)]
1576 pub(crate) fn of_unit_type(&self) -> ExtensionSubstFormat1<'a, ()> {
1580 match self {
1581 ExtensionSubtable::Single(inner) => inner.of_unit_type(),
1582 ExtensionSubtable::Multiple(inner) => inner.of_unit_type(),
1583 ExtensionSubtable::Alternate(inner) => inner.of_unit_type(),
1584 ExtensionSubtable::Ligature(inner) => inner.of_unit_type(),
1585 ExtensionSubtable::Contextual(inner) => inner.of_unit_type(),
1586 ExtensionSubtable::ChainContextual(inner) => inner.of_unit_type(),
1587 ExtensionSubtable::Reverse(inner) => inner.of_unit_type(),
1588 }
1589 }
1590}
1591
1592#[cfg(feature = "experimental_traverse")]
1593impl<'a> ExtensionSubtable<'a> {
1594 fn dyn_inner(&self) -> &(dyn SomeTable<'a> + 'a) {
1595 match self {
1596 ExtensionSubtable::Single(table) => table,
1597 ExtensionSubtable::Multiple(table) => table,
1598 ExtensionSubtable::Alternate(table) => table,
1599 ExtensionSubtable::Ligature(table) => table,
1600 ExtensionSubtable::Contextual(table) => table,
1601 ExtensionSubtable::ChainContextual(table) => table,
1602 ExtensionSubtable::Reverse(table) => table,
1603 }
1604 }
1605}
1606
1607#[cfg(feature = "experimental_traverse")]
1608impl<'a> SomeTable<'a> for ExtensionSubtable<'a> {
1609 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1610 self.dyn_inner().get_field(idx)
1611 }
1612 fn type_name(&self) -> &str {
1613 self.dyn_inner().type_name()
1614 }
1615}
1616
1617#[cfg(feature = "experimental_traverse")]
1618impl std::fmt::Debug for ExtensionSubtable<'_> {
1619 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1620 self.dyn_inner().fmt(f)
1621 }
1622}
1623
1624impl Format<u16> for ReverseChainSingleSubstFormat1<'_> {
1625 const FORMAT: u16 = 1;
1626}
1627
1628impl<'a> MinByteRange<'a> for ReverseChainSingleSubstFormat1<'a> {
1629 fn min_byte_range(&self) -> Range<usize> {
1630 0..self.substitute_glyph_ids_byte_range().end
1631 }
1632 fn min_table_bytes(&self) -> &'a [u8] {
1633 let range = self.min_byte_range();
1634 self.data.as_bytes().get(range).unwrap_or_default()
1635 }
1636}
1637
1638impl<'a> FontRead<'a> for ReverseChainSingleSubstFormat1<'a> {
1639 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1640 #[allow(clippy::absurd_extreme_comparisons)]
1641 if data.len() < Self::MIN_SIZE {
1642 return Err(ReadError::OutOfBounds);
1643 }
1644 Ok(Self { data })
1645 }
1646}
1647
1648#[derive(Clone)]
1650pub struct ReverseChainSingleSubstFormat1<'a> {
1651 data: FontData<'a>,
1652}
1653
1654#[allow(clippy::needless_lifetimes)]
1655impl<'a> ReverseChainSingleSubstFormat1<'a> {
1656 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1657 + Offset16::RAW_BYTE_LEN
1658 + u16::RAW_BYTE_LEN
1659 + u16::RAW_BYTE_LEN
1660 + u16::RAW_BYTE_LEN);
1661 basic_table_impls!(impl_the_methods);
1662
1663 pub fn subst_format(&self) -> u16 {
1665 let range = self.subst_format_byte_range();
1666 self.data.read_at(range.start).ok().unwrap()
1667 }
1668
1669 pub fn coverage_offset(&self) -> Offset16 {
1672 let range = self.coverage_offset_byte_range();
1673 self.data.read_at(range.start).ok().unwrap()
1674 }
1675
1676 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
1678 let data = self.data;
1679 self.coverage_offset().resolve(data)
1680 }
1681
1682 pub fn backtrack_glyph_count(&self) -> u16 {
1684 let range = self.backtrack_glyph_count_byte_range();
1685 self.data.read_at(range.start).ok().unwrap()
1686 }
1687
1688 pub fn backtrack_coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
1691 let range = self.backtrack_coverage_offsets_byte_range();
1692 self.data.read_array(range).ok().unwrap_or_default()
1693 }
1694
1695 pub fn backtrack_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
1697 let data = self.data;
1698 let offsets = self.backtrack_coverage_offsets();
1699 ArrayOfOffsets::new(offsets, data, ())
1700 }
1701
1702 pub fn lookahead_glyph_count(&self) -> u16 {
1704 let range = self.lookahead_glyph_count_byte_range();
1705 self.data.read_at(range.start).ok().unwrap_or_default()
1706 }
1707
1708 pub fn lookahead_coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
1711 let range = self.lookahead_coverage_offsets_byte_range();
1712 self.data.read_array(range).ok().unwrap_or_default()
1713 }
1714
1715 pub fn lookahead_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
1717 let data = self.data;
1718 let offsets = self.lookahead_coverage_offsets();
1719 ArrayOfOffsets::new(offsets, data, ())
1720 }
1721
1722 pub fn glyph_count(&self) -> u16 {
1724 let range = self.glyph_count_byte_range();
1725 self.data.read_at(range.start).ok().unwrap_or_default()
1726 }
1727
1728 pub fn substitute_glyph_ids(&self) -> &'a [BigEndian<GlyphId16>] {
1730 let range = self.substitute_glyph_ids_byte_range();
1731 self.data.read_array(range).ok().unwrap_or_default()
1732 }
1733
1734 pub fn subst_format_byte_range(&self) -> Range<usize> {
1735 let start = 0;
1736 start..start + u16::RAW_BYTE_LEN
1737 }
1738
1739 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
1740 let start = self.subst_format_byte_range().end;
1741 start..start + Offset16::RAW_BYTE_LEN
1742 }
1743
1744 pub fn backtrack_glyph_count_byte_range(&self) -> Range<usize> {
1745 let start = self.coverage_offset_byte_range().end;
1746 start..start + u16::RAW_BYTE_LEN
1747 }
1748
1749 pub fn backtrack_coverage_offsets_byte_range(&self) -> Range<usize> {
1750 let backtrack_glyph_count = self.backtrack_glyph_count();
1751 let start = self.backtrack_glyph_count_byte_range().end;
1752 start..start + (backtrack_glyph_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
1753 }
1754
1755 pub fn lookahead_glyph_count_byte_range(&self) -> Range<usize> {
1756 let start = self.backtrack_coverage_offsets_byte_range().end;
1757 start..start + u16::RAW_BYTE_LEN
1758 }
1759
1760 pub fn lookahead_coverage_offsets_byte_range(&self) -> Range<usize> {
1761 let lookahead_glyph_count = self.lookahead_glyph_count();
1762 let start = self.lookahead_glyph_count_byte_range().end;
1763 start..start + (lookahead_glyph_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
1764 }
1765
1766 pub fn glyph_count_byte_range(&self) -> Range<usize> {
1767 let start = self.lookahead_coverage_offsets_byte_range().end;
1768 start..start + u16::RAW_BYTE_LEN
1769 }
1770
1771 pub fn substitute_glyph_ids_byte_range(&self) -> Range<usize> {
1772 let glyph_count = self.glyph_count();
1773 let start = self.glyph_count_byte_range().end;
1774 start..start + (glyph_count as usize).saturating_mul(GlyphId16::RAW_BYTE_LEN)
1775 }
1776}
1777
1778const _: () = assert!(FontData::default_data_long_enough(
1779 ReverseChainSingleSubstFormat1::MIN_SIZE
1780));
1781
1782impl Default for ReverseChainSingleSubstFormat1<'_> {
1783 fn default() -> Self {
1784 Self {
1785 data: FontData::default_format_1_u16_table_data(),
1786 }
1787 }
1788}
1789
1790#[cfg(feature = "experimental_traverse")]
1791impl<'a> SomeTable<'a> for ReverseChainSingleSubstFormat1<'a> {
1792 fn type_name(&self) -> &str {
1793 "ReverseChainSingleSubstFormat1"
1794 }
1795 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1796 match idx {
1797 0usize => Some(Field::new("subst_format", self.subst_format())),
1798 1usize => Some(Field::new(
1799 "coverage_offset",
1800 FieldType::offset(self.coverage_offset(), self.coverage()),
1801 )),
1802 2usize => Some(Field::new(
1803 "backtrack_glyph_count",
1804 self.backtrack_glyph_count(),
1805 )),
1806 3usize => Some(Field::new(
1807 "backtrack_coverage_offsets",
1808 FieldType::from(self.backtrack_coverages()),
1809 )),
1810 4usize => Some(Field::new(
1811 "lookahead_glyph_count",
1812 self.lookahead_glyph_count(),
1813 )),
1814 5usize => Some(Field::new(
1815 "lookahead_coverage_offsets",
1816 FieldType::from(self.lookahead_coverages()),
1817 )),
1818 6usize => Some(Field::new("glyph_count", self.glyph_count())),
1819 7usize => Some(Field::new(
1820 "substitute_glyph_ids",
1821 self.substitute_glyph_ids(),
1822 )),
1823 _ => None,
1824 }
1825 }
1826}
1827
1828#[cfg(feature = "experimental_traverse")]
1829#[allow(clippy::needless_lifetimes)]
1830impl<'a> std::fmt::Debug for ReverseChainSingleSubstFormat1<'a> {
1831 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1832 (self as &dyn SomeTable<'a>).fmt(f)
1833 }
1834}