changeset 17270:ba865ea9c7e9

Add simple FreeType font cache in class ft_manager. * libinterp/corefcn/txt-eng-ft.cc (ft_face_destroyed): New static function. (ft_manager::font_destroyed): New static method. (ft_manager::do_font_destroyed): New method. (ft_manager::ft_key, ft_manager::ft_cache): New typedef's. (ft_manager::cache): New member, storing weak references to loaded fonts. (ft_manager::do_get_font): Look for font into the cache. Use fontconfig and freetype if not found. Insert newly loaded fonts into the cache. Install finalizer to update the cache on font destruction.
author Michael Goffioul <michael.goffioul@gmail.com>
date Sun, 18 Aug 2013 16:36:41 -0400
parents 5b088598df1d
children cb7233cfbf43
files libinterp/corefcn/txt-eng-ft.cc
diffstat 1 files changed, 66 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/txt-eng-ft.cc	Sun Aug 18 16:36:38 2013 -0400
+++ b/libinterp/corefcn/txt-eng-ft.cc	Sun Aug 18 16:36:41 2013 -0400
@@ -31,6 +31,8 @@
 #endif
 
 #include <iostream>
+#include <map>
+#include <utility>
 
 #include "singleton-cleanup.h"
 
@@ -65,6 +67,9 @@
 #include "PermMatrix.h"
 #endif
 
+// Forward declaration
+static void ft_face_destroyed (void* object);
+
 class
 ft_manager
 {
@@ -99,10 +104,24 @@
               ? instance->do_get_font (name, weight, angle, size)
               : 0); }
 
+  static void font_destroyed (FT_Face face)
+    {
+      if (instance_ok ())
+        instance->do_font_destroyed (face);
+    }
+
 private:
 
   static ft_manager *instance;
 
+  typedef std::pair<std::string, double> ft_key;
+  typedef std::map<ft_key, FT_Face> ft_cache;
+
+  // Cache the fonts loaded by freetype. This cache only contains
+  // weak references to the fonts, strong references are only present
+  // in class ft_render.
+  ft_cache cache;
+
 private:
 
   // No copying!
@@ -149,6 +168,18 @@
     {
       FT_Face retval = 0;
 
+      // Look first into the font cache, then use fontconfig. If the font
+      // is present in the cache, simply add a reference and return it.
+
+      ft_key key (name + ":" + weight + ":" + angle, size);
+      ft_cache::const_iterator it = cache.find (key);
+
+      if (it != cache.end ())
+        {
+          FT_Reference_Face (it->second);
+          return it->second;
+        }
+
       std::string file;
 
 #if defined (HAVE_FONTCONFIG)
@@ -221,12 +252,41 @@
 #endif
         }
 
-      if (! file.empty () && FT_New_Face (library, file.c_str (), 0, &retval))
-        ::warning ("ft_manager: unable to load font: %s", file.c_str ());
+      if (! file.empty ())
+        {
+          if (FT_New_Face (library, file.c_str (), 0, &retval))
+            ::warning ("ft_manager: unable to load font: %s", file.c_str ());
+          else
+            {
+              // Install a finalizer to notify ft_manager that the font is
+              // being destroyed. The class ft_manager only keeps weak
+              // references to font objects.
+
+              retval->generic.data = new ft_key (key);
+              retval->generic.finalizer = ft_face_destroyed;
+
+              // Insert loaded font into the cache.
+
+              cache[key] = retval;
+            }
+        }
 
       return retval;
     }
 
+  void do_font_destroyed (FT_Face face)
+    {
+      if (face->generic.data)
+        {
+          ft_key* pkey =
+            reinterpret_cast<ft_key*> (face->generic.data);
+
+          cache.erase (*pkey);
+          delete pkey;
+          face->generic.data = 0;
+        }
+    }
+
 private:
   FT_Library library;
   bool freetype_initialized;
@@ -235,6 +295,10 @@
 
 ft_manager* ft_manager::instance = 0;
 
+static void
+ft_face_destroyed (void* object)
+{ ft_manager::font_destroyed (reinterpret_cast<FT_Face> (object)); }
+
 // ---------------------------------------------------------------------------
 
 ft_render::ft_render (void)