rustybuzz/hb/
aat_map.rs
1use alloc::vec::Vec;
2
3use super::aat_layout::*;
4use super::{hb_font_t, hb_mask_t, hb_tag_t};
5
6#[derive(Default)]
7pub struct hb_aat_map_t {
8 pub chain_flags: Vec<hb_mask_t>,
9}
10
11#[derive(Copy, Clone)]
12pub struct feature_info_t {
13 pub kind: u16,
14 pub setting: u16,
15 pub is_exclusive: bool,
16}
17
18#[derive(Default)]
19pub struct hb_aat_map_builder_t {
20 pub features: Vec<feature_info_t>,
21}
22
23impl hb_aat_map_builder_t {
24 pub fn add_feature(&mut self, face: &hb_font_t, tag: hb_tag_t, value: u32) -> Option<()> {
25 const FEATURE_TYPE_CHARACTER_ALTERNATIVES: u16 = 17;
26
27 let feat = face.tables().feat?;
28
29 if tag == hb_tag_t::from_bytes(b"aalt") {
30 let exposes_feature = feat
31 .names
32 .find(FEATURE_TYPE_CHARACTER_ALTERNATIVES)
33 .map(|f| f.setting_names.len() != 0)
34 .unwrap_or(false);
35
36 if !exposes_feature {
37 return Some(());
38 }
39
40 self.features.push(feature_info_t {
41 kind: FEATURE_TYPE_CHARACTER_ALTERNATIVES,
42 setting: value as u16,
43 is_exclusive: true,
44 });
45 }
46
47 let idx = feature_mappings
48 .binary_search_by(|map| map.ot_feature_tag.cmp(&tag))
49 .ok()?;
50 let mapping = &feature_mappings[idx];
51
52 let mut feature = feat.names.find(mapping.aat_feature_type as u16);
53
54 match feature {
55 Some(feature) if feature.setting_names.len() != 0 => {}
56 _ => {
57 if mapping.aat_feature_type == HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE
61 && mapping.selector_to_enable
62 == HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS
63 {
64 feature = feat
65 .names
66 .find(HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE as u16);
67 }
68 }
69 }
70
71 match feature {
72 Some(feature) if feature.setting_names.len() != 0 => {
73 let setting = if value != 0 {
74 mapping.selector_to_enable
75 } else {
76 mapping.selector_to_disable
77 } as u16;
78
79 self.features.push(feature_info_t {
80 kind: mapping.aat_feature_type as u16,
81 setting,
82 is_exclusive: feature.exclusive,
83 });
84 }
85 _ => {}
86 }
87
88 Some(())
89 }
90
91 pub fn has_feature(&self, kind: u16, setting: u16) -> bool {
92 self.features
93 .binary_search_by(|probe| {
94 if probe.kind != kind {
95 probe.kind.cmp(&kind)
96 } else {
97 probe.setting.cmp(&setting)
98 }
99 })
100 .is_ok()
101 }
102
103 pub fn compile(&mut self, face: &hb_font_t) -> hb_aat_map_t {
104 self.features.sort_by(|a, b| {
106 if a.kind != b.kind {
107 a.kind.cmp(&b.kind)
108 } else if !a.is_exclusive && (a.setting & !1) != (b.setting & !1) {
109 a.setting.cmp(&b.setting)
110 } else {
111 core::cmp::Ordering::Equal
112 }
113 });
114
115 let mut j = 0;
116 for i in 0..self.features.len() {
117 let non_exclusive = !self.features[i].is_exclusive
121 && (self.features[i].setting & !1) != (self.features[j].setting & !1);
122
123 if self.features[i].kind != self.features[j].kind || non_exclusive {
124 j += 1;
125 self.features[j] = self.features[i];
126 }
127 }
128 self.features.truncate(j + 1);
129
130 super::aat_layout_morx_table::compile_flags(face, self).unwrap_or_default()
131 }
132}