read_fonts/tables/
feat.rs

1//! The [feature name](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6feat.html) table.
2
3include!("../../generated/generated_feat.rs");
4
5impl Feat<'_> {
6    /// Returns the name for the given feature code.
7    pub fn find(&self, feature: u16) -> Option<FeatureName> {
8        let names = self.names();
9        let ix = names
10            .binary_search_by(|name| name.feature().cmp(&feature))
11            .ok()?;
12        names.get(ix).copied()
13    }
14}
15
16impl FeatureName {
17    /// Returns true if the feature settings are mutually exclusive.
18    pub fn is_exclusive(&self) -> bool {
19        // Bit 31 signifies a mutually exclusive feature
20        self.feature_flags() & 0x8000 != 0
21    }
22
23    /// Returns the index of the default setting for the feature.
24    pub fn default_setting_index(&self) -> u16 {
25        // If bit 30 is set, the default setting index is in the low byte
26        if self.feature_flags() & 0x4000 != 0 {
27            self.feature_flags() & 0xFF
28        } else {
29            0
30        }
31    }
32}
33
34#[cfg(test)]
35mod tests {
36    use font_test_data::bebuffer::BeBuffer;
37
38    use super::*;
39
40    #[test]
41    fn feat_example() {
42        let feat_data = build_feat_example();
43        let feat = Feat::read(feat_data.data().into()).unwrap();
44        let names = feat.names();
45        #[rustfmt::skip]
46        let expected_name_fields = [
47            // (feature, n_settings, flags, name, exclusive, default_index)
48            (0, 1, 0, NameId::new(260), false, 0),
49            (1, 1, 0, NameId::new(256), false, 0),
50            (3, 3, 0x8000, NameId::new(262), true, 0),
51            (6, 2, 0xC001, NameId::new(258), true, 1),
52        ];
53        let name_fields = names
54            .iter()
55            .map(|name| {
56                (
57                    name.feature(),
58                    name.n_settings(),
59                    name.feature_flags(),
60                    name.name_index(),
61                    name.is_exclusive(),
62                    name.default_setting_index(),
63                )
64            })
65            .collect::<Vec<_>>();
66        assert_eq!(name_fields, expected_name_fields);
67        #[rustfmt::skip]
68        let expected_setting_names: [&[(u16, NameId)]; 4] = [
69            &[(0, NameId::new(261))],
70            &[(2, NameId::new(257))],
71            &[(0, NameId::new(268)), (3, NameId::new(264)), (4, NameId::new(265))],
72            &[(0, NameId::new(259)), (1, NameId::new(260))],
73        ];
74        let setting_names = names
75            .iter()
76            .map(|name| {
77                let settings = name.setting_table(feat.offset_data()).unwrap();
78                settings
79                    .settings()
80                    .iter()
81                    .map(|setting| (setting.setting(), setting.name_index()))
82                    .collect::<Vec<_>>()
83            })
84            .collect::<Vec<_>>();
85        assert!(expected_setting_names.iter().eq(setting_names.iter()));
86    }
87
88    #[test]
89    fn feat_find() {
90        let feat_data = build_feat_example();
91        let feat = Feat::read(feat_data.data().into()).unwrap();
92        // List of available feature types
93        let valid_features = [0, 1, 3, 6];
94        for i in 0..10 {
95            let is_valid = valid_features.contains(&i);
96            let name = feat.find(i);
97            if is_valid {
98                assert_eq!(name.unwrap().feature(), i);
99            } else {
100                assert!(name.is_none());
101            }
102        }
103    }
104
105    fn build_feat_example() -> BeBuffer {
106        // Example taken from bottom of <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6feat.html>
107        let mut buf = BeBuffer::new();
108        // header
109        buf = buf.push(0x00010000u32).extend([4u16, 0, 0, 0]);
110        // feature name array
111        buf = buf.extend([0u16, 1]).push(60u32).extend([0u16, 260]);
112        buf = buf.extend([1u16, 1]).push(64u32).extend([0u16, 256]);
113        buf = buf.extend([3u16, 3]).push(68u32).extend([0x8000u16, 262]);
114        buf = buf.extend([6u16, 2]).push(80u32).extend([0xC001u16, 258]);
115        // The setting name array
116        buf.extend([0u16, 261, 2, 257, 0, 268, 3, 264, 4, 265, 0, 259, 1, 260])
117    }
118}