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);
}
Example #2
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);
}
Example #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*/ ) {
                //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);
}
HB_Bool HB_ThaiShape(HB_ShaperItem *item)
{
    HB_Bool openType = FALSE;
    unsigned short *logClusters = item->log_clusters;
    int i;
    int clusterIndex;
    int cStart, cEnd;
    int fristGlyphIndex;
    int prevOutputIndex;
    int outputClusterLength;

    HB_ShaperItem shapedItem = *item;

    THDEBUG("item->item.pos: %d, item->item.length: %d", item->item.pos, item->item.length);

    ThaiShapeCategory glyphSet = thaiCheckShapeCategory(item);

    HB_UChar16 * output = (HB_UChar16 *)malloc(sizeof(HB_UChar16) * (item->item.length << 1));
    hb_int32 *charIndex = (hb_int32 *)malloc(sizeof(hb_int32) * (item->item.length << 1));
    hb_int32 *clusterStart = (hb_int32 *)malloc(sizeof(hb_int32) * (item->item.length << 1));
    int clusterCount = 0;

    hb_int32 strLen = thaiCompose(item->string, item->item.pos, item->item.length, glyphSet,
            CH_DOTTED_CIRCLE, output, charIndex, &clusterCount, clusterStart);
    THDEBUG("reordered strLen: %d", strLen);

#ifdef THAI_DEBUG
    THDEBUG("clusterCount: %d", clusterCount);
    for (i = 0; i < strLen; ++i) {
        THDEBUG("charIndex[%d]: %d, clusterStart[%d]: %d", i, charIndex[i], i, clusterStart[i]);
    }
#endif

    shapedItem.string = output;
    shapedItem.stringLength = strLen;

    fristGlyphIndex = 0;
    prevOutputIndex = 0;
    for (clusterIndex = 0; clusterIndex < clusterCount; ++clusterIndex) {
        cStart = clusterStart[clusterIndex];
        if (clusterIndex == clusterCount - 1) {
            cEnd = item->item.length;
        } else {
            cEnd = clusterStart[clusterIndex + 1];
        }

        outputClusterLength = 0;
        for (i = prevOutputIndex; i < strLen && charIndex[i] < cEnd; ++i) {
            ++outputClusterLength;
        }
        THDEBUG("        outputClusterLength %d", outputClusterLength);

        shapedItem.item.pos = prevOutputIndex;
        shapedItem.item.length = outputClusterLength;
        shapedItem.glyphs = item->glyphs + fristGlyphIndex;
        shapedItem.attributes = item->attributes + fristGlyphIndex;
        shapedItem.advances = item->advances + fristGlyphIndex;
        shapedItem.offsets = item->offsets + fristGlyphIndex;
        shapedItem.num_glyphs = item->num_glyphs - fristGlyphIndex;
        shapedItem.log_clusters = item->log_clusters + cStart;

        HB_BasicShape(&shapedItem);

        for (i = cStart; i < cEnd; ++i) {
            item->log_clusters[i] = fristGlyphIndex;
        }

        prevOutputIndex += outputClusterLength;
        fristGlyphIndex += shapedItem.num_glyphs;
    }

    for (i = item->item.length; i < prevOutputIndex; ++i) {
        item->log_clusters[i] = 0;
    }

    item->num_glyphs = fristGlyphIndex;
    THDEBUG("shapedItem.num_glyphs: %d", item->num_glyphs);

    free(clusterStart);
    free(charIndex);
    free(output);
    return TRUE;
}