1 | use alloc::boxed::Box; |
2 | use core::any::Any; |
3 | |
4 | use super::buffer::*; |
5 | use super::common::TagExt; |
6 | use super::ot_shape::*; |
7 | use super::ot_shape_normalize::*; |
8 | use super::ot_shape_plan::hb_ot_shape_plan_t; |
9 | use super::{hb_font_t, hb_tag_t, script, Direction, Script}; |
10 | |
11 | impl hb_glyph_info_t { |
12 | pub(crate) fn ot_shaper_var_u8_category(&self) -> u8 { |
13 | let v: &[u8; 4] = bytemuck::cast_ref(&self.var2); |
14 | v[2] |
15 | } |
16 | |
17 | pub(crate) fn set_ot_shaper_var_u8_category(&mut self, c: u8) { |
18 | let v: &mut [u8; 4] = bytemuck::cast_mut(&mut self.var2); |
19 | v[2] = c; |
20 | } |
21 | |
22 | pub(crate) fn ot_shaper_var_u8_auxiliary(&self) -> u8 { |
23 | let v: &[u8; 4] = bytemuck::cast_ref(&self.var2); |
24 | v[3] |
25 | } |
26 | |
27 | pub(crate) fn set_ot_shaper_var_u8_auxiliary(&mut self, c: u8) { |
28 | let v: &mut [u8; 4] = bytemuck::cast_mut(&mut self.var2); |
29 | v[3] = c; |
30 | } |
31 | } |
32 | |
33 | pub const MAX_COMBINING_MARKS: usize = 32; |
34 | |
35 | pub type hb_ot_shape_zero_width_marks_type_t = u32; |
36 | pub const HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: u32 = 0; |
37 | pub const HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY: u32 = 1; |
38 | pub const HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: u32 = 2; |
39 | |
40 | pub type DecomposeFn = fn(&hb_ot_shape_normalize_context_t, char) -> Option<(char, char)>; |
41 | pub type ComposeFn = fn(&hb_ot_shape_normalize_context_t, char, char) -> Option<char>; |
42 | |
43 | pub const DEFAULT_SHAPER: hb_ot_shaper_t = hb_ot_shaper_t { |
44 | collect_features: None, |
45 | override_features: None, |
46 | create_data: None, |
47 | preprocess_text: None, |
48 | postprocess_glyphs: None, |
49 | normalization_preference: HB_OT_SHAPE_NORMALIZATION_MODE_AUTO, |
50 | decompose: None, |
51 | compose: None, |
52 | setup_masks: None, |
53 | gpos_tag: None, |
54 | reorder_marks: None, |
55 | zero_width_marks: HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE, |
56 | fallback_position: true, |
57 | }; |
58 | |
59 | pub struct hb_ot_shaper_t { |
60 | /// Called during `shape_plan()`. |
61 | /// Shapers should use plan.map to add their features and callbacks. |
62 | pub collect_features: Option<fn(&mut hb_ot_shape_planner_t)>, |
63 | |
64 | /// Called during `shape_plan()`. |
65 | /// Shapers should use plan.map to override features and add callbacks after |
66 | /// common features are added. |
67 | pub override_features: Option<fn(&mut hb_ot_shape_planner_t)>, |
68 | |
69 | /// Called at the end of `shape_plan()`. |
70 | /// Whatever shapers return will be accessible through `plan.data()` later. |
71 | pub create_data: Option<fn(&hb_ot_shape_plan_t) -> Box<dyn Any + Send + Sync>>, |
72 | |
73 | /// Called during `shape()`. |
74 | /// Shapers can use to modify text before shaping starts. |
75 | pub preprocess_text: Option<fn(&hb_ot_shape_plan_t, &hb_font_t, &mut hb_buffer_t)>, |
76 | |
77 | /// Called during `shape()`. |
78 | /// Shapers can use to modify text before shaping starts. |
79 | pub postprocess_glyphs: Option<fn(&hb_ot_shape_plan_t, &hb_font_t, &mut hb_buffer_t)>, |
80 | |
81 | /// How to normalize. |
82 | pub normalization_preference: hb_ot_shape_normalization_mode_t, |
83 | |
84 | /// Called during `shape()`'s normalization. |
85 | pub decompose: Option<DecomposeFn>, |
86 | |
87 | /// Called during `shape()`'s normalization. |
88 | pub compose: Option<ComposeFn>, |
89 | |
90 | /// Called during `shape()`. |
91 | /// Shapers should use map to get feature masks and set on buffer. |
92 | /// Shapers may NOT modify characters. |
93 | pub setup_masks: Option<fn(&hb_ot_shape_plan_t, &hb_font_t, &mut hb_buffer_t)>, |
94 | |
95 | /// If not `None`, then must match found GPOS script tag for |
96 | /// GPOS to be applied. Otherwise, fallback positioning will be used. |
97 | pub gpos_tag: Option<hb_tag_t>, |
98 | |
99 | /// Called during `shape()`. |
100 | /// Shapers can use to modify ordering of combining marks. |
101 | pub reorder_marks: Option<fn(&hb_ot_shape_plan_t, &mut hb_buffer_t, usize, usize)>, |
102 | |
103 | /// If and when to zero-width marks. |
104 | pub zero_width_marks: hb_ot_shape_zero_width_marks_type_t, |
105 | |
106 | /// Whether to use fallback mark positioning. |
107 | pub fallback_position: bool, |
108 | } |
109 | |
110 | // Same as default but no mark advance zeroing / fallback positioning. |
111 | // Dumbest shaper ever, basically. |
112 | pub const DUMBER_SHAPER: hb_ot_shaper_t = hb_ot_shaper_t { |
113 | collect_features: None, |
114 | override_features: None, |
115 | create_data: None, |
116 | preprocess_text: None, |
117 | postprocess_glyphs: None, |
118 | normalization_preference: HB_OT_SHAPE_NORMALIZATION_MODE_AUTO, |
119 | decompose: None, |
120 | compose: None, |
121 | setup_masks: None, |
122 | gpos_tag: None, |
123 | reorder_marks: None, |
124 | zero_width_marks: HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, |
125 | fallback_position: false, |
126 | }; |
127 | |
128 | pub fn hb_ot_shape_complex_categorize( |
129 | script: Script, |
130 | direction: Direction, |
131 | gsub_script: Option<hb_tag_t>, |
132 | ) -> &'static hb_ot_shaper_t { |
133 | match script { |
134 | // Unicode-1.1 additions |
135 | script::ARABIC |
136 | |
137 | // Unicode-3.0 additions |
138 | | script::SYRIAC => { |
139 | // For Arabic script, use the Arabic shaper even if no OT script tag was found. |
140 | // This is because we do fallback shaping for Arabic script (and not others). |
141 | // But note that Arabic shaping is applicable only to horizontal layout; for |
142 | // vertical text, just use the generic shaper instead. |
143 | // |
144 | // TODO: Does this still apply? Arabic fallback shaping was removed. |
145 | if (gsub_script != Some(hb_tag_t::default_script()) || script == script::ARABIC) |
146 | && direction.is_horizontal() |
147 | { |
148 | &crate::hb::ot_shaper_arabic::ARABIC_SHAPER |
149 | } else { |
150 | &DEFAULT_SHAPER |
151 | } |
152 | } |
153 | |
154 | // Unicode-1.1 additions |
155 | script::THAI |
156 | | script::LAO => &crate::hb::ot_shaper_thai::THAI_SHAPER, |
157 | |
158 | // Unicode-1.1 additions |
159 | script::HANGUL => &crate::hb::ot_shaper_hangul::HANGUL_SHAPER, |
160 | |
161 | // Unicode-1.1 additions |
162 | script::HEBREW => &crate::hb::ot_shaper_hebrew::HEBREW_SHAPER, |
163 | |
164 | // Unicode-1.1 additions |
165 | script::BENGALI |
166 | | script::DEVANAGARI |
167 | | script::GUJARATI |
168 | | script::GURMUKHI |
169 | | script::KANNADA |
170 | | script::MALAYALAM |
171 | | script::ORIYA |
172 | | script::TAMIL |
173 | | script::TELUGU => { |
174 | // If the designer designed the font for the 'DFLT' script, |
175 | // (or we ended up arbitrarily pick 'latn'), use the default shaper. |
176 | // Otherwise, use the specific shaper. |
177 | // |
178 | // If it's indy3 tag, send to USE. |
179 | if gsub_script == Some(hb_tag_t::default_script()) || |
180 | gsub_script == Some(hb_tag_t::from_bytes(b"latn" )) { |
181 | &DEFAULT_SHAPER |
182 | } else if gsub_script.map_or(false, |tag| tag.to_bytes()[3] == b'3' ) { |
183 | &crate::hb::ot_shaper_use::UNIVERSAL_SHAPER |
184 | } else { |
185 | &crate::hb::ot_shaper_indic::INDIC_SHAPER |
186 | } |
187 | } |
188 | |
189 | script::KHMER => &crate::hb::ot_shaper_khmer::KHMER_SHAPER, |
190 | |
191 | script::MYANMAR => { |
192 | // If the designer designed the font for the 'DFLT' script, |
193 | // (or we ended up arbitrarily pick 'latn'), use the default shaper. |
194 | // Otherwise, use the specific shaper. |
195 | // |
196 | // If designer designed for 'mymr' tag, also send to default |
197 | // shaper. That's tag used from before Myanmar shaping spec |
198 | // was developed. The shaping spec uses 'mym2' tag. |
199 | if gsub_script == Some(hb_tag_t::default_script()) || |
200 | gsub_script == Some(hb_tag_t::from_bytes(b"latn" )) || |
201 | gsub_script == Some(hb_tag_t::from_bytes(b"mymr" )) |
202 | { |
203 | &DEFAULT_SHAPER |
204 | } else { |
205 | &crate::hb::ot_shaper_myanmar::MYANMAR_SHAPER |
206 | } |
207 | } |
208 | |
209 | // https://github.com/harfbuzz/harfbuzz/issues/1162 |
210 | script::MYANMAR_ZAWGYI => &crate::hb::ot_shaper_myanmar::MYANMAR_ZAWGYI_SHAPER, |
211 | |
212 | // Unicode-2.0 additions |
213 | script::TIBETAN |
214 | |
215 | // Unicode-3.0 additions |
216 | | script::MONGOLIAN |
217 | | script::SINHALA |
218 | |
219 | // Unicode-3.2 additions |
220 | | script::BUHID |
221 | | script::HANUNOO |
222 | | script::TAGALOG |
223 | | script::TAGBANWA |
224 | |
225 | // Unicode-4.0 additions |
226 | | script::LIMBU |
227 | | script::TAI_LE |
228 | |
229 | // Unicode-4.1 additions |
230 | | script::BUGINESE |
231 | | script::KHAROSHTHI |
232 | | script::SYLOTI_NAGRI |
233 | | script::TIFINAGH |
234 | |
235 | // Unicode-5.0 additions |
236 | | script::BALINESE |
237 | | script::NKO |
238 | | script::PHAGS_PA |
239 | |
240 | // Unicode-5.1 additions |
241 | | script::CHAM |
242 | | script::KAYAH_LI |
243 | | script::LEPCHA |
244 | | script::REJANG |
245 | | script::SAURASHTRA |
246 | | script::SUNDANESE |
247 | |
248 | // Unicode-5.2 additions |
249 | | script::EGYPTIAN_HIEROGLYPHS |
250 | | script::JAVANESE |
251 | | script::KAITHI |
252 | | script::MEETEI_MAYEK |
253 | | script::TAI_THAM |
254 | | script::TAI_VIET |
255 | |
256 | // Unicode-6.0 additions |
257 | | script::BATAK |
258 | | script::BRAHMI |
259 | | script::MANDAIC |
260 | |
261 | // Unicode-6.1 additions |
262 | | script::CHAKMA |
263 | | script::MIAO |
264 | | script::SHARADA |
265 | | script::TAKRI |
266 | |
267 | // Unicode-7.0 additions |
268 | | script::DUPLOYAN |
269 | | script::GRANTHA |
270 | | script::KHOJKI |
271 | | script::KHUDAWADI |
272 | | script::MAHAJANI |
273 | | script::MANICHAEAN |
274 | | script::MODI |
275 | | script::PAHAWH_HMONG |
276 | | script::PSALTER_PAHLAVI |
277 | | script::SIDDHAM |
278 | | script::TIRHUTA |
279 | |
280 | // Unicode-8.0 additions |
281 | | script::AHOM |
282 | | script::MULTANI |
283 | |
284 | // Unicode-9.0 additions |
285 | | script::ADLAM |
286 | | script::BHAIKSUKI |
287 | | script::MARCHEN |
288 | | script::NEWA |
289 | |
290 | // Unicode-10.0 additions |
291 | | script::MASARAM_GONDI |
292 | | script::SOYOMBO |
293 | | script::ZANABAZAR_SQUARE |
294 | |
295 | // Unicode-11.0 additions |
296 | | script::DOGRA |
297 | | script::GUNJALA_GONDI |
298 | | script::HANIFI_ROHINGYA |
299 | | script::MAKASAR |
300 | | script::MEDEFAIDRIN |
301 | | script::OLD_SOGDIAN |
302 | | script::SOGDIAN |
303 | |
304 | // Unicode-12.0 additions |
305 | | script::ELYMAIC |
306 | | script::NANDINAGARI |
307 | | script::NYIAKENG_PUACHUE_HMONG |
308 | | script::WANCHO |
309 | |
310 | // Unicode-13.0 additions |
311 | | script::CHORASMIAN |
312 | | script::DIVES_AKURU |
313 | | script::KHITAN_SMALL_SCRIPT |
314 | | script::YEZIDI |
315 | |
316 | // Unicode-14.0 additions |
317 | | script::CYPRO_MINOAN |
318 | | script::OLD_UYGHUR |
319 | | script::TANGSA |
320 | | script::TOTO |
321 | | script::VITHKUQI |
322 | |
323 | // Unicode-15.0 additions |
324 | | script::KAWI |
325 | | script::NAG_MUNDARI |
326 | |
327 | // Unicode-16.0 additions |
328 | | script::GARAY |
329 | | script::GURUNG_KHEMA |
330 | | script::KIRAT_RAI |
331 | | script::OL_ONAL |
332 | | script::SUNUWAR |
333 | | script::TODHRI |
334 | | script::TULU_TIGALARI |
335 | |
336 | => { |
337 | // If the designer designed the font for the 'DFLT' script, |
338 | // (or we ended up arbitrarily pick 'latn'), use the default shaper. |
339 | // Otherwise, use the specific shaper. |
340 | // Note that for some simple scripts, there may not be *any* |
341 | // GSUB/GPOS needed, so there may be no scripts found! |
342 | if gsub_script == Some(hb_tag_t::default_script()) || |
343 | gsub_script == Some(hb_tag_t::from_bytes(b"latn" )) { |
344 | &DEFAULT_SHAPER |
345 | } else { |
346 | &crate::hb::ot_shaper_use::UNIVERSAL_SHAPER |
347 | } |
348 | } |
349 | |
350 | _ => &DEFAULT_SHAPER |
351 | } |
352 | } |
353 | |