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;
}
Beispiel #2
0
/*
 * 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;
}
Beispiel #3
0
/* 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;
}
Beispiel #5
0
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;
}
Beispiel #7
0
/*
  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;
}
Beispiel #8
0
// 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;
}