Fri, 16 Jan 2015 18:13:44 +0100
Integrate suggestion from review to improve consistency with existing code.
michael@0 | 1 | /* |
michael@0 | 2 | * Copyright © 2010,2011,2012 Google, Inc. |
michael@0 | 3 | * |
michael@0 | 4 | * This is part of HarfBuzz, a text shaping library. |
michael@0 | 5 | * |
michael@0 | 6 | * Permission is hereby granted, without written agreement and without |
michael@0 | 7 | * license or royalty fees, to use, copy, modify, and distribute this |
michael@0 | 8 | * software and its documentation for any purpose, provided that the |
michael@0 | 9 | * above copyright notice and the following two paragraphs appear in |
michael@0 | 10 | * all copies of this software. |
michael@0 | 11 | * |
michael@0 | 12 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
michael@0 | 13 | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
michael@0 | 14 | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
michael@0 | 15 | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
michael@0 | 16 | * DAMAGE. |
michael@0 | 17 | * |
michael@0 | 18 | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
michael@0 | 19 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
michael@0 | 20 | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
michael@0 | 21 | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
michael@0 | 22 | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
michael@0 | 23 | * |
michael@0 | 24 | * Google Author(s): Behdad Esfahbod |
michael@0 | 25 | */ |
michael@0 | 26 | |
michael@0 | 27 | #ifndef HB_OT_SHAPE_COMPLEX_PRIVATE_HH |
michael@0 | 28 | #define HB_OT_SHAPE_COMPLEX_PRIVATE_HH |
michael@0 | 29 | |
michael@0 | 30 | #include "hb-private.hh" |
michael@0 | 31 | |
michael@0 | 32 | #include "hb-ot-shape-private.hh" |
michael@0 | 33 | #include "hb-ot-shape-normalize-private.hh" |
michael@0 | 34 | |
michael@0 | 35 | |
michael@0 | 36 | |
michael@0 | 37 | /* buffer var allocations, used by complex shapers */ |
michael@0 | 38 | #define complex_var_u8_0() var2.u8[2] |
michael@0 | 39 | #define complex_var_u8_1() var2.u8[3] |
michael@0 | 40 | |
michael@0 | 41 | |
michael@0 | 42 | enum hb_ot_shape_zero_width_marks_type_t { |
michael@0 | 43 | HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, |
michael@0 | 44 | // HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY, |
michael@0 | 45 | HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE, |
michael@0 | 46 | HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY, |
michael@0 | 47 | HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE, |
michael@0 | 48 | |
michael@0 | 49 | HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT = HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE |
michael@0 | 50 | }; |
michael@0 | 51 | |
michael@0 | 52 | |
michael@0 | 53 | /* Master OT shaper list */ |
michael@0 | 54 | #define HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS \ |
michael@0 | 55 | HB_COMPLEX_SHAPER_IMPLEMENT (default) /* should be first */ \ |
michael@0 | 56 | HB_COMPLEX_SHAPER_IMPLEMENT (arabic) \ |
michael@0 | 57 | HB_COMPLEX_SHAPER_IMPLEMENT (hangul) \ |
michael@0 | 58 | HB_COMPLEX_SHAPER_IMPLEMENT (hebrew) \ |
michael@0 | 59 | HB_COMPLEX_SHAPER_IMPLEMENT (indic) \ |
michael@0 | 60 | HB_COMPLEX_SHAPER_IMPLEMENT (myanmar) \ |
michael@0 | 61 | HB_COMPLEX_SHAPER_IMPLEMENT (sea) \ |
michael@0 | 62 | HB_COMPLEX_SHAPER_IMPLEMENT (thai) \ |
michael@0 | 63 | HB_COMPLEX_SHAPER_IMPLEMENT (tibetan) \ |
michael@0 | 64 | /* ^--- Add new shapers here */ |
michael@0 | 65 | |
michael@0 | 66 | |
michael@0 | 67 | struct hb_ot_complex_shaper_t |
michael@0 | 68 | { |
michael@0 | 69 | char name[8]; |
michael@0 | 70 | |
michael@0 | 71 | /* collect_features() |
michael@0 | 72 | * Called during shape_plan(). |
michael@0 | 73 | * Shapers should use plan->map to add their features and callbacks. |
michael@0 | 74 | * May be NULL. |
michael@0 | 75 | */ |
michael@0 | 76 | void (*collect_features) (hb_ot_shape_planner_t *plan); |
michael@0 | 77 | |
michael@0 | 78 | /* override_features() |
michael@0 | 79 | * Called during shape_plan(). |
michael@0 | 80 | * Shapers should use plan->map to override features and add callbacks after |
michael@0 | 81 | * common features are added. |
michael@0 | 82 | * May be NULL. |
michael@0 | 83 | */ |
michael@0 | 84 | void (*override_features) (hb_ot_shape_planner_t *plan); |
michael@0 | 85 | |
michael@0 | 86 | |
michael@0 | 87 | /* data_create() |
michael@0 | 88 | * Called at the end of shape_plan(). |
michael@0 | 89 | * Whatever shapers return will be accessible through plan->data later. |
michael@0 | 90 | * If NULL is returned, means a plan failure. |
michael@0 | 91 | */ |
michael@0 | 92 | void *(*data_create) (const hb_ot_shape_plan_t *plan); |
michael@0 | 93 | |
michael@0 | 94 | /* data_destroy() |
michael@0 | 95 | * Called when the shape_plan is being destroyed. |
michael@0 | 96 | * plan->data is passed here for destruction. |
michael@0 | 97 | * If NULL is returned, means a plan failure. |
michael@0 | 98 | * May be NULL. |
michael@0 | 99 | */ |
michael@0 | 100 | void (*data_destroy) (void *data); |
michael@0 | 101 | |
michael@0 | 102 | |
michael@0 | 103 | /* preprocess_text() |
michael@0 | 104 | * Called during shape(). |
michael@0 | 105 | * Shapers can use to modify text before shaping starts. |
michael@0 | 106 | * May be NULL. |
michael@0 | 107 | */ |
michael@0 | 108 | void (*preprocess_text) (const hb_ot_shape_plan_t *plan, |
michael@0 | 109 | hb_buffer_t *buffer, |
michael@0 | 110 | hb_font_t *font); |
michael@0 | 111 | |
michael@0 | 112 | |
michael@0 | 113 | hb_ot_shape_normalization_mode_t normalization_preference; |
michael@0 | 114 | |
michael@0 | 115 | /* decompose() |
michael@0 | 116 | * Called during shape()'s normalization. |
michael@0 | 117 | * May be NULL. |
michael@0 | 118 | */ |
michael@0 | 119 | bool (*decompose) (const hb_ot_shape_normalize_context_t *c, |
michael@0 | 120 | hb_codepoint_t ab, |
michael@0 | 121 | hb_codepoint_t *a, |
michael@0 | 122 | hb_codepoint_t *b); |
michael@0 | 123 | |
michael@0 | 124 | /* compose() |
michael@0 | 125 | * Called during shape()'s normalization. |
michael@0 | 126 | * May be NULL. |
michael@0 | 127 | */ |
michael@0 | 128 | bool (*compose) (const hb_ot_shape_normalize_context_t *c, |
michael@0 | 129 | hb_codepoint_t a, |
michael@0 | 130 | hb_codepoint_t b, |
michael@0 | 131 | hb_codepoint_t *ab); |
michael@0 | 132 | |
michael@0 | 133 | /* setup_masks() |
michael@0 | 134 | * Called during shape(). |
michael@0 | 135 | * Shapers should use map to get feature masks and set on buffer. |
michael@0 | 136 | * Shapers may NOT modify characters. |
michael@0 | 137 | * May be NULL. |
michael@0 | 138 | */ |
michael@0 | 139 | void (*setup_masks) (const hb_ot_shape_plan_t *plan, |
michael@0 | 140 | hb_buffer_t *buffer, |
michael@0 | 141 | hb_font_t *font); |
michael@0 | 142 | |
michael@0 | 143 | hb_ot_shape_zero_width_marks_type_t zero_width_marks; |
michael@0 | 144 | |
michael@0 | 145 | bool fallback_position; |
michael@0 | 146 | }; |
michael@0 | 147 | |
michael@0 | 148 | #define HB_COMPLEX_SHAPER_IMPLEMENT(name) extern HB_INTERNAL const hb_ot_complex_shaper_t _hb_ot_complex_shaper_##name; |
michael@0 | 149 | HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS |
michael@0 | 150 | #undef HB_COMPLEX_SHAPER_IMPLEMENT |
michael@0 | 151 | |
michael@0 | 152 | |
michael@0 | 153 | static inline const hb_ot_complex_shaper_t * |
michael@0 | 154 | hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner) |
michael@0 | 155 | { |
michael@0 | 156 | switch ((hb_tag_t) planner->props.script) |
michael@0 | 157 | { |
michael@0 | 158 | default: |
michael@0 | 159 | return &_hb_ot_complex_shaper_default; |
michael@0 | 160 | |
michael@0 | 161 | |
michael@0 | 162 | /* Unicode-1.1 additions */ |
michael@0 | 163 | case HB_SCRIPT_ARABIC: |
michael@0 | 164 | |
michael@0 | 165 | /* Unicode-3.0 additions */ |
michael@0 | 166 | case HB_SCRIPT_MONGOLIAN: |
michael@0 | 167 | case HB_SCRIPT_SYRIAC: |
michael@0 | 168 | |
michael@0 | 169 | /* Unicode-5.0 additions */ |
michael@0 | 170 | case HB_SCRIPT_NKO: |
michael@0 | 171 | case HB_SCRIPT_PHAGS_PA: |
michael@0 | 172 | |
michael@0 | 173 | /* Unicode-6.0 additions */ |
michael@0 | 174 | case HB_SCRIPT_MANDAIC: |
michael@0 | 175 | |
michael@0 | 176 | /* For Arabic script, use the Arabic shaper even if no OT script tag was found. |
michael@0 | 177 | * This is because we do fallback shaping for Arabic script (and not others). */ |
michael@0 | 178 | if (planner->map.chosen_script[0] != HB_OT_TAG_DEFAULT_SCRIPT || |
michael@0 | 179 | planner->props.script == HB_SCRIPT_ARABIC) |
michael@0 | 180 | return &_hb_ot_complex_shaper_arabic; |
michael@0 | 181 | else |
michael@0 | 182 | return &_hb_ot_complex_shaper_default; |
michael@0 | 183 | |
michael@0 | 184 | |
michael@0 | 185 | /* Unicode-1.1 additions */ |
michael@0 | 186 | case HB_SCRIPT_THAI: |
michael@0 | 187 | case HB_SCRIPT_LAO: |
michael@0 | 188 | |
michael@0 | 189 | return &_hb_ot_complex_shaper_thai; |
michael@0 | 190 | |
michael@0 | 191 | |
michael@0 | 192 | /* Unicode-1.1 additions */ |
michael@0 | 193 | case HB_SCRIPT_HANGUL: |
michael@0 | 194 | |
michael@0 | 195 | return &_hb_ot_complex_shaper_hangul; |
michael@0 | 196 | |
michael@0 | 197 | |
michael@0 | 198 | /* Unicode-2.0 additions */ |
michael@0 | 199 | case HB_SCRIPT_TIBETAN: |
michael@0 | 200 | |
michael@0 | 201 | return &_hb_ot_complex_shaper_tibetan; |
michael@0 | 202 | |
michael@0 | 203 | |
michael@0 | 204 | /* Unicode-1.1 additions */ |
michael@0 | 205 | case HB_SCRIPT_HEBREW: |
michael@0 | 206 | |
michael@0 | 207 | return &_hb_ot_complex_shaper_hebrew; |
michael@0 | 208 | |
michael@0 | 209 | |
michael@0 | 210 | /* ^--- Add new shapers here */ |
michael@0 | 211 | |
michael@0 | 212 | |
michael@0 | 213 | #if 0 |
michael@0 | 214 | /* Note: |
michael@0 | 215 | * |
michael@0 | 216 | * These disabled scripts are listed in ucd/IndicSyllabicCategory.txt, but according |
michael@0 | 217 | * to Martin Hosken and Jonathan Kew do not require complex shaping. |
michael@0 | 218 | * |
michael@0 | 219 | * TODO We should automate figuring out which scripts do not need complex shaping |
michael@0 | 220 | * |
michael@0 | 221 | * TODO We currently keep data for these scripts in our indic table. Need to fix the |
michael@0 | 222 | * generator to not do that. |
michael@0 | 223 | */ |
michael@0 | 224 | |
michael@0 | 225 | |
michael@0 | 226 | /* Simple? */ |
michael@0 | 227 | |
michael@0 | 228 | /* Unicode-3.2 additions */ |
michael@0 | 229 | case HB_SCRIPT_BUHID: |
michael@0 | 230 | case HB_SCRIPT_HANUNOO: |
michael@0 | 231 | |
michael@0 | 232 | /* Unicode-5.1 additions */ |
michael@0 | 233 | case HB_SCRIPT_SAURASHTRA: |
michael@0 | 234 | |
michael@0 | 235 | /* Unicode-6.0 additions */ |
michael@0 | 236 | case HB_SCRIPT_BATAK: |
michael@0 | 237 | case HB_SCRIPT_BRAHMI: |
michael@0 | 238 | |
michael@0 | 239 | |
michael@0 | 240 | /* Simple */ |
michael@0 | 241 | |
michael@0 | 242 | /* Unicode-1.1 additions */ |
michael@0 | 243 | /* These have their own shaper now. */ |
michael@0 | 244 | case HB_SCRIPT_LAO: |
michael@0 | 245 | case HB_SCRIPT_THAI: |
michael@0 | 246 | |
michael@0 | 247 | /* Unicode-3.2 additions */ |
michael@0 | 248 | case HB_SCRIPT_TAGALOG: |
michael@0 | 249 | case HB_SCRIPT_TAGBANWA: |
michael@0 | 250 | |
michael@0 | 251 | /* Unicode-4.0 additions */ |
michael@0 | 252 | case HB_SCRIPT_LIMBU: |
michael@0 | 253 | case HB_SCRIPT_TAI_LE: |
michael@0 | 254 | |
michael@0 | 255 | /* Unicode-4.1 additions */ |
michael@0 | 256 | case HB_SCRIPT_KHAROSHTHI: |
michael@0 | 257 | case HB_SCRIPT_SYLOTI_NAGRI: |
michael@0 | 258 | |
michael@0 | 259 | /* Unicode-5.1 additions */ |
michael@0 | 260 | case HB_SCRIPT_KAYAH_LI: |
michael@0 | 261 | |
michael@0 | 262 | /* Unicode-5.2 additions */ |
michael@0 | 263 | case HB_SCRIPT_TAI_VIET: |
michael@0 | 264 | |
michael@0 | 265 | |
michael@0 | 266 | #endif |
michael@0 | 267 | |
michael@0 | 268 | /* Unicode-1.1 additions */ |
michael@0 | 269 | case HB_SCRIPT_BENGALI: |
michael@0 | 270 | case HB_SCRIPT_DEVANAGARI: |
michael@0 | 271 | case HB_SCRIPT_GUJARATI: |
michael@0 | 272 | case HB_SCRIPT_GURMUKHI: |
michael@0 | 273 | case HB_SCRIPT_KANNADA: |
michael@0 | 274 | case HB_SCRIPT_MALAYALAM: |
michael@0 | 275 | case HB_SCRIPT_ORIYA: |
michael@0 | 276 | case HB_SCRIPT_TAMIL: |
michael@0 | 277 | case HB_SCRIPT_TELUGU: |
michael@0 | 278 | |
michael@0 | 279 | /* Unicode-3.0 additions */ |
michael@0 | 280 | case HB_SCRIPT_SINHALA: |
michael@0 | 281 | |
michael@0 | 282 | /* Unicode-5.0 additions */ |
michael@0 | 283 | case HB_SCRIPT_BALINESE: |
michael@0 | 284 | |
michael@0 | 285 | /* Unicode-5.1 additions */ |
michael@0 | 286 | case HB_SCRIPT_LEPCHA: |
michael@0 | 287 | case HB_SCRIPT_REJANG: |
michael@0 | 288 | case HB_SCRIPT_SUNDANESE: |
michael@0 | 289 | |
michael@0 | 290 | /* Unicode-5.2 additions */ |
michael@0 | 291 | case HB_SCRIPT_JAVANESE: |
michael@0 | 292 | case HB_SCRIPT_KAITHI: |
michael@0 | 293 | case HB_SCRIPT_MEETEI_MAYEK: |
michael@0 | 294 | |
michael@0 | 295 | /* Unicode-6.0 additions */ |
michael@0 | 296 | |
michael@0 | 297 | /* Unicode-6.1 additions */ |
michael@0 | 298 | case HB_SCRIPT_CHAKMA: |
michael@0 | 299 | case HB_SCRIPT_SHARADA: |
michael@0 | 300 | case HB_SCRIPT_TAKRI: |
michael@0 | 301 | |
michael@0 | 302 | /* If the designer designed the font for the 'DFLT' script, |
michael@0 | 303 | * use the default shaper. Otherwise, use the Indic shaper. |
michael@0 | 304 | * Note that for some simple scripts, there may not be *any* |
michael@0 | 305 | * GSUB/GPOS needed, so there may be no scripts found! */ |
michael@0 | 306 | if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T')) |
michael@0 | 307 | return &_hb_ot_complex_shaper_default; |
michael@0 | 308 | else |
michael@0 | 309 | return &_hb_ot_complex_shaper_indic; |
michael@0 | 310 | |
michael@0 | 311 | case HB_SCRIPT_KHMER: |
michael@0 | 312 | /* A number of Khmer fonts in the wild don't have a 'pref' feature, |
michael@0 | 313 | * and as such won't shape properly via the Indic shaper; |
michael@0 | 314 | * however, they typically have 'liga' / 'clig' features that implement |
michael@0 | 315 | * the necessary "reordering" by means of ligature substitutions. |
michael@0 | 316 | * So we send such pref-less fonts through the generic shaper instead. */ |
michael@0 | 317 | if (planner->map.found_script[0] && |
michael@0 | 318 | hb_ot_layout_language_find_feature (planner->face, HB_OT_TAG_GSUB, |
michael@0 | 319 | planner->map.script_index[0], |
michael@0 | 320 | planner->map.language_index[0], |
michael@0 | 321 | HB_TAG ('p','r','e','f'), |
michael@0 | 322 | NULL)) |
michael@0 | 323 | return &_hb_ot_complex_shaper_indic; |
michael@0 | 324 | else |
michael@0 | 325 | return &_hb_ot_complex_shaper_default; |
michael@0 | 326 | |
michael@0 | 327 | case HB_SCRIPT_MYANMAR: |
michael@0 | 328 | /* For Myanmar, we only want to use the Myanmar shaper if the "new" script |
michael@0 | 329 | * tag is found. For "old" script tag we want to use the default shaper. */ |
michael@0 | 330 | if (planner->map.chosen_script[0] == HB_TAG ('m','y','m','2')) |
michael@0 | 331 | return &_hb_ot_complex_shaper_myanmar; |
michael@0 | 332 | else |
michael@0 | 333 | return &_hb_ot_complex_shaper_default; |
michael@0 | 334 | |
michael@0 | 335 | /* Unicode-4.1 additions */ |
michael@0 | 336 | case HB_SCRIPT_BUGINESE: |
michael@0 | 337 | case HB_SCRIPT_NEW_TAI_LUE: |
michael@0 | 338 | |
michael@0 | 339 | /* Unicode-5.1 additions */ |
michael@0 | 340 | case HB_SCRIPT_CHAM: |
michael@0 | 341 | |
michael@0 | 342 | /* Unicode-5.2 additions */ |
michael@0 | 343 | case HB_SCRIPT_TAI_THAM: |
michael@0 | 344 | |
michael@0 | 345 | /* If the designer designed the font for the 'DFLT' script, |
michael@0 | 346 | * use the default shaper. Otherwise, use the Indic shaper. |
michael@0 | 347 | * Note that for some simple scripts, there may not be *any* |
michael@0 | 348 | * GSUB/GPOS needed, so there may be no scripts found! */ |
michael@0 | 349 | if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T')) |
michael@0 | 350 | return &_hb_ot_complex_shaper_default; |
michael@0 | 351 | else |
michael@0 | 352 | return &_hb_ot_complex_shaper_sea; |
michael@0 | 353 | } |
michael@0 | 354 | } |
michael@0 | 355 | |
michael@0 | 356 | |
michael@0 | 357 | #endif /* HB_OT_SHAPE_COMPLEX_PRIVATE_HH */ |