/src/ttf-parser/src/tables/fvar.rs
Line | Count | Source |
1 | | //! A [Font Variations Table]( |
2 | | //! https://docs.microsoft.com/en-us/typography/opentype/spec/fvar) implementation. |
3 | | |
4 | | use core::num::NonZeroU16; |
5 | | |
6 | | use crate::parser::{Fixed, FromData, LazyArray16, Offset, Offset16, Stream, f32_bound}; |
7 | | use crate::{NormalizedCoordinate, Tag}; |
8 | | |
9 | | /// A [variation axis](https://docs.microsoft.com/en-us/typography/opentype/spec/fvar#variationaxisrecord). |
10 | | #[repr(C)] |
11 | | #[allow(missing_docs)] |
12 | | #[derive(Clone, Copy, PartialEq, Debug)] |
13 | | pub struct VariationAxis { |
14 | | pub tag: Tag, |
15 | | pub min_value: f32, |
16 | | pub def_value: f32, |
17 | | pub max_value: f32, |
18 | | /// An axis name in the `name` table. |
19 | | pub name_id: u16, |
20 | | pub hidden: bool, |
21 | | } |
22 | | |
23 | | impl FromData for VariationAxis { |
24 | | const SIZE: usize = 20; |
25 | | |
26 | 21.6k | fn parse(data: &[u8]) -> Option<Self> { |
27 | 21.6k | let mut s = Stream::new(data); |
28 | 21.6k | let tag = s.read::<Tag>()?; |
29 | 21.6k | let min_value = s.read::<Fixed>()?; |
30 | 21.6k | let def_value = s.read::<Fixed>()?; |
31 | 21.6k | let max_value = s.read::<Fixed>()?; |
32 | 21.6k | let flags = s.read::<u16>()?; |
33 | 21.6k | let name_id = s.read::<u16>()?; |
34 | | |
35 | 21.6k | Some(VariationAxis { |
36 | 21.6k | tag, |
37 | 21.6k | min_value: def_value.0.min(min_value.0), |
38 | 21.6k | def_value: def_value.0, |
39 | 21.6k | max_value: def_value.0.max(max_value.0), |
40 | 21.6k | name_id, |
41 | 21.6k | hidden: flags & 1 == 1, |
42 | 21.6k | }) |
43 | 21.6k | } |
44 | | } |
45 | | |
46 | | impl VariationAxis { |
47 | | /// Returns a normalized variation coordinate for this axis. |
48 | 5.30k | pub(crate) fn normalized_value(&self, mut v: f32) -> NormalizedCoordinate { |
49 | | // Based on |
50 | | // https://docs.microsoft.com/en-us/typography/opentype/spec/avar#overview |
51 | | |
52 | 5.30k | v = f32_bound(self.min_value, v, self.max_value); |
53 | 5.30k | if v == self.def_value { |
54 | 1.65k | v = 0.0; |
55 | 3.64k | } else if v < self.def_value { |
56 | 776 | v = (v - self.def_value) / (self.def_value - self.min_value); |
57 | 2.86k | } else { |
58 | 2.86k | v = (v - self.def_value) / (self.max_value - self.def_value); |
59 | 2.86k | } |
60 | | |
61 | 5.30k | NormalizedCoordinate::from(v) |
62 | 5.30k | } |
63 | | } |
64 | | |
65 | | /// A [Font Variations Table]( |
66 | | /// https://docs.microsoft.com/en-us/typography/opentype/spec/fvar). |
67 | | #[derive(Clone, Copy, Debug)] |
68 | | pub struct Table<'a> { |
69 | | /// A list of variation axes. |
70 | | pub axes: LazyArray16<'a, VariationAxis>, |
71 | | } |
72 | | |
73 | | impl<'a> Table<'a> { |
74 | | /// Parses a table from raw data. |
75 | 8.91k | pub fn parse(data: &'a [u8]) -> Option<Self> { |
76 | 8.91k | let mut s = Stream::new(data); |
77 | 8.91k | let version = s.read::<u32>()?; |
78 | 8.90k | if version != 0x00010000 { |
79 | 328 | return None; |
80 | 8.57k | } |
81 | | |
82 | 8.57k | let axes_array_offset = s.read::<Offset16>()?; |
83 | 8.56k | s.skip::<u16>(); // reserved |
84 | 8.56k | let axis_count = s.read::<u16>()?; |
85 | | |
86 | | // 'If axisCount is zero, then the font is not functional as a variable font, |
87 | | // and must be treated as a non-variable font; |
88 | | // any variation-specific tables or data is ignored.' |
89 | 8.55k | let axis_count = NonZeroU16::new(axis_count)?; |
90 | | |
91 | 8.52k | let mut s = Stream::new_at(data, axes_array_offset.to_usize())?; |
92 | 8.46k | let axes = s.read_array16::<VariationAxis>(axis_count.get())?; |
93 | | |
94 | 8.27k | Some(Table { axes }) |
95 | 8.91k | } |
96 | | } |