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