Home | History | Annotate | Download | only in src
      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