Skip to main content

harfrust/hb/
ot_shaper.rs

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