static HB_Bool tibetan_shape_syllable(HB_Bool openType, HB_ShaperItem *item, HB_Bool invalid) { hb_uint32 i; const HB_UChar16 *str = item->string + item->item.pos; int len = item->item.length; #ifndef NO_OPENTYPE const int availableGlyphs = item->num_glyphs; #endif HB_Bool haveGlyphs; HB_STACKARRAY(HB_UChar16, reordered, len + 4); if (item->num_glyphs < item->item.length + 4) { item->num_glyphs = item->item.length + 4; HB_FREE_STACKARRAY(reordered); return FALSE; } if (invalid) { *reordered = 0x25cc; memcpy(reordered+1, str, len*sizeof(HB_UChar16)); len++; str = reordered; } haveGlyphs = item->font->klass->convertStringToGlyphIndices(item->font, str, len, item->glyphs, &item->num_glyphs, item->item.bidiLevel % 2); HB_FREE_STACKARRAY(reordered); if (!haveGlyphs) return FALSE; for (i = 0; i < item->item.length; i++) { item->attributes[i].mark = FALSE; item->attributes[i].clusterStart = FALSE; item->attributes[i].justification = 0; item->attributes[i].zeroWidth = FALSE; /* IDEBUG(" %d: %4x", i, str[i]); */ } /* now we have the syllable in the right order, and can start running it through open type. */ #ifndef NO_OPENTYPE if (openType) { HB_OpenTypeShape(item, /*properties*/0); if (!HB_OpenTypePosition(item, availableGlyphs, /*doLogClusters*/FALSE)) return FALSE; } else { HB_HeuristicPosition(item); } #endif item->attributes[0].clusterStart = TRUE; return TRUE; }
/* * THAI Shaping. */ HB_Bool HB_ThaiShape (HB_ShaperItem *shaper_item) { if ( !HB_ThaiConvertStringToGlyphIndices (shaper_item) ) return false; HB_ThaiHeuristicSetGlyphAttributes (shaper_item); #ifndef NO_OPENTYPE const int availableGlyphs = shaper_item->num_glyphs; if ( HB_SelectScript (shaper_item, thai_features) ) { HB_OpenTypeShape (shaper_item, /*properties*/0); return HB_OpenTypePosition (shaper_item, availableGlyphs, /*doLogClusters*/true); } #endif HB_HeuristicPosition (shaper_item); return true; }
/* Hebrew shaping. In the non opentype case we try to use the presentation forms specified for Hebrew. Especially for the ligatures with Dagesh this gives much better results than we could achieve manually. */ HB_Bool HB_HebrewShape(HB_ShaperItem *shaper_item) { enum { Dagesh = 0x5bc, ShinDot = 0x5c1, SinDot = 0x5c2, Patah = 0x5b7, Qamats = 0x5b8, Holam = 0x5b9, Rafe = 0x5bf }; assert(shaper_item->item.script == HB_Script_Hebrew); #ifndef NO_OPENTYPE if (HB_SelectScript(shaper_item, hebrew_features)) { const int availableGlyphs = shaper_item->num_glyphs; if (!HB_ConvertStringToGlyphIndices(shaper_item)) return FALSE; HB_HeuristicSetGlyphAttributes(shaper_item); HB_OpenTypeShape(shaper_item, /*properties*/0); return HB_OpenTypePosition(shaper_item, availableGlyphs, /*doLogClusters*/TRUE); } #endif { const HB_UChar16 *uc = shaper_item->string + shaper_item->item.pos; unsigned short *logClusters = shaper_item->log_clusters; HB_GlyphAttributes *attributes = shaper_item->attributes; HB_Bool haveGlyphs; int slen = 1; int cluster_start = 0; hb_uint32 i; HB_STACKARRAY(HB_UChar16, shapedChars, 2 * shaper_item->item.length); *shapedChars = *uc; logClusters[0] = 0; for (i = 1; i < shaper_item->item.length; ++i) { hb_uint16 base = shapedChars[cluster_start]; hb_uint16 shaped = 0; HB_Bool invalid = FALSE; if (uc[i] == Dagesh) { if (base >= 0x5d0 && base <= 0x5ea && base != 0x5d7 && base != 0x5dd && base != 0x5df && base != 0x5e2 && base != 0x5e5) { shaped = base - 0x5d0 + 0xfb30; } else if (base == 0xfb2a || base == 0xfb2b /* Shin with Shin or Sin dot */) { shaped = base + 2; } else { invalid = TRUE; } } else if (uc[i] == ShinDot) { if (base == 0x05e9) shaped = 0xfb2a; else if (base == 0xfb49) shaped = 0xfb2c; else invalid = TRUE; } else if (uc[i] == SinDot) { if (base == 0x05e9) shaped = 0xfb2b; else if (base == 0xfb49) shaped = 0xfb2d; else invalid = TRUE; } else if (uc[i] == Patah) { if (base == 0x5d0) shaped = 0xfb2e; } else if (uc[i] == Qamats) { if (base == 0x5d0) shaped = 0xfb2f; } else if (uc[i] == Holam) { if (base == 0x5d5) shaped = 0xfb4b; } else if (uc[i] == Rafe) { if (base == 0x5d1) shaped = 0xfb4c; else if (base == 0x5db) shaped = 0xfb4d; else if (base == 0x5e4) shaped = 0xfb4e; } if (invalid) { shapedChars[slen] = 0x25cc; attributes[slen].clusterStart = TRUE; attributes[slen].mark = FALSE; attributes[slen].combiningClass = 0; cluster_start = slen; ++slen; } if (shaped) { if (shaper_item->font->klass->canRender(shaper_item->font, (HB_UChar16 *)&shaped, 1)) { shapedChars[cluster_start] = shaped; } else shaped = 0; } if (!shaped) { HB_CharCategory category; int cmb; shapedChars[slen] = uc[i]; HB_GetUnicodeCharProperties(shaper_item->ufuncs, uc[i], &category, &cmb); if (category != HB_Mark_NonSpacing) { attributes[slen].clusterStart = TRUE; attributes[slen].mark = FALSE; attributes[slen].combiningClass = 0; attributes[slen].dontPrint = HB_IsControlChar(uc[i]); cluster_start = slen; } else { attributes[slen].clusterStart = FALSE; attributes[slen].mark = TRUE; attributes[slen].combiningClass = cmb; } ++slen; } logClusters[i] = cluster_start; } haveGlyphs = shaper_item->font->klass ->convertStringToGlyphIndices(shaper_item->font, shapedChars, slen, shaper_item->glyphs, &shaper_item->num_glyphs, shaper_item->item.bidiLevel % 2); HB_FREE_STACKARRAY(shapedChars); if (!haveGlyphs) return FALSE; HB_HeuristicPosition(shaper_item); } return TRUE; }
static HB_Bool myanmar_shape_syllable(HB_Bool openType, HB_ShaperItem *item, HB_Bool invalid) { /* // MMDEBUG("\nsyllable from %d len %d, str='%s'", item->item.pos, item->item.length, // item->string->mid(item->from, item->length).toUtf8().data()); */ #ifndef NO_OPENTYPE const int availableGlyphs = item->num_glyphs; #endif const HB_UChar16 *uc = item->string + item->item.pos; int vowel_e = -1; int kinzi = -1; int medial_ra = -1; int base = -1; int i; int len = 0; unsigned short reordered[32]; unsigned char properties[32]; enum { AboveForm = 0x01, PreForm = 0x02, PostForm = 0x04, BelowForm = 0x08 }; HB_Bool lastWasVirama = FALSE; int basePos = -1; memset(properties, 0, 32*sizeof(unsigned char)); /* according to the table the max length of a syllable should be around 14 chars */ assert(item->item.length < 32); #ifdef MYANMAR_DEBUG printf("original:"); for (i = 0; i < (int)item->item.length; i++) { printf(" %d: %4x", i, uc[i]); } #endif for (i = 0; i < (int)item->item.length; ++i) { HB_UChar16 chr = uc[i]; if (chr == Mymr_C_VOWEL_E) { vowel_e = i; continue; } if (i == 0 && chr == Mymr_C_NGA && i + 2 < (int)item->item.length && uc[i+1] == Mymr_C_VIRAMA) { int mc = getMyanmarCharClass(uc[i+2]); /*MMDEBUG("maybe kinzi: mc=%x", mc);*/ if ((mc & Mymr_CF_CONSONANT) == Mymr_CF_CONSONANT) { kinzi = i; continue; } } if (base >= 0 && chr == Mymr_C_VIRAMA && i + 1 < (int)item->item.length && uc[i+1] == Mymr_C_RA) { medial_ra = i; continue; } if (base < 0) base = i; } MMDEBUG("\n base=%d, vowel_e=%d, kinzi=%d, medial_ra=%d", base, vowel_e, kinzi, medial_ra); /* write vowel_e if found */ if (vowel_e >= 0) { reordered[0] = Mymr_C_VOWEL_E; len = 1; } /* write medial_ra */ if (medial_ra >= 0) { reordered[len] = Mymr_C_VIRAMA; reordered[len+1] = Mymr_C_RA; properties[len] = PreForm; properties[len+1] = PreForm; len += 2; } /* shall we add a dotted circle? If in the position in which the base should be (first char in the string) there is a character that has the Dotted circle flag (a character that cannot be a base) then write a dotted circle */ if (invalid) { reordered[len] = C_DOTTED_CIRCLE; ++len; } /* copy the rest of the syllable to the output, inserting the kinzi at the correct place */ for (i = 0; i < (int)item->item.length; ++i) { hb_uint16 chr = uc[i]; MymrCharClass cc; if (i == vowel_e) continue; if (i == medial_ra || i == kinzi) { ++i; continue; } cc = getMyanmarCharClass(uc[i]); if (kinzi >= 0 && i > base && (cc & Mymr_CF_AFTER_KINZI)) { reordered[len] = Mymr_C_NGA; reordered[len+1] = Mymr_C_VIRAMA; if (len > 0) properties[len-1] = AboveForm; properties[len] = AboveForm; len += 2; kinzi = -1; } if (lastWasVirama) { int prop = 0; switch(cc & Mymr_CF_POS_MASK) { case Mymr_CF_POS_BEFORE: prop = PreForm; break; case Mymr_CF_POS_BELOW: prop = BelowForm; break; case Mymr_CF_POS_ABOVE: prop = AboveForm; break; case Mymr_CF_POS_AFTER: prop = PostForm; break; default: break; } properties[len-1] = prop; properties[len] = prop; if(basePos >= 0 && basePos == len-2) properties[len-2] = prop; } lastWasVirama = (chr == Mymr_C_VIRAMA); if(i == base) basePos = len; if ((chr != Mymr_C_SIGN_ZWNJ && chr != Mymr_C_SIGN_ZWJ) || !len) { reordered[len] = chr; ++len; } } if (kinzi >= 0) { reordered[len] = Mymr_C_NGA; reordered[len+1] = Mymr_C_VIRAMA; properties[len] = AboveForm; properties[len+1] = AboveForm; len += 2; } if (!item->font->klass->convertStringToGlyphIndices(item->font, reordered, len, item->glyphs, &item->num_glyphs, item->item.bidiLevel % 2)) return FALSE; MMDEBUG("after shaping: len=%d", len); for (i = 0; i < len; i++) { item->attributes[i].mark = FALSE; item->attributes[i].clusterStart = FALSE; item->attributes[i].justification = 0; item->attributes[i].zeroWidth = FALSE; MMDEBUG(" %d: %4x property=%x", i, reordered[i], properties[i]); } /* now we have the syllable in the right order, and can start running it through open type. */ #ifndef NO_OPENTYPE if (openType) { hb_uint32 where[32]; for (i = 0; i < len; ++i) { where[i] = ~(PreSubstProperty | BelowSubstProperty | AboveSubstProperty | PostSubstProperty | CligProperty | PositioningProperties); if (properties[i] & PreForm) where[i] &= ~PreFormProperty; if (properties[i] & BelowForm) where[i] &= ~BelowFormProperty; if (properties[i] & AboveForm) where[i] &= ~AboveFormProperty; if (properties[i] & PostForm) where[i] &= ~PostFormProperty; } HB_OpenTypeShape(item, where); if (!HB_OpenTypePosition(item, availableGlyphs, /*doLogClusters*/FALSE)) return FALSE; } else #endif { MMDEBUG("Not using openType"); HB_HeuristicPosition(item); } item->attributes[0].clusterStart = TRUE; return TRUE; }
static HB_Bool khmer_shape_syllable(HB_Bool openType, HB_ShaperItem *item) { /* KHDEBUG("syllable from %d len %d, str='%s'", item->from, item->length, item->string->mid(item->from, item->length).toUtf8().data()); */ int len = 0; int syllableEnd = item->item.pos + item->item.length; unsigned short reordered[16]; unsigned char properties[16]; enum { AboveForm = 0x01, PreForm = 0x02, PostForm = 0x04, BelowForm = 0x08 }; #ifndef NO_OPENTYPE const int availableGlyphs = item->num_glyphs; #endif int coengRo; int i; /* according to the specs this is the max length one can get ### the real value should be smaller */ assert(item->item.length < 13); memset(properties, 0, 16*sizeof(unsigned char)); #ifdef KHMER_DEBUG qDebug("original:"); for (int i = from; i < syllableEnd; i++) { qDebug(" %d: %4x", i, string[i]); } #endif /* // write a pre vowel or the pre part of a split vowel first // and look out for coeng + ro. RO is the only vowel of type 2, and // therefore the only one that requires saving space before the base. */ coengRo = -1; /* There is no Coeng Ro, if found this value will change */ for (i = item->item.pos; i < syllableEnd; i += 1) { KhmerCharClass charClass = getKhmerCharClass(item->string[i]); /* if a split vowel, write the pre part. In Khmer the pre part is the same for all split vowels, same glyph as pre vowel C_VOWEL_E */ if (charClass & CF_SPLIT_VOWEL) { reordered[len] = C_VOWEL_E; properties[len] = PreForm; ++len; break; /* there can be only one vowel */ } /* if a vowel with pos before write it out */ if (charClass & CF_POS_BEFORE) { reordered[len] = item->string[i]; properties[len] = PreForm; ++len; break; /* there can be only one vowel */ } /* look for coeng + ro and remember position works because coeng + ro is always in front of a vowel (if there is a vowel) and because CC_CONSONANT2 is enough to identify it, as it is the only consonant with this flag */ if ( (charClass & CF_COENG) && (i + 1 < syllableEnd) && ( (getKhmerCharClass(item->string[i+1]) & CF_CLASS_MASK) == CC_CONSONANT2) ) { coengRo = i; } } /* write coeng + ro if found */ if (coengRo > -1) { reordered[len] = C_COENG; properties[len] = PreForm; ++len; reordered[len] = C_RO; properties[len] = PreForm; ++len; } /* shall we add a dotted circle? If in the position in which the base should be (first char in the string) there is a character that has the Dotted circle flag (a character that cannot be a base) then write a dotted circle */ if (getKhmerCharClass(item->string[item->item.pos]) & CF_DOTTED_CIRCLE) { reordered[len] = C_DOTTED_CIRCLE; ++len; } /* copy what is left to the output, skipping before vowels and coeng Ro if they are present */ for (i = item->item.pos; i < syllableEnd; i += 1) { HB_UChar16 uc = item->string[i]; KhmerCharClass charClass = getKhmerCharClass(uc); /* skip a before vowel, it was already processed */ if (charClass & CF_POS_BEFORE) { continue; } /* skip coeng + ro, it was already processed */ if (i == coengRo) { i += 1; continue; } switch (charClass & CF_POS_MASK) { case CF_POS_ABOVE : reordered[len] = uc; properties[len] = AboveForm; ++len; break; case CF_POS_AFTER : reordered[len] = uc; properties[len] = PostForm; ++len; break; case CF_POS_BELOW : reordered[len] = uc; properties[len] = BelowForm; ++len; break; default: /* assign the correct flags to a coeng consonant Consonants of type 3 are taged as Post forms and those type 1 as below forms */ if ( (charClass & CF_COENG) && i + 1 < syllableEnd ) { unsigned char property = (getKhmerCharClass(item->string[i+1]) & CF_CLASS_MASK) == CC_CONSONANT3 ? PostForm : BelowForm; reordered[len] = uc; properties[len] = property; ++len; i += 1; reordered[len] = item->string[i]; properties[len] = property; ++len; break; } /* if a shifter is followed by an above vowel change the shifter to below form, an above vowel can have two possible positions i + 1 or i + 3 (position i+1 corresponds to unicode 3, position i+3 to Unicode 4) and there is an extra rule for C_VOWEL_AA + C_SIGN_NIKAHIT also for two different positions, right after the shifter or after a vowel (Unicode 4) */ if ( (charClass & CF_SHIFTER) && (i + 1 < syllableEnd) ) { if (getKhmerCharClass(item->string[i+1]) & CF_ABOVE_VOWEL ) { reordered[len] = uc; properties[len] = BelowForm; ++len; break; } if (i + 2 < syllableEnd && (item->string[i+1] == C_VOWEL_AA) && (item->string[i+2] == C_SIGN_NIKAHIT) ) { reordered[len] = uc; properties[len] = BelowForm; ++len; break; } if (i + 3 < syllableEnd && (getKhmerCharClass(item->string[i+3]) & CF_ABOVE_VOWEL) ) { reordered[len] = uc; properties[len] = BelowForm; ++len; break; } if (i + 4 < syllableEnd && (item->string[i+3] == C_VOWEL_AA) && (item->string[i+4] == C_SIGN_NIKAHIT) ) { reordered[len] = uc; properties[len] = BelowForm; ++len; break; } } /* default - any other characters */ reordered[len] = uc; ++len; break; } /* switch */ } /* for */ if (!item->font->klass->convertStringToGlyphIndices(item->font, reordered, len, item->glyphs, &item->num_glyphs, item->item.bidiLevel % 2)) return FALSE; KHDEBUG("after shaping: len=%d", len); for (i = 0; i < len; i++) { item->attributes[i].mark = FALSE; item->attributes[i].clusterStart = FALSE; item->attributes[i].justification = 0; item->attributes[i].zeroWidth = FALSE; KHDEBUG(" %d: %4x property=%x", i, reordered[i], properties[i]); } /* now we have the syllable in the right order, and can start running it through open type. */ #ifndef NO_OPENTYPE if (openType) { hb_uint32 where[16]; for (i = 0; i < len; ++i) { where[i] = ~(PreSubstProperty | BelowSubstProperty | AboveSubstProperty | PostSubstProperty | CligProperty | PositioningProperties); if (properties[i] == PreForm) where[i] &= ~PreFormProperty; else if (properties[i] == BelowForm) where[i] &= ~BelowFormProperty; else if (properties[i] == AboveForm) where[i] &= ~AboveFormProperty; else if (properties[i] == PostForm) where[i] &= ~PostFormProperty; } HB_OpenTypeShape(item, where); if (!HB_OpenTypePosition(item, availableGlyphs, /*doLogClusters*/FALSE)) return FALSE; } else #endif { KHDEBUG("Not using openType"); HB_HeuristicPosition(item); } item->attributes[0].clusterStart = TRUE; return TRUE; }
static HB_Bool hangul_shape_syllable(HB_ShaperItem *item, HB_Bool openType) { const HB_UChar16 *ch = item->string + item->item.pos; int len = item->item.length; #ifndef NO_OPENTYPE const int availableGlyphs = item->num_glyphs; #endif int i; HB_UChar16 composed = 0; /* see if we can compose the syllable into a modern hangul */ if (item->item.length == 2) { int LIndex = ch[0] - Hangul_LBase; int VIndex = ch[1] - Hangul_VBase; if (LIndex >= 0 && LIndex < Hangul_LCount && VIndex >= 0 && VIndex < Hangul_VCount) composed = (LIndex * Hangul_VCount + VIndex) * Hangul_TCount + Hangul_SBase; } else if (item->item.length == 3) { int LIndex = ch[0] - Hangul_LBase; int VIndex = ch[1] - Hangul_VBase; int TIndex = ch[2] - Hangul_TBase; if (LIndex >= 0 && LIndex < Hangul_LCount && VIndex >= 0 && VIndex < Hangul_VCount && TIndex >= 0 && TIndex < Hangul_TCount) composed = (LIndex * Hangul_VCount + VIndex) * Hangul_TCount + TIndex + Hangul_SBase; } /* if we have a modern hangul use the composed form */ if (composed) { ch = &composed; len = 1; } if (!item->font->klass->convertStringToGlyphIndices(item->font, ch, len, item->glyphs, &item->num_glyphs, item->item.bidiLevel % 2)) return FALSE; for (i = 0; i < len; i++) { item->attributes[i].mark = FALSE; item->attributes[i].clusterStart = FALSE; item->attributes[i].justification = 0; item->attributes[i].zeroWidth = FALSE; /*IDEBUG(" %d: %4x", i, ch[i].unicode()); */ } #ifndef NO_OPENTYPE if (!composed && openType) { HB_Bool positioned; HB_STACKARRAY(unsigned short, logClusters, len); for (i = 0; i < len; ++i) logClusters[i] = i; item->log_clusters = logClusters; HB_OpenTypeShape(item, /*properties*/0); positioned = HB_OpenTypePosition(item, availableGlyphs, /*doLogClusters*/FALSE); HB_FREE_STACKARRAY(logClusters); if (!positioned) return FALSE; } else { HB_HeuristicPosition(item); } #endif item->attributes[0].clusterStart = TRUE; return TRUE; }
/* Greek shaping. Heuristic positioning can't render polytonic greek correctly. We're a lot better off mapping greek chars with diacritics to the characters in the extended greek region in Unicode if possible. */ HB_Bool HB_GreekShape(HB_ShaperItem *shaper_item) { const int availableGlyphs = shaper_item->num_glyphs; const HB_UChar16 *uc = shaper_item->string + shaper_item->item.pos; unsigned short *logClusters = shaper_item->log_clusters; HB_GlyphAttributes *attributes = shaper_item->attributes; HB_Bool haveGlyphs; int slen = 1; int cluster_start = 0; hb_uint32 i; HB_STACKARRAY(HB_UChar16, shapedChars, 2 * shaper_item->item.length); assert(shaper_item->item.script == HB_Script_Greek); *shapedChars = *uc; logClusters[0] = 0; attributes[0].mark = false; attributes[0].clusterStart = true; attributes[0].dontPrint = false; for (i = 1; i < shaper_item->item.length; ++i) { hb_uint16 base = shapedChars[slen-1]; hb_uint16 shaped = 0; if (uc[i] == 0x300) shaped = compose_0x300(base); else if (uc[i] == 0x301) shaped = compose_0x301(base); else if (uc[i] == 0x304) shaped = compose_0x304(base); else if (uc[i] == 0x306) shaped = compose_0x306(base); else if (uc[i] == 0x308) shaped = compose_0x308(base); else if (uc[i] == 0x313) shaped = compose_0x313(base); else if (uc[i] == 0x314) shaped = compose_0x314(base); else if (uc[i] == 0x342) shaped = compose_0x342(base); else if (uc[i] == 0x345) shaped = compose_0x345(base); if (shaped) { if (shaper_item->font->klass->canRender(shaper_item->font, (HB_UChar16 *)&shaped, 1)) { shapedChars[slen-1] = shaped; } else { shaped = 0; } } if (!shaped) { HB_CharCategory category; int cmb; shapedChars[slen] = uc[i]; HB_GetUnicodeCharProperties(uc[i], &category, &cmb); if (category != HB_Mark_NonSpacing) { attributes[slen].clusterStart = TRUE; attributes[slen].mark = FALSE; attributes[slen].combiningClass = 0; attributes[slen].dontPrint = HB_IsControlChar(uc[i]); cluster_start = slen; } else { attributes[slen].clusterStart = FALSE; attributes[slen].mark = TRUE; attributes[slen].combiningClass = cmb; } ++slen; } logClusters[i] = cluster_start; } haveGlyphs = shaper_item->font->klass ->convertStringToGlyphIndices(shaper_item->font, shapedChars, slen, shaper_item->glyphs, &shaper_item->num_glyphs, shaper_item->item.bidiLevel % 2); HB_FREE_STACKARRAY(shapedChars); if (!haveGlyphs) return FALSE; #ifndef NO_OPENTYPE if (HB_SelectScript(shaper_item, greek_features)) { HB_OpenTypeShape(shaper_item, /*properties*/0); return HB_OpenTypePosition(shaper_item, availableGlyphs, /*doLogClusters*/TRUE); } #endif HB_HeuristicPosition(shaper_item); return TRUE; }
// Porting the pango-myanmar module for reordering a syllable correctly when shape it. static HB_Bool myanmar_shape_syllable(HB_Bool openType, HB_ShaperItem *item, HB_Bool invalid) { /* // MMDEBUG("\nsyllable from %d len %d, str='%s'", item->item.pos, item->item.length, // item->string->mid(item->from, item->length).toUtf8().data()); */ #ifndef NO_OPENTYPE const int availableGlyphs = item->num_glyphs; #endif const HB_UChar16 *uc = item->string + item->item.pos; int vowel_e = -1; int kinzi = -1; int medial_ra = -1; int i; int len = 0; unsigned short reordered[32]; unsigned char properties[32]; enum { AboveForm = 0x01, PreForm = 0x02, PostForm = 0x04, BelowForm = 0x08 }; memset(properties, 0, 32*sizeof(unsigned char)); /* according to the table the max length of a syllable should be around 14 chars */ assert(item->item.length < 32); #ifdef MYANMAR_DEBUG printf("original:"); for (i = 0; i < (int)item->item.length; i++) { MMDEBUG(" %d: %4x", i, uc[i]); } #endif len = 0; MymrCharClass char_class; int basE = 0, cursor = 0; while (basE < (int)item->item.length) { medial_ra = -1; /* There is no Medial Ra, if found this value will change */ kinzi = -1; /* There is no Kinzi, if found this value will change */ if (getMyanmarCharClass(uc[cursor]) & Mymr_CF_VIRAMA) basE = findBase(uc, cursor, (int)item->item.length); else basE = findBase(uc, cursor + 1, (int)item->item.length); for (i = cursor; i < basE; i += 1) { char_class = getMyanmarCharClass(uc[i]); /* look for kinzi and remember position */ if (((char_class & Mymr_CF_CLASS_MASK) == Mymr_CC_NGA) && (i + 2 < basE) && ((getMyanmarCharClass(uc[i + 1]) & Mymr_CF_CLASS_MASK) == Mymr_CC_ASAT) && (getMyanmarCharClass(uc[i + 2]) & Mymr_CF_VIRAMA)) { if (i + 3 == (int)item->item.length) { reordered[len] = Mymr_C_DOTTED_CIRCLE; len += 1; } else if (getMyanmarCharClass(uc[i + 3]) & Mymr_CF_CONSONANT) { kinzi = i; cursor += 3; } } /* if vowel e, wirte it out */ if (i > 0 && ((getMyanmarCharClass(uc[i -1]) & Mymr_CF_CLASS_MASK) != Mymr_CC_CONSONANT) && (char_class & Mymr_CF_DEP_VOWEL) && (char_class & Mymr_CF_POS_BEFORE)) { reordered[len] = Mymr_C_VOWEL_E; properties[len] = PostForm; len += 1; } /* look for medial ra and remember position */ if ((char_class & Mymr_CF_CLASS_MASK) == Mymr_CC_MEDIAL_R) { medial_ra = i; } } /* write medial ra if found */ if (medial_ra > -1) { reordered[len] = Mymr_C_MEDIAL_R; properties[len] = PreForm; len += 1; } /* shall we add a dotted circle? * If in the position in which the base should be (first char in the string) there is * a character that has the Dotted circle flag (a character that cannot be a base) * then write a dotted circle */ if (getMyanmarCharClass(uc[cursor]) & Mymr_CF_DOTTED_CIRCLE) { /* add dotted circle */ reordered[len] = Mymr_C_DOTTED_CIRCLE; len += 1; } /* copy what is left to the output, skipping before vowels and * medial Ra if they are present */ for (i = cursor; i < basE; i += 1) { char_class = getMyanmarCharClass(uc[i]); /* skip vowel e, it was already processed */ if (i > 0 && ((getMyanmarCharClass(uc[i -1]) & Mymr_CF_CLASS_MASK) != Mymr_CC_CONSONANT) &&(char_class & Mymr_CF_DEP_VOWEL) && (char_class & Mymr_CF_POS_BEFORE)) { continue; } /* skip medial ra, it was already processed */ if (i == medial_ra) { continue; } switch (char_class & Mymr_CF_POS_MASK) { case Mymr_CF_POS_ABOVE: reordered[len] = uc[i]; properties[len] = AboveForm; len += 1; break; case Mymr_CF_POS_AFTER: reordered[len] = uc[i]; properties[len] = PostForm; len += 1; break; case Mymr_CF_POS_BELOW: reordered[len] = uc[i]; properties[len] = BelowForm; len += 1; break; default: /* assign the correct flags to Medials */ if ((char_class & Mymr_CF_MEDIAL) && i + 1 < basE) { if ((char_class & Mymr_CF_CLASS_MASK) == Mymr_CC_MEDIAL_Y) { /* medial ya which possess below and right */ reordered[len] = uc[i]; properties[len] = PostForm; len += 1; break; } else { /* others wa, ha only below */ reordered[len] = uc[i]; properties[len] = BelowForm; len += 1; break; } } if ((char_class & Mymr_CF_VIRAMA) && i + 1 < basE) { if ((getMyanmarCharClass(uc[i + 1]) & Mymr_CF_CLASS_MASK) == Mymr_CC_CONSONANT) { /* subscript consonant */ reordered[len] = uc[i]; properties[len] = BelowForm; len += 1; break; } } /* assign the correct flags to consonant with subscript consonant */ if ((char_class & Mymr_CF_CONSONANT) && i + 2 < basE) { if ((getMyanmarCharClass(uc[i + 1]) & Mymr_CF_VIRAMA) && (getMyanmarCharClass(uc[i + 2]) & Mymr_CF_CLASS_MASK) == Mymr_CC_CONSONANT) { reordered[len] = uc[i]; properties[len] = BelowForm; len += 1; break; } } /* kinzi_to_be */ if (((char_class & Mymr_CF_CLASS_MASK) == Mymr_CC_NGA) && (getMyanmarCharClass(uc[i + 1]) & Mymr_CF_ASAT) && (getMyanmarCharClass(uc[i + 2]) & Mymr_CF_VIRAMA) ) { reordered[len] = uc[i]; i += 1; reordered[len + 1] = uc[i]; i += 1; reordered[len + 2] = uc[i]; properties[len] = AboveForm; properties[len + 1] = AboveForm; properties[len + 2] = AboveForm; len += 3; break; } /* default - any others */ reordered[len] = uc[i]; len += 1; break; }/* switch */ if (kinzi > -1 && i == cursor) { reordered[len] = Mymr_C_NGA; reordered[len + 1] = Mymr_C_ASAT; reordered[len + 2] = Mymr_C_VIRAMA; properties[len] = AboveForm; properties[len + 1] = AboveForm; properties[len + 2] = AboveForm; len += 3; } } /* for: loop for a baseE */ cursor = basE; } /* while: loop for a syllable*/ if (!item->font->klass->convertStringToGlyphIndices(item->font, reordered, len, item->glyphs, &item->num_glyphs, item->item.bidiLevel % 2)) return FALSE; MMDEBUG("after shaping: len=%d", len); for (i = 0; i < len; i++) { item->attributes[i].mark = FALSE; item->attributes[i].clusterStart = FALSE; item->attributes[i].justification = 0; item->attributes[i].zeroWidth = FALSE; MMDEBUG(" %d: %4x property=%x", i, reordered[i], properties[i]); } /* now we have the syllable in the right order, and can start running it through open type. */ #ifndef NO_OPENTYPE if (openType) { hb_uint32 where[32]; for (i = 0; i < len; ++i) { where[i] = ~(PreSubstProperty | BelowSubstProperty | AboveSubstProperty | PostSubstProperty | CligProperty | PositioningProperties); if (properties[i] & PreForm) where[i] &= ~PreFormProperty; if (properties[i] & BelowForm) where[i] &= ~BelowFormProperty; if (properties[i] & AboveForm) where[i] &= ~AboveFormProperty; if (properties[i] & PostForm) where[i] &= ~PostFormProperty; } HB_OpenTypeShape(item, where); if (!HB_OpenTypePosition(item, availableGlyphs, /*doLogClusters*/FALSE)) return FALSE; } else #endif { MMDEBUG("Not using openType"); HB_HeuristicPosition(item); } item->attributes[0].clusterStart = TRUE; return TRUE; }