write_fonts/tables/
stat.rs

1//! The STAT table
2
3include!("../../generated/generated_stat.rs");
4
5impl Stat {
6    /// Create a new STAT 1.2 table
7    pub fn new(
8        design_axes: Vec<AxisRecord>,
9        axis_values: Vec<AxisValue>,
10        elided_fallback_name_id: NameId,
11    ) -> Self {
12        Stat {
13            design_axes: design_axes.into(),
14            offset_to_axis_values: NullableOffsetMarker::new(
15                (!axis_values.is_empty())
16                    .then(|| axis_values.into_iter().map(Into::into).collect()),
17            ),
18            elided_fallback_name_id: Some(elided_fallback_name_id),
19        }
20    }
21}
22
23// we use a custom conversion here because we use a shim table in read-fonts
24// (required because it is an offset to an array of offsets, which is too recursive for us)
25// but in write-fonts we want to skip the shim table and just use a vec.
26#[allow(clippy::unwrap_or_default)] // we need to be explicit to provide type info
27fn convert_axis_value_offsets(
28    from: Option<Result<read_fonts::tables::stat::AxisValueArray, ReadError>>,
29) -> NullableOffsetMarker<Vec<OffsetMarker<AxisValue>>, WIDTH_32> {
30    from.map(|inner| {
31        inner
32            .ok()
33            .map(|array| array.axis_values().to_owned_obj(array.offset_data()))
34            .unwrap_or_else(Vec::new)
35    })
36    .into()
37}
38
39#[cfg(test)]
40mod tests {
41    use crate::dump_table;
42    use read_fonts::tables::stat as read_stat;
43
44    use super::*;
45
46    #[test]
47    fn smoke_test() {
48        let table = Stat::new(
49            vec![AxisRecord::new(Tag::new(b"wght"), NameId::new(257), 1)],
50            vec![
51                AxisValue::format_1(
52                    0,
53                    AxisValueTableFlags::empty(),
54                    NameId::new(258),
55                    Fixed::from_f64(100.),
56                ),
57                AxisValue::format_1(
58                    0,
59                    AxisValueTableFlags::empty(),
60                    NameId::new(261),
61                    Fixed::from_f64(400.),
62                ),
63            ],
64            NameId::new(0),
65        );
66
67        let bytes = dump_table(&table).unwrap();
68        let read = read_stat::Stat::read(FontData::new(&bytes)).unwrap();
69
70        assert_eq!(read.design_axes().unwrap().len(), 1);
71        assert_eq!(read.axis_value_count(), 2);
72        let axis_values = read.offset_to_axis_values().unwrap().unwrap();
73        assert_eq!(axis_values.axis_value_offsets().len(), 2);
74        let value2 = axis_values.axis_values().get(1).unwrap();
75        let read_stat::AxisValue::Format1(value2) = value2 else {
76            panic!("wrong format");
77        };
78        assert_eq!(value2.value_name_id(), NameId::new(261));
79    }
80}