/src/ttf-parser/src/ggg/feature_variations.rs
Line | Count | Source |
1 | | use super::{Feature, FeatureIndex, RecordListItem, VariationIndex}; |
2 | | use crate::parser::{FromData, LazyArray16, LazyArray32}; |
3 | | use crate::parser::{Offset, Offset32, Stream}; |
4 | | use crate::{NormalizedCoordinate, Tag}; |
5 | | |
6 | | /// A [Feature Variations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featurevariations-table). |
7 | | #[derive(Clone, Copy, Debug)] |
8 | | pub struct FeatureVariations<'a> { |
9 | | data: &'a [u8], |
10 | | records: LazyArray32<'a, FeatureVariationRecord>, |
11 | | } |
12 | | |
13 | | impl<'a> FeatureVariations<'a> { |
14 | 265 | pub(crate) fn parse(data: &'a [u8]) -> Option<Self> { |
15 | 265 | let mut s = Stream::new(data); |
16 | 265 | let major_version = s.read::<u16>()?; |
17 | 257 | s.skip::<u16>(); // minor version |
18 | 257 | if major_version != 1 { |
19 | 147 | return None; |
20 | 110 | } |
21 | | |
22 | 110 | let count = s.read::<u32>()?; |
23 | 94 | let records = s.read_array32(count)?; |
24 | 24 | Some(Self { data, records }) |
25 | 265 | } |
26 | | |
27 | | /// Returns a [`VariationIndex`] for variation coordinates. |
28 | 0 | pub fn find_index(&self, coords: &[NormalizedCoordinate]) -> Option<VariationIndex> { |
29 | 0 | for i in 0..self.records.len() { |
30 | 0 | let record = self.records.get(i)?; |
31 | 0 | let offset = record.conditions.to_usize(); |
32 | 0 | let set = ConditionSet::parse(self.data.get(offset..)?)?; |
33 | 0 | if set.evaluate(coords) { |
34 | 0 | return Some(i); |
35 | 0 | } |
36 | | } |
37 | 0 | None |
38 | 0 | } |
39 | | |
40 | | /// Returns a [`Feature`] at specified indices. |
41 | 0 | pub fn find_substitute( |
42 | 0 | &self, |
43 | 0 | feature_index: FeatureIndex, |
44 | 0 | variation_index: VariationIndex, |
45 | 0 | ) -> Option<Feature<'a>> { |
46 | 0 | let offset = self.records.get(variation_index)?.substitutions.to_usize(); |
47 | 0 | let subst = FeatureTableSubstitution::parse(self.data.get(offset..)?)?; |
48 | 0 | subst.find_substitute(feature_index) |
49 | 0 | } |
50 | | } |
51 | | |
52 | | #[derive(Clone, Copy, Debug)] |
53 | | struct FeatureVariationRecord { |
54 | | conditions: Offset32, |
55 | | substitutions: Offset32, |
56 | | } |
57 | | |
58 | | impl FromData for FeatureVariationRecord { |
59 | | const SIZE: usize = 8; |
60 | | |
61 | | #[inline] |
62 | 0 | fn parse(data: &[u8]) -> Option<Self> { |
63 | 0 | let mut s = Stream::new(data); |
64 | | Some(Self { |
65 | 0 | conditions: s.read::<Offset32>()?, |
66 | 0 | substitutions: s.read::<Offset32>()?, |
67 | | }) |
68 | 0 | } |
69 | | } |
70 | | |
71 | | #[derive(Clone, Copy, Debug)] |
72 | | struct ConditionSet<'a> { |
73 | | data: &'a [u8], |
74 | | conditions: LazyArray16<'a, Offset32>, |
75 | | } |
76 | | |
77 | | impl<'a> ConditionSet<'a> { |
78 | 0 | fn parse(data: &'a [u8]) -> Option<Self> { |
79 | 0 | let mut s = Stream::new(data); |
80 | 0 | let count = s.read::<u16>()?; |
81 | 0 | let conditions = s.read_array16(count)?; |
82 | 0 | Some(Self { data, conditions }) |
83 | 0 | } |
84 | | |
85 | 0 | fn evaluate(&self, coords: &[NormalizedCoordinate]) -> bool { |
86 | 0 | self.conditions.into_iter().all(|offset| { |
87 | 0 | self.data |
88 | 0 | .get(offset.to_usize()..) |
89 | 0 | .and_then(Condition::parse) |
90 | 0 | .map_or(false, |c| c.evaluate(coords)) |
91 | 0 | }) |
92 | 0 | } |
93 | | } |
94 | | |
95 | | #[derive(Clone, Copy, Debug)] |
96 | | enum Condition { |
97 | | Format1 { |
98 | | axis_index: u16, |
99 | | filter_range_min: i16, |
100 | | filter_range_max: i16, |
101 | | }, |
102 | | } |
103 | | |
104 | | impl Condition { |
105 | 0 | fn parse(data: &[u8]) -> Option<Self> { |
106 | 0 | let mut s = Stream::new(data); |
107 | 0 | let format = s.read::<u16>()?; |
108 | 0 | match format { |
109 | | 1 => { |
110 | 0 | let axis_index = s.read::<u16>()?; |
111 | 0 | let filter_range_min = s.read::<i16>()?; |
112 | 0 | let filter_range_max = s.read::<i16>()?; |
113 | 0 | Some(Self::Format1 { |
114 | 0 | axis_index, |
115 | 0 | filter_range_min, |
116 | 0 | filter_range_max, |
117 | 0 | }) |
118 | | } |
119 | 0 | _ => None, |
120 | | } |
121 | 0 | } |
122 | | |
123 | 0 | fn evaluate(&self, coords: &[NormalizedCoordinate]) -> bool { |
124 | | let Self::Format1 { |
125 | 0 | axis_index, |
126 | 0 | filter_range_min, |
127 | 0 | filter_range_max, |
128 | 0 | } = *self; |
129 | 0 | let coord = coords |
130 | 0 | .get(usize::from(axis_index)) |
131 | 0 | .map(|c| c.get()) |
132 | 0 | .unwrap_or(0); |
133 | 0 | filter_range_min <= coord && coord <= filter_range_max |
134 | 0 | } |
135 | | } |
136 | | |
137 | | #[derive(Clone, Copy, Debug)] |
138 | | struct FeatureTableSubstitution<'a> { |
139 | | data: &'a [u8], |
140 | | records: LazyArray16<'a, FeatureTableSubstitutionRecord>, |
141 | | } |
142 | | |
143 | | impl<'a> FeatureTableSubstitution<'a> { |
144 | 0 | fn parse(data: &'a [u8]) -> Option<Self> { |
145 | 0 | let mut s = Stream::new(data); |
146 | 0 | let major_version = s.read::<u16>()?; |
147 | 0 | s.skip::<u16>(); // minor version |
148 | 0 | if major_version != 1 { |
149 | 0 | return None; |
150 | 0 | } |
151 | | |
152 | 0 | let count = s.read::<u16>()?; |
153 | 0 | let records = s.read_array16(count)?; |
154 | 0 | Some(Self { data, records }) |
155 | 0 | } |
156 | | |
157 | 0 | fn find_substitute(&self, feature_index: FeatureIndex) -> Option<Feature<'a>> { |
158 | 0 | for record in self.records { |
159 | 0 | if record.feature_index == feature_index { |
160 | 0 | let offset = record.feature.to_usize(); |
161 | | // TODO: set tag |
162 | 0 | return Feature::parse(Tag::from_bytes(b"DFLT"), self.data.get(offset..)?); |
163 | 0 | } |
164 | | } |
165 | 0 | None |
166 | 0 | } |
167 | | } |
168 | | |
169 | | #[derive(Clone, Copy, Debug)] |
170 | | struct FeatureTableSubstitutionRecord { |
171 | | feature_index: FeatureIndex, |
172 | | feature: Offset32, |
173 | | } |
174 | | |
175 | | impl FromData for FeatureTableSubstitutionRecord { |
176 | | const SIZE: usize = 6; |
177 | | |
178 | | #[inline] |
179 | 0 | fn parse(data: &[u8]) -> Option<Self> { |
180 | 0 | let mut s = Stream::new(data); |
181 | | Some(Self { |
182 | 0 | feature_index: s.read::<FeatureIndex>()?, |
183 | 0 | feature: s.read::<Offset32>()?, |
184 | | }) |
185 | 0 | } |
186 | | } |