swash/
variation.rs
1use super::internal::{var::*, RawFont};
2use super::{
3 setting::Setting,
4 string::{LocalizedString, StringId},
5 FontRef, NormalizedCoord, Tag,
6};
7
8#[derive(Copy, Clone)]
10pub struct VariationsProxy {
11 fvar: u32,
12 avar: u32,
13 len: usize,
14}
15
16impl VariationsProxy {
17 pub fn from_font(font: &FontRef) -> Self {
19 let fvar = font.table_offset(FVAR);
20 let table = Fvar::from_font(font).unwrap_or_else(|| Fvar::new(&[]));
21 let avar = font.table_offset(AVAR);
22 let len = table.axis_count() as usize;
23 Self { fvar, avar, len }
24 }
25
26 pub fn materialize<'a>(&self, font: &FontRef<'a>) -> Variations<'a> {
29 let data = if self.fvar != 0 {
30 font.data.get(self.fvar as usize..).unwrap_or(&[])
31 } else {
32 &[]
33 };
34 Variations {
35 font: *font,
36 fvar: Fvar::new(data),
37 avar: self.avar,
38 len: self.len,
39 pos: 0,
40 }
41 }
42}
43
44#[derive(Copy, Clone)]
46pub struct Variations<'a> {
47 font: FontRef<'a>,
48 fvar: Fvar<'a>,
49 avar: u32,
50 len: usize,
51 pos: usize,
52}
53
54impl<'a> Variations<'a> {
55 pub(crate) fn from_font(font: &FontRef<'a>) -> Self {
56 let fvar = Fvar::from_font(font).unwrap_or_else(|| Fvar::new(&[]));
57 let avar = font.table_offset(AVAR);
58 let len = fvar.axis_count() as usize;
59 Self {
60 font: *font,
61 fvar,
62 avar,
63 len,
64 pos: 0,
65 }
66 }
67
68 fn get(&self, index: usize) -> Option<Variation<'a>> {
69 let axis = self.fvar.get_axis(index as u16)?;
70 Some(Variation {
71 font: self.font,
72 axis,
73 avar: self.avar,
74 })
75 }
76
77 pub fn find_by_tag(&self, tag: Tag) -> Option<Variation<'a>> {
83 for i in 0..self.len {
84 if let Some(var) = self.get(i) {
85 if var.tag() == tag {
86 return Some(var);
87 }
88 }
89 }
90 None
91 }
92
93 pub fn normalized_coords<I>(&self, settings: I) -> impl Iterator<Item = NormalizedCoord> + Clone
96 where
97 I: IntoIterator,
98 I::Item: Into<Setting<f32>>,
99 {
100 let mut copy = *self;
101 copy.pos = 0;
102 let mut coords = [0i16; 32];
103 let len = self.len.min(32);
104 for setting in settings {
105 let val = setting.into();
106 let tag = val.tag;
107 for (var, coord) in copy.take(len).zip(coords.iter_mut()) {
108 if var.axis.tag == tag {
109 *coord = var.normalize(val.value);
110 }
111 }
112 }
113 (0..len).map(move |i| coords[i])
114 }
115}
116
117impl_iter!(Variations, Variation);
118
119#[derive(Copy, Clone)]
121pub struct Variation<'a> {
122 font: FontRef<'a>,
123 axis: VarAxis,
124 avar: u32,
125}
126
127impl<'a> Variation<'a> {
128 pub fn index(&self) -> usize {
130 self.axis.index as usize
131 }
132
133 pub fn tag(&self) -> Tag {
135 self.axis.tag
136 }
137
138 pub fn name_id(&self) -> StringId {
140 StringId::Other(self.axis.name_id)
141 }
142
143 pub fn name(&self, language: Option<&str>) -> Option<LocalizedString<'a>> {
146 self.font
147 .localized_strings()
148 .find_by_id(self.name_id(), language)
149 }
150
151 pub fn is_hidden(&self) -> bool {
153 self.axis.is_hidden()
154 }
155
156 pub fn min_value(&self) -> f32 {
158 self.axis.min.to_f32()
159 }
160
161 pub fn max_value(&self) -> f32 {
163 self.axis.max.to_f32()
164 }
165
166 pub fn default_value(&self) -> f32 {
168 self.axis.default.to_f32()
169 }
170
171 pub fn normalize(&self, value: f32) -> NormalizedCoord {
173 let avar = if self.avar != 0 {
174 Some((self.font.data, self.avar))
175 } else {
176 None
177 };
178 self.axis.normalized_coord(value.into(), avar)
179 }
180}
181
182#[derive(Copy, Clone)]
184pub struct Instances<'a> {
185 font: FontRef<'a>,
186 fvar: Fvar<'a>,
187 avar: u32,
188 len: usize,
189 pos: usize,
190}
191
192impl<'a> Instances<'a> {
193 pub(crate) fn from_font(font: &FontRef<'a>) -> Self {
194 let fvar = Fvar::from_font(font).unwrap_or_else(|| Fvar::new(&[]));
195 let avar = font.table_offset(AVAR);
196 Self {
197 font: *font,
198 fvar,
199 avar,
200 len: fvar.instance_count() as usize,
201 pos: 0,
202 }
203 }
204
205 fn get(&self, index: usize) -> Option<Instance<'a>> {
206 let inner = self.fvar.get_instance(index as u16)?;
207 Some(Instance {
208 parent: *self,
209 inner,
210 })
211 }
212
213 pub fn find_by_name(&self, name: &str) -> Option<Instance<'a>> {
219 let strings = self.font.localized_strings();
220 for i in 0..self.len {
221 if let Some(instance) = self.get(i) {
222 let id = instance.name_id();
223 for instance_name in strings.filter(|s| s.id() == id) {
224 if instance_name.chars().eq(name.chars()) {
225 return Some(instance);
226 }
227 }
228 }
229 }
230 None
231 }
232 pub fn find_by_postscript_name(&self, name: &str) -> Option<Instance<'a>> {
238 let strings = self.font.localized_strings();
239 for i in 0..self.len {
240 if let Some(instance) = self.get(i) {
241 if let Some(id) = instance.postscript_name_id() {
242 for instance_name in strings.filter(|s| s.id() == id) {
243 if instance_name.chars().eq(name.chars()) {
244 return Some(instance);
245 }
246 }
247 }
248 }
249 }
250 None
251 }
252}
253
254impl_iter!(Instances, Instance);
255
256#[derive(Copy, Clone)]
258pub struct Instance<'a> {
259 parent: Instances<'a>,
260 inner: VarInstance<'a>,
261}
262
263impl<'a> Instance<'a> {
264 pub fn index(&self) -> usize {
266 self.inner.index as usize
267 }
268
269 pub fn name_id(&self) -> StringId {
271 StringId::Other(self.inner.name_id)
272 }
273
274 pub fn name(&self, language: Option<&str>) -> Option<LocalizedString<'a>> {
277 self.parent
278 .font
279 .localized_strings()
280 .find_by_id(self.name_id(), language)
281 }
282
283 pub fn postscript_name_id(&self) -> Option<StringId> {
285 self.inner.postscript_name_id.map(StringId::Other)
286 }
287
288 pub fn postscript_name(&self, language: Option<&str>) -> Option<LocalizedString<'a>> {
291 self.parent
292 .font
293 .localized_strings()
294 .find_by_id(self.postscript_name_id()?, language)
295 }
296
297 pub fn values(&self) -> impl Iterator<Item = f32> + 'a {
299 self.inner.values.iter().map(|v| v.to_f32())
300 }
301
302 pub fn normalized_coords(&self) -> impl Iterator<Item = NormalizedCoord> + 'a {
304 let avar = if self.parent.avar != 0 {
305 Some((self.parent.font.data, self.parent.avar))
306 } else {
307 None
308 };
309 let fvar = self.parent.fvar;
310 (0..fvar.axis_count())
311 .map(move |i| fvar.get_axis(i).unwrap_or_default())
312 .zip(self.inner.values)
313 .map(move |(axis, value)| axis.normalized_coord(value, avar))
314 }
315}