| 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 | |