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::layout::*;
8use crate::hb::{hb_font_t, hb_mask_t, hb_tag_t};
9
10#[doc(alias = "hb_aat_map_t")]
14#[derive(Default)]
15pub struct AatMap {
16 pub chain_flags: Vec<Vec<RangeFlags>>,
17}
18
19#[derive(Copy, Clone)]
23pub struct RangeFlags {
24 pub flags: hb_mask_t,
25 pub cluster_first: u32,
26 pub cluster_last: u32, }
28
29#[doc(alias = "hb_aat_map_builder_t")]
33pub struct AatMapBuilder {
34 pub current_features: Vec<FeatureInfo>,
35 pub features: Vec<FeatureRange>,
36 pub range_first: usize,
37 pub range_last: usize,
38}
39
40impl Default for AatMapBuilder {
41 fn default() -> Self {
42 Self {
43 range_first: HB_FEATURE_GLOBAL_START as usize,
44 range_last: HB_FEATURE_GLOBAL_END as usize,
45 current_features: Vec::default(),
46 features: Vec::default(),
47 }
48 }
49}
50
51impl AatMapBuilder {
52 pub fn add_feature(&mut self, face: &hb_font_t, feature: &Feature) -> Option<()> {
53 let feat = face.aat_tables.feat.as_ref()?;
54
55 if feature.tag == hb_tag_t::new(b"aalt") {
56 let exposes_feature = feat
57 .find(FEATURE_TYPE_CHARACTER_ALTERNATIVES as u16)
58 .is_some_and(|f| f.n_settings() != 0);
59
60 if !exposes_feature {
61 return Some(());
62 }
63
64 self.features.push(FeatureRange {
65 start: feature.start,
66 end: feature.end,
67 info: FeatureInfo {
68 kind: FEATURE_TYPE_CHARACTER_ALTERNATIVES as u16,
69 setting: u16::try_from(feature.value).unwrap(),
70 is_exclusive: true,
71 },
72 });
73 }
74
75 let idx = feature_mappings
76 .binary_search_by(|map| map.ot_feature_tag.cmp(&feature.tag))
77 .ok()?;
78 let mapping = &feature_mappings[idx];
79
80 let mut feature_name = feat.find(mapping.aat_feature_type as u16);
81
82 match feature_name {
83 Some(feature) if feature.n_settings() != 0 => {}
84 _ => {
85 if mapping.aat_feature_type == FEATURE_TYPE_LOWER_CASE
89 && mapping.selector_to_enable == FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS
90 {
91 feature_name = feat.find(FEATURE_TYPE_LETTER_CASE as u16);
92 }
93 }
94 }
95
96 match feature_name {
97 Some(feature_name) if feature_name.n_settings() != 0 => {
98 let setting = if feature.value != 0 {
99 mapping.selector_to_enable
100 } else {
101 mapping.selector_to_disable
102 } as u16;
103
104 self.features.push(FeatureRange {
105 start: feature.start,
106 end: feature.end,
107 info: FeatureInfo {
108 kind: mapping.aat_feature_type as u16,
109 setting,
110 is_exclusive: feature_name.is_exclusive(),
111 },
112 });
113 }
114 _ => {}
115 }
116
117 Some(())
118 }
119
120 pub fn compile(&mut self, face: &hb_font_t, m: &mut AatMap) {
121 let mut feature_events = vec![];
123 for feature in &self.features {
124 if feature.start == feature.end {
125 continue;
126 }
127
128 feature_events.push(FeatureEvent {
129 index: feature.start as usize,
130 start: true,
131 feature: feature.info,
132 });
133
134 feature_events.push(FeatureEvent {
135 index: feature.end as usize,
136 start: false,
137 feature: feature.info,
138 });
139 }
140
141 feature_events.sort();
142
143 feature_events.push(FeatureEvent {
145 index: u32::MAX as usize,
146 start: false,
147 feature: FeatureInfo::default(),
148 });
149
150 let mut active_features = vec![];
152 let mut last_index = 0;
153
154 for event in &feature_events {
155 if event.index != last_index {
156 self.current_features.clone_from(&active_features);
159 self.range_first = last_index;
160 self.range_last = event.index.wrapping_sub(1);
161
162 if !self.current_features.is_empty() {
163 self.current_features.sort();
164 let mut j = 0;
165 for i in 1..self.current_features.len() {
166 let non_exclusive = !self.current_features[i].is_exclusive
170 && (self.current_features[i].setting & !1)
171 != (self.current_features[j].setting & !1);
172
173 if self.current_features[i].kind != self.current_features[j].kind
174 || non_exclusive
175 {
176 j += 1;
177 self.current_features[j] = self.current_features[i];
178 }
179 }
180 self.current_features.truncate(j + 1);
181 }
182
183 super::layout_morx_table::compile_flags(face, self, m);
184 last_index = event.index;
185 }
186
187 if event.start {
188 active_features.push(event.feature);
189 } else {
190 if let Some(index) = active_features.iter().position(|&f| f == event.feature) {
191 active_features.remove(index);
192 }
193 }
194 }
195
196 for chain_flags in &mut m.chain_flags {
197 if let Some(last) = chain_flags.last_mut() {
198 last.cluster_last = HB_FEATURE_GLOBAL_END;
199 }
200 }
201 }
202}
203
204#[derive(Copy, Clone, PartialEq, Eq, Default)]
208pub struct FeatureInfo {
209 pub kind: u16,
210 pub setting: u16,
211 pub is_exclusive: bool,
212}
213
214impl Ord for FeatureInfo {
215 fn cmp(&self, other: &Self) -> Ordering {
216 self.partial_cmp(other).unwrap()
217 }
218}
219
220impl PartialOrd for FeatureInfo {
221 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
222 if self.kind != other.kind {
223 Some(self.kind.cmp(&other.kind))
224 } else if !self.is_exclusive && (self.setting & !1) != (other.setting & !1) {
225 Some(self.setting.cmp(&other.setting))
226 } else {
227 Some(Ordering::Equal)
228 }
229 }
230}
231
232#[derive(Copy, Clone, PartialEq, Eq)]
236pub struct FeatureRange {
237 pub info: FeatureInfo,
238 pub start: u32,
239 pub end: u32,
240}
241
242#[derive(Copy, Clone, Eq, PartialEq)]
246struct FeatureEvent {
247 pub index: usize,
248 pub start: bool,
249 pub feature: FeatureInfo,
250}
251
252impl Ord for FeatureEvent {
253 fn cmp(&self, other: &Self) -> Ordering {
254 self.partial_cmp(other).unwrap()
255 }
256}
257
258impl PartialOrd for FeatureEvent {
259 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
260 if self.index != other.index {
261 Some(self.index.cmp(&other.index))
262 } else if self.start != other.start {
263 Some(self.start.cmp(&other.start))
264 } else {
265 Some(Ordering::Equal)
266 }
267 }
268}