diff options
Diffstat (limited to 'pango/pangoft2.c')
-rw-r--r-- | pango/pangoft2.c | 196 |
1 files changed, 152 insertions, 44 deletions
diff --git a/pango/pangoft2.c b/pango/pangoft2.c index 897a0c3c..ab942dc5 100644 --- a/pango/pangoft2.c +++ b/pango/pangoft2.c @@ -51,6 +51,13 @@ struct _PangoFT2FontClass PangoFontClass parent_class; }; +typedef struct +{ + FT_Bitmap bitmap; + int bitmap_left; + int bitmap_top; +} PangoFT2RenderedGlyph; + static PangoFontClass *parent_class; /* Parent class structure for PangoFT2Font */ static void pango_ft2_font_class_init (PangoFT2FontClass *class); @@ -256,6 +263,44 @@ pango_ft2_font_class_init (PangoFT2FontClass *class) font_class->get_metrics = pango_ft2_font_get_metrics; } +static void +pango_ft2_free_rendered_glyph (PangoFT2RenderedGlyph *rendered) +{ + g_free (rendered->bitmap.buffer); + g_free (rendered); +} + +static PangoFT2RenderedGlyph * +pango_ft2_font_render_glyph (PangoFont *font, + int glyph_index) +{ + PangoFT2RenderedGlyph *rendered; + FT_Face face; + + rendered = g_new (PangoFT2RenderedGlyph, 1); + + face = pango_ft2_font_get_face (font); + + if (face) + { + /* Draw glyph */ + /* FIXME hint or not? */ + FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT); + FT_Render_Glyph (face->glyph, ft_render_mode_normal); + + rendered->bitmap = face->glyph->bitmap; + rendered->bitmap.buffer = g_memdup (face->glyph->bitmap.buffer, + face->glyph->bitmap.rows * face->glyph->bitmap.pitch); + rendered->bitmap_left = face->glyph->bitmap_left; + rendered->bitmap_top = face->glyph->bitmap_top; + } + else + g_error ("Couldn't get face for PangoFT2Face"); + + return rendered; +} + + /** * pango_ft2_render: * @bitmap: the FreeType2 bitmap onto which to draw the string @@ -273,14 +318,13 @@ pango_ft2_render (FT_Bitmap *bitmap, int x, int y) { - FT_Face face; - FT_Face prev_face = NULL; - FT_UInt glyph_index, prev_index; + FT_UInt glyph_index; int i; int x_position = 0; int ix, iy, ixoff, iyoff, y_start, y_limit, x_start, x_limit; PangoGlyphInfo *gi; guchar *dest, *src; + gboolean add_glyph_to_cache; g_return_if_fail (bitmap != NULL); g_return_if_fail (glyphs != NULL); @@ -292,41 +336,42 @@ pango_ft2_render (FT_Bitmap *bitmap, { if (gi->glyph) { + PangoFT2RenderedGlyph *rendered_glyph; glyph_index = gi->glyph; - face = pango_ft2_font_get_face (font); - if (face) + rendered_glyph = pango_ft2_font_get_cache_glyph_data (font, glyph_index); + add_glyph_to_cache = FALSE; + if (rendered_glyph == NULL) { - /* Draw glyph */ - /* FIXME hint or not? */ - FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT); - FT_Render_Glyph (face->glyph, ft_render_mode_normal); - - ixoff = x + PANGO_PIXELS (x_position + gi->geometry.x_offset); - iyoff = y + PANGO_PIXELS (gi->geometry.y_offset); - - x_start = MAX (0, - (ixoff + face->glyph->bitmap_left)); - x_limit = MIN (face->glyph->bitmap.width, bitmap->width - (ixoff + face->glyph->bitmap_left)); + rendered_glyph = pango_ft2_font_render_glyph (font, glyph_index); + add_glyph_to_cache = TRUE; + } + + ixoff = x + PANGO_PIXELS (x_position + gi->geometry.x_offset); + iyoff = y + PANGO_PIXELS (gi->geometry.y_offset); + + x_start = MAX (0, - (ixoff + rendered_glyph->bitmap_left)); + x_limit = MIN (rendered_glyph->bitmap.width, bitmap->width - (ixoff + rendered_glyph->bitmap_left)); - y_start = MAX (0, - (iyoff - face->glyph->bitmap_top)); - y_limit = MIN (face->glyph->bitmap.rows, bitmap->rows - (iyoff - face->glyph->bitmap_top)); + y_start = MAX (0, - (iyoff - rendered_glyph->bitmap_top)); + y_limit = MIN (rendered_glyph->bitmap.rows, bitmap->rows - (iyoff - rendered_glyph->bitmap_top)); - PING (("glyph %d:%d: bitmap: %dx%d, left:%d top:%d", - i, glyph_index, - face->glyph->bitmap.width, face->glyph->bitmap.rows, - face->glyph->bitmap_left, face->glyph->bitmap_top)); - PING (("xstart:%d xlim:%d ystart:%d ylim:%d", - x_start, x_limit, y_start, y_limit)); + PING (("glyph %d:%d: bitmap: %dx%d, left:%d top:%d", + i, glyph_index, + rendered_glyph->bitmap.width, rendered_glyph->bitmap.rows, + rendered_glyph->bitmap_left, rendered_glyph->bitmap_top)); + PING (("xstart:%d xlim:%d ystart:%d ylim:%d", + x_start, x_limit, y_start, y_limit)); - if (face->glyph->bitmap.pixel_mode == ft_pixel_mode_grays) + if (rendered_glyph->bitmap.pixel_mode == ft_pixel_mode_grays) for (iy = y_start; iy < y_limit; iy++) { dest = bitmap->buffer + - (iyoff - face->glyph->bitmap_top + iy) * bitmap->pitch + - ixoff + face->glyph->bitmap_left + x_start; + (iyoff - rendered_glyph->bitmap_top + iy) * bitmap->pitch + + ixoff + rendered_glyph->bitmap_left + x_start; - src = face->glyph->bitmap.buffer + - iy * face->glyph->bitmap.pitch + x_start; + src = rendered_glyph->bitmap.buffer + + iy * rendered_glyph->bitmap.pitch + x_start; for (ix = x_start; ix < x_limit; ix++) { @@ -344,16 +389,16 @@ pango_ft2_render (FT_Bitmap *bitmap, src++; } } - else if (face->glyph->bitmap.pixel_mode == ft_pixel_mode_mono) + else if (rendered_glyph->bitmap.pixel_mode == ft_pixel_mode_mono) for (iy = y_start; iy < y_limit; iy++) { dest = bitmap->buffer + - (iyoff - face->glyph->bitmap_top + iy) * bitmap->pitch + - ixoff + face->glyph->bitmap_left + + (iyoff - rendered_glyph->bitmap_top + iy) * bitmap->pitch + + ixoff + rendered_glyph->bitmap_left + x_start; - src = face->glyph->bitmap.buffer + - iy*face->glyph->bitmap.pitch; + src = rendered_glyph->bitmap.buffer + + iy*rendered_glyph->bitmap.pitch; for (ix = x_start; ix < x_limit; ix++) { @@ -366,10 +411,13 @@ pango_ft2_render (FT_Bitmap *bitmap, } else g_warning ("pango_ft2_render: Unrecognized glyph bitmap pixel mode %d\n", - face->glyph->bitmap.pixel_mode); + rendered_glyph->bitmap.pixel_mode); - prev_face = face; - prev_index = glyph_index; + if (add_glyph_to_cache) + { + pango_ft2_font_set_glyph_cache_destroy (font, + (GDestroyNotify) pango_ft2_free_rendered_glyph); + pango_ft2_font_set_cache_glyph_data (font, glyph_index, rendered_glyph); } } @@ -385,11 +433,10 @@ pango_ft2_get_per_char (FT_Face face, return &face->glyph->metrics; } -static void -pango_ft2_font_get_glyph_extents (PangoFont *font, - PangoGlyph glyph, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect) +static PangoFT2GlyphInfo * +pango_ft2_font_get_glyph_info (PangoFont *font, + PangoGlyph glyph, + gboolean create) { PangoFT2Font *ft2font = (PangoFT2Font *)font; PangoFT2GlyphInfo *info; @@ -397,10 +444,10 @@ pango_ft2_font_get_glyph_extents (PangoFont *font, info = g_hash_table_lookup (ft2font->glyph_info, GUINT_TO_POINTER (glyph)); - if (!info) + if ((info == NULL) && create) { FT_Face face = pango_ft2_font_get_face (font); - info = g_new (PangoFT2GlyphInfo, 1); + info = g_new0 (PangoFT2GlyphInfo, 1); if (glyph && (gm = pango_ft2_get_per_char (face, glyph))) { @@ -431,6 +478,19 @@ pango_ft2_font_get_glyph_extents (PangoFont *font, g_hash_table_insert (ft2font->glyph_info, GUINT_TO_POINTER(glyph), info); } + return info; +} + +static void +pango_ft2_font_get_glyph_extents (PangoFont *font, + PangoGlyph glyph, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect) +{ + PangoFT2GlyphInfo *info; + + info = pango_ft2_font_get_glyph_info (font, glyph, TRUE); + if (ink_rect) *ink_rect = info->ink_rect; if (logical_rect) @@ -533,6 +593,12 @@ pango_ft2_font_dispose (GObject *object) static gboolean pango_ft2_free_glyph_info_callback (gpointer key, gpointer value, gpointer data) { + PangoFT2Font *font = PANGO_FT2_FONT (data); + PangoFT2GlyphInfo *info = value; + + if (font->glyph_cache_destroy && info->cached_glyph) + (*font->glyph_cache_destroy) (info->cached_glyph); + g_free (value); return TRUE; } @@ -556,7 +622,7 @@ pango_ft2_font_finalize (GObject *object) g_object_unref (G_OBJECT (ft2font->fontmap)); g_hash_table_foreach_remove (ft2font->glyph_info, - pango_ft2_free_glyph_info_callback, NULL); + pango_ft2_free_glyph_info_callback, object); g_hash_table_destroy (ft2font->glyph_info); G_OBJECT_CLASS (parent_class)->finalize (object); @@ -914,3 +980,45 @@ _pango_ft2_ft_strerror (FT_Error error) return default_msg; } } + + +void * +pango_ft2_font_get_cache_glyph_data (PangoFont *font, + int glyph_index) +{ + PangoFT2GlyphInfo *info; + + g_return_val_if_fail (PANGO_FT2_IS_FONT (font), NULL); + + info = pango_ft2_font_get_glyph_info (font, glyph_index, FALSE); + + if (info == NULL) + return NULL; + + return info->cached_glyph; +} + +void +pango_ft2_font_set_cache_glyph_data (PangoFont *font, + int glyph_index, + void *cached_glyph) +{ + PangoFT2GlyphInfo *info; + + g_return_if_fail (PANGO_FT2_IS_FONT (font)); + + info = pango_ft2_font_get_glyph_info (font, glyph_index, TRUE); + + info->cached_glyph = cached_glyph; + + /* TODO: Implement limiting of the number of cached glyphs */ +} + +void +pango_ft2_font_set_glyph_cache_destroy (PangoFont *font, + GDestroyNotify destroy_notify) +{ + g_return_if_fail (PANGO_FT2_IS_FONT (font)); + + PANGO_FT2_FONT (font)->glyph_cache_destroy = destroy_notify; +} |