read_fonts/tables/
gpos.rs1#[path = "./value_record.rs"]
6mod value_record;
7
8use crate::array::ComputedArray;
9
10pub use super::layout::{
12 ClassDef, CoverageTable, Device, DeviceOrVariationIndex, FeatureList, FeatureVariations,
13 Lookup, ScriptList,
14};
15use super::layout::{ExtensionLookup, LookupFlag, Subtables};
16pub use value_record::ValueRecord;
17
18#[cfg(test)]
19#[path = "../tests/test_gpos.rs"]
20mod spec_tests;
21
22include!("../../generated/generated_gpos.rs");
23
24pub type PositionLookupList<'a> = super::layout::LookupList<'a, PositionLookup<'a>>;
26
27pub type PositionSequenceContext<'a> = super::layout::SequenceContext<'a>;
29
30pub type PositionChainContext<'a> = super::layout::ChainedSequenceContext<'a>;
32
33impl<'a> AnchorTable<'a> {
34 pub fn x_device(&self) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>> {
37 match self {
38 AnchorTable::Format3(inner) => inner.x_device(),
39 _ => None,
40 }
41 }
42
43 pub fn y_device(&self) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>> {
46 match self {
47 AnchorTable::Format3(inner) => inner.y_device(),
48 _ => None,
49 }
50 }
51}
52
53impl<'a, T: FontRead<'a>> ExtensionLookup<'a, T> for ExtensionPosFormat1<'a, T> {
54 fn extension(&self) -> Result<T, ReadError> {
55 self.extension()
56 }
57}
58
59type PosSubtables<'a, T> = Subtables<'a, T, ExtensionPosFormat1<'a, T>>;
60
61pub enum PositionSubtables<'a> {
67 Single(PosSubtables<'a, SinglePos<'a>>),
68 Pair(PosSubtables<'a, PairPos<'a>>),
69 Cursive(PosSubtables<'a, CursivePosFormat1<'a>>),
70 MarkToBase(PosSubtables<'a, MarkBasePosFormat1<'a>>),
71 MarkToLig(PosSubtables<'a, MarkLigPosFormat1<'a>>),
72 MarkToMark(PosSubtables<'a, MarkMarkPosFormat1<'a>>),
73 Contextual(PosSubtables<'a, PositionSequenceContext<'a>>),
74 ChainContextual(PosSubtables<'a, PositionChainContext<'a>>),
75}
76
77impl<'a> PositionLookup<'a> {
78 pub fn lookup_flag(&self) -> LookupFlag {
79 self.of_unit_type().lookup_flag()
80 }
81
82 pub fn lookup_type(&self) -> u16 {
84 self.of_unit_type().lookup_type()
85 }
86
87 pub fn mark_filtering_set(&self) -> Option<u16> {
88 self.of_unit_type().mark_filtering_set()
89 }
90
91 pub fn subtables(&self) -> Result<PositionSubtables<'a>, ReadError> {
96 let raw_lookup = self.of_unit_type();
97 let offsets = raw_lookup.subtable_offsets();
98 let data = raw_lookup.offset_data();
99 match raw_lookup.lookup_type() {
100 1 => Ok(PositionSubtables::Single(Subtables::new(offsets, data))),
101 2 => Ok(PositionSubtables::Pair(Subtables::new(offsets, data))),
102 3 => Ok(PositionSubtables::Cursive(Subtables::new(offsets, data))),
103 4 => Ok(PositionSubtables::MarkToBase(Subtables::new(offsets, data))),
104 5 => Ok(PositionSubtables::MarkToLig(Subtables::new(offsets, data))),
105 6 => Ok(PositionSubtables::MarkToMark(Subtables::new(offsets, data))),
106 7 => Ok(PositionSubtables::Contextual(Subtables::new(offsets, data))),
107 8 => Ok(PositionSubtables::ChainContextual(Subtables::new(
108 offsets, data,
109 ))),
110 9 => {
111 let first = offsets.first().ok_or(ReadError::OutOfBounds)?.get();
112 let ext: ExtensionPosFormat1<()> = first.resolve(data)?;
113 match ext.extension_lookup_type() {
114 1 => Ok(PositionSubtables::Single(Subtables::new_ext(offsets, data))),
115 2 => Ok(PositionSubtables::Pair(Subtables::new_ext(offsets, data))),
116 3 => Ok(PositionSubtables::Cursive(Subtables::new_ext(
117 offsets, data,
118 ))),
119 4 => Ok(PositionSubtables::MarkToBase(Subtables::new_ext(
120 offsets, data,
121 ))),
122 5 => Ok(PositionSubtables::MarkToLig(Subtables::new_ext(
123 offsets, data,
124 ))),
125 6 => Ok(PositionSubtables::MarkToMark(Subtables::new_ext(
126 offsets, data,
127 ))),
128 7 => Ok(PositionSubtables::Contextual(Subtables::new_ext(
129 offsets, data,
130 ))),
131 8 => Ok(PositionSubtables::ChainContextual(Subtables::new_ext(
132 offsets, data,
133 ))),
134 other => Err(ReadError::InvalidFormat(other as _)),
135 }
136 }
137 other => Err(ReadError::InvalidFormat(other as _)),
138 }
139 }
140}