swash/
variation.rs

1use super::internal::{var::*, RawFont};
2use super::{
3    setting::Setting,
4    string::{LocalizedString, StringId},
5    FontRef, NormalizedCoord, Tag,
6};
7
8/// Proxy for rematerializing variations collections.
9#[derive(Copy, Clone)]
10pub struct VariationsProxy {
11    fvar: u32,
12    avar: u32,
13    len: usize,
14}
15
16impl VariationsProxy {
17    /// Creates a variations proxy from the specified font.
18    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    /// Materializes variations from the specified font. This proxy must have
27    /// been created by the same font.
28    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/// Iterator over a collection of font variations.
45#[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    /// Searches for a variation with the specified tag.
78    ///
79    /// ## Iteration behavior
80    /// This function searches the entire variation collection without regard
81    /// for the current state of the iterator.
82    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    /// Returns an iterator over the set of normalized coordinates
94    /// corresponding to the specified variation settings.
95    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/// Axis of variation in a variable font.
120#[derive(Copy, Clone)]
121pub struct Variation<'a> {
122    font: FontRef<'a>,
123    axis: VarAxis,
124    avar: u32,
125}
126
127impl<'a> Variation<'a> {
128    /// Returns the index of the variation.
129    pub fn index(&self) -> usize {
130        self.axis.index as usize
131    }
132
133    /// Returns the tag that identifies the variation.
134    pub fn tag(&self) -> Tag {
135        self.axis.tag
136    }
137
138    /// Returns the name identifier for the variation.
139    pub fn name_id(&self) -> StringId {
140        StringId::Other(self.axis.name_id)
141    }
142
143    /// Returns the name for the variation, optionally for a
144    /// particular language.
145    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    /// Returns true if the variation should be hidden from users.
152    pub fn is_hidden(&self) -> bool {
153        self.axis.is_hidden()
154    }
155
156    /// Returns the minimum value of the variation.
157    pub fn min_value(&self) -> f32 {
158        self.axis.min.to_f32()
159    }
160
161    /// Returns the maximum value of the variation.
162    pub fn max_value(&self) -> f32 {
163        self.axis.max.to_f32()
164    }
165
166    /// Returns the default value of the variation.
167    pub fn default_value(&self) -> f32 {
168        self.axis.default.to_f32()
169    }
170
171    /// Computes a normalized coordinate for the specified value.
172    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/// Iterator over a collection of named variation instances.
183#[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    /// Searches for an instance with the specified name.
214    ///
215    /// ## Iteration behavior
216    /// This function searches the entire instance collection without regard
217    /// for the current state of the iterator.
218    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    /// Searches for an instance with the specified PostScript name.
233    ///
234    /// ## Iteration behavior
235    /// This function searches the entire instance collection without regard
236    /// for the current state of the iterator.
237    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/// Named instance in a variable font.
257#[derive(Copy, Clone)]
258pub struct Instance<'a> {
259    parent: Instances<'a>,
260    inner: VarInstance<'a>,
261}
262
263impl<'a> Instance<'a> {
264    /// Returns the index of the instance.
265    pub fn index(&self) -> usize {
266        self.inner.index as usize
267    }
268
269    /// Returns the name identifier for the instance.
270    pub fn name_id(&self) -> StringId {
271        StringId::Other(self.inner.name_id)
272    }
273
274    /// Returns the name for the instance, optionally for a
275    /// particular language.
276    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    /// Returns the PostScript name identifier for the instance.
284    pub fn postscript_name_id(&self) -> Option<StringId> {
285        self.inner.postscript_name_id.map(StringId::Other)
286    }
287
288    /// Returns the PostScript name for the instance, optionally for a
289    /// particular language.
290    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    /// Returns an iterator over the variation values of the instance.
298    pub fn values(&self) -> impl Iterator<Item = f32> + 'a {
299        self.inner.values.iter().map(|v| v.to_f32())
300    }
301
302    /// Returns an iterator over the normalized coordinates for the instance.
303    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}