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