1 /* 2 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 3 * 4 * This is part of HarfBuzz, an OpenType Layout engine library. 5 * 6 * Permission is hereby granted, without written agreement and without 7 * license or royalty fees, to use, copy, modify, and distribute this 8 * software and its documentation for any purpose, provided that the 9 * above copyright notice and the following two paragraphs appear in 10 * all copies of this software. 11 * 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16 * DAMAGE. 17 * 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23 */ 24 25 #include "harfbuzz-shaper.h" 26 #include "harfbuzz-shaper-private.h" 27 28 #include <assert.h> 29 #include <stdio.h> 30 31 enum MymrCharClassValues 32 { 33 Mymr_CC_RESERVED = 0, 34 Mymr_CC_CONSONANT = 1, /* Consonant of type 1, that has subscript form */ 35 Mymr_CC_CONSONANT2 = 2, /* Consonant of type 2, that has no subscript form */ 36 Mymr_CC_NGA = 3, /* Consonant NGA */ 37 Mymr_CC_YA = 4, /* Consonant YA */ 38 Mymr_CC_RA = 5, /* Consonant RA */ 39 Mymr_CC_WA = 6, /* Consonant WA */ 40 Mymr_CC_HA = 7, /* Consonant HA */ 41 Mymr_CC_IND_VOWEL = 8, /* Independent vowel */ 42 Mymr_CC_ZERO_WIDTH_NJ_MARK = 9, /* Zero Width non joiner character (0x200C) */ 43 Mymr_CC_VIRAMA = 10, /* Subscript consonant combining character */ 44 Mymr_CC_PRE_VOWEL = 11, /* Dependent vowel, prebase (Vowel e) */ 45 Mymr_CC_BELOW_VOWEL = 12, /* Dependent vowel, prebase (Vowel u, uu) */ 46 Mymr_CC_ABOVE_VOWEL = 13, /* Dependent vowel, prebase (Vowel i, ii, ai) */ 47 Mymr_CC_POST_VOWEL = 14, /* Dependent vowel, prebase (Vowel aa) */ 48 Mymr_CC_SIGN_ABOVE = 15, 49 Mymr_CC_SIGN_BELOW = 16, 50 Mymr_CC_SIGN_AFTER = 17, 51 Mymr_CC_ZERO_WIDTH_J_MARK = 18, /* Zero width joiner character */ 52 Mymr_CC_COUNT = 19 /* This is the number of character classes */ 53 }; 54 55 enum MymrCharClassFlags 56 { 57 Mymr_CF_CLASS_MASK = 0x0000FFFF, 58 59 Mymr_CF_CONSONANT = 0x01000000, /* flag to speed up comparing */ 60 Mymr_CF_MEDIAL = 0x02000000, /* flag to speed up comparing */ 61 Mymr_CF_IND_VOWEL = 0x04000000, /* flag to speed up comparing */ 62 Mymr_CF_DEP_VOWEL = 0x08000000, /* flag to speed up comparing */ 63 Mymr_CF_DOTTED_CIRCLE = 0x10000000, /* add a dotted circle if a character with this flag is the first in a syllable */ 64 Mymr_CF_VIRAMA = 0x20000000, /* flag to speed up comparing */ 65 66 /* position flags */ 67 Mymr_CF_POS_BEFORE = 0x00080000, 68 Mymr_CF_POS_BELOW = 0x00040000, 69 Mymr_CF_POS_ABOVE = 0x00020000, 70 Mymr_CF_POS_AFTER = 0x00010000, 71 Mymr_CF_POS_MASK = 0x000f0000, 72 73 Mymr_CF_AFTER_KINZI = 0x00100000 74 }; 75 76 /* Characters that get refrered to by name */ 77 enum MymrChar 78 { 79 Mymr_C_SIGN_ZWNJ = 0x200C, 80 Mymr_C_SIGN_ZWJ = 0x200D, 81 Mymr_C_DOTTED_CIRCLE = 0x25CC, 82 Mymr_C_RA = 0x101B, 83 Mymr_C_YA = 0x101A, 84 Mymr_C_NGA = 0x1004, 85 Mymr_C_VOWEL_E = 0x1031, 86 Mymr_C_VIRAMA = 0x1039 87 }; 88 89 enum 90 { 91 Mymr_xx = Mymr_CC_RESERVED, 92 Mymr_c1 = Mymr_CC_CONSONANT | Mymr_CF_CONSONANT | Mymr_CF_POS_BELOW, 93 Mymr_c2 = Mymr_CC_CONSONANT2 | Mymr_CF_CONSONANT, 94 Mymr_ng = Mymr_CC_NGA | Mymr_CF_CONSONANT | Mymr_CF_POS_ABOVE, 95 Mymr_ya = Mymr_CC_YA | Mymr_CF_CONSONANT | Mymr_CF_MEDIAL | Mymr_CF_POS_AFTER | Mymr_CF_AFTER_KINZI, 96 Mymr_ra = Mymr_CC_RA | Mymr_CF_CONSONANT | Mymr_CF_MEDIAL | Mymr_CF_POS_BEFORE, 97 Mymr_wa = Mymr_CC_WA | Mymr_CF_CONSONANT | Mymr_CF_MEDIAL | Mymr_CF_POS_BELOW, 98 Mymr_ha = Mymr_CC_HA | Mymr_CF_CONSONANT | Mymr_CF_MEDIAL | Mymr_CF_POS_BELOW, 99 Mymr_id = Mymr_CC_IND_VOWEL | Mymr_CF_IND_VOWEL, 100 Mymr_vi = Mymr_CC_VIRAMA | Mymr_CF_VIRAMA | Mymr_CF_POS_ABOVE | Mymr_CF_DOTTED_CIRCLE, 101 Mymr_dl = Mymr_CC_PRE_VOWEL | Mymr_CF_DEP_VOWEL | Mymr_CF_POS_BEFORE | Mymr_CF_DOTTED_CIRCLE | Mymr_CF_AFTER_KINZI, 102 Mymr_db = Mymr_CC_BELOW_VOWEL | Mymr_CF_DEP_VOWEL | Mymr_CF_POS_BELOW | Mymr_CF_DOTTED_CIRCLE | Mymr_CF_AFTER_KINZI, 103 Mymr_da = Mymr_CC_ABOVE_VOWEL | Mymr_CF_DEP_VOWEL | Mymr_CF_POS_ABOVE | Mymr_CF_DOTTED_CIRCLE | Mymr_CF_AFTER_KINZI, 104 Mymr_dr = Mymr_CC_POST_VOWEL | Mymr_CF_DEP_VOWEL | Mymr_CF_POS_AFTER | Mymr_CF_DOTTED_CIRCLE | Mymr_CF_AFTER_KINZI, 105 Mymr_sa = Mymr_CC_SIGN_ABOVE | Mymr_CF_DOTTED_CIRCLE | Mymr_CF_POS_ABOVE | Mymr_CF_AFTER_KINZI, 106 Mymr_sb = Mymr_CC_SIGN_BELOW | Mymr_CF_DOTTED_CIRCLE | Mymr_CF_POS_BELOW | Mymr_CF_AFTER_KINZI, 107 Mymr_sp = Mymr_CC_SIGN_AFTER | Mymr_CF_DOTTED_CIRCLE | Mymr_CF_AFTER_KINZI 108 }; 109 110 111 typedef int MymrCharClass; 112 113 114 static const MymrCharClass mymrCharClasses[] = 115 { 116 Mymr_c1, Mymr_c1, Mymr_c1, Mymr_c1, Mymr_ng, Mymr_c1, Mymr_c1, Mymr_c1, 117 Mymr_c1, Mymr_c1, Mymr_c2, Mymr_c1, Mymr_c1, Mymr_c1, Mymr_c1, Mymr_c1, /* 1000 - 100F */ 118 Mymr_c1, Mymr_c1, Mymr_c1, Mymr_c1, Mymr_c1, Mymr_c1, Mymr_c1, Mymr_c1, 119 Mymr_c1, Mymr_c1, Mymr_ya, Mymr_ra, Mymr_c1, Mymr_wa, Mymr_c1, Mymr_ha, /* 1010 - 101F */ 120 Mymr_c2, Mymr_c2, Mymr_xx, Mymr_id, Mymr_id, Mymr_id, Mymr_id, Mymr_id, 121 Mymr_xx, Mymr_id, Mymr_id, Mymr_xx, Mymr_dr, Mymr_da, Mymr_da, Mymr_db, /* 1020 - 102F */ 122 Mymr_db, Mymr_dl, Mymr_da, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_sa, Mymr_sb, 123 Mymr_sp, Mymr_vi, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, /* 1030 - 103F */ 124 Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, 125 Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, /* 1040 - 104F */ 126 Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, 127 Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, /* 1050 - 105F */ 128 }; 129 130 static MymrCharClass 131 getMyanmarCharClass (HB_UChar16 ch) 132 { 133 if (ch == Mymr_C_SIGN_ZWJ) 134 return Mymr_CC_ZERO_WIDTH_J_MARK; 135 136 if (ch == Mymr_C_SIGN_ZWNJ) 137 return Mymr_CC_ZERO_WIDTH_NJ_MARK; 138 139 if (ch < 0x1000 || ch > 0x105f) 140 return Mymr_CC_RESERVED; 141 142 return mymrCharClasses[ch - 0x1000]; 143 } 144 145 static const signed char mymrStateTable[][Mymr_CC_COUNT] = 146 { 147 /* xx c1, c2 ng ya ra wa ha id zwnj vi dl db da dr sa sb sp zwj */ 148 { 1, 4, 4, 2, 4, 4, 4, 4, 24, 1, 27, 17, 18, 19, 20, 21, 1, 1, 4}, /* 0 - ground state */ 149 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 1 - exit state (or sp to the right of the syllable) */ 150 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 17, 18, 19, 20, 21, -1, -1, 4}, /* 2 - NGA */ 151 {-1, 4, 4, 4, 4, 4, 4, 4, -1, 23, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 3 - Virama after NGA */ 152 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 17, 18, 19, 20, 21, 1, 1, -1}, /* 4 - Base consonant */ 153 {-2, 6, -2, -2, 7, 8, 9, 10, -2, 23, -2, -2, -2, -2, -2, -2, -2, -2, -2}, /* 5 - First virama */ 154 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 25, 17, 18, 19, 20, 21, -1, -1, -1}, /* 6 - c1 after virama */ 155 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, 17, 18, 19, 20, 21, -1, -1, -1}, /* 7 - ya after virama */ 156 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, 17, 18, 19, 20, 21, -1, -1, -1}, /* 8 - ra after virama */ 157 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, 17, 18, 19, 20, 21, -1, -1, -1}, /* 9 - wa after virama */ 158 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 17, 18, 19, 20, 21, -1, -1, -1}, /* 10 - ha after virama */ 159 {-1, -1, -1, -1, 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 11 - Virama after NGA+zwj */ 160 {-2, -2, -2, -2, -2, -2, 13, 14, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2}, /* 12 - Second virama */ 161 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 15, 17, 18, 19, 20, 21, -1, -1, -1}, /* 13 - wa after virama */ 162 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 17, 18, 19, 20, 21, -1, -1, -1}, /* 14 - ha after virama */ 163 {-2, -2, -2, -2, -2, -2, -2, 16, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2}, /* 15 - Third virama */ 164 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 17, 18, 19, 20, 21, -1, -1, -1}, /* 16 - ha after virama */ 165 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 20, 21, 1, 1, -1}, /* 17 - dl, Dependent vowel e */ 166 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 19, -1, 21, 1, 1, -1}, /* 18 - db, Dependent vowel u,uu */ 167 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, -1}, /* 19 - da, Dependent vowel i,ii,ai */ 168 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, 1, 1, -1}, /* 20 - dr, Dependent vowel aa */ 169 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1}, /* 21 - sa, Sign anusvara */ 170 {-1, -1, -1, -1, -1, -1, -1, -1, -1, 23, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 22 - atha */ 171 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1}, /* 23 - zwnj for atha */ 172 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1}, /* 24 - Independent vowel */ 173 {-2, -2, -2, -2, 26, 26, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2}, /* 25 - Virama after subscript consonant */ 174 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, 17, 18, 19, 20, 21, -1, 1, -1}, /* 26 - ra/ya after subscript consonant + virama */ 175 {-1, 6, -1, -1, 7, 8, 9, 10, -1, 23, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 27 - Virama after ground state */ 176 /* exit state -2 is for invalid order of medials and combination of invalids 177 with virama where virama should treat as start of next syllable 178 */ 179 }; 180 181 182 183 /*#define MYANMAR_DEBUG */ 184 #ifdef MYANMAR_DEBUG 185 #define MMDEBUG qDebug 186 #else 187 #define MMDEBUG if(0) printf 188 #endif 189 190 /* 191 // Given an input string of characters and a location in which to start looking 192 // calculate, using the state table, which one is the last character of the syllable 193 // that starts in the starting position. 194 */ 195 static int myanmar_nextSyllableBoundary(const HB_UChar16 *s, int start, int end, HB_Bool *invalid) 196 { 197 const HB_UChar16 *uc = s + start; 198 int state = 0; 199 int pos = start; 200 *invalid = FALSE; 201 202 while (pos < end) { 203 MymrCharClass charClass = getMyanmarCharClass(*uc); 204 state = mymrStateTable[state][charClass & Mymr_CF_CLASS_MASK]; 205 if (pos == start) 206 *invalid = (HB_Bool)(charClass & Mymr_CF_DOTTED_CIRCLE); 207 208 MMDEBUG("state[%d]=%d class=%8x (uc=%4x)", pos - start, state, charClass, *uc); 209 210 if (state < 0) { 211 if (state < -1) 212 --pos; 213 break; 214 } 215 ++uc; 216 ++pos; 217 } 218 return pos; 219 } 220 221 #ifndef NO_OPENTYPE 222 /* ###### might have to change order of above and below forms and substitutions, 223 but according to Unicode below comes before above */ 224 static const HB_OpenTypeFeature myanmar_features[] = { 225 { HB_MAKE_TAG('p', 'r', 'e', 'f'), PreFormProperty }, 226 { HB_MAKE_TAG('b', 'l', 'w', 'f'), BelowFormProperty }, 227 { HB_MAKE_TAG('a', 'b', 'v', 'f'), AboveFormProperty }, 228 { HB_MAKE_TAG('p', 's', 't', 'f'), PostFormProperty }, 229 { HB_MAKE_TAG('p', 'r', 'e', 's'), PreSubstProperty }, 230 { HB_MAKE_TAG('b', 'l', 'w', 's'), BelowSubstProperty }, 231 { HB_MAKE_TAG('a', 'b', 'v', 's'), AboveSubstProperty }, 232 { HB_MAKE_TAG('p', 's', 't', 's'), PostSubstProperty }, 233 { HB_MAKE_TAG('r', 'l', 'i', 'g'), CligProperty }, /* Myanmar1 uses this instead of the other features */ 234 { 0, 0 } 235 }; 236 #endif 237 238 239 /* 240 // Visual order before shaping should be: 241 // 242 // [Vowel Mark E] 243 // [Virama + Medial Ra] 244 // [Base] 245 // [Virama + Consonant] 246 // [Nga + Virama] (Kinzi) ### should probably come before post forms (medial ya) 247 // [Vowels] 248 // [Marks] 249 // 250 // This means that we can keep the logical order apart from having to 251 // move the pre vowel, medial ra and kinzi 252 */ 253 254 static HB_Bool myanmar_shape_syllable(HB_Bool openType, HB_ShaperItem *item, HB_Bool invalid) 255 { 256 /* 257 // MMDEBUG("\nsyllable from %d len %d, str='%s'", item->item.pos, item->item.length, 258 // item->string->mid(item->from, item->length).toUtf8().data()); 259 */ 260 261 #ifndef NO_OPENTYPE 262 const int availableGlyphs = item->num_glyphs; 263 #endif 264 const HB_UChar16 *uc = item->string + item->item.pos; 265 int vowel_e = -1; 266 int kinzi = -1; 267 int medial_ra = -1; 268 int base = -1; 269 int i; 270 int len = 0; 271 unsigned short reordered[32]; 272 unsigned char properties[32]; 273 enum { 274 AboveForm = 0x01, 275 PreForm = 0x02, 276 PostForm = 0x04, 277 BelowForm = 0x08 278 }; 279 HB_Bool lastWasVirama = FALSE; 280 int basePos = -1; 281 282 memset(properties, 0, 32*sizeof(unsigned char)); 283 284 /* according to the table the max length of a syllable should be around 14 chars */ 285 assert(item->item.length < 32); 286 287 #ifdef MYANMAR_DEBUG 288 printf("original:"); 289 for (i = 0; i < (int)item->item.length; i++) { 290 printf(" %d: %4x", i, uc[i]); 291 } 292 #endif 293 for (i = 0; i < (int)item->item.length; ++i) { 294 HB_UChar16 chr = uc[i]; 295 296 if (chr == Mymr_C_VOWEL_E) { 297 vowel_e = i; 298 continue; 299 } 300 if (i == 0 301 && chr == Mymr_C_NGA 302 && i + 2 < (int)item->item.length 303 && uc[i+1] == Mymr_C_VIRAMA) { 304 int mc = getMyanmarCharClass(uc[i+2]); 305 /*MMDEBUG("maybe kinzi: mc=%x", mc);*/ 306 if ((mc & Mymr_CF_CONSONANT) == Mymr_CF_CONSONANT) { 307 kinzi = i; 308 continue; 309 } 310 } 311 if (base >= 0 312 && chr == Mymr_C_VIRAMA 313 && i + 1 < (int)item->item.length 314 && uc[i+1] == Mymr_C_RA) { 315 medial_ra = i; 316 continue; 317 } 318 if (base < 0) 319 base = i; 320 } 321 322 MMDEBUG("\n base=%d, vowel_e=%d, kinzi=%d, medial_ra=%d", base, vowel_e, kinzi, medial_ra); 323 /* write vowel_e if found */ 324 if (vowel_e >= 0) { 325 reordered[0] = Mymr_C_VOWEL_E; 326 len = 1; 327 } 328 /* write medial_ra */ 329 if (medial_ra >= 0) { 330 reordered[len] = Mymr_C_VIRAMA; 331 reordered[len+1] = Mymr_C_RA; 332 properties[len] = PreForm; 333 properties[len+1] = PreForm; 334 len += 2; 335 } 336 337 /* shall we add a dotted circle? 338 If in the position in which the base should be (first char in the string) there is 339 a character that has the Dotted circle flag (a character that cannot be a base) 340 then write a dotted circle */ 341 if (invalid) { 342 reordered[len] = C_DOTTED_CIRCLE; 343 ++len; 344 } 345 346 /* copy the rest of the syllable to the output, inserting the kinzi 347 at the correct place */ 348 for (i = 0; i < (int)item->item.length; ++i) { 349 hb_uint16 chr = uc[i]; 350 MymrCharClass cc; 351 if (i == vowel_e) 352 continue; 353 if (i == medial_ra || i == kinzi) { 354 ++i; 355 continue; 356 } 357 358 cc = getMyanmarCharClass(uc[i]); 359 if (kinzi >= 0 && i > base && (cc & Mymr_CF_AFTER_KINZI)) { 360 reordered[len] = Mymr_C_NGA; 361 reordered[len+1] = Mymr_C_VIRAMA; 362 properties[len-1] = AboveForm; 363 properties[len] = AboveForm; 364 len += 2; 365 kinzi = -1; 366 } 367 368 if (lastWasVirama) { 369 int prop = 0; 370 switch(cc & Mymr_CF_POS_MASK) { 371 case Mymr_CF_POS_BEFORE: 372 prop = PreForm; 373 break; 374 case Mymr_CF_POS_BELOW: 375 prop = BelowForm; 376 break; 377 case Mymr_CF_POS_ABOVE: 378 prop = AboveForm; 379 break; 380 case Mymr_CF_POS_AFTER: 381 prop = PostForm; 382 break; 383 default: 384 break; 385 } 386 properties[len-1] = prop; 387 properties[len] = prop; 388 if(basePos >= 0 && basePos == len-2) 389 properties[len-2] = prop; 390 } 391 lastWasVirama = (chr == Mymr_C_VIRAMA); 392 if(i == base) 393 basePos = len; 394 395 if ((chr != Mymr_C_SIGN_ZWNJ && chr != Mymr_C_SIGN_ZWJ) || !len) { 396 reordered[len] = chr; 397 ++len; 398 } 399 } 400 if (kinzi >= 0) { 401 reordered[len] = Mymr_C_NGA; 402 reordered[len+1] = Mymr_C_VIRAMA; 403 properties[len] = AboveForm; 404 properties[len+1] = AboveForm; 405 len += 2; 406 } 407 408 if (!item->font->klass->convertStringToGlyphIndices(item->font, 409 reordered, len, 410 item->glyphs, &item->num_glyphs, 411 item->item.bidiLevel % 2)) 412 return FALSE; 413 414 MMDEBUG("after shaping: len=%d", len); 415 for (i = 0; i < len; i++) { 416 item->attributes[i].mark = FALSE; 417 item->attributes[i].clusterStart = FALSE; 418 item->attributes[i].justification = 0; 419 item->attributes[i].zeroWidth = FALSE; 420 MMDEBUG(" %d: %4x property=%x", i, reordered[i], properties[i]); 421 } 422 423 /* now we have the syllable in the right order, and can start running it through open type. */ 424 425 #ifndef NO_OPENTYPE 426 if (openType) { 427 hb_uint32 where[32]; 428 429 for (i = 0; i < len; ++i) { 430 where[i] = ~(PreSubstProperty 431 | BelowSubstProperty 432 | AboveSubstProperty 433 | PostSubstProperty 434 | CligProperty 435 | PositioningProperties); 436 if (properties[i] & PreForm) 437 where[i] &= ~PreFormProperty; 438 if (properties[i] & BelowForm) 439 where[i] &= ~BelowFormProperty; 440 if (properties[i] & AboveForm) 441 where[i] &= ~AboveFormProperty; 442 if (properties[i] & PostForm) 443 where[i] &= ~PostFormProperty; 444 } 445 446 HB_OpenTypeShape(item, where); 447 if (!HB_OpenTypePosition(item, availableGlyphs, /*doLogClusters*/FALSE)) 448 return FALSE; 449 } else 450 #endif 451 { 452 MMDEBUG("Not using openType"); 453 HB_HeuristicPosition(item); 454 } 455 456 item->attributes[0].clusterStart = TRUE; 457 return TRUE; 458 } 459 460 HB_Bool HB_MyanmarShape(HB_ShaperItem *item) 461 { 462 HB_Bool openType = FALSE; 463 unsigned short *logClusters = item->log_clusters; 464 465 HB_ShaperItem syllable = *item; 466 int first_glyph = 0; 467 468 int sstart = item->item.pos; 469 int end = sstart + item->item.length; 470 int i = 0; 471 472 assert(item->item.script == HB_Script_Myanmar); 473 #ifndef NO_OPENTYPE 474 openType = HB_SelectScript(item, myanmar_features); 475 #endif 476 477 MMDEBUG("myanmar_shape: from %d length %d", item->item.pos, item->item.length); 478 while (sstart < end) { 479 HB_Bool invalid; 480 int send = myanmar_nextSyllableBoundary(item->string, sstart, end, &invalid); 481 MMDEBUG("syllable from %d, length %d, invalid=%s", sstart, send-sstart, 482 invalid ? "TRUE" : "FALSE"); 483 syllable.item.pos = sstart; 484 syllable.item.length = send-sstart; 485 syllable.glyphs = item->glyphs + first_glyph; 486 syllable.attributes = item->attributes + first_glyph; 487 syllable.advances = item->advances + first_glyph; 488 syllable.offsets = item->offsets + first_glyph; 489 syllable.num_glyphs = item->num_glyphs - first_glyph; 490 if (!myanmar_shape_syllable(openType, &syllable, invalid)) { 491 MMDEBUG("syllable shaping failed, syllable requests %d glyphs", syllable.num_glyphs); 492 item->num_glyphs += syllable.num_glyphs; 493 return FALSE; 494 } 495 496 /* fix logcluster array */ 497 MMDEBUG("syllable:"); 498 for (i = first_glyph; i < first_glyph + (int)syllable.num_glyphs; ++i) 499 MMDEBUG(" %d -> glyph %x", i, item->glyphs[i]); 500 MMDEBUG(" logclusters:"); 501 for (i = sstart; i < send; ++i) { 502 MMDEBUG(" %d -> glyph %d", i, first_glyph); 503 logClusters[i-item->item.pos] = first_glyph; 504 } 505 sstart = send; 506 first_glyph += syllable.num_glyphs; 507 } 508 item->num_glyphs = first_glyph; 509 return TRUE; 510 } 511 512 void HB_MyanmarAttributes(HB_Script script, const HB_UChar16 *text, hb_uint32 from, hb_uint32 len, HB_CharAttributes *attributes) 513 { 514 int end = from + len; 515 const HB_UChar16 *uc = text + from; 516 hb_uint32 i = 0; 517 HB_UNUSED(script); 518 attributes += from; 519 while (i < len) { 520 HB_Bool invalid; 521 hb_uint32 boundary = myanmar_nextSyllableBoundary(text, from+i, end, &invalid) - from; 522 523 attributes[i].charStop = TRUE; 524 if (i) 525 attributes[i-1].lineBreakType = HB_Break; 526 527 if (boundary > len-1) 528 boundary = len; 529 i++; 530 while (i < boundary) { 531 attributes[i].charStop = FALSE; 532 ++uc; 533 ++i; 534 } 535 assert(i == boundary); 536 } 537 } 538 539