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 | |
32 | #[derive (Default)] |
33 | pub struct Map { |
34 | pub chain_flags: Vec<Mask>, |
35 | } |
36 | |
37 | #[derive (Copy, Clone)] |
38 | pub struct FeatureInfo { |
39 | pub kind: u16, |
40 | pub setting: u16, |
41 | pub is_exclusive: bool, |
42 | } |
43 | |
44 | #[derive (Default)] |
45 | pub struct MapBuilder { |
46 | pub features: Vec<FeatureInfo>, |
47 | } |
48 | |
49 | impl MapBuilder { |
50 | pub fn add_feature(&mut self, face: &Face, tag: Tag, value: u32) -> Option<()> { |
51 | const FEATURE_TYPE_CHARACTER_ALTERNATIVES: u16 = 17; |
52 | |
53 | let feat = face.tables().feat?; |
54 | |
55 | if tag == Tag::from_bytes(b"aalt" ) { |
56 | let exposes_feature = feat |
57 | .names |
58 | .find(FEATURE_TYPE_CHARACTER_ALTERNATIVES) |
59 | .map(|f| f.setting_names.len() != 0) |
60 | .unwrap_or(false); |
61 | |
62 | if !exposes_feature { |
63 | return Some(()); |
64 | } |
65 | |
66 | self.features.push(FeatureInfo { |
67 | kind: FEATURE_TYPE_CHARACTER_ALTERNATIVES, |
68 | setting: value as u16, |
69 | is_exclusive: true, |
70 | }); |
71 | } |
72 | |
73 | let idx = FEATURE_MAPPINGS |
74 | .binary_search_by(|map| map.ot_feature_tag.cmp(&tag)) |
75 | .ok()?; |
76 | let mapping = &FEATURE_MAPPINGS[idx]; |
77 | |
78 | let mut feature = feat.names.find(mapping.aat_feature_type as u16); |
79 | |
80 | match feature { |
81 | Some(feature) if feature.setting_names.len() != 0 => {} |
82 | _ => { |
83 | // Special case: Chain::compile_flags will fall back to the deprecated version of |
84 | // small-caps if necessary, so we need to check for that possibility. |
85 | // https://github.com/harfbuzz/harfbuzz/issues/2307 |
86 | if mapping.aat_feature_type == FeatureType::LowerCase |
87 | && mapping.selector_to_enable == super::feature_selector::LOWER_CASE_SMALL_CAPS |
88 | { |
89 | feature = feat.names.find(FeatureType::LetterCase as u16); |
90 | } |
91 | } |
92 | } |
93 | |
94 | match feature { |
95 | Some(feature) if feature.setting_names.len() != 0 => { |
96 | let setting = if value != 0 { |
97 | mapping.selector_to_enable |
98 | } else { |
99 | mapping.selector_to_disable |
100 | } as u16; |
101 | |
102 | self.features.push(FeatureInfo { |
103 | kind: mapping.aat_feature_type as u16, |
104 | setting, |
105 | is_exclusive: feature.exclusive, |
106 | }); |
107 | } |
108 | _ => {} |
109 | } |
110 | |
111 | Some(()) |
112 | } |
113 | |
114 | pub fn has_feature(&self, kind: u16, setting: u16) -> bool { |
115 | self.features |
116 | .binary_search_by(|probe| { |
117 | if probe.kind != kind { |
118 | probe.kind.cmp(&kind) |
119 | } else { |
120 | probe.setting.cmp(&setting) |
121 | } |
122 | }) |
123 | .is_ok() |
124 | } |
125 | |
126 | pub fn compile(&mut self, face: &Face) -> Map { |
127 | // Sort features and merge duplicates. |
128 | self.features.sort_by(|a, b| { |
129 | if a.kind != b.kind { |
130 | a.kind.cmp(&b.kind) |
131 | } else if !a.is_exclusive && (a.setting & !1) != (b.setting & !1) { |
132 | a.setting.cmp(&b.setting) |
133 | } else { |
134 | core::cmp::Ordering::Equal |
135 | } |
136 | }); |
137 | |
138 | let mut j = 0; |
139 | for i in 0..self.features.len() { |
140 | // Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off |
141 | // respectively, so we mask out the low-order bit when checking for "duplicates" |
142 | // (selectors referring to the same feature setting) here. |
143 | let non_exclusive = !self.features[i].is_exclusive |
144 | && (self.features[i].setting & !1) != (self.features[j].setting & !1); |
145 | |
146 | if self.features[i].kind != self.features[j].kind || non_exclusive { |
147 | j += 1; |
148 | self.features[j] = self.features[i]; |
149 | } |
150 | } |
151 | self.features.truncate(j + 1); |
152 | |
153 | super::metamorphosis::compile_flags(face, self).unwrap_or_default() |
154 | } |
155 | } |
156 | |