ttf_parser/tables/
feat.rs

1//! A [Feature Name Table](
2//! https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6feat.html) implementation.
3
4use crate::parser::{FromData, LazyArray16, Offset, Offset32, Stream};
5
6#[derive(Clone, Copy, Debug)]
7struct FeatureNameRecord {
8    feature: u16,
9    setting_table_records_count: u16,
10    // Offset from the beginning of the table.
11    setting_table_offset: Offset32,
12    flags: u8,
13    default_setting_index: u8,
14    name_index: u16,
15}
16
17impl FromData for FeatureNameRecord {
18    const SIZE: usize = 12;
19
20    #[inline]
21    fn parse(data: &[u8]) -> Option<Self> {
22        let mut s = Stream::new(data);
23        Some(FeatureNameRecord {
24            feature: s.read::<u16>()?,
25            setting_table_records_count: s.read::<u16>()?,
26            setting_table_offset: s.read::<Offset32>()?,
27            flags: s.read::<u8>()?,
28            default_setting_index: s.read::<u8>()?,
29            name_index: s.read::<u16>()?,
30        })
31    }
32}
33
34
35/// A setting name.
36#[derive(Clone, Copy, Debug)]
37pub struct SettingName {
38    /// The setting.
39    pub setting: u16,
40    /// The `name` table index for the feature's name in a 256..32768 range.
41    pub name_index: u16,
42}
43
44impl FromData for SettingName {
45    const SIZE: usize = 4;
46
47    #[inline]
48    fn parse(data: &[u8]) -> Option<Self> {
49        let mut s = Stream::new(data);
50        Some(SettingName {
51            setting: s.read::<u16>()?,
52            name_index: s.read::<u16>()?,
53        })
54    }
55}
56
57
58/// A feature names.
59#[derive(Clone, Copy, Debug)]
60pub struct FeatureName<'a> {
61    /// The feature's ID.
62    pub feature: u16,
63    /// The feature's setting names.
64    pub setting_names: LazyArray16<'a, SettingName>,
65    /// The index of the default setting in the `setting_names`.
66    pub default_setting_index: u8,
67    /// The feature's exclusive settings. If set, the feature settings are mutually exclusive.
68    pub exclusive: bool,
69    /// The `name` table index for the feature's name in a 256..32768 range.
70    pub name_index: u16,
71}
72
73
74/// A list fo feature names.
75#[derive(Clone, Copy)]
76pub struct FeatureNames<'a> {
77    data: &'a [u8],
78    records: LazyArray16<'a, FeatureNameRecord>,
79}
80
81impl<'a> FeatureNames<'a> {
82    /// Returns a feature name at an index.
83    pub fn get(&self, index: u16) -> Option<FeatureName<'a>> {
84        let record = self.records.get(index)?;
85        let data = self.data.get(record.setting_table_offset.to_usize()..)?;
86        let mut s = Stream::new(data);
87        let setting_names = s.read_array16::<SettingName>(record.setting_table_records_count)?;
88        Some(FeatureName {
89            feature: record.feature,
90            setting_names,
91            default_setting_index:
92                if record.flags & 0x40 != 0 { record.default_setting_index } else { 0 },
93            exclusive: record.flags & 0x80 != 0,
94            name_index: record.name_index,
95        })
96    }
97
98    /// Finds a feature name by ID.
99    pub fn find(&self, feature: u16) -> Option<FeatureName<'a>> {
100        let index = self.records
101            .binary_search_by(|name| name.feature.cmp(&feature)).map(|(i, _)| i)?;
102        self.get(index)
103    }
104
105    /// Returns the number of feature names.
106    pub fn len(&self) -> u16 {
107        self.records.len()
108    }
109}
110
111impl<'a> core::fmt::Debug for FeatureNames<'a> {
112    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
113        f.debug_list().entries(self.into_iter()).finish()
114    }
115}
116
117impl<'a> IntoIterator for FeatureNames<'a> {
118    type Item = FeatureName<'a>;
119    type IntoIter = FeatureNamesIter<'a>;
120
121    #[inline]
122    fn into_iter(self) -> Self::IntoIter {
123        FeatureNamesIter {
124            names: self,
125            index: 0,
126        }
127    }
128}
129
130/// An iterator over [`FeatureNames`].
131#[allow(missing_debug_implementations)]
132pub struct FeatureNamesIter<'a> {
133    names: FeatureNames<'a>,
134    index: u16,
135}
136
137impl<'a> Iterator for FeatureNamesIter<'a> {
138    type Item = FeatureName<'a>;
139
140    fn next(&mut self) -> Option<Self::Item> {
141        if self.index < self.names.len() {
142            self.index += 1;
143            self.names.get(self.index - 1)
144        } else {
145            None
146        }
147    }
148}
149
150
151/// A [Feature Name Table](
152/// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6feat.html).
153#[derive(Clone, Copy, Debug)]
154pub struct Table<'a> {
155    /// A list of feature names. Sorted by `FeatureName.feature`.
156    pub names: FeatureNames<'a>,
157}
158
159impl<'a> Table<'a> {
160    /// Parses a table from raw data.
161    pub fn parse(data: &'a [u8]) -> Option<Self> {
162        let mut s = Stream::new(data);
163
164        let version = s.read::<u32>()?;
165        if version != 0x00010000 {
166            return None;
167        }
168
169        let count = s.read::<u16>()?;
170        s.advance_checked(6)?; // reserved
171        let records = s.read_array16::<FeatureNameRecord>(count)?;
172
173        Some(Table {
174            names: FeatureNames {
175                data,
176                records,
177            }
178        })
179    }
180}