HB_Bool HB_HangulShape(HB_ShaperItem *item)
{
    const HB_UChar16 *uc = item->string + item->item.pos;
    HB_Bool allPrecomposed = TRUE;
    int i;

    assert(item->item.script == HB_Script_Hangul);

    for (i = 0; i < (int)item->item.length; ++i) {
        if (!hangul_isPrecomposed(uc[i])) {
            allPrecomposed = FALSE;
            break;
        }
    }

    if (!allPrecomposed) {
        HB_Bool openType = FALSE;
        unsigned short *logClusters = item->log_clusters;
        HB_ShaperItem syllable;
        int first_glyph = 0;
        int sstart = item->item.pos;
        int end = sstart + item->item.length;

#ifndef NO_OPENTYPE
        openType = HB_SelectScript(item, hangul_features);
#endif
        syllable = *item;

        while (sstart < end) {
            int send = hangul_nextSyllableBoundary(item->string, sstart, end);

            syllable.item.pos = sstart;
            syllable.item.length = send-sstart;
            syllable.glyphs = item->glyphs + first_glyph;
            syllable.attributes = item->attributes + first_glyph;
            syllable.offsets = item->offsets + first_glyph;
            syllable.advances = item->advances + first_glyph;
            syllable.num_glyphs = item->num_glyphs - first_glyph;
            if (!hangul_shape_syllable(&syllable, openType)) {
                item->num_glyphs += syllable.num_glyphs;
                return FALSE;
            }
            /* fix logcluster array */
            for (i = sstart; i < send; ++i)
                logClusters[i-item->item.pos] = first_glyph;
            sstart = send;
            first_glyph += syllable.num_glyphs;
        }
        item->num_glyphs = first_glyph;
        return TRUE;
    }

    return HB_BasicShape(item);
}
HB_Bool HB_MyanmarShape(HB_ShaperItem *item)
{
    HB_Bool openType = FALSE;
    unsigned short *logClusters = item->log_clusters;

    HB_ShaperItem syllable = *item;
    int first_glyph = 0;

    int sstart = item->item.pos;
    int end = sstart + item->item.length;
    int i = 0;

    assert(item->item.script == HB_Script_Myanmar);
#ifndef NO_OPENTYPE
    openType = HB_SelectScript(item, myanmar_features);
#endif

    MMDEBUG("myanmar_shape: from %d length %d", item->item.pos, item->item.length);
    while (sstart < end) {
        HB_Bool invalid;
        int send = myanmar_nextSyllableBoundary(item->string, sstart, end, &invalid);
        MMDEBUG("syllable from %d, length %d, invalid=%s", sstart, send-sstart,
               invalid ? "TRUE" : "FALSE");
        syllable.item.pos = sstart;
        syllable.item.length = send-sstart;
        syllable.glyphs = item->glyphs + first_glyph;
        syllable.attributes = item->attributes + first_glyph;
        syllable.advances = item->advances + first_glyph;
        syllable.offsets = item->offsets + first_glyph;
        syllable.num_glyphs = item->num_glyphs - first_glyph;
        if (!myanmar_shape_syllable(openType, &syllable, invalid)) {
            MMDEBUG("syllable shaping failed, syllable requests %d glyphs", syllable.num_glyphs);
            item->num_glyphs += syllable.num_glyphs;
            return FALSE;
        }

        /* fix logcluster array */
        MMDEBUG("syllable:");
        for (i = first_glyph; i < first_glyph + (int)syllable.num_glyphs; ++i)
            MMDEBUG("        %d -> glyph %x", i, item->glyphs[i]);
        MMDEBUG("    logclusters:");
        for (i = sstart; i < send; ++i) {
            MMDEBUG("        %d -> glyph %d", i, first_glyph);
            logClusters[i-item->item.pos] = first_glyph;
        }
        sstart = send;
        first_glyph += syllable.num_glyphs;
    }
    item->num_glyphs = first_glyph;
    return TRUE;
}
Exemple #3
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;
}
HB_Bool HB_TibetanShape(HB_ShaperItem *item)
{

    HB_Bool openType = FALSE;
    unsigned short *logClusters = item->log_clusters;

    HB_ShaperItem syllable = *item;
    int first_glyph = 0;

    int sstart = item->item.pos;
    int end = sstart + item->item.length;

    assert(item->item.script == HB_Script_Tibetan);

#ifndef NO_OPENTYPE
    openType = HB_SelectScript(item, tibetan_features);
#endif

    while (sstart < end) {
        HB_Bool invalid;
        int i;
        int send = tibetan_nextSyllableBoundary(item->string, sstart, end, &invalid);
/*        IDEBUG("syllable from %d, length %d, invalid=%s", sstart, send-sstart,
                 invalid ? "TRUE" : "FALSE"); */
        syllable.item.pos = sstart;
        syllable.item.length = send-sstart;
        syllable.glyphs = item->glyphs + first_glyph;
        syllable.attributes = item->attributes + first_glyph;
        syllable.offsets = item->offsets + first_glyph;
        syllable.advances = item->advances + first_glyph;
        syllable.num_glyphs = item->num_glyphs - first_glyph;
        if (!tibetan_shape_syllable(openType, &syllable, invalid)) {
            item->num_glyphs += syllable.num_glyphs;
            return FALSE;
        }
        /* fix logcluster array */
        for (i = sstart; i < send; ++i)
            logClusters[i-item->item.pos] = first_glyph;
        sstart = send;
        first_glyph += syllable.num_glyphs;
    }
    item->num_glyphs = first_glyph;
    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;
}
/*
  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;
}