[vlc-commits] fontconfig: keep track of, and free, our configuration

Rémi Denis-Courmont git at videolan.org
Mon Mar 27 19:51:05 CEST 2017


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Mon Mar 27 20:20:07 2017 +0300| [f564aefb18482b2aa3e46a8b6c333e13fb4c2a81] | committer: Rémi Denis-Courmont

fontconfig: keep track of, and free, our configuration

Inspite of claims to the contrary in fontconfig 2.11 changes log,
FontConfig is really not thread-safe, since it uses atomic pointers
instead of proper reference counting. Consequently, LibVLC cannot
safely call FcFini() - it could crash another thread using FontConfig
concurrently.

Using our own configuration has the benefit of not leaking related
memory allocations, though it means that the LibVLC text renderer
cannot share the configuration with other components in the same
process.

Note that there are still leaks within FontConfig. Specifically, the
cache and the language/program default values are not freed, since that
would require FcFini(). If you care in your application, call FcFini()
after you have terminated all LibVLC instances.

Refs #16023.

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=f564aefb18482b2aa3e46a8b6c333e13fb4c2a81
---

 modules/text_renderer/freetype/fonts/fontconfig.c | 61 ++++++++++++++++-------
 modules/text_renderer/freetype/freetype.c         | 13 ++++-
 modules/text_renderer/freetype/platform_fonts.h   |  1 +
 3 files changed, 56 insertions(+), 19 deletions(-)

diff --git a/modules/text_renderer/freetype/fonts/fontconfig.c b/modules/text_renderer/freetype/fonts/fontconfig.c
index fe097d0..489d67d 100644
--- a/modules/text_renderer/freetype/fonts/fontconfig.c
+++ b/modules/text_renderer/freetype/fonts/fontconfig.c
@@ -34,6 +34,9 @@
 # include "config.h"
 #endif
 
+#include <assert.h>
+#include <stdint.h>
+
 #include <vlc_common.h>
 #include <vlc_filter.h>                     /* filter_sys_t */
 #include <vlc_dialog.h>                     /* FcCache dialog */
@@ -42,24 +45,35 @@
 
 #include "../platform_fonts.h"
 
