1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,558 @@ 1.4 +/* 1.5 + * Copyright © 2011,2012,2013 Google, Inc. 1.6 + * 1.7 + * This is part of HarfBuzz, a text shaping library. 1.8 + * 1.9 + * Permission is hereby granted, without written agreement and without 1.10 + * license or royalty fees, to use, copy, modify, and distribute this 1.11 + * software and its documentation for any purpose, provided that the 1.12 + * above copyright notice and the following two paragraphs appear in 1.13 + * all copies of this software. 1.14 + * 1.15 + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 1.16 + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 1.17 + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 1.18 + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 1.19 + * DAMAGE. 1.20 + * 1.21 + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 1.22 + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 1.23 + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 1.24 + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 1.25 + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 1.26 + * 1.27 + * Google Author(s): Behdad Esfahbod 1.28 + */ 1.29 + 1.30 +#include "hb-ot-shape-complex-indic-private.hh" 1.31 + 1.32 +/* buffer var allocations */ 1.33 +#define myanmar_category() complex_var_u8_0() /* myanmar_category_t */ 1.34 +#define myanmar_position() complex_var_u8_1() /* myanmar_position_t */ 1.35 + 1.36 + 1.37 +/* 1.38 + * Myanmar shaper. 1.39 + */ 1.40 + 1.41 +static const hb_tag_t 1.42 +basic_features[] = 1.43 +{ 1.44 + /* 1.45 + * Basic features. 1.46 + * These features are applied in order, one at a time, after initial_reordering. 1.47 + */ 1.48 + HB_TAG('r','p','h','f'), 1.49 + HB_TAG('p','r','e','f'), 1.50 + HB_TAG('b','l','w','f'), 1.51 + HB_TAG('p','s','t','f'), 1.52 +}; 1.53 +static const hb_tag_t 1.54 +other_features[] = 1.55 +{ 1.56 + /* 1.57 + * Other features. 1.58 + * These features are applied all at once, after final_reordering. 1.59 + */ 1.60 + HB_TAG('p','r','e','s'), 1.61 + HB_TAG('a','b','v','s'), 1.62 + HB_TAG('b','l','w','s'), 1.63 + HB_TAG('p','s','t','s'), 1.64 + /* Positioning features, though we don't care about the types. */ 1.65 + HB_TAG('d','i','s','t'), 1.66 + /* Pre-release version of Windows 8 Myanmar font had abvm,blwm 1.67 + * features. The released Windows 8 version of the font (as well 1.68 + * as the released spec) used 'mark' instead. The Windows 8 1.69 + * shaper however didn't apply 'mark' but did apply 'mkmk'. 1.70 + * Perhaps it applied abvm/blwm. This was fixed in a Windows 8 1.71 + * update, so now it applies mark/mkmk. We are guessing that 1.72 + * it still applies abvm/blwm too. 1.73 + */ 1.74 + HB_TAG('a','b','v','m'), 1.75 + HB_TAG('b','l','w','m'), 1.76 +}; 1.77 + 1.78 +static void 1.79 +setup_syllables (const hb_ot_shape_plan_t *plan, 1.80 + hb_font_t *font, 1.81 + hb_buffer_t *buffer); 1.82 +static void 1.83 +initial_reordering (const hb_ot_shape_plan_t *plan, 1.84 + hb_font_t *font, 1.85 + hb_buffer_t *buffer); 1.86 +static void 1.87 +final_reordering (const hb_ot_shape_plan_t *plan, 1.88 + hb_font_t *font, 1.89 + hb_buffer_t *buffer); 1.90 + 1.91 +static void 1.92 +collect_features_myanmar (hb_ot_shape_planner_t *plan) 1.93 +{ 1.94 + hb_ot_map_builder_t *map = &plan->map; 1.95 + 1.96 + /* Do this before any lookups have been applied. */ 1.97 + map->add_gsub_pause (setup_syllables); 1.98 + 1.99 + map->add_global_bool_feature (HB_TAG('l','o','c','l')); 1.100 + /* The Indic specs do not require ccmp, but we apply it here since if 1.101 + * there is a use of it, it's typically at the beginning. */ 1.102 + map->add_global_bool_feature (HB_TAG('c','c','m','p')); 1.103 + 1.104 + 1.105 + map->add_gsub_pause (initial_reordering); 1.106 + for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++) 1.107 + { 1.108 + map->add_feature (basic_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ); 1.109 + map->add_gsub_pause (NULL); 1.110 + } 1.111 + map->add_gsub_pause (final_reordering); 1.112 + for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++) 1.113 + map->add_feature (other_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ); 1.114 +} 1.115 + 1.116 +static void 1.117 +override_features_myanmar (hb_ot_shape_planner_t *plan) 1.118 +{ 1.119 + plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL); 1.120 +} 1.121 + 1.122 + 1.123 +enum syllable_type_t { 1.124 + consonant_syllable, 1.125 + punctuation_cluster, 1.126 + broken_cluster, 1.127 + non_myanmar_cluster, 1.128 +}; 1.129 + 1.130 +#include "hb-ot-shape-complex-myanmar-machine.hh" 1.131 + 1.132 + 1.133 +/* Note: This enum is duplicated in the -machine.rl source file. 1.134 + * Not sure how to avoid duplication. */ 1.135 +enum myanmar_category_t { 1.136 + OT_As = 18, /* Asat */ 1.137 + OT_D = 19, /* Digits except zero */ 1.138 + OT_D0 = 20, /* Digit zero */ 1.139 + OT_DB = OT_N, /* Dot below */ 1.140 + OT_GB = OT_DOTTEDCIRCLE, 1.141 + OT_MH = 21, /* Various consonant medial types */ 1.142 + OT_MR = 22, /* Various consonant medial types */ 1.143 + OT_MW = 23, /* Various consonant medial types */ 1.144 + OT_MY = 24, /* Various consonant medial types */ 1.145 + OT_PT = 25, /* Pwo and other tones */ 1.146 + OT_VAbv = 26, 1.147 + OT_VBlw = 27, 1.148 + OT_VPre = 28, 1.149 + OT_VPst = 29, 1.150 + OT_VS = 30, /* Variation selectors */ 1.151 + OT_P = 31 /* Punctuation */ 1.152 +}; 1.153 + 1.154 + 1.155 +static inline bool 1.156 +is_one_of (const hb_glyph_info_t &info, unsigned int flags) 1.157 +{ 1.158 + /* If it ligated, all bets are off. */ 1.159 + if (_hb_glyph_info_ligated (&info)) return false; 1.160 + return !!(FLAG (info.myanmar_category()) & flags); 1.161 +} 1.162 + 1.163 +/* Note: 1.164 + * 1.165 + * We treat Vowels and placeholders as if they were consonants. This is safe because Vowels 1.166 + * cannot happen in a consonant syllable. The plus side however is, we can call the 1.167 + * consonant syllable logic from the vowel syllable function and get it all right! */ 1.168 +#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_CM) | FLAG (OT_Ra) | FLAG (OT_V) | FLAG (OT_NBSP) | FLAG (OT_GB)) 1.169 +static inline bool 1.170 +is_consonant (const hb_glyph_info_t &info) 1.171 +{ 1.172 + return is_one_of (info, CONSONANT_FLAGS); 1.173 +} 1.174 + 1.175 + 1.176 +static inline void 1.177 +set_myanmar_properties (hb_glyph_info_t &info) 1.178 +{ 1.179 + hb_codepoint_t u = info.codepoint; 1.180 + unsigned int type = hb_indic_get_categories (u); 1.181 + indic_category_t cat = (indic_category_t) (type & 0x7F); 1.182 + indic_position_t pos = (indic_position_t) (type >> 8); 1.183 + 1.184 + /* Myanmar 1.185 + * http://www.microsoft.com/typography/OpenTypeDev/myanmar/intro.htm#analyze 1.186 + */ 1.187 + if (unlikely (hb_in_range<hb_codepoint_t> (u, 0xFE00, 0xFE0F))) 1.188 + cat = (indic_category_t) OT_VS; 1.189 + else if (unlikely (u == 0x200C)) cat = (indic_category_t) OT_ZWNJ; 1.190 + else if (unlikely (u == 0x200D)) cat = (indic_category_t) OT_ZWJ; 1.191 + 1.192 + switch (u) 1.193 + { 1.194 + case 0x104E: 1.195 + cat = (indic_category_t) OT_C; /* The spec says C, IndicSyllableCategory doesn't have. */ 1.196 + break; 1.197 + 1.198 + case 0x002D: case 0x00A0: case 0x00D7: case 0x2012: 1.199 + case 0x2013: case 0x2014: case 0x2015: case 0x2022: 1.200 + case 0x25CC: case 0x25FB: case 0x25FC: case 0x25FD: 1.201 + case 0x25FE: 1.202 + cat = (indic_category_t) OT_GB; 1.203 + break; 1.204 + 1.205 + case 0x1004: case 0x101B: case 0x105A: 1.206 + cat = (indic_category_t) OT_Ra; 1.207 + break; 1.208 + 1.209 + case 0x1032: case 0x1036: 1.210 + cat = (indic_category_t) OT_A; 1.211 + break; 1.212 + 1.213 + case 0x103A: 1.214 + cat = (indic_category_t) OT_As; 1.215 + break; 1.216 + 1.217 + case 0x1041: case 0x1042: case 0x1043: case 0x1044: 1.218 + case 0x1045: case 0x1046: case 0x1047: case 0x1048: 1.219 + case 0x1049: case 0x1090: case 0x1091: case 0x1092: 1.220 + case 0x1093: case 0x1094: case 0x1095: case 0x1096: 1.221 + case 0x1097: case 0x1098: case 0x1099: 1.222 + cat = (indic_category_t) OT_D; 1.223 + break; 1.224 + 1.225 + case 0x1040: 1.226 + cat = (indic_category_t) OT_D; /* XXX The spec says D0, but Uniscribe doesn't seem to do. */ 1.227 + break; 1.228 + 1.229 + case 0x103E: case 0x1060: 1.230 + cat = (indic_category_t) OT_MH; 1.231 + break; 1.232 + 1.233 + case 0x103C: 1.234 + cat = (indic_category_t) OT_MR; 1.235 + break; 1.236 + 1.237 + case 0x103D: case 0x1082: 1.238 + cat = (indic_category_t) OT_MW; 1.239 + break; 1.240 + 1.241 + case 0x103B: case 0x105E: case 0x105F: 1.242 + cat = (indic_category_t) OT_MY; 1.243 + break; 1.244 + 1.245 + case 0x1063: case 0x1064: case 0x1069: case 0x106A: 1.246 + case 0x106B: case 0x106C: case 0x106D: case 0xAA7B: 1.247 + cat = (indic_category_t) OT_PT; 1.248 + break; 1.249 + 1.250 + case 0x1038: case 0x1087: case 0x1088: case 0x1089: 1.251 + case 0x108A: case 0x108B: case 0x108C: case 0x108D: 1.252 + case 0x108F: case 0x109A: case 0x109B: case 0x109C: 1.253 + cat = (indic_category_t) OT_SM; 1.254 + break; 1.255 + 1.256 + case 0x104A: case 0x104B: 1.257 + cat = (indic_category_t) OT_P; 1.258 + break; 1.259 + } 1.260 + 1.261 + if (cat == OT_M) 1.262 + { 1.263 + switch ((int) pos) 1.264 + { 1.265 + case POS_PRE_C: cat = (indic_category_t) OT_VPre; 1.266 + pos = POS_PRE_M; break; 1.267 + case POS_ABOVE_C: cat = (indic_category_t) OT_VAbv; break; 1.268 + case POS_BELOW_C: cat = (indic_category_t) OT_VBlw; break; 1.269 + case POS_POST_C: cat = (indic_category_t) OT_VPst; break; 1.270 + } 1.271 + } 1.272 + 1.273 + info.myanmar_category() = (myanmar_category_t) cat; 1.274 + info.myanmar_position() = pos; 1.275 +} 1.276 + 1.277 + 1.278 + 1.279 +static void 1.280 +setup_masks_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED, 1.281 + hb_buffer_t *buffer, 1.282 + hb_font_t *font HB_UNUSED) 1.283 +{ 1.284 + HB_BUFFER_ALLOCATE_VAR (buffer, myanmar_category); 1.285 + HB_BUFFER_ALLOCATE_VAR (buffer, myanmar_position); 1.286 + 1.287 + /* We cannot setup masks here. We save information about characters 1.288 + * and setup masks later on in a pause-callback. */ 1.289 + 1.290 + unsigned int count = buffer->len; 1.291 + for (unsigned int i = 0; i < count; i++) 1.292 + set_myanmar_properties (buffer->info[i]); 1.293 +} 1.294 + 1.295 +static void 1.296 +setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, 1.297 + hb_font_t *font HB_UNUSED, 1.298 + hb_buffer_t *buffer) 1.299 +{ 1.300 + find_syllables (buffer); 1.301 +} 1.302 + 1.303 +static int 1.304 +compare_myanmar_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) 1.305 +{ 1.306 + int a = pa->myanmar_position(); 1.307 + int b = pb->myanmar_position(); 1.308 + 1.309 + return a < b ? -1 : a == b ? 0 : +1; 1.310 +} 1.311 + 1.312 + 1.313 +/* Rules from: 1.314 + * http://www.microsoft.com/typography/OpenTypeDev/myanmar/intro.htm */ 1.315 + 1.316 +static void 1.317 +initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, 1.318 + hb_face_t *face, 1.319 + hb_buffer_t *buffer, 1.320 + unsigned int start, unsigned int end) 1.321 +{ 1.322 + hb_glyph_info_t *info = buffer->info; 1.323 + 1.324 + unsigned int base = end; 1.325 + bool has_reph = false; 1.326 + 1.327 + { 1.328 + unsigned int limit = start; 1.329 + if (start + 3 <= end && 1.330 + info[start ].myanmar_category() == OT_Ra && 1.331 + info[start+1].myanmar_category() == OT_As && 1.332 + info[start+2].myanmar_category() == OT_H) 1.333 + { 1.334 + limit += 3; 1.335 + base = start; 1.336 + has_reph = true; 1.337 + } 1.338 + 1.339 + { 1.340 + if (!has_reph) 1.341 + base = limit; 1.342 + 1.343 + for (unsigned int i = limit; i < end; i++) 1.344 + if (is_consonant (info[i])) 1.345 + { 1.346 + base = i; 1.347 + break; 1.348 + } 1.349 + } 1.350 + } 1.351 + 1.352 + /* Reorder! */ 1.353 + { 1.354 + unsigned int i = start; 1.355 + for (; i < start + (has_reph ? 3 : 0); i++) 1.356 + info[i].myanmar_position() = POS_AFTER_MAIN; 1.357 + for (; i < base; i++) 1.358 + info[i].myanmar_position() = POS_PRE_C; 1.359 + if (i < end) 1.360 + { 1.361 + info[i].myanmar_position() = POS_BASE_C; 1.362 + i++; 1.363 + } 1.364 + indic_position_t pos = POS_AFTER_MAIN; 1.365 + /* The following loop may be ugly, but it implements all of 1.366 + * Myanmar reordering! */ 1.367 + for (; i < end; i++) 1.368 + { 1.369 + if (info[i].myanmar_category() == OT_MR) /* Pre-base reordering */ 1.370 + { 1.371 + info[i].myanmar_position() = POS_PRE_C; 1.372 + continue; 1.373 + } 1.374 + if (info[i].myanmar_position() < POS_BASE_C) /* Left matra */ 1.375 + { 1.376 + continue; 1.377 + } 1.378 + 1.379 + if (pos == POS_AFTER_MAIN && info[i].myanmar_category() == OT_VBlw) 1.380 + { 1.381 + pos = POS_BELOW_C; 1.382 + info[i].myanmar_position() = pos; 1.383 + continue; 1.384 + } 1.385 + 1.386 + if (pos == POS_BELOW_C && info[i].myanmar_category() == OT_A) 1.387 + { 1.388 + info[i].myanmar_position() = POS_BEFORE_SUB; 1.389 + continue; 1.390 + } 1.391 + if (pos == POS_BELOW_C && info[i].myanmar_category() == OT_VBlw) 1.392 + { 1.393 + info[i].myanmar_position() = pos; 1.394 + continue; 1.395 + } 1.396 + if (pos == POS_BELOW_C && info[i].myanmar_category() != OT_A) 1.397 + { 1.398 + pos = POS_AFTER_SUB; 1.399 + info[i].myanmar_position() = pos; 1.400 + continue; 1.401 + } 1.402 + info[i].myanmar_position() = pos; 1.403 + } 1.404 + } 1.405 + 1.406 + buffer->merge_clusters (start, end); 1.407 + /* Sit tight, rock 'n roll! */ 1.408 + hb_bubble_sort (info + start, end - start, compare_myanmar_order); 1.409 +} 1.410 + 1.411 +static void 1.412 +initial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan, 1.413 + hb_face_t *face, 1.414 + hb_buffer_t *buffer, 1.415 + unsigned int start, unsigned int end) 1.416 +{ 1.417 + /* We already inserted dotted-circles, so just call the consonant_syllable. */ 1.418 + initial_reordering_consonant_syllable (plan, face, buffer, start, end); 1.419 +} 1.420 + 1.421 +static void 1.422 +initial_reordering_punctuation_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED, 1.423 + hb_face_t *face HB_UNUSED, 1.424 + hb_buffer_t *buffer HB_UNUSED, 1.425 + unsigned int start HB_UNUSED, unsigned int end HB_UNUSED) 1.426 +{ 1.427 + /* Nothing to do right now. If we ever switch to using the output 1.428 + * buffer in the reordering process, we'd need to next_glyph() here. */ 1.429 +} 1.430 + 1.431 +static void 1.432 +initial_reordering_non_myanmar_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED, 1.433 + hb_face_t *face HB_UNUSED, 1.434 + hb_buffer_t *buffer HB_UNUSED, 1.435 + unsigned int start HB_UNUSED, unsigned int end HB_UNUSED) 1.436 +{ 1.437 + /* Nothing to do right now. If we ever switch to using the output 1.438 + * buffer in the reordering process, we'd need to next_glyph() here. */ 1.439 +} 1.440 + 1.441 + 1.442 +static void 1.443 +initial_reordering_syllable (const hb_ot_shape_plan_t *plan, 1.444 + hb_face_t *face, 1.445 + hb_buffer_t *buffer, 1.446 + unsigned int start, unsigned int end) 1.447 +{ 1.448 + syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F); 1.449 + switch (syllable_type) { 1.450 + case consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); return; 1.451 + case punctuation_cluster: initial_reordering_punctuation_cluster (plan, face, buffer, start, end); return; 1.452 + case broken_cluster: initial_reordering_broken_cluster (plan, face, buffer, start, end); return; 1.453 + case non_myanmar_cluster: initial_reordering_non_myanmar_cluster (plan, face, buffer, start, end); return; 1.454 + } 1.455 +} 1.456 + 1.457 +static inline void 1.458 +insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, 1.459 + hb_font_t *font, 1.460 + hb_buffer_t *buffer) 1.461 +{ 1.462 + /* Note: This loop is extra overhead, but should not be measurable. */ 1.463 + bool has_broken_syllables = false; 1.464 + unsigned int count = buffer->len; 1.465 + for (unsigned int i = 0; i < count; i++) 1.466 + if ((buffer->info[i].syllable() & 0x0F) == broken_cluster) { 1.467 + has_broken_syllables = true; 1.468 + break; 1.469 + } 1.470 + if (likely (!has_broken_syllables)) 1.471 + return; 1.472 + 1.473 + 1.474 + hb_codepoint_t dottedcircle_glyph; 1.475 + if (!font->get_glyph (0x25CC, 0, &dottedcircle_glyph)) 1.476 + return; 1.477 + 1.478 + hb_glyph_info_t dottedcircle = {0}; 1.479 + dottedcircle.codepoint = 0x25CC; 1.480 + set_myanmar_properties (dottedcircle); 1.481 + dottedcircle.codepoint = dottedcircle_glyph; 1.482 + 1.483 + buffer->clear_output (); 1.484 + 1.485 + buffer->idx = 0; 1.486 + unsigned int last_syllable = 0; 1.487 + while (buffer->idx < buffer->len) 1.488 + { 1.489 + unsigned int syllable = buffer->cur().syllable(); 1.490 + syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F); 1.491 + if (unlikely (last_syllable != syllable && syllable_type == broken_cluster)) 1.492 + { 1.493 + last_syllable = syllable; 1.494 + 1.495 + hb_glyph_info_t info = dottedcircle; 1.496 + info.cluster = buffer->cur().cluster; 1.497 + info.mask = buffer->cur().mask; 1.498 + info.syllable() = buffer->cur().syllable(); 1.499 + 1.500 + buffer->output_info (info); 1.501 + } 1.502 + else 1.503 + buffer->next_glyph (); 1.504 + } 1.505 + 1.506 + buffer->swap_buffers (); 1.507 +} 1.508 + 1.509 +static void 1.510 +initial_reordering (const hb_ot_shape_plan_t *plan, 1.511 + hb_font_t *font, 1.512 + hb_buffer_t *buffer) 1.513 +{ 1.514 + insert_dotted_circles (plan, font, buffer); 1.515 + 1.516 + hb_glyph_info_t *info = buffer->info; 1.517 + unsigned int count = buffer->len; 1.518 + if (unlikely (!count)) return; 1.519 + unsigned int last = 0; 1.520 + unsigned int last_syllable = info[0].syllable(); 1.521 + for (unsigned int i = 1; i < count; i++) 1.522 + if (last_syllable != info[i].syllable()) { 1.523 + initial_reordering_syllable (plan, font->face, buffer, last, i); 1.524 + last = i; 1.525 + last_syllable = info[last].syllable(); 1.526 + } 1.527 + initial_reordering_syllable (plan, font->face, buffer, last, count); 1.528 +} 1.529 + 1.530 +static void 1.531 +final_reordering (const hb_ot_shape_plan_t *plan, 1.532 + hb_font_t *font HB_UNUSED, 1.533 + hb_buffer_t *buffer) 1.534 +{ 1.535 + hb_glyph_info_t *info = buffer->info; 1.536 + unsigned int count = buffer->len; 1.537 + 1.538 + /* Zero syllables now... */ 1.539 + for (unsigned int i = 0; i < count; i++) 1.540 + info[i].syllable() = 0; 1.541 + 1.542 + HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_category); 1.543 + HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_position); 1.544 +} 1.545 + 1.546 + 1.547 +const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar = 1.548 +{ 1.549 + "myanmar", 1.550 + collect_features_myanmar, 1.551 + override_features_myanmar, 1.552 + NULL, /* data_create */ 1.553 + NULL, /* data_destroy */ 1.554 + NULL, /* preprocess_text */ 1.555 + HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, 1.556 + NULL, /* decompose */ 1.557 + NULL, /* compose */ 1.558 + setup_masks_myanmar, 1.559 + HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY, 1.560 + false, /* fallback_position */ 1.561 +};