Exemple #1
0
static VALUE
rg_log_attrs(VALUE self)
{
    PangoLogAttr* attrs;
    gint i, n_attrs;
    VALUE ary;

    pango_layout_get_log_attrs(_SELF(self), &attrs, &n_attrs);

    ary = rb_ary_new();

    for (i = 0; i < n_attrs; i++) {
        rb_ary_assoc(ary, BOXED2RVAL(&attrs[i], PANGO_TYPE_LOG_ATTR));
    }
    g_free(attrs);

    return ary;
}
void text_wrapper::DoLayout(void)
{
    // THE function
    // first some sanity checks
    if ( default_font == NULL ) return;
    if ( uni32_length <= 0 || utf8_length <= 0 ) return;
    // prepare the pangolayout object
    {
        //char *tc = pango_font_description_to_string(default_font->descr);
        //printf("layout with %s\n", tc);
        //free(tc);
    }
    pango_layout_set_font_description(pLayout, default_font->descr);
    pango_layout_set_text(pLayout, utf8_text, utf8_length);
    // reset the glyph string
    if ( glyph_text ) free(glyph_text);
    glyph_text = NULL;
    glyph_length = 0;

    double pango_to_ink = (1.0 / ((double)PANGO_SCALE)); // utility
    int max_g = 0;
    PangoLayoutIter *pIter = pango_layout_get_iter(pLayout); // and go!
    do {
        PangoLayoutLine *pLine = pango_layout_iter_get_line(pIter); // no need for unref
        int plOffset = pLine->start_index; // start of the line in the uni32_text
        PangoRectangle ink_r, log_r;
        pango_layout_iter_get_line_extents(pIter, &ink_r, &log_r);
        double plY = (1.0 / ((double)PANGO_SCALE)) * ((double)log_r.y); // start position of this line of the layout
        double plX = (1.0 / ((double)PANGO_SCALE)) * ((double)log_r.x);
        GSList *curR = pLine->runs; // get ready to iterate over the runs of this line
        while ( curR ) {
            PangoLayoutRun *pRun = (PangoLayoutRun*)curR->data;
            if ( pRun ) {
                int prOffset = pRun->item->offset; // start of the run in the line
                // a run has uniform font/directionality/etc...
                int o_g_l = glyph_length; // save the index of the first glyph we'll add
                for (int i = 0; i < pRun->glyphs->num_glyphs; i++) { // add glyph sequentially, reading them from the run
                    // realloc the structures
                    if ( glyph_length >= max_g ) {
                        max_g = 2 * glyph_length + 1;
                        one_glyph *newdata = static_cast<one_glyph*>(realloc(glyph_text, (max_g + 1) * sizeof(one_glyph)));
                        if (newdata != NULL)
                        {
                            glyph_text = newdata;
                        }
                        else
                        {
                            g_warning("Failed to reallocate glyph_text");
                        }
                    }
                    // fill the glyph info
                    glyph_text[glyph_length].font = pRun->item->analysis.font;
                    glyph_text[glyph_length].gl = pRun->glyphs->glyphs[i].glyph;
                    glyph_text[glyph_length].uni_st = plOffset + prOffset + pRun->glyphs->log_clusters[i];
                    // depending on the directionality, the last uni32 codepoint for this glyph is the first of the next char
                    // or the first of the previous
                    if ( pRun->item->analysis.level == 1 ) {
                        // rtl
                        if ( i < pRun->glyphs->num_glyphs - 1 ) {
                            glyph_text[glyph_length + 1].uni_en = glyph_text[glyph_length].uni_st;
                        }
                        glyph_text[glyph_length].uni_dir = 1;
                        glyph_text[glyph_length + 1].uni_dir = 1; // set the directionality for the next too, so that the last glyph in
                        // the array has the correct direction
                    } else {
                        // ltr
                        if ( i > 0 ) {
                            glyph_text[glyph_length - 1].uni_en = glyph_text[glyph_length].uni_st;
                        }
                        glyph_text[glyph_length].uni_dir = 0;
                        glyph_text[glyph_length + 1].uni_dir = 0;
                    }
                    // set the position
                    // the layout is an infinite line
                    glyph_text[glyph_length].x = plX + pango_to_ink * ((double)pRun->glyphs->glyphs[i].geometry.x_offset);
                    glyph_text[glyph_length].y = plY + pango_to_ink * ((double)pRun->glyphs->glyphs[i].geometry.y_offset);
                    // advance to the next glyph
                    plX += pango_to_ink * ((double)pRun->glyphs->glyphs[i].geometry.width);
                    // and set the next glyph's position, in case it's the terminating glyph
                    glyph_text[glyph_length + 1].x = plX;
                    glyph_text[glyph_length + 1].y = plY;
                    glyph_length++;
                }
                // and finish filling the info
                // notably, the uni_en of the last char in ltr text and the uni_en of the first in rtl are still not set
                if ( pRun->item->analysis.level == 1 ) {
                    // rtl
                    if ( glyph_length > o_g_l ) glyph_text[o_g_l].uni_en = plOffset + prOffset + pRun->item->length;
                } else {
                    if ( glyph_length > 0 ) glyph_text[glyph_length - 1].uni_en = plOffset + prOffset + pRun->item->length;
                }
                // the terminating glyph has glyph_id=0 because it means 'no glyph'
                glyph_text[glyph_length].gl = 0;
                // and is associated with no text (but you cannot set uni_st=uni_en=0, because the termination
                // is expected to be the glyph for the termination of the uni32_text)
                glyph_text[glyph_length].uni_st = glyph_text[glyph_length].uni_en = plOffset + prOffset + pRun->item->length;
            }
            curR = curR->next;
        }
    } while ( pango_layout_iter_next_line(pIter) );
    pango_layout_iter_free(pIter);

    // grunt work done. now some additional info for layout: computing letters, mostly (one letter = several glyphs sometimes)
    PangoLogAttr *pAttrs = NULL;
    int nbAttr = 0;
    // get the layout attrs, they hold the boundaries pango computed
    pango_layout_get_log_attrs(pLayout, &pAttrs, &nbAttr);
    // feed to MakeTextBoundaries which knows what to do with these
    MakeTextBoundaries(pAttrs, nbAttr);
    // the array of boundaries is full, but out-of-order
    SortBoundaries();
    // boundary array is ready to be used, call chunktext to fill the *_start fields of the glyphs, and compute
    // the boxed version of the text for sp-typeset
    ChunkText();
    // get rid of the attributes
    if ( pAttrs ) g_free(pAttrs);

    // cleaning up
    for (int i = 0; i < glyph_length; i++) {
        glyph_text[i].uni_st = uni32_codepoint[glyph_text[i].uni_st];
        glyph_text[i].uni_en = uni32_codepoint[glyph_text[i].uni_en];
        glyph_text[i].x /= 512; // why is this not default_font->parent->fontsize?
        glyph_text[i].y /= 512;
    }
    if ( glyph_length > 0 ) {
        glyph_text[glyph_length].x /= 512;
        glyph_text[glyph_length].y /= 512;
    }
}
static gboolean
layout_is_ellipsized(PangoLayout *layout)
{
    /* pango_layout_is_ellipsized() is a new function in Pango-1.16; we
     * emulate it here by trying to look for the ellipsis run
     */
    PangoLogAttr *log_attrs;
    int n_attrs;
    PangoLayoutIter *iter;
    gboolean result = FALSE;

    /* Short circuit when we aren't ellipsizing at all */
    if (pango_layout_get_ellipsize(layout) == PANGO_ELLIPSIZE_NONE)
        return FALSE;
    
    pango_layout_get_log_attrs(layout, &log_attrs, &n_attrs);
    
    iter = pango_layout_get_iter(layout);
    do {
        PangoGlyphItem *run;
        int n_glyphs;
        int start_index;
        int n_graphemes;
        int i;

        run = pango_layout_iter_get_run(iter);
        if (!run)
            continue;

        n_glyphs = run->glyphs->num_glyphs;
        start_index = pango_layout_iter_get_index(iter);
        
        /* Check the number of clusters in the run ... if it is greater
         * than 1, then it isn't an ellipsis
         */
        if (run->glyphs->log_clusters[0] != run->glyphs->log_clusters[n_glyphs - 1])
            continue;

        /* Now check the number of graphemes in the run ... if it is less
         * than 3, it's probably an isolated 'fi' ligature or something
         * like that rather than an ellipsis.
         */
        n_graphemes = 0;
        for (i = 0; i < run->item->num_chars && i + start_index < n_attrs; i++)
            if (log_attrs[i + start_index].is_cursor_position)
                n_graphemes++;

        if (n_graphemes < 3)
            continue;

        /* OK, at this point it is probably an ellipsis; it's possible that
         * the text consists of just the letters 'ffi' and the font has a ligature
         * for that or something, but it's not too likely.
         */
        result = TRUE;
        break;
                
    } while (pango_layout_iter_next_run(iter));

    pango_layout_iter_free(iter);

    g_free(log_attrs);

    return result;
}