+static FcConfig *config;
+static uintptr_t refs;
+static vlc_mutex_t lock = VLC_STATIC_MUTEX;
+
 int FontConfig_Prepare( filter_t *p_filter )
 {
-    /* */
+    mtime_t ts;
+
+    vlc_mutex_lock( &lock );
+    if( refs++ > 0 )
+    {
+        vlc_mutex_unlock( &lock );
+        return VLC_SUCCESS;
+    }
+
     msg_Dbg( p_filter, "Building font databases.");
-    mtime_t t1, t2;
-    t1 = mdate();
+    ts = mdate();
 
-#ifdef __OS2__
-    FcInit();
-#endif
+#ifndef _WIN32
+    config = FcInitLoadConfigAndFonts();
+    if( unlikely(config == NULL) )
+        refs = 0;
 
-#if defined( _WIN32 )
-    int i_ret;
+#else
     unsigned int i_dialog_id = 0;
     dialog_progress_bar_t *p_dialog = NULL;
-    FcConfig *fcConfig = FcInitLoadConfig();
+    config = FcInitLoadConfig();
 
-    i_ret =
+    int i_ret =
         vlc_dialog_display_progress( p_filter, true, 0.0, NULL,
                                      _("Building font cache"),
                                      _("Please wait while your font cache is rebuilt.\n"
@@ -67,15 +81,29 @@ int FontConfig_Prepare( filter_t *p_filter )
 
     i_dialog_id = i_ret > 0 ? i_ret : 0;
 
-    if( FcConfigBuildFonts( fcConfig ) == FcFalse )
+    if( FcConfigBuildFonts( config ) == FcFalse )
         return VLC_ENOMEM;
 
     if( i_dialog_id != 0 )
         vlc_dialog_cancel( p_filter, i_dialog_id );
+
 #endif
-    t2 = mdate();
-    msg_Dbg( p_filter, "Took %ld microseconds", (long)((t2 - t1)) );
-    return VLC_SUCCESS;
+
+    vlc_mutex_unlock( &lock );
+    ts -= mdate();
+    msg_Dbg( p_filter, "Took %ld microseconds", (long)ts );
+
+    return (config != NULL) ? VLC_SUCCESS : VLC_EGENERIC;
+}
+
+void FontConfig_Unprepare(void)
+{
+    vlc_mutex_lock( &lock );
+    assert( refs > 0 );
+    if( --refs == 0 )
+        FcConfigDestroy( config );
+
+    vlc_mutex_unlock( &lock );
 }
 
 const vlc_family_t *FontConfig_GetFamily( filter_t *p_filter, const char *psz_family )
@@ -114,7 +142,6 @@ const vlc_family_t *FontConfig_GetFamily( filter_t *p_filter, const char *psz_fa
         FcChar8* val_s;
         FcBool val_b;
         char *psz_fontfile = NULL;
-        FcConfig* config = NULL;
 
         /* Create a pattern and fill it */
         pat = FcPatternCreate();
@@ -201,11 +228,11 @@ vlc_family_t *FontConfig_GetFallbacks( filter_t *p_filter, const char *psz_famil
     family.type = FcTypeString;
     family.u.s = ( const FcChar8* ) psz_family;
     FcPatternAdd( p_pattern, FC_FAMILY, family, FcFalse );
-    if( FcConfigSubstitute( NULL, p_pattern, FcMatchPattern ) == FcTrue )
+    if( FcConfigSubstitute( config, p_pattern, FcMatchPattern ) == FcTrue )
     {
         FcDefaultSubstitute( p_pattern );
         FcResult result;
-        FcFontSet* p_font_set = FcFontSort( NULL, p_pattern, FcTrue, NULL, &result );
+        FcFontSet* p_font_set = FcFontSort( config, p_pattern, FcTrue, NULL, &result );
         if( p_font_set )
         {
             for( int i = 0; i < p_font_set->nfont; ++i )
diff --git a/modules/text_renderer/freetype/freetype.c b/modules/text_renderer/freetype/freetype.c
index 76a60fe..582eb5d 100644
--- a/modules/text_renderer/freetype/freetype.c
+++ b/modules/text_renderer/freetype/freetype.c
@@ -1266,7 +1266,9 @@ static int Create( vlc_object_t *p_this )
     p_sys->pf_select = Generic_Select;
     p_sys->pf_get_family = FontConfig_GetFamily;
     p_sys->pf_get_fallbacks = FontConfig_GetFallbacks;
-    FontConfig_Prepare( p_filter );
+    if( FontConfig_Prepare( p_filter ) )
+        goto error;
+
 #elif defined( __APPLE__ )
     p_sys->pf_select = Generic_Select;
     p_sys->pf_get_family = CoreText_GetFamily;
@@ -1308,6 +1310,9 @@ static int Create( vlc_object_t *p_this )
     if( !p_sys->p_face )
     {
         msg_Err( p_filter, "Error loading default face" );
+#ifdef HAVE_FONTCONFIG
+        FontConfig_Unprepare();
+#endif
         goto error;
     }
 
@@ -1365,7 +1370,11 @@ static void Destroy( vlc_object_t *p_this )
         free( p_sys->pp_font_attachments );
     }
 
-#if defined( _WIN32 )
+#ifdef HAVE_FONTCONFIG
+    if( p_sys->p_face != NULL )
+        FontConfig_Unprepare();
+
+#elif defined( _WIN32 )
     if( p_sys->pf_get_family == DWrite_GetFamily )
         ReleaseDWrite( p_filter );
 #endif
diff --git a/modules/text_renderer/freetype/platform_fonts.h b/modules/text_renderer/freetype/platform_fonts.h
index 83af800..932f45b 100644
--- a/modules/text_renderer/freetype/platform_fonts.h
+++ b/modules/text_renderer/freetype/platform_fonts.h
@@ -145,6 +145,7 @@ vlc_family_t *FontConfig_GetFallbacks( filter_t *p_filter, const char *psz_famil
                                        uni_char_t codepoint );
 const vlc_family_t *FontConfig_GetFamily( filter_t *p_filter, const char *psz_family );
 int FontConfig_Prepare( filter_t *p_filter );
+void FontConfig_Unprepare( void );
 #endif /* FONTCONFIG */
 
 #if defined( _WIN32 )



More information about the vlc-commits mailing list