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;
}
/* 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;
}
Exemple #3
0
/*
 * convert to the correct display level of THAI vowels and marks.
 */
static HB_Bool HB_ThaiConvertStringToGlyphIndices (HB_ShaperItem *item)
{
    char s[128];
    char *cstr = s;
    const HB_UChar16 *string = item->string + item->item.pos;
    const hb_uint32 len = item->item.length;
    unsigned short *logClusters = item->log_clusters;
    hb_uint32 i = 0, slen = 0;

    if (!init_libthai())
        return HB_BasicShape (item);

    if (len >= 128)
        cstr = (char *)malloc(len*sizeof(char) + 1);

    if (!cstr)
        return HB_BasicShape (item);

    to_tis620(string, len, cstr);

    /* Get font type */
    static ThaiFontType font_type;
    static HB_Font itemFont;
    if (itemFont != item->font) {
        font_type = getThaiFontType (item);
        itemFont = item->font;
    }

    /* allocate temporary glyphs buffers */
    HB_STACKARRAY (HB_UChar16, glyphString, (item->item.length * 2));

    while (i < item->item.length) {
        struct thcell_t tis_cell;
        unsigned char rglyphs[4];
        int cell_length;
        int lgn = 0;
        HB_Bool haveSaraAm = false;

        cell_length = th_next_cell ((const unsigned char *)cstr + i, len - i, &tis_cell, true); /* !item->fixedPitch); */
        haveSaraAm  = (cstr[i + cell_length - 1] == (char)0xd3);

        /* set shaper item's log_clusters */
        logClusters[i] = slen;
        for (int j = 1; j < cell_length; j++) {
            logClusters[i + j] = logClusters[i];
        }

        /* Find Logical Glyphs by font type */
        switch (font_type) {
        case TIS:
            lgn = th_render_cell_tis (tis_cell, rglyphs, sizeof(rglyphs) / sizeof(rglyphs[0]), true);
            break;
        case WIN:
            lgn = th_render_cell_mac (tis_cell, rglyphs, sizeof(rglyphs) / sizeof(rglyphs[0]), true);
            break;
        case MAC:
            lgn = th_render_cell_win (tis_cell, rglyphs, sizeof(rglyphs) / sizeof(rglyphs[0]), true);
            break;
        }

        /* Add glyphs to glyphs string and setting some attributes */
        for (int lgi = 0; lgi < lgn; lgi++) {
            if ( rglyphs[lgi] == 0xdd/*TH_BLANK_BASE_GLYPH*/ ) {
                glyphString[slen++] = C_DOTTED_CIRCLE;
            } else if ((unsigned char)cstr[i] == (unsigned char)~0) {
                // The only glyphs that should be passed to this function that cannot be mapped to
                // tis620 are the ones of type Inherited class.  Pass these glyphs untouched.
                glyphString[slen++] = string[i];
                if (string[i] == 0x200D || string[i] == 0x200C) {
                    // Check that we do not run out of bounds when setting item->attributes.  If we do
                    // run out of bounds then this function will return false, the necessary amount of
                    // memory is reallocated, and this function will then be called again.
                    if (slen <= item->num_glyphs)
                        item->attributes[slen-1].dontPrint = true; // Hide ZWJ and ZWNJ characters
                }
            } else {
                glyphString[slen++] = (HB_UChar16) thai_get_glyph_index (font_type, rglyphs[lgi]);
            }
        }

        /* Special case to handle U+0E33 (SARA AM, ำ): SARA AM is normally written at the end of a
         * word with a base character and an optional top character before it. For example, U+0E0B
         * (base), U+0E49 (top), U+0E33 (SARA AM). The sequence should be converted to 4 glyphs:
         * base, hilo (the little circle in the top left part of SARA AM, NIKHAHIT), top, then the
         * right part of SARA AM (SARA AA).
         *
         * The painting process finds out the starting glyph and ending glyph of a character
         * sequence by checking the logClusters array. In this case, logClusters array should
         * ideally be [ 0, 1, 3 ] so that glyphsStart = 0 and glyphsEnd = 3 (slen - 1) to paint out
         * all the glyphs generated.
         *
         * A special case in this special case is when we have no base character. When an isolated
         * SARA AM is processed (cell_length = 1), libthai will produce 3 glyphs: dotted circle
         * (indicates that the base is empty), NIKHAHIT then SARA AA. If logClusters[0] = 1, it will
         * paint from the second glyph in the glyphs array. So in this case logClusters[0] should
         * point to the first glyph it produces, aka. the dotted circle. */
        if (haveSaraAm) {
            logClusters[i + cell_length - 1] = cell_length == 1 ? slen - 3 : slen - 1;
            if (tis_cell.top != 0) {
                if (cell_length > 1) {
                    /* set the logClusters[top character] to slen - 2 as it points to the second to
                     * lastglyph (slen - 2) */
                    logClusters[i + cell_length - 2] = slen - 2;
                }
            }
            /* check for overflow */
            if (logClusters[i + cell_length - 1] > slen)
                logClusters[i + cell_length - 1] = 0;
        }

        i += cell_length;
    }
    glyphString[slen] = (HB_UChar16) '\0';

    /* for check, should reallocate space or not */
    HB_Bool spaceOK = (item->num_glyphs >= slen);

    /* Convert to Glyph indices */
    HB_Bool haveGlyphs = item->font->klass->convertStringToGlyphIndices (
                             item->font,
                             glyphString, slen,
                             item->glyphs, &item->num_glyphs,
                             item->shaperFlags);

    HB_FREE_STACKARRAY (glyphString);

    if (len >= 128)
        free(cstr);

    return (haveGlyphs && spaceOK);
}
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;
}
Exemple #5
0
/*
 * convert to the correct display level of THAI vowels and marks.
 */
