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 + (transforms::to_usize(glyph_count)).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 + (transforms::to_usize(sequence_count)).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 + (transforms::to_usize(glyph_count)).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
917 ..start
918 + (transforms::to_usize(alternate_set_count)).saturating_mul(Offset16::RAW_BYTE_LEN)
919 }
920}
921
922const _: () = assert!(FontData::default_data_long_enough(
923 AlternateSubstFormat1::MIN_SIZE
924));
925
926impl Default for AlternateSubstFormat1<'_> {
927 fn default() -> Self {
928 Self {
929 data: FontData::default_format_1_u16_table_data(),
930 }
931 }
932}
933
934#[cfg(feature = "experimental_traverse")]
935impl<'a> SomeTable<'a> for AlternateSubstFormat1<'a> {
936 fn type_name(&self) -> &str {
937 "AlternateSubstFormat1"
938 }
939 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
940 match idx {
941 0usize => Some(Field::new("subst_format", self.subst_format())),
942 1usize => Some(Field::new(
943 "coverage_offset",
944 FieldType::offset(self.coverage_offset(), self.coverage()),
945 )),
946 2usize => Some(Field::new(
947 "alternate_set_count",
948 self.alternate_set_count(),
949 )),
950 3usize => Some(Field::new(
951 "alternate_set_offsets",
952 FieldType::from(self.alternate_sets()),
953 )),
954 _ => None,
955 }
956 }
957}
958
959#[cfg(feature = "experimental_traverse")]
960#[allow(clippy::needless_lifetimes)]
961impl<'a> std::fmt::Debug for AlternateSubstFormat1<'a> {
962 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
963 (self as &dyn SomeTable<'a>).fmt(f)
964 }
965}
966
967impl<'a> MinByteRange<'a> for AlternateSet<'a> {
968 fn min_byte_range(&self) -> Range<usize> {
969 0..self.alternate_glyph_ids_byte_range().end
970 }
971 fn min_table_bytes(&self) -> &'a [u8] {
972 let range = self.min_byte_range();
973 self.data.as_bytes().get(range).unwrap_or_default()
974 }
975}
976
977impl<'a> FontRead<'a> for AlternateSet<'a> {
978 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
979 #[allow(clippy::absurd_extreme_comparisons)]
980 if data.len() < Self::MIN_SIZE {
981 return Err(ReadError::OutOfBounds);
982 }
983 Ok(Self { data })
984 }
985}
986
987#[derive(Clone)]
989pub struct AlternateSet<'a> {
990 data: FontData<'a>,
991}
992
993#[allow(clippy::needless_lifetimes)]
994impl<'a> AlternateSet<'a> {
995 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
996 basic_table_impls!(impl_the_methods);
997
998 pub fn glyph_count(&self) -> u16 {
1000 let range = self.glyph_count_byte_range();
1001 self.data.read_at(range.start).ok().unwrap()
1002 }
1003
1004 pub fn alternate_glyph_ids(&self) -> &'a [BigEndian<GlyphId16>] {
1006 let range = self.alternate_glyph_ids_byte_range();
1007 self.data.read_array(range).ok().unwrap_or_default()
1008 }
1009
1010 pub fn glyph_count_byte_range(&self) -> Range<usize> {
1011 let start = 0;
1012 start..start + u16::RAW_BYTE_LEN
1013 }
1014
1015 pub fn alternate_glyph_ids_byte_range(&self) -> Range<usize> {
1016 let glyph_count = self.glyph_count();
1017 let start = self.glyph_count_byte_range().end;
1018 start..start + (transforms::to_usize(glyph_count)).saturating_mul(GlyphId16::RAW_BYTE_LEN)
1019 }
1020}
1021
1022const _: () = assert!(FontData::default_data_long_enough(AlternateSet::MIN_SIZE));
1023
1024impl Default for AlternateSet<'_> {
1025 fn default() -> Self {
1026 Self {
1027 data: FontData::default_table_data(),
1028 }
1029 }
1030}
1031
1032#[cfg(feature = "experimental_traverse")]
1033impl<'a> SomeTable<'a> for AlternateSet<'a> {
1034 fn type_name(&self) -> &str {
1035 "AlternateSet"
1036 }
1037 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1038 match idx {
1039 0usize => Some(Field::new("glyph_count", self.glyph_count())),
1040 1usize => Some(Field::new(
1041 "alternate_glyph_ids",
1042 self.alternate_glyph_ids(),
1043 )),
1044 _ => None,
1045 }
1046 }
1047}
1048
1049#[cfg(feature = "experimental_traverse")]
1050#[allow(clippy::needless_lifetimes)]
1051impl<'a> std::fmt::Debug for AlternateSet<'a> {
1052 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1053 (self as &dyn SomeTable<'a>).fmt(f)
1054 }
1055}
1056
1057impl Format<u16> for LigatureSubstFormat1<'_> {
1058 const FORMAT: u16 = 1;
1059}
1060
1061impl<'a> MinByteRange<'a> for LigatureSubstFormat1<'a> {
1062 fn min_byte_range(&self) -> Range<usize> {
1063 0..self.ligature_set_offsets_byte_range().end
1064 }
1065 fn min_table_bytes(&self) -> &'a [u8] {
1066 let range = self.min_byte_range();
1067 self.data.as_bytes().get(range).unwrap_or_default()
1068 }
1069}
1070
1071impl<'a> FontRead<'a> for LigatureSubstFormat1<'a> {
1072 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1073 #[allow(clippy::absurd_extreme_comparisons)]
1074 if data.len() < Self::MIN_SIZE {
1075 return Err(ReadError::OutOfBounds);
1076 }
1077 Ok(Self { data })
1078 }
1079}
1080
1081#[derive(Clone)]
1083pub struct LigatureSubstFormat1<'a> {
1084 data: FontData<'a>,
1085}
1086
1087#[allow(clippy::needless_lifetimes)]
1088impl<'a> LigatureSubstFormat1<'a> {
1089 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1090 basic_table_impls!(impl_the_methods);
1091
1092 pub fn subst_format(&self) -> u16 {
1094 let range = self.subst_format_byte_range();
1095 self.data.read_at(range.start).ok().unwrap()
1096 }
1097
1098 pub fn coverage_offset(&self) -> Offset16 {
1101 let range = self.coverage_offset_byte_range();
1102 self.data.read_at(range.start).ok().unwrap()
1103 }
1104
1105 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
1107 let data = self.data;
1108 self.coverage_offset().resolve(data)
1109 }
1110
1111 pub fn ligature_set_count(&self) -> u16 {
1113 let range = self.ligature_set_count_byte_range();
1114 self.data.read_at(range.start).ok().unwrap()
1115 }
1116
1117 pub fn ligature_set_offsets(&self) -> &'a [BigEndian<Offset16>] {
1120 let range = self.ligature_set_offsets_byte_range();
1121 self.data.read_array(range).ok().unwrap_or_default()
1122 }
1123
1124 pub fn ligature_sets(&self) -> ArrayOfOffsets<'a, LigatureSet<'a>, Offset16> {
1126 let data = self.data;
1127 let offsets = self.ligature_set_offsets();
1128 ArrayOfOffsets::new(offsets, data, ())
1129 }
1130
1131 pub fn subst_format_byte_range(&self) -> Range<usize> {
1132 let start = 0;
1133 start..start + u16::RAW_BYTE_LEN
1134 }
1135
1136 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
1137 let start = self.subst_format_byte_range().end;
1138 start..start + Offset16::RAW_BYTE_LEN
1139 }
1140
1141 pub fn ligature_set_count_byte_range(&self) -> Range<usize> {
1142 let start = self.coverage_offset_byte_range().end;
1143 start..start + u16::RAW_BYTE_LEN
1144 }
1145
1146 pub fn ligature_set_offsets_byte_range(&self) -> Range<usize> {
1147 let ligature_set_count = self.ligature_set_count();
1148 let start = self.ligature_set_count_byte_range().end;
1149 start
1150 ..start
1151 + (transforms::to_usize(ligature_set_count)).saturating_mul(Offset16::RAW_BYTE_LEN)
1152 }
1153}
1154
1155const _: () = assert!(FontData::default_data_long_enough(
1156 LigatureSubstFormat1::MIN_SIZE
1157));
1158
1159impl Default for LigatureSubstFormat1<'_> {
1160 fn default() -> Self {
1161 Self {
1162 data: FontData::default_format_1_u16_table_data(),
1163 }
1164 }
1165}
1166
1167#[cfg(feature = "experimental_traverse")]
1168impl<'a> SomeTable<'a> for LigatureSubstFormat1<'a> {
1169 fn type_name(&self) -> &str {
1170 "LigatureSubstFormat1"
1171 }
1172 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1173 match idx {
1174 0usize => Some(Field::new("subst_format", self.subst_format())),
1175 1usize => Some(Field::new(
1176 "coverage_offset",
1177 FieldType::offset(self.coverage_offset(), self.coverage()),
1178 )),
1179 2usize => Some(Field::new("ligature_set_count", self.ligature_set_count())),
1180 3usize => Some(Field::new(
1181 "ligature_set_offsets",
1182 FieldType::from(self.ligature_sets()),
1183 )),
1184 _ => None,
1185 }
1186 }
1187}
1188
1189#[cfg(feature = "experimental_traverse")]
1190#[allow(clippy::needless_lifetimes)]
1191impl<'a> std::fmt::Debug for LigatureSubstFormat1<'a> {
1192 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1193 (self as &dyn SomeTable<'a>).fmt(f)
1194 }
1195}
1196
1197impl<'a> MinByteRange<'a> for LigatureSet<'a> {
1198 fn min_byte_range(&self) -> Range<usize> {
1199 0..self.ligature_offsets_byte_range().end
1200 }
1201 fn min_table_bytes(&self) -> &'a [u8] {
1202 let range = self.min_byte_range();
1203 self.data.as_bytes().get(range).unwrap_or_default()
1204 }
1205}
1206
1207impl<'a> FontRead<'a> for LigatureSet<'a> {
1208 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1209 #[allow(clippy::absurd_extreme_comparisons)]
1210 if data.len() < Self::MIN_SIZE {
1211 return Err(ReadError::OutOfBounds);
1212 }
1213 Ok(Self { data })
1214 }
1215}
1216
1217#[derive(Clone)]
1219pub struct LigatureSet<'a> {
1220 data: FontData<'a>,
1221}
1222
1223#[allow(clippy::needless_lifetimes)]
1224impl<'a> LigatureSet<'a> {
1225 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
1226 basic_table_impls!(impl_the_methods);
1227
1228 pub fn ligature_count(&self) -> u16 {
1230 let range = self.ligature_count_byte_range();
1231 self.data.read_at(range.start).ok().unwrap()
1232 }
1233
1234 pub fn ligature_offsets(&self) -> &'a [BigEndian<Offset16>] {
1237 let range = self.ligature_offsets_byte_range();
1238 self.data.read_array(range).ok().unwrap_or_default()
1239 }
1240
1241 pub fn ligatures(&self) -> ArrayOfOffsets<'a, Ligature<'a>, Offset16> {
1243 let data = self.data;
1244 let offsets = self.ligature_offsets();
1245 ArrayOfOffsets::new(offsets, data, ())
1246 }
1247
1248 pub fn ligature_count_byte_range(&self) -> Range<usize> {
1249 let start = 0;
1250 start..start + u16::RAW_BYTE_LEN
1251 }
1252
1253 pub fn ligature_offsets_byte_range(&self) -> Range<usize> {
1254 let ligature_count = self.ligature_count();
1255 let start = self.ligature_count_byte_range().end;
1256 start..start + (transforms::to_usize(ligature_count)).saturating_mul(Offset16::RAW_BYTE_LEN)
1257 }
1258}
1259
1260const _: () = assert!(FontData::default_data_long_enough(LigatureSet::MIN_SIZE));
1261
1262impl Default for LigatureSet<'_> {
1263 fn default() -> Self {
1264 Self {
1265 data: FontData::default_table_data(),
1266 }
1267 }
1268}
1269
1270#[cfg(feature = "experimental_traverse")]
1271impl<'a> SomeTable<'a> for LigatureSet<'a> {
1272 fn type_name(&self) -> &str {
1273 "LigatureSet"
1274 }
1275 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1276 match idx {
1277 0usize => Some(Field::new("ligature_count", self.ligature_count())),
1278 1usize => Some(Field::new(
1279 "ligature_offsets",
1280 FieldType::from(self.ligatures()),
1281 )),
1282 _ => None,
1283 }
1284 }
1285}
1286
1287#[cfg(feature = "experimental_traverse")]
1288#[allow(clippy::needless_lifetimes)]
1289impl<'a> std::fmt::Debug for LigatureSet<'a> {
1290 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1291 (self as &dyn SomeTable<'a>).fmt(f)
1292 }
1293}
1294
1295impl<'a> MinByteRange<'a> for Ligature<'a> {
1296 fn min_byte_range(&self) -> Range<usize> {
1297 0..self.component_glyph_ids_byte_range().end
1298 }
1299 fn min_table_bytes(&self) -> &'a [u8] {
1300 let range = self.min_byte_range();
1301 self.data.as_bytes().get(range).unwrap_or_default()
1302 }
1303}
1304
1305impl<'a> FontRead<'a> for Ligature<'a> {
1306 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1307 #[allow(clippy::absurd_extreme_comparisons)]
1308 if data.len() < Self::MIN_SIZE {
1309 return Err(ReadError::OutOfBounds);
1310 }
1311 Ok(Self { data })
1312 }
1313}
1314
1315#[derive(Clone)]
1317pub struct Ligature<'a> {
1318 data: FontData<'a>,
1319}
1320
1321#[allow(clippy::needless_lifetimes)]
1322impl<'a> Ligature<'a> {
1323 pub const MIN_SIZE: usize = (GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1324 basic_table_impls!(impl_the_methods);
1325
1326 pub fn ligature_glyph(&self) -> GlyphId16 {
1328 let range = self.ligature_glyph_byte_range();
1329 self.data.read_at(range.start).ok().unwrap()
1330 }
1331
1332 pub fn component_count(&self) -> u16 {
1334 let range = self.component_count_byte_range();
1335 self.data.read_at(range.start).ok().unwrap()
1336 }
1337
1338 pub fn component_glyph_ids(&self) -> &'a [BigEndian<GlyphId16>] {
1341 let range = self.component_glyph_ids_byte_range();
1342 self.data.read_array(range).ok().unwrap_or_default()
1343 }
1344
1345 pub fn ligature_glyph_byte_range(&self) -> Range<usize> {
1346 let start = 0;
1347 start..start + GlyphId16::RAW_BYTE_LEN
1348 }
1349
1350 pub fn component_count_byte_range(&self) -> Range<usize> {
1351 let start = self.ligature_glyph_byte_range().end;
1352 start..start + u16::RAW_BYTE_LEN
1353 }
1354
1355 pub fn component_glyph_ids_byte_range(&self) -> Range<usize> {
1356 let component_count = self.component_count();
1357 let start = self.component_count_byte_range().end;
1358 start
1359 ..start
1360 + (transforms::subtract(component_count, 1_usize))
1361 .saturating_mul(GlyphId16::RAW_BYTE_LEN)
1362 }
1363}
1364
1365const _: () = assert!(FontData::default_data_long_enough(Ligature::MIN_SIZE));
1366
1367impl Default for Ligature<'_> {
1368 fn default() -> Self {
1369 Self {
1370 data: FontData::default_table_data(),
1371 }
1372 }
1373}
1374
1375#[cfg(feature = "experimental_traverse")]
1376impl<'a> SomeTable<'a> for Ligature<'a> {
1377 fn type_name(&self) -> &str {
1378 "Ligature"
1379 }
1380 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1381 match idx {
1382 0usize => Some(Field::new("ligature_glyph", self.ligature_glyph())),
1383 1usize => Some(Field::new("component_count", self.component_count())),
1384 2usize => Some(Field::new(
1385 "component_glyph_ids",
1386 self.component_glyph_ids(),
1387 )),
1388 _ => None,
1389 }
1390 }
1391}
1392
1393#[cfg(feature = "experimental_traverse")]
1394#[allow(clippy::needless_lifetimes)]
1395impl<'a> std::fmt::Debug for Ligature<'a> {
1396 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1397 (self as &dyn SomeTable<'a>).fmt(f)
1398 }
1399}
1400
1401impl Format<u16> for ExtensionSubstFormat1<'_> {
1402 const FORMAT: u16 = 1;
1403}
1404
1405impl Discriminant for ExtensionSubstFormat1<'_, ()> {
1406 fn read_discriminant(data: FontData<'_>) -> Result<u16, ReadError> {
1407 data.read_at(u16::RAW_BYTE_LEN)
1408 }
1409}
1410
1411impl<'a, T> MinByteRange<'a> for ExtensionSubstFormat1<'a, T> {
1412 fn min_byte_range(&self) -> Range<usize> {
1413 0..self.extension_offset_byte_range().end
1414 }
1415 fn min_table_bytes(&self) -> &'a [u8] {
1416 let range = self.min_byte_range();
1417 self.data.as_bytes().get(range).unwrap_or_default()
1418 }
1419}
1420
1421impl<'a, T> FontRead<'a> for ExtensionSubstFormat1<'a, T> {
1422 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1423 #[allow(clippy::absurd_extreme_comparisons)]
1424 if data.len() < Self::MIN_SIZE {
1425 return Err(ReadError::OutOfBounds);
1426 }
1427 Ok(Self {
1428 data,
1429 offset_type: std::marker::PhantomData,
1430 })
1431 }
1432}
1433
1434impl<'a, T> ExtensionSubstFormat1<'a, T> {
1435 #[allow(dead_code)]
1436 pub(crate) fn of_unit_type(&self) -> ExtensionSubstFormat1<'a, ()> {
1438 ExtensionSubstFormat1 {
1439 data: self.data,
1440 offset_type: std::marker::PhantomData,
1441 }
1442 }
1443}
1444
1445#[derive(Clone)]
1447pub struct ExtensionSubstFormat1<'a, T = ()> {
1448 data: FontData<'a>,
1449 offset_type: std::marker::PhantomData<*const T>,
1450}
1451
1452#[allow(clippy::needless_lifetimes)]
1453impl<'a, T> ExtensionSubstFormat1<'a, T> {
1454 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN);
1455 basic_table_impls!(impl_the_methods);
1456
1457 pub fn subst_format(&self) -> u16 {
1459 let range = self.subst_format_byte_range();
1460 self.data.read_at(range.start).ok().unwrap()
1461 }
1462
1463 pub fn extension_lookup_type(&self) -> u16 {
1466 let range = self.extension_lookup_type_byte_range();
1467 self.data.read_at(range.start).ok().unwrap()
1468 }
1469
1470 pub fn extension_offset(&self) -> Offset32 {
1474 let range = self.extension_offset_byte_range();
1475 self.data.read_at(range.start).ok().unwrap()
1476 }
1477
1478 pub fn extension(&self) -> Result<T, ReadError>
1480 where
1481 T: FontRead<'a>,
1482 {
1483 let data = self.data;
1484 self.extension_offset().resolve(data)
1485 }
1486
1487 pub fn subst_format_byte_range(&self) -> Range<usize> {
1488 let start = 0;
1489 start..start + u16::RAW_BYTE_LEN
1490 }
1491
1492 pub fn extension_lookup_type_byte_range(&self) -> Range<usize> {
1493 let start = self.subst_format_byte_range().end;
1494 start..start + u16::RAW_BYTE_LEN
1495 }
1496
1497 pub fn extension_offset_byte_range(&self) -> Range<usize> {
1498 let start = self.extension_lookup_type_byte_range().end;
1499 start..start + Offset32::RAW_BYTE_LEN
1500 }
1501}
1502
1503const _: () = assert!(FontData::default_data_long_enough(
1504 ExtensionSubstFormat1::<()>::MIN_SIZE
1505));
1506
1507impl<T> Default for ExtensionSubstFormat1<'_, T> {
1508 fn default() -> Self {
1509 Self {
1510 data: FontData::default_format_1_u16_table_data(),
1511 offset_type: std::marker::PhantomData,
1512 }
1513 }
1514}
1515
1516#[cfg(feature = "experimental_traverse")]
1517impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> SomeTable<'a> for ExtensionSubstFormat1<'a, T> {
1518 fn type_name(&self) -> &str {
1519 "ExtensionSubstFormat1"
1520 }
1521 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1522 match idx {
1523 0usize => Some(Field::new("subst_format", self.subst_format())),
1524 1usize => Some(Field::new(
1525 "extension_lookup_type",
1526 self.extension_lookup_type(),
1527 )),
1528 2usize => Some(Field::new(
1529 "extension_offset",
1530 FieldType::offset(self.extension_offset(), self.extension()),
1531 )),
1532 _ => None,
1533 }
1534 }
1535}
1536
1537#[cfg(feature = "experimental_traverse")]
1538#[allow(clippy::needless_lifetimes)]
1539impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> std::fmt::Debug for ExtensionSubstFormat1<'a, T> {
1540 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1541 (self as &dyn SomeTable<'a>).fmt(f)
1542 }
1543}
1544
1545pub enum ExtensionSubtable<'a> {
1547 Single(ExtensionSubstFormat1<'a, SingleSubst<'a>>),
1548 Multiple(ExtensionSubstFormat1<'a, MultipleSubstFormat1<'a>>),
1549 Alternate(ExtensionSubstFormat1<'a, AlternateSubstFormat1<'a>>),
1550 Ligature(ExtensionSubstFormat1<'a, LigatureSubstFormat1<'a>>),
1551 Contextual(ExtensionSubstFormat1<'a, SubstitutionSequenceContext<'a>>),
1552 ChainContextual(ExtensionSubstFormat1<'a, SubstitutionChainContext<'a>>),
1553 Reverse(ExtensionSubstFormat1<'a, ReverseChainSingleSubstFormat1<'a>>),
1554}
1555
1556impl Default for ExtensionSubtable<'_> {
1557 fn default() -> Self {
1558 Self::Single(Default::default())
1559 }
1560}
1561
1562impl<'a> FontRead<'a> for ExtensionSubtable<'a> {
1563 fn read(bytes: FontData<'a>) -> Result<Self, ReadError> {
1564 let discriminant = ExtensionSubstFormat1::read_discriminant(bytes)?;
1565 match discriminant {
1566 1 => Ok(ExtensionSubtable::Single(FontRead::read(bytes)?)),
1567 2 => Ok(ExtensionSubtable::Multiple(FontRead::read(bytes)?)),
1568 3 => Ok(ExtensionSubtable::Alternate(FontRead::read(bytes)?)),
1569 4 => Ok(ExtensionSubtable::Ligature(FontRead::read(bytes)?)),
1570 5 => Ok(ExtensionSubtable::Contextual(FontRead::read(bytes)?)),
1571 6 => Ok(ExtensionSubtable::ChainContextual(FontRead::read(bytes)?)),
1572 8 => Ok(ExtensionSubtable::Reverse(FontRead::read(bytes)?)),
1573 other => Err(ReadError::InvalidFormat(other.into())),
1574 }
1575 }
1576}
1577
1578impl<'a> ExtensionSubtable<'a> {
1579 #[allow(dead_code)]
1580 pub(crate) fn of_unit_type(&self) -> ExtensionSubstFormat1<'a, ()> {
1584 match self {
1585 ExtensionSubtable::Single(inner) => inner.of_unit_type(),
1586 ExtensionSubtable::Multiple(inner) => inner.of_unit_type(),
1587 ExtensionSubtable::Alternate(inner) => inner.of_unit_type(),
1588 ExtensionSubtable::Ligature(inner) => inner.of_unit_type(),
1589 ExtensionSubtable::Contextual(inner) => inner.of_unit_type(),
1590 ExtensionSubtable::ChainContextual(inner) => inner.of_unit_type(),
1591 ExtensionSubtable::Reverse(inner) => inner.of_unit_type(),
1592 }
1593 }
1594}
1595
1596#[cfg(feature = "experimental_traverse")]
1597impl<'a> ExtensionSubtable<'a> {
1598 fn dyn_inner(&self) -> &(dyn SomeTable<'a> + 'a) {
1599 match self {
1600 ExtensionSubtable::Single(table) => table,
1601 ExtensionSubtable::Multiple(table) => table,
1602 ExtensionSubtable::Alternate(table) => table,
1603 ExtensionSubtable::Ligature(table) => table,
1604 ExtensionSubtable::Contextual(table) => table,
1605 ExtensionSubtable::ChainContextual(table) => table,
1606 ExtensionSubtable::Reverse(table) => table,
1607 }
1608 }
1609}
1610
1611#[cfg(feature = "experimental_traverse")]
1612impl<'a> SomeTable<'a> for ExtensionSubtable<'a> {
1613 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1614 self.dyn_inner().get_field(idx)
1615 }
1616 fn type_name(&self) -> &str {
1617 self.dyn_inner().type_name()
1618 }
1619}
1620
1621#[cfg(feature = "experimental_traverse")]
1622impl std::fmt::Debug for ExtensionSubtable<'_> {
1623 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1624 self.dyn_inner().fmt(f)
1625 }
1626}
1627
1628impl Format<u16> for ReverseChainSingleSubstFormat1<'_> {
1629 const FORMAT: u16 = 1;
1630}
1631
1632impl<'a> MinByteRange<'a> for ReverseChainSingleSubstFormat1<'a> {
1633 fn min_byte_range(&self) -> Range<usize> {
1634 0..self.substitute_glyph_ids_byte_range().end
1635 }
1636 fn min_table_bytes(&self) -> &'a [u8] {
1637 let range = self.min_byte_range();
1638 self.data.as_bytes().get(range).unwrap_or_default()
1639 }
1640}
1641
1642impl<'a> FontRead<'a> for ReverseChainSingleSubstFormat1<'a> {
1643 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1644 #[allow(clippy::absurd_extreme_comparisons)]
1645 if data.len() < Self::MIN_SIZE {
1646 return Err(ReadError::OutOfBounds);
1647 }
1648 Ok(Self { data })
1649 }
1650}
1651
1652#[derive(Clone)]
1654pub struct ReverseChainSingleSubstFormat1<'a> {
1655 data: FontData<'a>,
1656}
1657
1658#[allow(clippy::needless_lifetimes)]
1659impl<'a> ReverseChainSingleSubstFormat1<'a> {
1660 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1661 + Offset16::RAW_BYTE_LEN
1662 + u16::RAW_BYTE_LEN
1663 + u16::RAW_BYTE_LEN
1664 + u16::RAW_BYTE_LEN);
1665 basic_table_impls!(impl_the_methods);
1666
1667 pub fn subst_format(&self) -> u16 {
1669 let range = self.subst_format_byte_range();
1670 self.data.read_at(range.start).ok().unwrap()
1671 }
1672
1673 pub fn coverage_offset(&self) -> Offset16 {
1676 let range = self.coverage_offset_byte_range();
1677 self.data.read_at(range.start).ok().unwrap()
1678 }
1679
1680 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
1682 let data = self.data;
1683 self.coverage_offset().resolve(data)
1684 }
1685
1686 pub fn backtrack_glyph_count(&self) -> u16 {
1688 let range = self.backtrack_glyph_count_byte_range();
1689 self.data.read_at(range.start).ok().unwrap()
1690 }
1691
1692 pub fn backtrack_coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
1695 let range = self.backtrack_coverage_offsets_byte_range();
1696 self.data.read_array(range).ok().unwrap_or_default()
1697 }
1698
1699 pub fn backtrack_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
1701 let data = self.data;
1702 let offsets = self.backtrack_coverage_offsets();
1703 ArrayOfOffsets::new(offsets, data, ())
1704 }
1705
1706 pub fn lookahead_glyph_count(&self) -> u16 {
1708 let range = self.lookahead_glyph_count_byte_range();
1709 self.data.read_at(range.start).ok().unwrap_or_default()
1710 }
1711
1712 pub fn lookahead_coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
1715 let range = self.lookahead_coverage_offsets_byte_range();
1716 self.data.read_array(range).ok().unwrap_or_default()
1717 }
1718
1719 pub fn lookahead_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
1721 let data = self.data;
1722 let offsets = self.lookahead_coverage_offsets();
1723 ArrayOfOffsets::new(offsets, data, ())
1724 }
1725
1726 pub fn glyph_count(&self) -> u16 {
1728 let range = self.glyph_count_byte_range();
1729 self.data.read_at(range.start).ok().unwrap_or_default()
1730 }
1731
1732 pub fn substitute_glyph_ids(&self) -> &'a [BigEndian<GlyphId16>] {
1734 let range = self.substitute_glyph_ids_byte_range();
1735 self.data.read_array(range).ok().unwrap_or_default()
1736 }
1737
1738 pub fn subst_format_byte_range(&self) -> Range<usize> {
1739 let start = 0;
1740 start..start + u16::RAW_BYTE_LEN
1741 }
1742
1743 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
1744 let start = self.subst_format_byte_range().end;
1745 start..start + Offset16::RAW_BYTE_LEN
1746 }
1747
1748 pub fn backtrack_glyph_count_byte_range(&self) -> Range<usize> {
1749 let start = self.coverage_offset_byte_range().end;
1750 start..start + u16::RAW_BYTE_LEN
1751 }
1752
1753 pub fn backtrack_coverage_offsets_byte_range(&self) -> Range<usize> {
1754 let backtrack_glyph_count = self.backtrack_glyph_count();
1755 let start = self.backtrack_glyph_count_byte_range().end;
1756 start
1757 ..start
1758 + (transforms::to_usize(backtrack_glyph_count))
1759 .saturating_mul(Offset16::RAW_BYTE_LEN)
1760 }
1761
1762 pub fn lookahead_glyph_count_byte_range(&self) -> Range<usize> {
1763 let start = self.backtrack_coverage_offsets_byte_range().end;
1764 start..start + u16::RAW_BYTE_LEN
1765 }
1766
1767 pub fn lookahead_coverage_offsets_byte_range(&self) -> Range<usize> {
1768 let lookahead_glyph_count = self.lookahead_glyph_count();
1769 let start = self.lookahead_glyph_count_byte_range().end;
1770 start
1771 ..start
1772 + (transforms::to_usize(lookahead_glyph_count))
1773 .saturating_mul(Offset16::RAW_BYTE_LEN)
1774 }
1775
1776 pub fn glyph_count_byte_range(&self) -> Range<usize> {
1777 let start = self.lookahead_coverage_offsets_byte_range().end;
1778 start..start + u16::RAW_BYTE_LEN
1779 }
1780
1781 pub fn substitute_glyph_ids_byte_range(&self) -> Range<usize> {
1782 let glyph_count = self.glyph_count();
1783 let start = self.glyph_count_byte_range().end;
1784 start..start + (transforms::to_usize(glyph_count)).saturating_mul(GlyphId16::RAW_BYTE_LEN)
1785 }
1786}
1787
1788const _: () = assert!(FontData::default_data_long_enough(
1789 ReverseChainSingleSubstFormat1::MIN_SIZE
1790));
1791
1792impl Default for ReverseChainSingleSubstFormat1<'_> {
1793 fn default() -> Self {
1794 Self {
1795 data: FontData::default_format_1_u16_table_data(),
1796 }
1797 }
1798}
1799
1800#[cfg(feature = "experimental_traverse")]
1801impl<'a> SomeTable<'a> for ReverseChainSingleSubstFormat1<'a> {
1802 fn type_name(&self) -> &str {
1803 "ReverseChainSingleSubstFormat1"
1804 }
1805 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1806 match idx {
1807 0usize => Some(Field::new("subst_format", self.subst_format())),
1808 1usize => Some(Field::new(
1809 "coverage_offset",
1810 FieldType::offset(self.coverage_offset(), self.coverage()),
1811 )),
1812 2usize => Some(Field::new(
1813 "backtrack_glyph_count",
1814 self.backtrack_glyph_count(),
1815 )),
1816 3usize => Some(Field::new(
1817 "backtrack_coverage_offsets",
1818 FieldType::from(self.backtrack_coverages()),
1819 )),
1820 4usize => Some(Field::new(
1821 "lookahead_glyph_count",
1822 self.lookahead_glyph_count(),
1823 )),
1824 5usize => Some(Field::new(
1825 "lookahead_coverage_offsets",
1826 FieldType::from(self.lookahead_coverages()),
1827 )),
1828 6usize => Some(Field::new("glyph_count", self.glyph_count())),
1829 7usize => Some(Field::new(
1830 "substitute_glyph_ids",
1831 self.substitute_glyph_ids(),
1832 )),
1833 _ => None,
1834 }
1835 }
1836}
1837
1838#[cfg(feature = "experimental_traverse")]
1839#[allow(clippy::needless_lifetimes)]
1840impl<'a> std::fmt::Debug for ReverseChainSingleSubstFormat1<'a> {
1841 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1842 (self as &dyn SomeTable<'a>).fmt(f)
1843 }
1844}