rustybuzz/hb/
aat_map.rs

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}