# HG changeset patch # User Michael Goffioul # Date 1376858201 14400 # Node ID ba865ea9c7e9ee7a62710491adae92c9d8963122 # Parent 5b088598df1d6aa65f89393ab03e9574a2aa849c 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. diff --git a/libinterp/corefcn/txt-eng-ft.cc b/libinterp/corefcn/txt-eng-ft.cc --- a/libinterp/corefcn/txt-eng-ft.cc +++ b/libinterp/corefcn/txt-eng-ft.cc @@ -31,6 +31,8 @@ #endif #include +#include +#include #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 ft_key; + typedef std::map 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 (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 (object)); } + // --------------------------------------------------------------------------- ft_render::ft_render (void)