diff options
author | Raph Levien <raph@src.gnome.org> | 2000-09-07 00:47:57 +0000 |
---|---|---|
committer | Raph Levien <raph@src.gnome.org> | 2000-09-07 00:47:57 +0000 |
commit | 5aab9e79f067deb7f1264d91caa5ffab742358ba (patch) | |
tree | 30a8ee2d9e9fc5cb481106599ec11f91c836397d /librsvg | |
parent | c93ace12256e214dde62573a481d09de61212b93 (diff) | |
download | nautilus-5aab9e79f067deb7f1264d91caa5ffab742358ba.tar.gz |
Glyph cache evicts glyphs when full. Some mem leaks cleaned up.
Diffstat (limited to 'librsvg')
-rw-r--r-- | librsvg/rsvg-ft.c | 94 | ||||
-rw-r--r-- | librsvg/test-ft-gtk.c | 9 |
2 files changed, 99 insertions, 4 deletions
diff --git a/librsvg/rsvg-ft.c b/librsvg/rsvg-ft.c index 35d42dd75..09548b48d 100644 --- a/librsvg/rsvg-ft.c +++ b/librsvg/rsvg-ft.c @@ -50,6 +50,8 @@ typedef struct _RsvgFTFontCacheEntry RsvgFTFontCacheEntry; typedef struct _RsvgFTGlyphDesc RsvgFTGlyphDesc; typedef struct _RsvgFTGlyphCacheEntry RsvgFTGlyphCacheEntry; +#define SUBPIXEL_FRACTION 4 + struct _RsvgFTCtx { FT_Library ftlib; @@ -97,6 +99,7 @@ struct _RsvgFTGlyphCacheEntry { RsvgFTGlyphCacheEntry *prev, *next; /* for lru list */ int x0, y0; /* relative to affine */ RsvgFTGlyph *glyph; + RsvgFTGlyphDesc *desc; }; /* Glyph cache fun stuff */ @@ -163,6 +166,63 @@ rsvg_ft_glyph_lookup (RsvgFTCtx *ctx, const RsvgFTGlyphDesc *desc, } /** + * rsvg_ft_glyph_bytes: Determine the number of bytes in a glyph. + * @glyph: Glyph. + * + * Determines the number of bytes used by @glyph, for the purposes of + * caching. Note: I'm not counting malloc overhead. Maybe I should. + * + * Return value: Number of bytes used by glyph. + **/ +static int +rsvg_ft_glyph_bytes (RsvgFTGlyph *glyph) +{ + return glyph->rowstride * glyph->height + sizeof (RsvgFTGlyph); +} + +/** + * rsvg_gt_glyph_evict: Evict lru glyph from glyph cache. + * @ctx: The RsvgFT context. + * + * Chooses the least recently used glyph that without a refcount, and + * evicts it. + * + * Return value: true if a glyph was successfully evicted. + **/ +static gboolean +rsvg_ft_glyph_evict (RsvgFTCtx *ctx) +{ + RsvgFTGlyphCacheEntry *victim; + RsvgFTGlyph *glyph; + + for (victim = ctx->glyph_last; victim != NULL; victim = victim->prev) + if (victim->glyph->refcnt == 1) + break; + + if (victim == NULL) + return FALSE; + + if (victim->prev != NULL) + victim->prev->next = victim->next; + else + ctx->glyph_first = victim->next; + if (victim->next != NULL) + victim->next->prev = victim->prev; + else + ctx->glyph_last = victim->prev; + + glyph = victim->glyph; + ctx->glyph_bytes -= rsvg_ft_glyph_bytes (glyph); + rsvg_ft_glyph_unref (glyph); + + g_hash_table_remove (ctx->glyph_hash_table, victim->desc); + g_free (victim->desc); + g_free (victim); + + return TRUE; +} + +/** * rsvg_ft_glyph_insert: Insert a glyph into the glyph cache. * @ctx: The RsvgFT context. * @desc: Glyph descriptor. @@ -181,7 +241,16 @@ rsvg_ft_glyph_insert (RsvgFTCtx *ctx, const RsvgFTGlyphDesc *desc, RsvgFTGlyphDesc *new_desc; RsvgFTGlyphCacheEntry *entry; - /* todo: check for full cache and evict if so */ + ctx->glyph_bytes += rsvg_ft_glyph_bytes (glyph); + + /* check for full cache and evict if so */ + while (ctx->glyph_bytes > ctx->glyph_bytes_max) { + if (!rsvg_ft_glyph_evict (ctx)) { + g_warning ("rsvg_ft_glyph_insert: unable to free any glyph cache entry, suggesting resource leak."); + break; + } + } + new_desc = g_new (RsvgFTGlyphDesc, 1); memcpy (new_desc, desc, sizeof (RsvgFTGlyphDesc)); entry = g_new (RsvgFTGlyphCacheEntry, 1); @@ -194,6 +263,7 @@ rsvg_ft_glyph_insert (RsvgFTCtx *ctx, const RsvgFTGlyphDesc *desc, } ctx->glyph_first = entry; entry->glyph = glyph; + entry->desc = new_desc; entry->x0 = x0; entry->y0 = y0; g_hash_table_insert (ctx->glyph_hash_table, new_desc, entry); @@ -231,7 +301,9 @@ rsvg_ft_ctx_new (void) { void rsvg_ft_ctx_done (RsvgFTCtx *ctx) { int i; + RsvgFTGlyphCacheEntry *glyph_ce, *next; + g_hash_table_destroy (ctx->font_hash_table); for (i = 0; i < ctx->n_font_list; i++) { RsvgFTFontCacheEntry *entry = ctx->font_list[i]; RsvgFTFont *font = entry->font; @@ -243,6 +315,17 @@ rsvg_ft_ctx_done (RsvgFTCtx *ctx) { } } g_free (ctx->font_list); + + /* Free glyph cache. */ + g_hash_table_destroy (ctx->glyph_hash_table); + for (glyph_ce = ctx->glyph_first; glyph_ce != NULL; glyph_ce = next) { + free (glyph_ce->desc); + free (glyph_ce->glyph->buf); + free (glyph_ce->glyph); + next = glyph_ce->next; + free (glyph_ce); + } + FT_Done_FreeType (ctx->ftlib); g_free (ctx); } @@ -581,7 +664,7 @@ rsvg_ft_get_glyph_cached (RsvgFTCtx *ctx, RsvgFTFontHandle fh, desc.char_width = floor (sx * 64 + 0.5); desc.char_height = floor (sy * 64 + 0.5); desc.glyph_index = glyph_ix; - x_sp = floor (4 * (affine[4] - floor (affine[4]))); + x_sp = floor (SUBPIXEL_FRACTION * (affine[4] - floor (affine[4]))); desc.x_subpixel = x_sp; desc.y_subpixel = 0; #ifdef VERBOSE @@ -591,8 +674,13 @@ rsvg_ft_get_glyph_cached (RsvgFTCtx *ctx, RsvgFTFontHandle fh, result = rsvg_ft_glyph_lookup (ctx, &desc, xy); if (result == NULL) { int x0, y0; + double my_affine[6]; + + memcpy (my_affine, affine, sizeof(my_affine)); + my_affine[4] = floor (affine[4]) + + (1.0 / SUBPIXEL_FRACTION) * x_sp; font = rsvg_ft_font_resolve (ctx, fh); - result = rsvg_ft_get_glyph (font, glyph_ix, sx, sy, affine, xy); + result = rsvg_ft_get_glyph (font, glyph_ix, sx, sy, my_affine, xy); if (result == NULL) return NULL; x0 = xy[0] - floor (affine[4]); diff --git a/librsvg/test-ft-gtk.c b/librsvg/test-ft-gtk.c index d0605a443..7c32c9cb4 100644 --- a/librsvg/test-ft-gtk.c +++ b/librsvg/test-ft-gtk.c @@ -300,6 +300,13 @@ start_scrolling (GtkWidget *widget, TestCtx *ctx) gtk_label_set_text (GTK_LABEL (ctx->status), "Scrolling..."); } +static void +test_ft_quit (GtkWidget *widget, TestCtx *ctx) +{ + rsvg_ft_ctx_done (ctx->ctx); + gtk_main_quit (); +} + static TestCtx *new_test_window (const char *fn, int width, int height) { GtkWidget *topwin; @@ -313,7 +320,7 @@ static TestCtx *new_test_window (const char *fn, int width, int height) topwin = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_signal_connect (GTK_OBJECT (topwin), "destroy", - (GtkSignalFunc) gtk_main_quit, NULL); + (GtkSignalFunc) test_ft_quit, ctx); vbox = gtk_vbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (topwin), vbox); |