void text_widget_set_text ( struct TEXT_WIDGET_HANDLE handle, const char* text, int length ) { if ( handle.d == NULL || handle.d->layout == NULL ) return; pango_layout_set_markup( handle.d->layout, text, length ); // The idea here is to make sure that the VGFont contains // all the glyphs at the proper size so that when we want // to draw, we can can just call vgDrawGlyphs (well, maybe // not since PangoGlyphInfo is not an array of glyph // indexes; aww). PangoLayoutIter* li = pango_layout_get_iter( handle.d->layout ); do { PangoLayoutRun* run = pango_layout_iter_get_run( li ); if ( run == NULL ) continue; PangoFont* font = run->item->analysis.font; // Well, you can see how C is not the most ideal language for // abstraction. Have to read the documentation to discover // that this font is a PangoFcFont. FT_Face face = pango_fc_font_lock_face( (PangoFcFont*)font ); if ( face != NULL ) { struct VG_DATA* vg_data = face->size->generic.data; if ( vg_data == NULL ) { vg_data = vg_data_new(); face->size->generic.data = vg_data; face->size->generic.finalizer = vg_data_free; } int g; for ( g = 0; g < run->glyphs->num_glyphs; g++ ) { int byte = run->glyphs->glyphs[g].glyph / 8; int bit = 1 << ( run->glyphs->glyphs[g].glyph & 0x7 ); if ( ! ( vg_data->cmap[byte] & bit ) ) { vg_data->cmap[byte] |= bit; add_char( vg_data->font, face, run->glyphs->glyphs[g].glyph ); } } pango_fc_font_unlock_face( (PangoFcFont*)font ); } } while ( pango_layout_iter_next_run( li ) ); pango_layout_iter_free( li ); }
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; }
void text_widget_draw_text ( struct TEXT_WIDGET_HANDLE handle ) { if ( handle.d == NULL || handle.d->layout == NULL ) return; vgSetPaint( handle.d->foreground, VG_FILL_PATH ); vgSeti( VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE ); vgLoadIdentity(); #if 0 // Overscan (in dots, evidently). vgTranslate( 14.f, 8.f ); #endif // Offset in mm. vgScale( handle.d->dpmm_x, handle.d->dpmm_y ); // Move to the corner. vgTranslate( handle.d->x_mm, handle.d->y_mm ); // Back to dots. vgScale( 1.f/handle.d->dpmm_x, 1.f/handle.d->dpmm_y ); int height = PANGO_PIXELS( pango_layout_get_height( handle.d->layout ) ); PangoLayoutIter* li = pango_layout_get_iter( handle.d->layout ); do { PangoLayoutRun* run = pango_layout_iter_get_run( li ); if ( run == NULL ) continue; PangoRectangle logical_rect; int baseline_pango = pango_layout_iter_get_baseline( li ); int baseline_pixel = PANGO_PIXELS( baseline_pango ); pango_layout_iter_get_run_extents( li, NULL, &logical_rect ); int x_pixel = PANGO_PIXELS( logical_rect.x ); PangoFont* pg_font = run->item->analysis.font; FT_Face face = pango_fc_font_lock_face( (PangoFcFont*)pg_font ); if ( face != NULL ) { struct VG_DATA* vg_data = face->size->generic.data; if ( vg_data != NULL ) { // About the only extra attribute we can manage is the foreground // color. But, it might be nice to render a background color // to see just how badly the text is fitted into the widget // box. GSList* attr_item = run->item->analysis.extra_attrs; while ( attr_item ) { PangoAttribute* attr = attr_item->data; switch ( attr->klass->type ) { case PANGO_ATTR_FOREGROUND: { PangoColor color = ((PangoAttrColor*)attr)->color; VGfloat new_color[] = { (float)color.red / 65535.f, (float)color.green / 65535.f, (float)color.blue / 65535.f, 1.f }; VGPaint new_paint = vgCreatePaint(); vgSetParameterfv( new_paint, VG_PAINT_COLOR, 4, new_color ); vgSetPaint( new_paint, VG_FILL_PATH ); vgDestroyPaint( new_paint ); } break; default: printf( "\tHmm. Unknown attribute: %d\n", attr->klass->type ); } attr_item = attr_item->next; } // Note: inverted Y coordinate VGfloat point[2] = { x_pixel, height - baseline_pixel }; vgSetfv( VG_GLYPH_ORIGIN, 2, point ); VGFont vg_font = vg_data->font; int g; for ( g = 0; g < run->glyphs->num_glyphs; g++ ) { vgDrawGlyph( vg_font, run->glyphs->glyphs[g].glyph, VG_FILL_PATH, VG_TRUE ); } if ( vgGetPaint( VG_FILL_PATH ) != handle.d->foreground ) { vgSetPaint( handle.d->foreground, VG_FILL_PATH ); } } pango_fc_font_unlock_face( (PangoFcFont*)pg_font ); } } while ( pango_layout_iter_next_run( li ) ); // Iterators are not free. pango_layout_iter_free( li); }
static void dump_runs (PangoLayout *layout, GString *string) { PangoLayoutIter *iter; PangoLayoutRun *run; PangoItem *item; const gchar *text; gint index, index2; gboolean has_more; gchar *char_str; gint i; gchar *font; text = pango_layout_get_text (layout); iter = pango_layout_get_iter (layout); has_more = TRUE; index = pango_layout_iter_get_index (iter); i = 0; while (has_more) { run = pango_layout_iter_get_run (iter); has_more = pango_layout_iter_next_run (iter); i++; if (has_more) { index2 = pango_layout_iter_get_index (iter); char_str = g_strndup (text + index, index2 - index); } else { char_str = g_strdup (text + index); } if (run) { item = ((PangoGlyphItem*)run)->item; font = font_name (item->analysis.font); g_string_append_printf (string, "i=%d, index=%d, chars=%d, level=%d, gravity=%s, flags=%d, font=%s, script=%s, language=%s, '%s'\n", i, index, item->num_chars, item->analysis.level, gravity_name (item->analysis.gravity), item->analysis.flags, "OMITTED", /* for some reason, this fails on build.gnome.org, so leave it out */ script_name (item->analysis.script), pango_language_to_string (item->analysis.language), char_str); dump_extra_attrs (item->analysis.extra_attrs, string); g_free (font); } else { g_string_append_printf (string, "i=%d, index=%d, no run, line end\n", i, index); } g_free (char_str); index = index2; } pango_layout_iter_free (iter); }
static VALUE layout_iter_get_run(VALUE self) { PangoLayoutRun* run = pango_layout_iter_get_run(_SELF(self)); return BOXED2RVAL(run, PANGO_TYPE_GLYPH_ITEM); }