static HB_Bool HB_ThaiConvertStringToGlyphIndices (HB_ShaperItem *item)
{
    char s[128];
    char *cstr = s;
    const HB_UChar16 *string = item->string + item->item.pos;
    const hb_uint32 len = item->item.length;
    unsigned short *logClusters = item->log_clusters;
    hb_uint32 i = 0, slen = 0;

    if (!init_libthai())
        return HB_BasicShape (item);

    if (len >= 128)
        cstr = (char *)malloc(len*sizeof(char) + 1);

    if (!cstr)
        return HB_BasicShape (item);

    to_tis620(string, len, cstr);

    /* Get font type */
    static ThaiFontType font_type;
    static HB_Font itemFont;
    if (itemFont != item->font) {
        font_type = getThaiFontType (item);
        itemFont = item->font;
    }

    /* allocate temporary glyphs buffers */
    HB_STACKARRAY (HB_UChar16, glyphString, (item->item.length * 2));

    while (i < item->item.length) {
        struct thcell_t tis_cell;
        unsigned char rglyphs[4];
        int cell_length;
        int lgn = 0;
        HB_Bool haveSaraAm = false;

        cell_length = th_next_cell ((const unsigned char *)cstr + i, len - i, &tis_cell, true); /* !item->fixedPitch); */
        haveSaraAm  = (cstr[i + cell_length - 1] == (char)0xd3);

        /* set shaper item's log_clusters */
        logClusters[i] = slen;
        for (int j = 1; j < cell_length; j++) {
            logClusters[i + j] = logClusters[i];
        }

        /* Find Logical Glyphs by font type */
        switch (font_type) {
            case TIS: lgn = th_render_cell_tis (tis_cell, rglyphs, sizeof(rglyphs) / sizeof(rglyphs[0]), true); break;
            case WIN: lgn = th_render_cell_mac (tis_cell, rglyphs, sizeof(rglyphs) / sizeof(rglyphs[0]), true); break;
            case MAC: lgn = th_render_cell_win (tis_cell, rglyphs, sizeof(rglyphs) / sizeof(rglyphs[0]), true); break;
        }

        /* Add glyphs to glyphs string and setting some attributes */
        for (int lgi = 0; lgi < lgn; lgi++) {
            if ( rglyphs[lgi] == 0xdd/*TH_BLANK_BASE_GLYPH*/ ) {
                //if ( !item->fixedPitch ) {
                    glyphString[slen++] = C_DOTTED_CIRCLE;
                    item->attributes[slen-1].dontPrint = true; // FIXME this will hide all dotted circle
                //}
            }
            else {
                glyphString[slen++] = (HB_UChar16) thai_get_glyph_index (font_type, rglyphs[lgi]);
            }
        }

        if (haveSaraAm) {
            logClusters[i + cell_length - 1] = slen - 1; // Set logClusters before NIKAHIT
            if (tis_cell.top != 0)
                logClusters[i + cell_length - 2] = slen - 2; // Set logClusters before NIKAHIT when tis_cell has top
            if (logClusters[i + cell_length - 1] > slen)
                logClusters[i + cell_length - 1] = 0;
        }

        i += cell_length;
    }
    glyphString[slen] = (HB_UChar16) '\0';

    /* for check, should reallocate space or not */
    HB_Bool spaceOK = (item->num_glyphs >= slen);

    /* Convert to Glyph indices */
    HB_Bool haveGlyphs = item->font->klass->convertStringToGlyphIndices (
                                          item->font,
                                          glyphString, slen,
                                          item->glyphs, &item->num_glyphs,
                                          item->shaperFlags);

    HB_FREE_STACKARRAY (glyphString);

    if (len >= 128)
        free(cstr);

    return (haveGlyphs && spaceOK);
}
/*
  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;
}