1 | use alloc::vec::Vec; |
2 | |
3 | use super::feature_mappings::FEATURE_MAPPINGS; |
4 | use crate::{Face, Mask, Tag}; |
5 | |
6 | #[repr (u8)] |
7 | #[derive (Clone, Copy, PartialEq)] |
8 | pub enum FeatureType { |
9 | Ligatures = 1, |
10 | LetterCase = 3, |
11 | VerticalSubstitution = 4, |
12 | NumberSpacing = 6, |
13 | VerticalPosition = 10, |
14 | Fractions = 11, |
15 | TypographicExtras = 14, |
16 | MathematicalExtras = 15, |
17 | StyleOptions = 19, |
18 | CharacterShape = 20, |
19 | NumberCase = 21, |
20 | TextSpacing = 22, |
21 | Transliteration = 23, |
22 | RubyKana = 28, |
23 | ItalicCjkRoman = 32, |
24 | CaseSensitiveLayout = 33, |
25 | AlternateKana = 34, |
26 | StylisticAlternatives = 35, |
27 | ContextualAlternatives = 36, |
28 | LowerCase = 37, |
29 | UpperCase = 38, |
30 | |
31 | // In harfbuzz, they just use the number 40 for "hist" but don't give it a name |
32 | Dummy = 40, |
33 | } |
34 | |
35 | #[derive (Default)] |
36 | pub struct Map { |
37 | pub chain_flags: Vec<Mask>, |
38 | } |
39 | |
40 | #[derive (Copy, Clone)] |
41 | pub struct FeatureInfo { |
42 | pub kind: u16, |
43 | pub setting: u16, |
44 | pub is_exclusive: bool, |
45 | } |
46 | |
47 | #[derive (Default)] |
48 | pub struct MapBuilder { |
49 | pub features: Vec<FeatureInfo>, |
50 | } |
51 | |
52 | impl MapBuilder { |
53 | pub fn add_feature(&mut self, face: &Face, tag: Tag, value: u32) -> Option<()> { |
54 | const FEATURE_TYPE_CHARACTER_ALTERNATIVES: u16 = 17; |
55 | |
56 | let feat = face.tables().feat?; |
57 | |
58 | if tag == Tag::from_bytes(b"aalt" ) { |
59 | let exposes_feature = feat |
60 | .names |
61 | .find(FEATURE_TYPE_CHARACTER_ALTERNATIVES) |
62 | .map(|f| f.setting_names.len() != 0) |
63 | .unwrap_or(false); |
64 | |
65 | if !exposes_feature { |
66 | return Some(()); |
67 | } |
68 | |
69 | self.features.push(FeatureInfo { |
70 | kind: FEATURE_TYPE_CHARACTER_ALTERNATIVES, |
71 | setting: value as u16, |
72 | is_exclusive: true, |
73 | }); |
74 | } |
75 | |
76 | let idx = FEATURE_MAPPINGS |
77 | .binary_search_by(|map| map.ot_feature_tag.cmp(&tag)) |
78 | .ok()?; |
79 | let mapping = &FEATURE_MAPPINGS[idx]; |
80 | |
81 | let mut feature = feat.names.find(mapping.aat_feature_type as u16); |
82 | |
83 | match feature { |
84 | Some(feature) if feature.setting_names.len() != 0 => {} |
85 | _ => { |
86 | // Special case: Chain::compile_flags will fall back to the deprecated version of |
87 | // small-caps if necessary, so we need to check for that possibility. |
88 | // https://github.com/harfbuzz/harfbuzz/issues/2307 |
89 | if mapping.aat_feature_type == FeatureType::LowerCase |
90 | && mapping.selector_to_enable == super::feature_selector::LOWER_CASE_SMALL_CAPS |
91 | { |
92 | feature = feat.names.find(FeatureType::LetterCase as u16); |
93 | } |
94 | } |
95 | } |
96 | |
97 | match feature { |
98 | Some(feature) if feature.setting_names.len() != 0 => { |
99 | let setting = if value != 0 { |
100 | mapping.selector_to_enable |
101 | } else { |
102 | mapping.selector_to_disable |
103 | } as u16; |
104 | |
105 | self.features.push(FeatureInfo { |
106 | kind: mapping.aat_feature_type as u16, |
107 | setting, |
108 | is_exclusive: feature.exclusive, |
109 | }); |
110 | } |
111 | _ => {} |
112 | } |
113 | |
114 | Some(()) |
115 | } |
116 | |
117 | pub fn has_feature(&self, kind: u16, setting: u16) -> bool { |
118 | self.features |
119 | .binary_search_by(|probe| { |
120 | if probe.kind != kind { |
121 | probe.kind.cmp(&kind) |
122 | } else { |
123 | probe.setting.cmp(&setting) |
124 | } |
125 | }) |
126 | .is_ok() |
127 | } |
128 | |
129 | pub fn compile(&mut self, face: &Face) -> Map { |
130 | // Sort features and merge duplicates. |
131 | self.features.sort_by(|a, b| { |
132 | if a.kind != b.kind { |
133 | a.kind.cmp(&b.kind) |
134 | } else if !a.is_exclusive && (a.setting & !1) != (b.setting & !1) { |
135 | a.setting.cmp(&b.setting) |
136 | } else { |
137 | core::cmp::Ordering::Equal |
138 | } |
139 | }); |
140 | |
141 | let mut j = 0; |
142 | for i in 0..self.features.len() { |
143 | // Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off |
144 | // respectively, so we mask out the low-order bit when checking for "duplicates" |
145 | // (selectors referring to the same feature setting) here. |
146 | let non_exclusive = !self.features[i].is_exclusive |
147 | && (self.features[i].setting & !1) != (self.features[j].setting & !1); |
148 | |
149 | if self.features[i].kind != self.features[j].kind || non_exclusive { |
150 | j += 1; |
151 | self.features[j] = self.features[i]; |
152 | } |
153 | } |
154 | self.features.truncate(j + 1); |
155 | |
156 | super::metamorphosis::compile_flags(face, self).unwrap_or_default() |
157 | } |
158 | } |
159 | |