1use crate::hb::common::{HB_FEATURE_GLOBAL_END, HB_FEATURE_GLOBAL_START};
2use crate::Feature;
3use alloc::vec;
4use alloc::vec::Vec;
5use core::cmp::Ordering;
6
7use super::aat_layout::*;
8use super::{hb_font_t, hb_mask_t, hb_tag_t};
9
10#[derive(Default)]
11pub struct hb_aat_map_t {
12 pub chain_flags: Vec<Vec<range_flags_t>>,
13}
14
15#[derive(Copy, Clone, PartialEq, Eq, Default)]
16pub struct feature_info_t {
17 pub kind: u16,
18 pub setting: u16,
19 pub is_exclusive: bool,
20}
21
22impl Ord for feature_info_t {
23 fn cmp(&self, other: &Self) -> Ordering {
24 self.partial_cmp(other).unwrap()
25 }
26}
27
28impl PartialOrd for feature_info_t {
29 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
30 if self.kind != other.kind {
31 Some(self.kind.cmp(&other.kind))
32 } else if !self.is_exclusive && (self.setting & !1) != (other.setting & !1) {
33 Some(self.setting.cmp(&other.setting))
34 } else {
35 Some(core::cmp::Ordering::Equal)
36 }
37 }
38}
39
40#[derive(Copy, Clone, PartialEq, Eq)]
41pub struct feature_range_t {
42 pub info: feature_info_t,
43 pub start: u32,
44 pub end: u32,
45}
46
47#[derive(Copy, Clone, Eq, PartialEq)]
48struct feature_event_t {
49 pub index: usize,
50 pub start: bool,
51 pub feature: feature_info_t,
52}
53
54#[derive(Copy, Clone)]
55pub struct range_flags_t {
56 pub flags: hb_mask_t,
57 pub cluster_first: u32,
58 pub cluster_last: u32, // end - 1
59}
60
61impl Ord for feature_event_t {
62 fn cmp(&self, other: &Self) -> Ordering {
63 self.partial_cmp(other).unwrap()
64 }
65}
66
67impl PartialOrd for feature_event_t {
68 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
69 if self.index != other.index {
70 Some(self.index.cmp(&other.index))
71 } else if self.start != other.start {
72 Some(self.start.cmp(&other.start))
73 } else {
74 Some(Ordering::Equal)
75 }
76 }
77}
78
79pub struct hb_aat_map_builder_t {
80 pub current_features: Vec<feature_info_t>,
81 pub features: Vec<feature_range_t>,
82 pub range_first: usize,
83 pub range_last: usize,
84}
85
86impl Default for hb_aat_map_builder_t {
87 fn default() -> Self {
88 Self {
89 range_first: HB_FEATURE_GLOBAL_START as usize,
90 range_last: HB_FEATURE_GLOBAL_END as usize,
91 current_features: Vec::default(),
92 features: Vec::default(),
93 }
94 }
95}
96
97impl hb_aat_map_builder_t {
98 pub fn add_feature(&mut self, face: &hb_font_t, feature: &Feature) -> Option<()> {
99 let feat = face.tables().feat?;
100
101 if feature.tag == hb_tag_t::from_bytes(b"aalt") {
102 let exposes_feature = feat
103 .names
104 .find(HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES as u16)
105 .map(|f| !f.setting_names.is_empty())
106 .unwrap_or(false);
107
108 if !exposes_feature {
109 return Some(());
110 }
111
112 self.features.push(feature_range_t {
113 start: feature.start,
114 end: feature.end,
115 info: feature_info_t {
116 kind: HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES as u16,
117 setting: u16::try_from(feature.value).unwrap(),
118 is_exclusive: true,
119 },
120 });
121 }
122
123 let idx = feature_mappings
124 .binary_search_by(|map| map.ot_feature_tag.cmp(&feature.tag))
125 .ok()?;
126 let mapping = &feature_mappings[idx];
127
128 let mut feature_name = feat.names.find(mapping.aat_feature_type as u16);
129
130 match feature_name {
131 Some(feature) if !feature.setting_names.is_empty() => {}
132 _ => {
133 // Special case: Chain::compile_flags will fall back to the deprecated version of
134 // small-caps if necessary, so we need to check for that possibility.
135 // https://github.com/harfbuzz/harfbuzz/issues/2307
136 if mapping.aat_feature_type == HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE
137 && mapping.selector_to_enable
138 == HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS
139 {
140 feature_name = feat
141 .names
142 .find(HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE as u16);
143 }
144 }
145 }
146
147 match feature_name {
148 Some(feature_name) if !feature_name.setting_names.is_empty() => {
149 let setting = if feature.value != 0 {
150 mapping.selector_to_enable
151 } else {
152 mapping.selector_to_disable
153 } as u16;
154
155 self.features.push(feature_range_t {
156 start: feature.start,
157 end: feature.end,
158 info: feature_info_t {
159 kind: mapping.aat_feature_type as u16,
160 setting,
161 is_exclusive: feature_name.exclusive,
162 },
163 });
164 }
165 _ => {}
166 }
167
168 Some(())
169 }
170
171 pub fn compile(&mut self, face: &hb_font_t, m: &mut hb_aat_map_t) {
172 // Compute active features per range, and compile each.
173 let mut feature_events = vec![];
174 for feature in &self.features {
175 if feature.start == feature.end {
176 continue;
177 }
178
179 feature_events.push(feature_event_t {
180 index: feature.start as usize,
181 start: true,
182 feature: feature.info,
183 });
184
185 feature_events.push(feature_event_t {
186 index: feature.end as usize,
187 start: false,
188 feature: feature.info,
189 })
190 }
191
192 feature_events.sort();
193
194 // Add a strategic final event.
195 feature_events.push(feature_event_t {
196 index: u32::MAX as usize,
197 start: false,
198 feature: feature_info_t::default(),
199 });
200
201 // Scan events and save features for each range.
202 let mut active_features = vec![];
203 let mut last_index = 0;
204
205 for event in &feature_events {
206 if event.index != last_index {
207 // Save a snapshot of active features and the range.
208 // Sort features and merge duplicates.
209 self.current_features = active_features.clone();
210 self.range_first = last_index;
211 self.range_last = event.index.wrapping_sub(1);
212
213 if !self.current_features.is_empty() {
214 self.current_features.sort();
215 let mut j = 0;
216 for i in 1..self.current_features.len() {
217 // Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off
218 // respectively, so we mask out the low-order bit when checking for "duplicates"
219 // (selectors referring to the same feature setting) here.
220 let non_exclusive = !self.current_features[i].is_exclusive
221 && (self.current_features[i].setting & !1)
222 != (self.current_features[j].setting & !1);
223
224 if self.current_features[i].kind != self.current_features[j].kind
225 || non_exclusive
226 {
227 j += 1;
228 self.current_features[j] = self.current_features[i];
229 }
230 }
231 self.current_features.truncate(j + 1);
232 }
233
234 super::aat_layout_morx_table::compile_flags(face, self, m);
235 last_index = event.index;
236 }
237
238 if event.start {
239 active_features.push(event.feature);
240 } else {
241 if let Some(index) = active_features.iter().position(|&f| f == event.feature) {
242 active_features.remove(index);
243 }
244 }
245 }
246
247 for chain_flags in m.chain_flags.iter_mut() {
248 if let Some(last) = chain_flags.last_mut() {
249 last.cluster_last = HB_FEATURE_GLOBAL_END;
250 }
251 }
252 }
253}
254