| OLD | NEW |
| (Empty) |
| 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 subscrip
t form */ | |
| 35 Mymr_CC_CONSONANT2 = 2, /* Consonant of type 2, that has no subsc
ript 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 (0x200
C) */ | |
| 43 Mymr_CC_VIRAMA = 10, /* Subscript consonant combining characte
r */ | |
| 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 classe
s */ | |
| 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 w
ith 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_AFTE
R | Mymr_CF_AFTER_KINZI, | |
| 96 Mymr_ra = Mymr_CC_RA | Mymr_CF_CONSONANT | Mymr_CF_MEDIAL | Mymr_CF_POS_BEFO
RE, | |
| 97 Mymr_wa = Mymr_CC_WA | Mymr_CF_CONSONANT | Mymr_CF_MEDIAL | Mymr_CF_POS_BELO
W, | |
| 98 Mymr_ha = Mymr_CC_HA | Mymr_CF_CONSONANT | Mymr_CF_MEDIAL | Mymr_CF_POS_BELO
W, | |
| 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_DOTT
ED_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 | M
ymr_CF_AFTER_KINZI, | |
| 106 Mymr_sb = Mymr_CC_SIGN_BELOW | Mymr_CF_DOTTED_CIRCLE | Mymr_CF_POS_BELOW | M
ymr_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, /* 1
000 - 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, /* 1
010 - 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, /* 1
020 - 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, /* 1
030 - 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, /* 1
040 - 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, /* 1
050 - 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 syl
lable | |
| 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 ins
tead 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 c
hars */ | |
| 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, ki
nzi, 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 if (len > 0) | |
| 363 properties[len-1] = AboveForm; | |
| 364 properties[len] = AboveForm; | |
| 365 len += 2; | |
| 366 kinzi = -1; | |
| 367 } | |
| 368 | |
| 369 if (lastWasVirama) { | |
| 370 int prop = 0; | |
| 371 switch(cc & Mymr_CF_POS_MASK) { | |
| 372 case Mymr_CF_POS_BEFORE: | |
| 373 prop = PreForm; | |
| 374 break; | |
| 375 case Mymr_CF_POS_BELOW: | |
| 376 prop = BelowForm; | |
| 377 break; | |
| 378 case Mymr_CF_POS_ABOVE: | |
| 379 prop = AboveForm; | |
| 380 break; | |
| 381 case Mymr_CF_POS_AFTER: | |
| 382 prop = PostForm; | |
| 383 break; | |
| 384 default: | |
| 385 break; | |
| 386 } | |
| 387 properties[len-1] = prop; | |
| 388 properties[len] = prop; | |
| 389 if(basePos >= 0 && basePos == len-2) | |
| 390 properties[len-2] = prop; | |
| 391 } | |
| 392 lastWasVirama = (chr == Mymr_C_VIRAMA); | |
| 393 if(i == base) | |
| 394 basePos = len; | |
| 395 | |
| 396 if ((chr != Mymr_C_SIGN_ZWNJ && chr != Mymr_C_SIGN_ZWJ) || !len) { | |
| 397 reordered[len] = chr; | |
| 398 ++len; | |
| 399 } | |
| 400 } | |
| 401 if (kinzi >= 0) { | |
| 402 reordered[len] = Mymr_C_NGA; | |
| 403 reordered[len+1] = Mymr_C_VIRAMA; | |
| 404 properties[len] = AboveForm; | |
| 405 properties[len+1] = AboveForm; | |
| 406 len += 2; | |
| 407 } | |
| 408 | |
| 409 if (!item->font->klass->convertStringToGlyphIndices(item->font, | |
| 410 reordered, len, | |
| 411 item->glyphs, &item->num
_glyphs, | |
| 412 item->item.bidiLevel % 2
)) | |
| 413 return FALSE; | |
| 414 | |
| 415 MMDEBUG("after shaping: len=%d", len); | |
| 416 for (i = 0; i < len; i++) { | |
| 417 item->attributes[i].mark = FALSE; | |
| 418 item->attributes[i].clusterStart = FALSE; | |
| 419 item->attributes[i].justification = 0; | |
| 420 item->attributes[i].zeroWidth = FALSE; | |
| 421 MMDEBUG(" %d: %4x property=%x", i, reordered[i], properties[i]); | |
| 422 } | |
| 423 | |
| 424 /* now we have the syllable in the right order, and can start running it thr
ough open type. */ | |
| 425 | |
| 426 #ifndef NO_OPENTYPE | |
| 427 if (openType) { | |
| 428 hb_uint32 where[32]; | |
| 429 | |
| 430 for (i = 0; i < len; ++i) { | |
| 431 where[i] = ~(PreSubstProperty | |
| 432 | BelowSubstProperty | |
| 433 | AboveSubstProperty | |
| 434 | PostSubstProperty | |
| 435 | CligProperty | |
| 436 | PositioningProperties); | |
| 437 if (properties[i] & PreForm) | |
| 438 where[i] &= ~PreFormProperty; | |
| 439 if (properties[i] & BelowForm) | |
| 440 where[i] &= ~BelowFormProperty; | |
| 441 if (properties[i] & AboveForm) | |
| 442 where[i] &= ~AboveFormProperty; | |
| 443 if (properties[i] & PostForm) | |
| 444 where[i] &= ~PostFormProperty; | |
| 445 } | |
| 446 | |
| 447 HB_OpenTypeShape(item, where); | |
| 448 if (!HB_OpenTypePosition(item, availableGlyphs, /*doLogClusters*/FALSE)) | |
| 449 return FALSE; | |
| 450 } else | |
| 451 #endif | |
| 452 { | |
| 453 MMDEBUG("Not using openType"); | |
| 454 HB_HeuristicPosition(item); | |
| 455 } | |
| 456 | |
| 457 item->attributes[0].clusterStart = TRUE; | |
| 458 return TRUE; | |
| 459 } | |
| 460 | |
| 461 HB_Bool HB_MyanmarShape(HB_ShaperItem *item) | |
| 462 { | |
| 463 HB_Bool openType = FALSE; | |
| 464 unsigned short *logClusters = item->log_clusters; | |
| 465 | |
| 466 HB_ShaperItem syllable = *item; | |
| 467 int first_glyph = 0; | |
| 468 | |
| 469 int sstart = item->item.pos; | |
| 470 int end = sstart + item->item.length; | |
| 471 int i = 0; | |
| 472 | |
| 473 assert(item->item.script == HB_Script_Myanmar); | |
| 474 #ifndef NO_OPENTYPE | |
| 475 openType = HB_SelectScript(item, myanmar_features); | |
| 476 #endif | |
| 477 | |
| 478 MMDEBUG("myanmar_shape: from %d length %d", item->item.pos, item->item.lengt
h); | |
| 479 while (sstart < end) { | |
| 480 HB_Bool invalid; | |
| 481 int send = myanmar_nextSyllableBoundary(item->string, sstart, end, &inva
lid); | |
| 482 MMDEBUG("syllable from %d, length %d, invalid=%s", sstart, send-sstart, | |
| 483 invalid ? "TRUE" : "FALSE"); | |
| 484 syllable.item.pos = sstart; | |
| 485 syllable.item.length = send-sstart; | |
| 486 syllable.glyphs = item->glyphs + first_glyph; | |
| 487 syllable.attributes = item->attributes + first_glyph; | |
| 488 syllable.advances = item->advances + first_glyph; | |
| 489 syllable.offsets = item->offsets + first_glyph; | |
| 490 syllable.num_glyphs = item->num_glyphs - first_glyph; | |
| 491 if (!myanmar_shape_syllable(openType, &syllable, invalid)) { | |
| 492 MMDEBUG("syllable shaping failed, syllable requests %d glyphs", syll
able.num_glyphs); | |
| 493 item->num_glyphs += syllable.num_glyphs; | |
| 494 return FALSE; | |
| 495 } | |
| 496 | |
| 497 /* fix logcluster array */ | |
| 498 MMDEBUG("syllable:"); | |
| 499 for (i = first_glyph; i < first_glyph + (int)syllable.num_glyphs; ++i) | |
| 500 MMDEBUG(" %d -> glyph %x", i, item->glyphs[i]); | |
| 501 MMDEBUG(" logclusters:"); | |
| 502 for (i = sstart; i < send; ++i) { | |
| 503 MMDEBUG(" %d -> glyph %d", i, first_glyph); | |
| 504 logClusters[i-item->item.pos] = first_glyph; | |
| 505 } | |
| 506 sstart = send; | |
| 507 first_glyph += syllable.num_glyphs; | |
| 508 } | |
| 509 item->num_glyphs = first_glyph; | |
| 510 return TRUE; | |
| 511 } | |
| 512 | |
| 513 void HB_MyanmarAttributes(HB_Script script, const HB_UChar16 *text, hb_uint32 fr
om, hb_uint32 len, HB_CharAttributes *attributes) | |
| 514 { | |
| 515 int end = from + len; | |
| 516 const HB_UChar16 *uc = text + from; | |
| 517 hb_uint32 i = 0; | |
| 518 HB_UNUSED(script); | |
| 519 attributes += from; | |
| 520 while (i < len) { | |
| 521 HB_Bool invalid; | |
| 522 hb_uint32 boundary = myanmar_nextSyllableBoundary(text, from+i, end, &in
valid) - from; | |
| 523 | |
| 524 attributes[i].charStop = TRUE; | |
| 525 if (i) | |
| 526 attributes[i-1].lineBreakType = HB_Break; | |
| 527 | |
| 528 if (boundary > len-1) | |
| 529 boundary = len; | |
| 530 i++; | |
| 531 while (i < boundary) { | |
| 532 attributes[i].charStop = FALSE; | |
| 533 ++uc; | |
| 534 ++i; | |
| 535 } | |
| 536 assert(i == boundary); | |
| 537 } | |
| 538 } | |
| 539 | |
| OLD | NEW |