summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaph Levien <raph@src.gnome.org>2000-09-08 07:52:22 +0000
committerRaph Levien <raph@src.gnome.org>2000-09-08 07:52:22 +0000
commit013bec11dbb7387dd7e03b96356372d08d17576a (patch)
tree372dccbfa0653fc0ba653d5805ddf8594f1c5018
parentfc0cba87318420992ac0982f77f255d81872b31c (diff)
downloadnautilus-013bec11dbb7387dd7e03b96356372d08d17576a.tar.gz
Implementation of font cache eviction, so font cache is now bounded in size.
-rw-r--r--librsvg/rsvg-ft.c137
1 files changed, 100 insertions, 37 deletions
diff --git a/librsvg/rsvg-ft.c b/librsvg/rsvg-ft.c
index bc6566963..97adc78a7 100644
--- a/librsvg/rsvg-ft.c
+++ b/librsvg/rsvg-ft.c
@@ -57,6 +57,22 @@ struct _RsvgFTCtx {
GHashTable *font_hash_table; /* map filename to RsvgFTFontCacheEntry */
+ /* Notes on the font list:
+
+ There is a font list entry for each font that is "intern"ed.
+ This entry persists for the life of the RsvgFTCtx structure.
+ These entry correspond one-to-one with font handles, which
+ begin at 0 and allocate upwards.
+
+ Each entry in the font list may be either loaded or not, as
+ indicated by the non-NULL status of the font element of the
+ RsvgFTFontCacheEntry.
+
+ The lru list (first and last pointers here, prev and next
+ pointers in the RsvgFTFontCacheEntry) contains only loaded
+ fonts. This should be considered an invariant.
+ */
+
int n_font_list;
RsvgFTFontCacheEntry **font_list;
RsvgFTFontCacheEntry *first, *last;
@@ -313,6 +329,7 @@ rsvg_ft_ctx_done (RsvgFTCtx *ctx) {
FT_Done_Face (font->face);
g_free (font);
}
+ g_free (entry);
}
g_free (ctx->font_list);
@@ -374,25 +391,7 @@ rsvg_ft_intern (RsvgFTCtx *ctx, const char *font_file_name)
RsvgFTFontCacheEntry *entry;
entry = g_hash_table_lookup (ctx->font_hash_table, font_file_name);
- if (entry != NULL) {
- /* found in font list */
-
- /* todo: I think moving the font to the front of the
- lru list should happen on resolve, not intern */
- /* move entry to front of LRU list */
- if (entry->prev != NULL) {
- entry->prev->next = entry->next;
- if (entry->next != NULL) {
- entry->next->prev = entry->prev;
- } else {
- ctx->last = entry->prev;
- }
- entry->prev = NULL;
- entry->next = ctx->first;
- ctx->first->prev = entry;
- ctx->first = entry;
- }
- } else {
+ if (entry == NULL) {
/* not found in font list */
int n_font_list;
@@ -403,12 +402,7 @@ rsvg_ft_intern (RsvgFTCtx *ctx, const char *font_file_name)
entry->handle = n_font_list;
entry->font = NULL;
entry->prev = NULL;
- entry->next = ctx->first;
- if (ctx->first != NULL)
- ctx->first->prev = entry;
- else
- ctx->last = entry;
- ctx->first = entry;
+ entry->next = NULL;
if (n_font_list == 0) {
ctx->font_list = g_new (RsvgFTFontCacheEntry *, 1);
} else if (!(n_font_list & (n_font_list - 1))) {
@@ -454,6 +448,53 @@ rsvg_ft_font_attach (RsvgFTCtx *ctx, RsvgFTFontHandle fh,
}
/**
+ * rsvg_ft_font_evict: Evict least recently used font from font cache.
+ * @ctx: Rsvg FT context.
+ *
+ * Removes the least recently used font from the font cache.
+ **/
+static void
+rsvg_ft_font_evict (RsvgFTCtx *ctx)
+{
+ RsvgFTFontCacheEntry *victim;
+ RsvgFTFont *font;
+
+#ifdef DEBUG
+ g_print ("rsvg_ft_font_evict: evicting!\n");
+#endif
+
+ victim = ctx->last;
+ if (victim == NULL) {
+ /* We definitely shouldn't get here, but if we do,
+ print an error message that helps explain why we
+ did. */
+ if (ctx->n_loaded_fonts > 0) {
+ g_error ("rsvg_ft_font_evict: no font in loaded font list to evict, but ctx->n_loaded_fonts = %d, internal invariant violated",
+ ctx->n_loaded_fonts);
+ } else {
+ g_error ("rsvg_ft_font_evict: ctx->n_loaded_fonts_max = %d, it must be positive",
+ ctx->n_loaded_fonts_max);
+ }
+ }
+
+ if (victim->prev == NULL)
+ ctx->first = NULL;
+ else
+ victim->prev->next = NULL;
+ if (victim->next != NULL) {
+ g_warning ("rsvg_ft_font_evict: last font in LRU font list has non-NULL next field, suggesting corruption of data structure");
+ }
+ ctx->last = victim->prev;
+
+ font = victim->font;
+ FT_Done_Face (font->face);
+ g_free (font);
+ victim->font = NULL;
+
+ ctx->n_loaded_fonts--;
+}
+
+/**
* rsvg_ft_font_resolve: Resolve a font handle.
* @ctx: Rsvg FT context.
* @fh: Font handle.
@@ -474,23 +515,46 @@ rsvg_ft_font_resolve (RsvgFTCtx *ctx, RsvgFTFontHandle fh)
return NULL;
entry = ctx->font_list[fh];
if (entry->font == NULL) {
- ctx->n_loaded_fonts++;
- while (ctx->n_loaded_fonts > ctx->n_loaded_fonts_max) {
- /* todo: evict lru */
- break;
+ while (ctx->n_loaded_fonts >= ctx->n_loaded_fonts_max) {
+ rsvg_ft_font_evict (ctx);
}
font = rsvg_ft_load (ctx, entry->fn);
- if (entry->fn_attached != NULL) {
- FT_Error error;
+ if (font != NULL) {
+ if (entry->fn_attached != NULL) {
+ FT_Error error;
+
+ error = FT_Attach_File (font->face,
+ entry->fn_attached);
+ }
+ entry->font = font;
+ ctx->n_loaded_fonts++;
- error = FT_Attach_File (font->face,
- entry->fn_attached);
+ /* insert entry at front of list */
+ entry->next = ctx->first;
+ if (ctx->first != NULL)
+ ctx->first->prev = entry;
+ else
+ ctx->last = entry;
+ ctx->first = entry;
}
- entry->font = font;
- }
- else {
+ } else {
font = entry->font;
+
+ /* move entry to front of LRU list */
+ if (entry->prev != NULL) {
+ entry->prev->next = entry->next;
+ if (entry->next != NULL) {
+ entry->next->prev = entry->prev;
+ } else {
+ ctx->last = entry->prev;
+ }
+ entry->prev = NULL;
+ entry->next = ctx->first;
+ ctx->first->prev = entry;
+ ctx->first = entry;
+ }
}
+
return font;
}
@@ -867,4 +931,3 @@ rsvg_ft_glyph_unref (RsvgFTGlyph *glyph)
g_free (glyph);
}
}
-