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