Folder structure changed
[framework/uifw/harfbuzz.git] / src / harfbuzz-myanmar.c
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 /* SAMSUNG - Kaja Changes -Start */
196 //static int myanmar_nextSyllableBoundary(const HB_UChar16 *s, int start, int end, HB_Bool *invalid)
197 int myanmar_nextSyllableBoundary(const HB_UChar16 *s, int start, int end, HB_Bool *invalid)
198 /* SAMSUNG - Kaja Changes -End */
199 {
200     const HB_UChar16 *uc = s + start;
201     int state = 0;
202     int pos = start;
203     *invalid = FALSE;
204
205     while (pos < end) {
206         MymrCharClass charClass = getMyanmarCharClass(*uc);
207         state = mymrStateTable[state][charClass & Mymr_CF_CLASS_MASK];
208         if (pos == start)
209             *invalid = (HB_Bool)(charClass & Mymr_CF_DOTTED_CIRCLE);
210
211         MMDEBUG("state[%d]=%d class=%8x (uc=%4x)", pos - start, state, charClass, *uc);
212
213         if (state < 0) {
214             if (state < -1)
215                 --pos;
216             break;
217         }
218         ++uc;
219         ++pos;
220     }
221     return pos;
222 }
223
224 #ifndef NO_OPENTYPE
225 /* ###### might have to change order of above and below forms and substitutions,
226    but according to Unicode below comes before above */
227 static const HB_OpenTypeFeature myanmar_features[] = {
228     { HB_MAKE_TAG('p', 'r', 'e', 'f'), PreFormProperty },
229     { HB_MAKE_TAG('b', 'l', 'w', 'f'), BelowFormProperty },
230     { HB_MAKE_TAG('a', 'b', 'v', 'f'), AboveFormProperty },
231     { HB_MAKE_TAG('p', 's', 't', 'f'), PostFormProperty },
232     { HB_MAKE_TAG('p', 'r', 'e', 's'), PreSubstProperty },
233     { HB_MAKE_TAG('b', 'l', 'w', 's'), BelowSubstProperty },
234     { HB_MAKE_TAG('a', 'b', 'v', 's'), AboveSubstProperty },
235     { HB_MAKE_TAG('p', 's', 't', 's'), PostSubstProperty },
236     { HB_MAKE_TAG('r', 'l', 'i', 'g'), CligProperty }, /* Myanmar1 uses this instead of the other features */
237     { 0, 0 }
238 };
239 #endif
240
241
242 /*
243 // Visual order before shaping should be:
244 //
245 //    [Vowel Mark E]
246 //    [Virama + Medial Ra]
247 //    [Base]
248 //    [Virama + Consonant]
249 //    [Nga + Virama] (Kinzi) ### should probably come before post forms (medial ya)
250 //    [Vowels]
251 //    [Marks]
252 //
253 // This means that we can keep the logical order apart from having to
254 // move the pre vowel, medial ra and kinzi
255 */
256
257 static HB_Bool myanmar_shape_syllable(HB_Bool openType, HB_ShaperItem *item, HB_Bool invalid)
258 {
259     /*
260 //    MMDEBUG("\nsyllable from %d len %d, str='%s'", item->item.pos, item->item.length,
261 //          item->string->mid(item->from, item->length).toUtf8().data());
262     */
263
264 #ifndef NO_OPENTYPE
265     const int availableGlyphs = item->num_glyphs;
266 #endif
267     const HB_UChar16 *uc = item->string + item->item.pos;
268     int vowel_e = -1;
269     int kinzi = -1;
270     int medial_ra = -1;
271     int base = -1;
272     int i;
273     int len = 0;
274     unsigned short reordered[32];
275     unsigned char properties[32];
276     enum {
277         AboveForm = 0x01,
278         PreForm = 0x02,
279         PostForm = 0x04,
280         BelowForm = 0x08
281     };
282     HB_Bool lastWasVirama = FALSE;
283     int basePos = -1;
284
285     memset(properties, 0, 32*sizeof(unsigned char));
286
287     /* according to the table the max length of a syllable should be around 14 chars */
288     assert(item->item.length < 32);
289
290 #ifdef MYANMAR_DEBUG
291     printf("original:");
292     for (i = 0; i < (int)item->item.length; i++) {
293         printf("    %d: %4x", i, uc[i]);
294     }
295 #endif
296     for (i = 0; i < (int)item->item.length; ++i) {
297         HB_UChar16 chr = uc[i];
298
299         if (chr == Mymr_C_VOWEL_E) {
300             vowel_e = i;
301             continue;
302         }
303         if (i == 0
304             && chr == Mymr_C_NGA
305             && i + 2 < (int)item->item.length
306             && uc[i+1] == Mymr_C_VIRAMA) {
307             int mc = getMyanmarCharClass(uc[i+2]);
308             /*MMDEBUG("maybe kinzi: mc=%x", mc);*/
309             if ((mc & Mymr_CF_CONSONANT) == Mymr_CF_CONSONANT) {
310                 kinzi = i;
311                 continue;
312             }
313         }
314         if (base >= 0
315             && chr == Mymr_C_VIRAMA
316             && i + 1 < (int)item->item.length
317             && uc[i+1] == Mymr_C_RA) {
318             medial_ra = i;
319             continue;
320         }
321         if (base < 0)
322             base = i;
323     }
324
325     MMDEBUG("\n  base=%d, vowel_e=%d, kinzi=%d, medial_ra=%d", base, vowel_e, kinzi, medial_ra);
326     /* write vowel_e if found */
327     if (vowel_e >= 0) {
328         reordered[0] = Mymr_C_VOWEL_E;
329         len = 1;
330     }
331     /* write medial_ra */
332     if (medial_ra >= 0) {
333         reordered[len] = Mymr_C_VIRAMA;
334         reordered[len+1] = Mymr_C_RA;
335         properties[len] = PreForm;
336         properties[len+1] = PreForm;
337         len += 2;
338     }
339
340     /* shall we add a dotted circle?
341        If in the position in which the base should be (first char in the string) there is
342        a character that has the Dotted circle flag (a character that cannot be a base)
343        then write a dotted circle */
344     if (invalid) {
345         reordered[len] = C_DOTTED_CIRCLE;
346         ++len;
347     }
348
349     /* copy the rest of the syllable to the output, inserting the kinzi
350        at the correct place */
351     for (i = 0; i < (int)item->item.length; ++i) {
352         hb_uint16 chr = uc[i];
353         MymrCharClass cc;
354         if (i == vowel_e)
355             continue;
356         if (i == medial_ra || i == kinzi) {
357             ++i;
358             continue;
359         }
360
361         cc = getMyanmarCharClass(uc[i]);
362         if (kinzi >= 0 && i > base && (cc & Mymr_CF_AFTER_KINZI)) {
363             reordered[len] = Mymr_C_NGA;
364             reordered[len+1] = Mymr_C_VIRAMA;
365             properties[len-1] = AboveForm;
366             properties[len] = AboveForm;
367             len += 2;
368             kinzi = -1;
369         }
370
371         if (lastWasVirama) {
372             int prop = 0;
373             switch(cc & Mymr_CF_POS_MASK) {
374             case Mymr_CF_POS_BEFORE:
375                 prop = PreForm;
376                 break;
377             case Mymr_CF_POS_BELOW:
378                 prop = BelowForm;
379                 break;
380             case Mymr_CF_POS_ABOVE:
381                 prop = AboveForm;
382                 break;
383             case Mymr_CF_POS_AFTER:
384                 prop = PostForm;
385                 break;
386             default:
387                 break;
388             }
389             properties[len-1] = prop;
390             properties[len] = prop;
391             if(basePos >= 0 && basePos == len-2)
392                 properties[len-2] = prop;
393         }
394         lastWasVirama = (chr == Mymr_C_VIRAMA);
395         if(i == base)
396             basePos = len;
397
398         if ((chr != Mymr_C_SIGN_ZWNJ && chr != Mymr_C_SIGN_ZWJ) || !len) {
399             reordered[len] = chr;
400             ++len;
401         }
402     }
403     if (kinzi >= 0) {
404         reordered[len] = Mymr_C_NGA;
405         reordered[len+1] = Mymr_C_VIRAMA;
406         properties[len] = AboveForm;
407         properties[len+1] = AboveForm;
408         len += 2;
409     }
410
411     if (!item->font->klass->convertStringToGlyphIndices(item->font,
412                                                         reordered, len,
413                                                         item->glyphs, &item->num_glyphs,
414                                                         item->item.bidiLevel % 2))
415         return FALSE;
416
417     MMDEBUG("after shaping: len=%d", len);
418     for (i = 0; i < len; i++) {
419         item->attributes[i].mark = FALSE;
420         item->attributes[i].clusterStart = FALSE;
421         item->attributes[i].justification = 0;
422         item->attributes[i].zeroWidth = FALSE;
423         MMDEBUG("    %d: %4x property=%x", i, reordered[i], properties[i]);
424     }
425
426     /* now we have the syllable in the right order, and can start running it through open type. */
427
428 #ifndef NO_OPENTYPE
429     if (openType) {
430         unsigned short logClusters[32];
431         hb_uint32 where[32];
432
433         for (i = 0; i < len; ++i)
434             logClusters[i] = i;
435
436         for (i = 0; i < len; ++i) {
437             where[i] = ~(PreSubstProperty
438                          | BelowSubstProperty
439                          | AboveSubstProperty
440                          | PostSubstProperty
441                          | CligProperty
442                          | PositioningProperties);
443             if (properties[i] & PreForm)
444                 where[i] &= ~PreFormProperty;
445             if (properties[i] & BelowForm)
446                 where[i] &= ~BelowFormProperty;
447             if (properties[i] & AboveForm)
448                 where[i] &= ~AboveFormProperty;
449             if (properties[i] & PostForm)
450                 where[i] &= ~PostFormProperty;
451         }
452
453         HB_OpenTypeShape(item, where);
454         if (!HB_OpenTypePosition(item, availableGlyphs, /*doLogClusters*/FALSE))
455             return FALSE;
456     } else
457 #endif
458     {
459         MMDEBUG("Not using openType");
460         HB_HeuristicPosition(item);
461     }
462
463     item->attributes[0].clusterStart = TRUE;
464     return TRUE;
465 }
466
467 HB_Bool HB_MyanmarShape(HB_ShaperItem *item)
468 {
469     HB_Bool openType = FALSE;
470     unsigned short *logClusters = item->log_clusters;
471
472     HB_ShaperItem syllable = *item;
473     int first_glyph = 0;
474
475     int sstart = item->item.pos;
476     int end = sstart + item->item.length;
477     int i = 0;
478
479     assert(item->item.script == HB_Script_Myanmar);
480 #ifndef NO_OPENTYPE
481     openType = HB_SelectScript(item, myanmar_features);
482 #endif
483
484     MMDEBUG("myanmar_shape: from %d length %d", item->item.pos, item->item.length);
485     while (sstart < end) {
486         HB_Bool invalid;
487         int send = myanmar_nextSyllableBoundary(item->string, sstart, end, &invalid);
488         MMDEBUG("syllable from %d, length %d, invalid=%s", sstart, send-sstart,
489                invalid ? "TRUE" : "FALSE");
490         syllable.item.pos = sstart;
491         syllable.item.length = send-sstart;
492         syllable.glyphs = item->glyphs + first_glyph;
493         syllable.attributes = item->attributes + first_glyph;
494         syllable.advances = item->advances + first_glyph;
495         syllable.offsets = item->offsets + first_glyph;
496         syllable.num_glyphs = item->num_glyphs - first_glyph;
497         if (!myanmar_shape_syllable(openType, &syllable, invalid)) {
498             MMDEBUG("syllable shaping failed, syllable requests %d glyphs", syllable.num_glyphs);
499             item->num_glyphs += syllable.num_glyphs;
500             return FALSE;
501         }
502
503         /* fix logcluster array */
504         MMDEBUG("syllable:");
505         for (i = first_glyph; i < first_glyph + (int)syllable.num_glyphs; ++i)
506             MMDEBUG("        %d -> glyph %x", i, item->glyphs[i]);
507         MMDEBUG("    logclusters:");
508         for (i = sstart; i < send; ++i) {
509             MMDEBUG("        %d -> glyph %d", i, first_glyph);
510             logClusters[i-item->item.pos] = first_glyph;
511         }
512         sstart = send;
513         first_glyph += syllable.num_glyphs;
514     }
515     item->num_glyphs = first_glyph;
516     return TRUE;
517 }
518
519 void HB_MyanmarAttributes(HB_Script script, const HB_UChar16 *text, hb_uint32 from, hb_uint32 len, HB_CharAttributes *attributes)
520 {
521     int end = from + len;
522     const HB_UChar16 *uc = text + from;
523     hb_uint32 i = 0;
524     HB_UNUSED(script);
525     attributes += from;
526     while (i < len) {
527         HB_Bool invalid;
528         hb_uint32 boundary = myanmar_nextSyllableBoundary(text, from+i, end, &invalid) - from;
529
530         attributes[i].charStop = TRUE;
531         if (i)
532             attributes[i-1].lineBreakType = HB_Break;
533
534         if (boundary > len-1)
535             boundary = len;
536         i++;
537         while (i < boundary) {
538             attributes[i].charStop = FALSE;
539             ++uc;
540             ++i;
541         }
542         assert(i == boundary);
543     }
544 }
545