* Evas: Improve RGBA_Font_* cache using hash and stringshare correctly.
authorcedric <cedric@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Mon, 15 Jun 2009 15:07:13 +0000 (15:07 +0000)
committercedric <cedric@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Mon, 15 Jun 2009 15:07:13 +0000 (15:07 +0000)
Note: This should not impact font rendering, but if you notice anything
wrong, please don't hesitate to report this to me.

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/evas@41050 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/lib/engines/common/evas_font.h
src/lib/engines/common/evas_font_load.c
src/lib/engines/common/evas_font_main.c
src/lib/include/evas_common.h

index c27a348..0eb3b41 100644 (file)
@@ -68,4 +68,7 @@ EAPI int               evas_common_font_query_char_coords    (RGBA_Font *fn, con
 EAPI int               evas_common_font_query_text_at_pos    (RGBA_Font *fn, const char *text, int x, int y, int *cx, int *cy, int *cw, int *ch);
 EAPI int               evas_common_font_query_last_up_to_pos (RGBA_Font *fn, const char *text, int x, int y);
 
+void evas_common_font_load_init(void);
+void evas_common_font_load_shutdown(void);
+
 #endif /* _EVAS_FONT_H */
index c57a1d1..5cedcc9 100644 (file)
 #include "evas_common.h"
 #include "evas_private.h"
 
+#include <assert.h>
+
 extern FT_Library         evas_ft_lib;
 
 static int                font_cache_usage = 0;
 static int                font_cache = 0;
-static Eina_Inlist * fonts_src = NULL;
-static Eina_Inlist * fonts = NULL;
+
+static Eina_Hash * fonts_src = NULL;
+static Eina_Hash * fonts = NULL;
+static Eina_List * fonts_lru = NULL;
 
 static Evas_Bool font_modify_cache_cb(const Eina_Hash *hash, const void *key, void *data, void *fdata);
 static Evas_Bool font_flush_free_glyph_cb(const Eina_Hash *hash, const void *key, void *data, void *fdata);
 
+static unsigned int
+_evas_font_cache_int_length(const RGBA_Font_Int *key)
+{
+   return 0;
+}
+
+static int
+_evas_font_cache_int_cmp(const RGBA_Font_Int *k1, int k1_length,
+                        const RGBA_Font_Int *k2, int k2_length)
+{
+   /* RGBA_Font_Source->name is a stringshare */
+   if (k1->src->name == k2->src->name)
+     return k1->size - k2->size;
+   return strcmp(k1->src->name, k2->src->name);;
+}
+
+static int
+_evas_font_cache_int_hash(const RGBA_Font_Int *key, int key_length)
+{
+   int hash;
+
+   hash = eina_hash_djb2(key->src->name, eina_stringshare_strlen(key->src->name) + 1);
+   hash ^= eina_hash_int32(&key->size, sizeof (int));
+
+   return hash;
+}
+
+static void
+_evas_common_font_source_free(RGBA_Font_Source *fs)
+{
+   FT_Done_Face(fs->ft.face);
+   if (fs->charmap) evas_array_hash_free(fs->charmap);
+   if (fs->name) eina_stringshare_del(fs->name);
+   free(fs);
+}
+
+
+static Eina_Bool
+font_flush_free_glyph_cb(const Eina_Hash *hash, const void *key, void *data, void *fdata)
+{
+   RGBA_Font_Glyph *fg;
+
+   fg = data;
+   FT_Done_Glyph(fg->glyph);
+   /* extension calls */
+   if (fg->ext_dat_free) fg->ext_dat_free(fg->ext_dat);
+   free(fg);
+   return 1;
+   hash = 0;
+   key = 0;
+   fdata = 0;
+}
+
+static void
+_evas_common_font_int_free(RGBA_Font_Int *fi)
+{
+   FT_Done_Size(fi->ft.size);
+
+   evas_common_font_int_modify_cache_by(fi, -1);
+
+   eina_hash_foreach(fi->glyphs, font_flush_free_glyph_cb, NULL);
+   eina_hash_free(fi->glyphs);
+
+   eina_hash_free(fi->kerning);
+   eina_hash_free(fi->indexes);
+
+#ifdef HAVE_PTHREAD
+   pthread_mutex_destroy(&fi->ft_mutex);
+#endif
+
+   evas_common_font_source_free(fi->src);
+
+   if (fi->references == 0)
+     fonts_lru = eina_list_remove(fonts_lru, fi);
+
+   free(fi);
+}
+
+void
+evas_common_font_load_init(void)
+{
+   fonts_src = eina_hash_string_small_new(EINA_FREE_CB(_evas_common_font_source_free));
+   fonts = eina_hash_new(EINA_KEY_LENGTH(_evas_font_cache_int_length),
+                        EINA_KEY_CMP(_evas_font_cache_int_cmp),
+                        EINA_KEY_HASH(_evas_font_cache_int_hash),
+                        EINA_FREE_CB(_evas_common_font_int_free),
+                        5);
+}
+
+void
+evas_common_font_load_shutdown(void)
+{
+   eina_hash_free(fonts);
+   fonts = NULL;
+
+   eina_hash_free(fonts_src);
+   fonts_src = NULL;
+}
+
 EAPI RGBA_Font_Source *
 evas_common_font_source_memory_load(const char *name, const void *data, int data_size)
 {
    int error;
    RGBA_Font_Source *fs;
 
+   assert(name != NULL);
+
    fs = calloc(1, sizeof(RGBA_Font_Source) + data_size);
    if (!fs) return NULL;
    fs->data = ((unsigned char *)fs) + sizeof(RGBA_Font_Source);
@@ -38,7 +143,8 @@ evas_common_font_source_memory_load(const char *name, const void *data, int data
    error = FT_Select_Charmap(fs->ft.face, ft_encoding_unicode);
    fs->ft.orig_upem = fs->ft.face->units_per_EM;
    fs->references = 1;
-   fonts_src = eina_inlist_prepend(fonts_src, EINA_INLIST_GET(fs));
+
+   eina_hash_direct_add(fonts_src, fs->name, fs);
    return fs;
 }
 
@@ -47,6 +153,8 @@ evas_common_font_source_load(const char *name)
 {
    RGBA_Font_Source *fs;
 
+   assert(name != NULL);
+
    fs = calloc(1, sizeof(RGBA_Font_Source));
    if (!fs) return NULL;
    fs->data = NULL;
@@ -60,7 +168,8 @@ evas_common_font_source_load(const char *name)
    fs->ft.orig_upem = 0;
 
    fs->references = 1;
-   fonts_src = eina_inlist_prepend(fonts_src, EINA_INLIST_GET(fs));
+
+   eina_hash_direct_add(fonts_src, fs->name, fs);
    return fs;
 }
 
@@ -94,14 +203,11 @@ evas_common_font_source_find(const char *name)
    RGBA_Font_Source *fs;
 
    if (!name) return NULL;
-   EINA_INLIST_FOREACH(fonts_src, fs)
+   fs = eina_hash_find(fonts_src, name);
+   if (fs)
      {
-       if ((fs->name) && (!strcmp(name, fs->name)))
-         {
-            fs->references++;
-            fonts_src = eina_inlist_demote(fonts_src, EINA_INLIST_GET(fs));
-            return fs;
-         }
+       fs->references++;
+       return fs;
      }
    return NULL;
 }
@@ -112,24 +218,17 @@ evas_common_font_source_free(RGBA_Font_Source *fs)
    fs->references--;
    if (fs->references > 0) return;
 
-   fonts_src = eina_inlist_remove(fonts_src, EINA_INLIST_GET(fs));
-   FT_Done_Face(fs->ft.face);
-   if (fs->charmap) evas_array_hash_free(fs->charmap);
-   if (fs->name) eina_stringshare_del(fs->name);
-   free(fs);
+   eina_hash_del(fonts_src, fs->name, fs);
 }
 
 EAPI void
 evas_common_font_size_use(RGBA_Font *fn)
 {
+   RGBA_Font_Int *fi;
    Eina_List *l;
 
-   for (l = fn->fonts; l; l = l->next)
+   EINA_LIST_FOREACH(fn->fonts, l, fi)
      {
-       RGBA_Font_Int *fi;
-
-       fi = l->data;
-
        if (fi->src->current_size != fi->size)
          {
             FT_Activate_Size(fi->ft.size);
@@ -178,7 +277,7 @@ _evas_common_font_double_int_hash(const unsigned int key[2], int key_length)
 }
 
 static void
-_evas_commont_font_int_cache_init(RGBA_Font_Int *fi)
+_evas_common_font_int_cache_init(RGBA_Font_Int *fi)
 {
    /* Add some font kerning cache. */
    fi->indexes = eina_hash_new(EINA_KEY_LENGTH(_evas_common_font_int_length),
@@ -194,7 +293,6 @@ _evas_commont_font_int_cache_init(RGBA_Font_Int *fi)
 #endif
 }
 
-
 EAPI RGBA_Font_Int *
 evas_common_font_int_memory_load(const char *name, int size, const void *data, int data_size)
 {
@@ -218,7 +316,7 @@ evas_common_font_int_memory_load(const char *name, int size, const void *data, i
 
    fi->size = size;
 
-   _evas_commont_font_int_cache_init(fi);
+   _evas_common_font_int_cache_init(fi);
 
    fi = evas_common_font_int_load_init(fi);
    evas_common_font_int_load_complete(fi);
@@ -249,7 +347,7 @@ evas_common_font_int_load(const char *name, int size)
 
    fi->size = size;
 
-   _evas_commont_font_int_cache_init(fi);
+   _evas_common_font_int_cache_init(fi);
 
    return evas_common_font_int_load_init(fi);
 }
@@ -261,7 +359,8 @@ evas_common_font_int_load_init(RGBA_Font_Int *fi)
    fi->glyphs = eina_hash_int32_new(NULL);
    fi->usage = 0;
    fi->references = 1;
-   fonts = eina_inlist_prepend(fonts, EINA_INLIST_GET(fi));
+
+   eina_hash_direct_add(fonts, fi, fi);
 
    return fi;
 }
@@ -359,6 +458,7 @@ evas_common_font_load(const char *name, int size)
                  fi->references--;
                  if (fi->references == 0)
                    {
+                      fonts_lru = eina_list_prepend(fonts_lru, fi);
                       evas_common_font_int_modify_cache_by(fi, 1);
                       evas_common_font_flush();
                    }
@@ -374,6 +474,7 @@ evas_common_font_load(const char *name, int size)
        fi->references--;
        if (fi->references == 0)
          {
+            fonts_lru = eina_list_prepend(fonts_lru, fi);
             evas_common_font_int_modify_cache_by(fi, 1);
             evas_common_font_flush();
          }
@@ -436,10 +537,11 @@ evas_common_font_free(RGBA_Font *fn)
        fi->references--;
        if (fi->references == 0)
          {
+            fonts_lru = eina_list_append(fonts_lru, fi);
             evas_common_font_int_modify_cache_by(fi, 1);
-            evas_common_font_flush();
          }
      }
+   evas_common_font_flush();
    eina_list_free(fn->fonts);
    LKD(fn->lock);
    free(fn);
@@ -580,71 +682,44 @@ evas_common_font_flush(void)
    while (font_cache_usage > font_cache) evas_common_font_flush_last();
 }
 
-static Eina_Bool
-font_flush_free_glyph_cb(const Eina_Hash *hash, const void *key, void *data, void *fdata)
-{
-   RGBA_Font_Glyph *fg;
-
-   fg = data;
-   FT_Done_Glyph(fg->glyph);
-   /* extension calls */
-   if (fg->ext_dat_free) fg->ext_dat_free(fg->ext_dat);
-   free(fg);
-   return 1;
-   hash = 0;
-   key = 0;
-   fdata = 0;
-}
-
 /* We run this when the cache gets larger than allowed size
  * We check cache size each time a fi->references goes to 0
  * PERFORMS: Find font_int(s) with references == 0 and delete them */
 EAPI void
 evas_common_font_flush_last(void)
 {
-   RGBA_Font_Int *fi_tmp;
    RGBA_Font_Int *fi = NULL;
 
-   EINA_INLIST_FOREACH(fonts, fi_tmp)
-     {
-       if (fi_tmp->references == 0) fi = fi_tmp;
-     }
-   if (!fi) return;
-
-   FT_Done_Size(fi->ft.size);
-
-   fonts = eina_inlist_remove(fonts, EINA_INLIST_GET(fi));
-   evas_common_font_int_modify_cache_by(fi, -1);
-
-   eina_hash_foreach(fi->glyphs, font_flush_free_glyph_cb, NULL);
-   eina_hash_free(fi->glyphs);
-
-   eina_hash_free(fi->kerning);
-   eina_hash_free(fi->indexes);
-
-#ifdef HAVE_PTHREAD
-   pthread_mutex_destroy(&fi->ft_mutex);
-#endif
+   if (!fonts_lru) return ;
 
-   evas_common_font_source_free(fi->src);
+   fi = eina_list_data_get(fonts_lru);
+   fonts_lru = eina_list_remove_list(fonts_lru, fonts_lru);
 
-   free(fi);
+   eina_hash_del(fonts, fi, fi);
 }
 
 EAPI RGBA_Font_Int *
 evas_common_font_int_find(const char *name, int size)
 {
+   RGBA_Font_Int tmp_fi;
+   RGBA_Font_Source tmp_fn;
    RGBA_Font_Int *fi;
 
-   EINA_INLIST_FOREACH(fonts, fi)
+   tmp_fn.name = (char*) eina_stringshare_add(name);
+   tmp_fi.src = &tmp_fn;
+   tmp_fi.size = size;
+
+   fi = eina_hash_find(fonts, &tmp_fi);
+   if (fi)
      {
-       if ((fi->size == size) && (!strcmp(name, fi->src->name)))
+       if (fi->references == 0)
          {
-            if (fi->references == 0) evas_common_font_int_modify_cache_by(fi, -1);
-            fi->references++;
-            fonts = eina_inlist_promote(fonts, EINA_INLIST_GET(fi));
-            return fi;
+            evas_common_font_int_modify_cache_by(fi, -1);
+            fonts_lru = eina_list_remove(fonts_lru, fi);
          }
+       fi->references++;
      }
-   return NULL;
+
+   eina_stringshare_del(tmp_fn.name);
+   return fi;
 }
index c8df596..8c7e0a7 100644 (file)
@@ -20,6 +20,7 @@ evas_common_font_init(void)
        initialised--;
        return;
      }
+   evas_common_font_load_init();
 }
 
 EAPI void
@@ -30,6 +31,7 @@ evas_common_font_shutdown(void)
    initialised--;
    if (initialised != 0) return;
 
+   evas_common_font_load_shutdown();
    evas_common_font_cache_set(0);
    evas_common_font_flush();
 
index c80f87c..b083140 100644 (file)
@@ -800,8 +800,6 @@ struct _RGBA_Font
 
 struct _RGBA_Font_Int
 {
-   EINA_INLIST;
-
    RGBA_Font_Source *src;
 
    int               size;
@@ -814,7 +812,7 @@ struct _RGBA_Font_Int
    Eina_Hash       *glyphs;
 
    LK(ft_mutex);
-   
+
    Eina_Hash       *kerning;
    Eina_Hash       *indexes;
 
@@ -822,12 +820,11 @@ struct _RGBA_Font_Int
    Font_Hint_Flags hinting;
 
    int              references;
+
 };
 
 struct _RGBA_Font_Source
 {
-   EINA_INLIST;
-
    const char       *name;
    const char       *file;