ttf_parser/tables/
avar.rs

1// https://docs.microsoft.com/en-us/typography/opentype/spec/avar
2
3use core::convert::TryFrom;
4use core::num::NonZeroU16;
5
6use crate::NormalizedCoordinate;
7use crate::parser::{Stream, FromData, LazyArray16};
8
9
10#[derive(Clone, Copy)]
11pub(crate) struct Table<'a> {
12    axis_count: NonZeroU16,
13    data: &'a [u8],
14}
15
16impl<'a> Table<'a> {
17    pub fn parse(data: &'a [u8]) -> Option<Self> {
18        let mut s = Stream::new(data);
19
20        let version: u32 = s.read()?;
21        if version != 0x00010000 {
22            return None;
23        }
24
25        s.skip::<u16>(); // reserved
26        // TODO: check that `axisCount` is the same as in `fvar`?
27        let axis_count: u16 = s.read()?;
28        let axis_count = NonZeroU16::new(axis_count)?;
29
30        let data = s.tail()?;
31
32        // Sanitize records.
33        for _ in 0..axis_count.get() {
34            let count: u16 = s.read()?;
35            s.advance_checked(AxisValueMapRecord::SIZE * usize::from(count))?;
36        }
37
38        Some(Table {
39            axis_count,
40            data,
41        })
42    }
43
44    pub fn map_coordinates(&self, coordinates: &mut [NormalizedCoordinate]) -> Option<()> {
45        if usize::from(self.axis_count.get()) != coordinates.len() {
46            return None;
47        }
48
49        let mut s = Stream::new(self.data);
50        for coord in coordinates {
51            let count: u16 = s.read()?;
52            let map = s.read_array16::<AxisValueMapRecord>(count)?;
53            *coord = NormalizedCoordinate::from(map_value(&map, coord.0)?);
54        }
55
56        Some(())
57    }
58}
59
60fn map_value(map: &LazyArray16<AxisValueMapRecord>, value: i16) -> Option<i16> {
61    // This code is based on harfbuzz implementation.
62
63    if map.len() == 0 {
64        return Some(value);
65    } else if map.len() == 1 {
66        let record = map.get(0)?;
67        return Some(value - record.from_coordinate + record.to_coordinate);
68    }
69
70    let record_0 = map.get(0)?;
71    if value <= record_0.from_coordinate {
72        return Some(value - record_0.from_coordinate + record_0.to_coordinate);
73    }
74
75    let mut i = 1;
76    while i < map.len() && value > map.get(i)?.from_coordinate {
77        i += 1;
78    }
79
80    if i == map.len() {
81        i -= 1;
82    }
83
84    let record_curr = map.get(i)?;
85    let curr_from = record_curr.from_coordinate;
86    let curr_to = record_curr.to_coordinate;
87    if value >= curr_from {
88        return Some(value - curr_from + curr_to);
89    }
90
91    let record_prev = map.get(i - 1)?;
92    let prev_from = record_prev.from_coordinate;
93    let prev_to = record_prev.to_coordinate;
94    if prev_from == curr_from {
95        return Some(prev_to);
96    }
97
98    let curr_from = i32::from(curr_from);
99    let curr_to = i32::from(curr_to);
100    let prev_from = i32::from(prev_from);
101    let prev_to = i32::from(prev_to);
102
103    let denom = curr_from - prev_from;
104    let k = (curr_to - prev_to) * (i32::from(value) - prev_from) + denom / 2;
105    let value = prev_to + k / denom;
106    i16::try_from(value).ok()
107}
108
109
110#[derive(Clone, Copy)]
111struct AxisValueMapRecord {
112    from_coordinate: i16,
113    to_coordinate: i16,
114}
115
116impl FromData for AxisValueMapRecord {
117    const SIZE: usize = 4;
118
119    #[inline]
120    fn parse(data: &[u8]) -> Option<Self> {
121        let mut s = Stream::new(data);
122        Some(AxisValueMapRecord {
123            from_coordinate: s.read::<i16>()?,
124            to_coordinate: s.read::<i16>()?,
125        })
126    }
127}