[vlc-commits] freetype: change callbacks and use fallback lists

Francois Cartegnie git at videolan.org
Mon Aug 24 17:38:58 CEST 2020


vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Wed Aug  5 11:20:04 2020 +0200| [9d0d3c19692147102c0ee3eef5fb6b6986b3eb35] | committer: Francois Cartegnie

freetype: change callbacks and use fallback lists

Makes use of explicit fallback to make a single
call to fontconfig.

Callbacks now returns error code
as we should be able to cache misses

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

 modules/text_renderer/freetype/fonts/android.c    |  27 ++--
 modules/text_renderer/freetype/fonts/backends.h   |  48 ++++--
 modules/text_renderer/freetype/fonts/darwin.c     |  29 +++-
 modules/text_renderer/freetype/fonts/dwrite.cpp   |  34 ++--
 modules/text_renderer/freetype/fonts/fontconfig.c |  94 +++++++----
 modules/text_renderer/freetype/fonts/win32.c      |  36 +++--
 modules/text_renderer/freetype/freetype.h         |   1 -
 modules/text_renderer/freetype/ftcache.c          |   5 +-
 modules/text_renderer/freetype/lru.c              |  28 +++-
 modules/text_renderer/freetype/lru.h              |   8 +-
 modules/text_renderer/freetype/platform_fonts.c   | 183 +++++++++++++++-------
 modules/text_renderer/freetype/platform_fonts.h   |  14 +-
 12 files changed, 347 insertions(+), 160 deletions(-)

diff --git a/modules/text_renderer/freetype/fonts/android.c b/modules/text_renderer/freetype/fonts/android.c
index a68949519f..d1651ed083 100644
--- a/modules/text_renderer/freetype/fonts/android.c
+++ b/modules/text_renderer/freetype/fonts/android.c
@@ -426,27 +426,24 @@ int Android_Prepare( vlc_font_select_t *fs )
     return VLC_SUCCESS;
 }
 
-const vlc_family_t *Android_GetFamily( vlc_font_select_t *fs, const char *psz_lcname )
+int Android_GetFamily( vlc_font_select_t *fs, const char *psz_lcname,
+                       const vlc_family_t **pp_result )
 {
-    vlc_family_t *p_family =
-            vlc_dictionary_value_for_key( &fs->family_map, psz_lcname );
+    *pp_result = vlc_dictionary_value_for_key( &fs->family_map, psz_lcname );
+    if( *pp_result == kVLCDictionaryNotFound )
+        *pp_result = NULL;
 
-    if( p_family == kVLCDictionaryNotFound )
-        return NULL;
-
-    return p_family;
+    return VLC_SUCCESS;
 }
 
-vlc_family_t *Android_GetFallbacks( vlc_font_select_t *fs, const char *psz_lcname,
-                                    uni_char_t codepoint )
+int Android_GetFallbacks( vlc_font_select_t *fs, const char *psz_lcname,
+                          uni_char_t codepoint, vlc_family_t **pp_result )
 {
     VLC_UNUSED( codepoint );
 
-    vlc_family_t *p_fallbacks =
-                vlc_dictionary_value_for_key( &fs->fallback_map, psz_lcname );
+    *pp_result = vlc_dictionary_value_for_key( &fs->fallback_map, psz_lcname );
+    if( *pp_result == kVLCDictionaryNotFound )
+        *pp_result = NULL;
 
-    if( p_fallbacks == kVLCDictionaryNotFound )
-        return NULL;
-
-    return p_fallbacks;
+    return VLC_SUCCESS;
 }
diff --git a/modules/text_renderer/freetype/fonts/backends.h b/modules/text_renderer/freetype/fonts/backends.h
index 88058b0449..abfc1b1ca5 100644
--- a/modules/text_renderer/freetype/fonts/backends.h
+++ b/modules/text_renderer/freetype/fonts/backends.h
@@ -21,21 +21,32 @@
 extern "C" {
 #endif
 
+#include "../lru.h"
+
 struct vlc_font_select_t
 {
     vlc_object_t *p_obj;
     filter_t *p_filter;
 
-    const vlc_family_t * (*pf_get_family) ( vlc_font_select_t *, const char *psz_family );
+    /* If the callbacks return VLC_SUCCESS, this means the result is valid
+       (can still be no match/NULL), and if not, this is a temp error. */
+    int (*pf_select_family) ( vlc_font_select_t *, const char *psz_family,
+                              const vlc_family_t ** );
+    int (*pf_select_among_families)( vlc_font_select_t *, const fontfamilies_t *,
+                                     const vlc_family_t ** );
 
-    vlc_family_t * (*pf_get_fallbacks) ( vlc_font_select_t *, const char *psz_family,
-                     uni_char_t codepoint );
+    int (*pf_get_fallbacks) ( vlc_font_select_t *, const char *psz_family,
+                              uni_char_t codepoint, vlc_family_t ** );
+    int (*pf_get_fallbacks_among_families) ( vlc_font_select_t *, const fontfamilies_t *,
+                                             uni_char_t codepoint, vlc_family_t ** );
 
     /**
      * This is the master family list. It owns the lists of vlc_font_t's
      * and should be freed using FreeFamiliesAndFonts()
      */
     vlc_family_t      *p_families;
+    /* We need to limit caching of lookups as we do not control the names */
+    vlc_lru           *families_lookup_lru;
 
     /**
      * This maps a family name to a vlc_family_t within the master list
@@ -60,37 +71,40 @@ struct vlc_font_select_t
  * PLATFORM SPECIFIC SELECTORS
  **/
 #ifdef HAVE_FONTCONFIG
-vlc_family_t *FontConfig_GetFallbacks( vlc_font_select_t *, const char *psz_family,
-                                       uni_char_t codepoint );
-const vlc_family_t *FontConfig_GetFamily( vlc_font_select_t *, const char *psz_family );
+int FontConfig_GetFallbacksAmongFamilies( vlc_font_select_t *, const fontfamilies_t *,
+                                          uni_char_t codepoint, vlc_family_t **pp_result );
+int FontConfig_GetFamily( vlc_font_select_t *, const char *psz_family, const vlc_family_t ** );
+int FontConfig_SelectAmongFamilies( vlc_font_select_t *fs, const fontfamilies_t *families,
+                                    const vlc_family_t **pp_result );
 int FontConfig_Prepare( vlc_font_select_t * );
 void FontConfig_Unprepare( vlc_font_select_t * );
 #endif /* FONTCONFIG */
 
 #if defined( _WIN32 )
-const vlc_family_t *DWrite_GetFamily( vlc_font_select_t *, const char *psz_family );
-vlc_family_t *DWrite_GetFallbacks( vlc_font_select_t *, const char *psz_family,
-                                  uni_char_t codepoint );
+int DWrite_GetFamily( vlc_font_select_t *, const char *psz_family, const vlc_family_t ** );
+int DWrite_GetFallbacks( vlc_font_select_t *, const char *psz_family,
+                         uni_char_t codepoint, vlc_family_t ** );
 int InitDWrite( vlc_font_select_t * );
 int ReleaseDWrite( vlc_font_select_t * );
 int DWrite_GetFontStream( vlc_font_select_t *, int i_index, FT_Stream *pp_stream );
 #if !VLC_WINSTORE_APP
-vlc_family_t *Win32_GetFallbacks( vlc_font_select_t *, const char *psz_family,
-                                  uni_char_t codepoint );
+int Win32_GetFallbacks( vlc_font_select_t *, const char *psz_family,
+                        uni_char_t codepoint, vlc_family_t ** );
 
-const vlc_family_t *Win32_GetFamily( vlc_font_select_t *, const char *psz_family );
+int Win32_GetFamily( vlc_font_select_t *, const char *psz_family, const vlc_family_t ** );
 #endif /* !VLC_WINSTORE_APP */
 #endif /* _WIN32 */
 
 #ifdef __APPLE__
-vlc_family_t *CoreText_GetFallbacks(vlc_font_select_t *, const char *psz_family, uni_char_t codepoint);
-const vlc_family_t *CoreText_GetFamily(vlc_font_select_t *, const char *psz_family);
+int CoreText_GetFallbacks(vlc_font_select_t *, const char *psz_family,
+                          uni_char_t codepoint, vlc_family_t **);
+int CoreText_GetFamily(vlc_font_select_t *, const char *psz_family, const vlc_family_t **);
 #endif /* __APPLE__ */
 
 #ifdef __ANDROID__
-const vlc_family_t *Android_GetFamily( vlc_font_select_t *, const char *psz_family );
-vlc_family_t *Android_GetFallbacks( vlc_font_select_t *, const char *psz_family,
-                                    uni_char_t codepoint );
+int Android_GetFamily( vlc_font_select_t *, const char *psz_family, const vlc_family_t ** );
+int Android_GetFallbacks( vlc_font_select_t *, const char *psz_family,
+                          uni_char_t codepoint, vlc_family_t ** );
 int Android_Prepare( vlc_font_select_t * );
 #endif /* __ANDROID__ */
 
diff --git a/modules/text_renderer/freetype/fonts/darwin.c b/modules/text_renderer/freetype/fonts/darwin.c
index 6816192be5..08a9f1c88d 100644
--- a/modules/text_renderer/freetype/fonts/darwin.c
+++ b/modules/text_renderer/freetype/fonts/darwin.c
@@ -159,10 +159,13 @@ static CFComparisonResult SortCTFontMatchResults(CTFontDescriptorRef desc1,
         return kCFCompareGreaterThan;
 }
 
-const vlc_family_t *CoreText_GetFamily(vlc_font_select_t *fs, const char *psz_lcname)
+int CoreText_GetFamily(vlc_font_select_t *fs, const char *psz_lcname,
+                       const vlc_family_t **pp_result)
 {
+    int i_ret = VLC_EGENERIC;
+
     if (unlikely(psz_lcname == NULL)) {
-        return NULL;
+        return VLC_EGENERIC;
     }
 
     psz_lcname = CoreText_TranslateGenericFamily(psz_lcname);
@@ -170,7 +173,8 @@ const vlc_family_t *CoreText_GetFamily(vlc_font_select_t *fs, const char *psz_lc
     /* let's double check if we have parsed this family already */
     vlc_family_t *p_family = vlc_dictionary_value_for_key(&fs->family_map, psz_lcname);
     if (p_family) {
-        return p_family;
+        *pp_result = p_family;
+        return VLC_SUCCESS;
     }
 
     CTFontCollectionRef coreTextFontCollection = NULL;
@@ -239,6 +243,8 @@ const vlc_family_t *CoreText_GetFamily(vlc_font_select_t *fs, const char *psz_lc
         addNewFontToFamily(fs, iter, path, p_family);
     }
 
+    i_ret = VLC_SUCCESS;
+
 end:
     if (matchedFontDescriptions != NULL) {
         CFRelease(matchedFontDescriptions);
@@ -255,13 +261,16 @@ end:
     CFRelease(coreTextFontDescriptorsArray);
     CFRelease(familyName);
 
-    return p_family;
+    *pp_result = p_family;
+    return i_ret;
 }
 
-vlc_family_t *CoreText_GetFallbacks(vlc_font_select_t *fs, const char *psz_lcname, uni_char_t codepoint)
+int CoreText_GetFallbacks(vlc_font_select_t *fs, const char *psz_lcname,
+                          uni_char_t codepoint, vlc_family_t **pp_result)
 {
+    int i_ret = VLC_EGENERIC;
     if (unlikely(psz_lcname == NULL)) {
-        return NULL;
+        return VLC_EGENERIC;
     }
 
     psz_lcname = CoreText_TranslateGenericFamily(psz_lcname);
@@ -299,6 +308,7 @@ vlc_family_t *CoreText_GetFallbacks(vlc_font_select_t *fs, const char *psz_lcnam
 
     p_family = vlc_dictionary_value_for_key(&fs->family_map, psz_lc_fallback);
     if (p_family) {
+        i_ret = VLC_SUCCESS;
         goto done;
     }
 
@@ -313,11 +323,14 @@ vlc_family_t *CoreText_GetFallbacks(vlc_font_select_t *fs, const char *psz_lcnam
 
     /* check if the path is empty, which can happen in rare circumstances */
     if (psz_fontPath == NULL || *psz_fontPath == '\0') {
+        i_ret = VLC_SUCCESS;
         goto done;
     }
 
     addNewFontToFamily(fs, fallbackFontDescriptor, strdup(psz_fontPath), p_family);
 
+    i_ret = VLC_SUCCESS;
+
 done:
     CFRelease(familyName);
     CFRelease(font);
@@ -331,5 +344,7 @@ done:
         CFRelease(postScriptFallbackFontname);
     if (fallbackFontDescriptor != NULL)
         CFRelease(fallbackFontDescriptor);
-    return p_family;
+
+    *pp_result = p_family;
+    return i_ret;
 }
diff --git a/modules/text_renderer/freetype/fonts/dwrite.cpp b/modules/text_renderer/freetype/fonts/dwrite.cpp
index 12216f7d92..0d7092e604 100644
--- a/modules/text_renderer/freetype/fonts/dwrite.cpp
+++ b/modules/text_renderer/freetype/fonts/dwrite.cpp
@@ -571,7 +571,8 @@ static void DWrite_ParseFamily( vlc_font_select_t *fs, IDWriteFontFamily *p_dw_f
     }
 }
 
-extern "C" const vlc_family_t *DWrite_GetFamily( vlc_font_select_t *fs, const char *psz_lcname )
+extern "C" int DWrite_GetFamily( vlc_font_select_t *fs, const char *psz_lcname,
+                                 const vlc_family_t **pp_result )
 {
     dw_sys_t                     *p_dw_sys     = ( dw_sys_t * ) fs->p_dw_sys;
     ComPtr< IDWriteFontFamily >   p_dw_family;
@@ -583,13 +584,16 @@ extern "C" const vlc_family_t *DWrite_GetFamily( vlc_font_select_t *fs, const ch
         ( vlc_family_t * ) vlc_dictionary_value_for_key( &fs->family_map, psz_lcname );
 
     if( p_family )
-        return p_family;
+    {
+        *pp_result = p_family;
+        return VLC_SUCCESS;
+    }
 
     p_family = NewFamily( fs, psz_lcname, &fs->p_families,
                           &fs->family_map, psz_lcname );
 
     if( unlikely( !p_family ) )
-        return NULL;
+        return VLC_EGENERIC;
 
     msg_Dbg( fs->p_obj, "DWrite_GetFamily(): family name: %s", psz_lcname );
 
@@ -674,7 +678,8 @@ extern "C" const vlc_family_t *DWrite_GetFamily( vlc_font_select_t *fs, const ch
 
 done:
     free( pwsz_family );
-    return p_family;
+    *pp_result = p_family;
+    return VLC_SUCCESS;
 }
 
 static char *DWrite_Fallback( vlc_font_select_t *fs, const char *psz_lcname,
@@ -750,12 +755,13 @@ done:
     return psz_result;
 }
 
-extern "C" vlc_family_t *DWrite_GetFallbacks( vlc_font_select_t *fs, const char *psz_lcname,
-                                              uni_char_t codepoint )
+extern "C" int DWrite_GetFallbacks( vlc_font_select_t *fs, const char *psz_lcname,
+                                    uni_char_t codepoint, vlc_family_t **pp_result )
 {
     vlc_family_t  *p_family      = NULL;
     vlc_family_t  *p_fallbacks   = NULL;
     char          *psz_fallback  = NULL;
+    int            i_ret         = VLC_EGENERIC;
 
     p_fallbacks = ( vlc_family_t * ) vlc_dictionary_value_for_key( &fs->fallback_map, psz_lcname );
 
@@ -775,12 +781,16 @@ extern "C" vlc_family_t *DWrite_GetFallbacks( vlc_font_select_t *fs, const char
         if( !psz_fallback )
             goto done;
 
-        const vlc_family_t *p_fallback = DWrite_GetFamily( fs, psz_fallback );
-        if( !p_fallback || !p_fallback->p_fonts )
+        const vlc_family_t *p_fallback = NULL;
+        if( DWrite_GetFamily( fs, psz_fallback, &p_fallback ) != VLC_SUCCESS )
             goto done;
 
-        if( !CheckFace( fs, p_fallback->p_fonts, codepoint ) )
+        if( !p_fallback || !p_fallback->p_fonts ||
+           !CheckFace( fs, p_fallback->p_fonts, codepoint ) )
+        {
+            i_ret = VLC_SUCCESS;
             goto done;
+        }
 
         p_family = NewFamily( fs, psz_fallback, NULL, NULL, NULL );
 
@@ -796,7 +806,11 @@ extern "C" vlc_family_t *DWrite_GetFallbacks( vlc_font_select_t *fs, const char
                                    psz_lcname, p_family );
     }
 
+    i_ret = VLC_SUCCESS;
+
 done:
     free( psz_fallback );
-    return p_family;
+
+    *pp_result = p_family;
+    return i_ret;
 }
diff --git a/modules/text_renderer/freetype/fonts/fontconfig.c b/modules/text_renderer/freetype/fonts/fontconfig.c
index 265f3ef9a9..fff08913f2 100644
--- a/modules/text_renderer/freetype/fonts/fontconfig.c
+++ b/modules/text_renderer/freetype/fonts/fontconfig.c
@@ -106,16 +106,10 @@ void FontConfig_Unprepare( vlc_font_select_t *fs )
     vlc_mutex_unlock( &lock );
 }
 
-const vlc_family_t *FontConfig_GetFamily( vlc_font_select_t *fs, const char *psz_lcname )
+int FontConfig_SelectAmongFamilies( vlc_font_select_t *fs, const fontfamilies_t *families,
+                                    const vlc_family_t **pp_result )
 {
-    vlc_family_t *p_family = vlc_dictionary_value_for_key( &fs->family_map, psz_lcname );
-    if( p_family != kVLCDictionaryNotFound )
-        return p_family;
-
-    p_family = NewFamily( fs, psz_lcname, &fs->p_families,
-                          &fs->family_map, psz_lcname );
-    if( !p_family )
-        return NULL;
+    vlc_family_t *p_family = NULL;
 
     for( int i = 0; i < 4; ++i ) /* Iterate through FC_{SLANT,WEIGHT} combos */
     {
@@ -134,7 +128,9 @@ const vlc_family_t *FontConfig_GetFamily( vlc_font_select_t *fs, const char *psz
         if (!pat) continue;
 
         /* */
-        FcPatternAddString( pat, FC_FAMILY, (const FcChar8*) psz_lcname );
+        const char *psz_lcname;
+        vlc_vector_foreach( psz_lcname, &families->vec )
+            FcPatternAddString( pat, FC_FAMILY, (const FcChar8*) psz_lcname );
         FcPatternAddBool( pat, FC_OUTLINE, FcTrue );
         FcPatternAddInteger( pat, FC_SLANT, b_italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
         FcPatternAddInteger( pat, FC_WEIGHT, b_bold ? FC_WEIGHT_EXTRABOLD : FC_WEIGHT_NORMAL );
@@ -152,25 +148,43 @@ const vlc_family_t *FontConfig_GetFamily( vlc_font_select_t *fs, const char *psz
         FcPatternDestroy( pat );
         if( !p_pat || result == FcResultNoMatch ) continue;
 
-        /* Check the new pattern */
-        if( ( FcResultMatch != FcPatternGetBool( p_pat, FC_OUTLINE, 0, &val_b ) )
-            || ( val_b != FcTrue ) )
+        if( FcResultMatch != FcPatternGetString( p_pat, FC_FAMILY, 0, &val_s ) )
         {
             FcPatternDestroy( p_pat );
             continue;
         }
 
-        if( FcResultMatch != FcPatternGetInteger( p_pat, FC_INDEX, 0, &i_index ) )
+        if( !p_family )
         {
-            i_index = 0;
+            char *psz_fnlc = LowercaseDup((const char *)val_s);
+            p_family = vlc_dictionary_value_for_key( &fs->family_map, psz_fnlc );
+            if( p_family == kVLCDictionaryNotFound )
+            {
+                p_family = NewFamily( fs, psz_fnlc, &fs->p_families,
+                                      &fs->family_map, psz_fnlc );
+                if( !p_family )
+                {
+                    free(psz_fnlc);
+                    FcPatternDestroy( pat );
+                    return VLC_ENOMEM;
+                }
+            }
+            free(psz_fnlc);
         }
 
-        if( FcResultMatch != FcPatternGetString( p_pat, FC_FAMILY, 0, &val_s ) )
+        /* Check the new pattern */
+        if( ( FcResultMatch != FcPatternGetBool( p_pat, FC_OUTLINE, 0, &val_b ) )
+            || ( val_b != FcTrue ) )
         {
             FcPatternDestroy( p_pat );
             continue;
         }
 
+        if( FcResultMatch != FcPatternGetInteger( p_pat, FC_INDEX, 0, &i_index ) )
+        {
+            i_index = 0;
+        }
+
         if( FcResultMatch == FcPatternGetString( p_pat, FC_FILE, 0, &val_s ) )
             psz_fontfile = strdup( (const char*)val_s );
 
@@ -182,28 +196,47 @@ const vlc_family_t *FontConfig_GetFamily( vlc_font_select_t *fs, const char *psz
         NewFont( psz_fontfile, i_index, b_bold, b_italic, p_family );
     }
 
-    return p_family;
+    *pp_result = p_family;
+    return VLC_SUCCESS;
+}
+
+int FontConfig_GetFamily( vlc_font_select_t *fs, const char *psz_lcname,
+                          const vlc_family_t **pp_result )
+{
+    fontfamilies_t families;
+    families.psz_key = psz_lcname;
+    vlc_vector_init( &families.vec );
+    vlc_vector_push( &families.vec, (char *) psz_lcname );
+    int ret = FontConfig_SelectAmongFamilies( fs, &families, pp_result );
+    vlc_vector_clear( &families.vec );
+    return ret;
 }
 
-vlc_family_t *FontConfig_GetFallbacks( vlc_font_select_t *fs, const char *psz_lcname,
-                                       uni_char_t codepoint )
+int FontConfig_GetFallbacksAmongFamilies( vlc_font_select_t *fs, const fontfamilies_t *families,
+                                          uni_char_t codepoint, vlc_family_t **pp_result )
 {
 
     VLC_UNUSED( codepoint );
+    vlc_family_t *p_family = NULL;
 
-    vlc_family_t *p_family =
-            vlc_dictionary_value_for_key( &fs->fallback_map, psz_lcname );
+    p_family = vlc_dictionary_value_for_key( &fs->fallback_map, families->psz_key );
     if( p_family != kVLCDictionaryNotFound )
-        return p_family;
+    {
+        *pp_result = p_family;
+        return VLC_SUCCESS;
+    }
     else
         p_family = NULL;
-
     const char *psz_last_name = "";
+
     FcPattern  *p_pattern = FcPatternCreate();
-    FcValue     family;
-    family.type = FcTypeString;
-    family.u.s = ( const FcChar8* ) psz_lcname;
-    FcPatternAdd( p_pattern, FC_FAMILY, family, FcFalse );
+    if (!p_pattern)
+        return VLC_EGENERIC;
+
+    const char *psz_lcname;
+    vlc_vector_foreach( psz_lcname, &families->vec )
+        FcPatternAddString( p_pattern, FC_FAMILY, (const FcChar8*) psz_lcname );
+
     if( FcConfigSubstitute( config, p_pattern, FcMatchPattern ) == FcTrue )
     {
         FcDefaultSubstitute( p_pattern );
@@ -229,7 +262,7 @@ vlc_family_t *FontConfig_GetFallbacks( vlc_font_select_t *fs, const char *psz_lc
                         FcPatternDestroy( p_pattern );
                         if( p_family )
                             FreeFamilies( p_family, NULL );
-                        return NULL;
+                        return VLC_EGENERIC;
                     }
 
                     psz_last_name = p_temp->psz_name;
@@ -241,7 +274,8 @@ vlc_family_t *FontConfig_GetFallbacks( vlc_font_select_t *fs, const char *psz_lc
     FcPatternDestroy( p_pattern );
 
     if( p_family )
-        vlc_dictionary_insert( &fs->fallback_map, psz_lcname, p_family );
+        vlc_dictionary_insert( &fs->fallback_map, families->psz_key, p_family );
 
-    return p_family;
+    *pp_result = p_family;
+    return VLC_SUCCESS;
 }
diff --git a/modules/text_renderer/freetype/fonts/win32.c b/modules/text_renderer/freetype/fonts/win32.c
index 00866595c7..39e58b7cfc 100644
--- a/modules/text_renderer/freetype/fonts/win32.c
+++ b/modules/text_renderer/freetype/fonts/win32.c
@@ -392,19 +392,22 @@ static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *lpelfe, const NEWTEXTM
     return 1;
 }
 
-const vlc_family_t *Win32_GetFamily( vlc_font_select_t *fs, const char *psz_lcname )
+int Win32_GetFamily( vlc_font_select_t *fs, const char *psz_lcname, const vlc_family_t **pp_result )
 {
     vlc_family_t *p_family =
         vlc_dictionary_value_for_key( &fs->family_map, psz_lcname );
 
     if( p_family )
-        return p_family;
+    {
+        *pp_result = p_family;
+        return VLC_SUCCESS;
+    }
 
     p_family = NewFamily( fs, psz_lcname, &fs->p_families,
                           &fs->family_map, psz_lcname );
 
     if( unlikely( !p_family ) )
-        return NULL;
+        return VLC_EGENERIC;
 
     LOGFONT lf;
     lf.lfCharSet = DEFAULT_CHARSET;
@@ -421,7 +424,8 @@ const vlc_family_t *Win32_GetFamily( vlc_font_select_t *fs, const char *psz_lcna
     EnumFontFamiliesEx(hDC, &lf, (FONTENUMPROC)&EnumFontCallback, (LPARAM)&ctx, 0);
     ReleaseDC(NULL, hDC);
 
-    return p_family;
+    *pp_result = p_family;
+    return VLC_SUCCESS;
 }
 
 static int CALLBACK MetaFileEnumProc( HDC hdc, HANDLETABLE* table,
@@ -516,12 +520,13 @@ error:
     return NULL;
 }
 
-vlc_family_t *Win32_GetFallbacks( vlc_font_select_t *fs, const char *psz_lcname,
-                                  uni_char_t codepoint )
+int Win32_GetFallbacks( vlc_font_select_t *fs, const char *psz_lcname,
+                        uni_char_t codepoint, vlc_family_t **pp_result )
 {
     vlc_family_t  *p_family      = NULL;
     vlc_family_t  *p_fallbacks   = NULL;
     char          *psz_uniscribe = NULL;
+    int            i_ret         = VLC_EGENERIC;
 
     p_fallbacks = vlc_dictionary_value_for_key( &fs->fallback_map, psz_lcname );
 
@@ -537,16 +542,22 @@ vlc_family_t *Win32_GetFallbacks( vlc_font_select_t *fs, const char *psz_lcname,
     if( !p_family )
     {
         psz_uniscribe = UniscribeFallback( psz_lcname, codepoint );
-
         if( !psz_uniscribe )
+        {
+            i_ret = VLC_SUCCESS;
             goto done;
+        }
 
-        const vlc_family_t *p_uniscribe = Win32_GetFamily( fs, psz_uniscribe );
-        if( !p_uniscribe || !p_uniscribe->p_fonts )
+        const vlc_family_t *p_uniscribe = NULL;
+        if( Win32_GetFamily( fs, psz_uniscribe, &p_uniscribe ) != VLC_SUCCESS )
             goto done;
 
-        if( !CheckFace( fs, p_uniscribe->p_fonts, codepoint ) )
+        if( !p_uniscribe || !p_uniscribe->p_fonts ||
+            !CheckFace( fs, p_uniscribe->p_fonts, codepoint ) )
+        {
+            i_ret = VLC_SUCCESS;
             goto done;
+        }
 
         p_family = NewFamily( fs, psz_uniscribe, NULL, NULL, NULL );
 
@@ -562,9 +573,12 @@ vlc_family_t *Win32_GetFallbacks( vlc_font_select_t *fs, const char *psz_lcname,
                                    psz_lcname, p_family );
     }
 
+    i_ret = VLC_SUCCESS;
+
 done:
     free( psz_uniscribe );
-    return p_family;
+    *pp_result = p_family;
+    return i_ret;
 }
 
 char * MakeFilePath( vlc_font_select_t *fs, const char *psz_filename )
diff --git a/modules/text_renderer/freetype/freetype.h b/modules/text_renderer/freetype/freetype.h
index aff536b8e1..7d3e9784a8 100644
--- a/modules/text_renderer/freetype/freetype.h
+++ b/modules/text_renderer/freetype/freetype.h
@@ -87,7 +87,6 @@ typedef struct vlc_font_select_t vlc_font_select_t;
  * This structure is part of the video output thread descriptor.
  * It describes the freetype specific properties of an output thread.
  *****************************************************************************/
-typedef struct VLC_VECTOR(char *) fontfamilies_t;
 typedef struct vlc_family_t vlc_family_t;
 typedef struct
 {
diff --git a/modules/text_renderer/freetype/ftcache.c b/modules/text_renderer/freetype/ftcache.c
index b4a0268392..f475c3c58e 100644
--- a/modules/text_renderer/freetype/ftcache.c
+++ b/modules/text_renderer/freetype/ftcache.c
@@ -175,9 +175,10 @@ static FT_Error RequestFace( FTC_FaceID face_id, FT_Library library,
     return 0;
 }
 
-static void LRUGlyphRefRelease( void *v )
+static void LRUGlyphRefRelease( void *priv, void *v )
 {
     vlc_ftcache_custom_glyph_ref_t ref = (vlc_ftcache_custom_glyph_ref_t) v;
+    VLC_UNUSED(priv);
     assert(ref->refcount);
     if( --ref->refcount == 0 )
     {
@@ -219,7 +220,7 @@ vlc_ftcache_t * vlc_ftcache_New( vlc_object_t *obj, FT_Library p_library,
     /* Dictionnaries for fonts */
     vlc_dictionary_init( &ftcache->face_ids, 50 );
 
-    ftcache->glyphs_lrucache = vlc_lru_New( 128, LRUGlyphRefRelease );
+    ftcache->glyphs_lrucache = vlc_lru_New( 128, LRUGlyphRefRelease, ftcache );
 
     if(!ftcache->glyphs_lrucache ||
        FTC_Manager_New( p_library, 4, 8, maxkb << 10,
diff --git a/modules/text_renderer/freetype/lru.c b/modules/text_renderer/freetype/lru.c
index 316a584755..226fd0510c 100644
--- a/modules/text_renderer/freetype/lru.c
+++ b/modules/text_renderer/freetype/lru.c
@@ -34,7 +34,8 @@ struct vlc_lru_entry
 
 struct vlc_lru
 {
-    void (*releaseValue)(void *);
+    void (*releaseValue)(void *, void *);
+    void *priv;
     unsigned max;
     vlc_dictionary_t dict;
     struct vlc_list list;
@@ -46,15 +47,18 @@ static void vlc_lru_releaseentry( void *value, void *priv )
     struct vlc_lru_entry *entry = value;
     struct vlc_lru *lru = priv;
     free(entry->psz_key);
-    lru->releaseValue(entry->value);
+    if( lru->releaseValue )
+        lru->releaseValue( lru->priv, entry->value );
     free(entry);
 }
 
-vlc_lru * vlc_lru_New( unsigned max, void(*releaseValue)(void *) )
+vlc_lru * vlc_lru_New( unsigned max,
+                       void(*releaseValue)(void *, void *), void *priv )
 {
     vlc_lru *lru = malloc(sizeof(*lru));
     if( lru )
     {
+        lru->priv = priv;
         lru->max = max;
         vlc_dictionary_init( &lru->dict, max );
         vlc_list_init( &lru->list );
@@ -70,6 +74,11 @@ void vlc_lru_Release( vlc_lru *lru )
     free( lru );
 }
 
+bool vlc_lru_HasKey( vlc_lru *lru, const char *psz_key )
+{
+    return vlc_dictionary_has_key( &lru->dict, psz_key );
+}
+
 void * vlc_lru_Get( vlc_lru *lru, const char *psz_key )
 {
     struct vlc_lru_entry *entry = vlc_dictionary_value_for_key( &lru->dict, psz_key );
@@ -94,13 +103,13 @@ void vlc_lru_Insert( vlc_lru *lru, const char *psz_key, void *value )
     struct vlc_lru_entry *entry = calloc(1, sizeof(*entry));
     if(!entry)
     {
-        lru->releaseValue(value);
+        lru->releaseValue(lru->priv, value);
         return;
     }
     entry->psz_key = strdup( psz_key );
     if(!entry->psz_key)
     {
-        lru->releaseValue(value);
+        lru->releaseValue(lru->priv, value);
         free(entry);
         return;
     }
@@ -121,3 +130,12 @@ void vlc_lru_Insert( vlc_lru *lru, const char *psz_key, void *value )
         vlc_lru_releaseentry(toremove, lru);
     }
 }
+
+void vlc_lru_Apply( vlc_lru *lru,
+                    void(*func)(void *, const char *, void *),
+                    void *priv )
+{
+    struct vlc_lru_entry *entry;
+    vlc_list_foreach( entry, &lru->list, node )
+        func( priv, entry->psz_key, entry->value );
+}
diff --git a/modules/text_renderer/freetype/lru.h b/modules/text_renderer/freetype/lru.h
index 3dcb72b66c..eb5ff3b1d6 100644
--- a/modules/text_renderer/freetype/lru.h
+++ b/modules/text_renderer/freetype/lru.h
@@ -26,12 +26,18 @@ extern "C" {
 
 typedef struct vlc_lru vlc_lru;
 
-vlc_lru * vlc_lru_New( unsigned max, void(*releaseValue)(void *) );
+vlc_lru * vlc_lru_New( unsigned max,
+                       void(*releaseValue)(void *, void *), void * );
 void vlc_lru_Release( vlc_lru *lru );
 
+bool   vlc_lru_HasKey( vlc_lru *lru, const char *psz_key );
 void * vlc_lru_Get( vlc_lru *lru, const char *psz_key );
 void   vlc_lru_Insert( vlc_lru *lru, const char *psz_key, void *value );
 
+void   vlc_lru_Apply( vlc_lru *lru,
+                      void(*func)(void *, const char *, void *),
+                      void * );
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/modules/text_renderer/freetype/platform_fonts.c b/modules/text_renderer/freetype/platform_fonts.c
index a74aa4a882..67446f280f 100644
--- a/modules/text_renderer/freetype/platform_fonts.c
+++ b/modules/text_renderer/freetype/platform_fonts.c
@@ -158,7 +158,7 @@ vlc_family_t *SearchFallbacks( vlc_font_select_t *fs, vlc_family_t *p_fallbacks,
     {
         if( !p_fallback->p_fonts )
         {
-            const vlc_family_t *p_temp = FontSelectGetFamily( fs, p_fallback->psz_name );
+            const vlc_family_t *p_temp = FontSelectFamily( fs, p_fallback->psz_name );
             if( !p_temp || !p_temp->p_fonts )
                 continue;
             p_fallback->p_fonts = p_temp->p_fonts;
@@ -396,7 +396,7 @@ vlc_family_t *InitDefaultList( vlc_font_select_t *fs, const char *const *ppsz_de
         if( !psz_lc )
             continue;
 
-        const vlc_family_t *p_family = FontSelectGetFamily( fs, psz_lc );
+        const vlc_family_t *p_family = FontSelectFamily( fs, psz_lc );
         if( p_family )
         {
             vlc_family_t *p_temp =
@@ -458,6 +458,14 @@ static void DumpFamily( vlc_object_t *p_obj, const vlc_family_t *p_family,
     }
 }
 
+static void DumpLRUElement( void *priv, const char *key, void *val )
+{
+    vlc_object_t *p_obj = priv;
+    vlc_family_t *p_family = val;
+    msg_Dbg( p_obj, "Key: %s", key );
+    DumpFamily( p_obj, p_family, false, -1 );
+}
+
 static void DumpDictionary( vlc_object_t *p_obj, const vlc_dictionary_t *p_dict,
                             bool b_dump_fonts, int i_max_families )
 {
@@ -488,10 +496,14 @@ void DumpFamilies( vlc_font_select_t *fs )
     msg_Dbg( p_obj, "family_map" );
     msg_Dbg( p_obj, "-----------------" );
     DumpDictionary( p_obj, &fs->family_map, false, 1 );
+    msg_Dbg( p_obj, "-----------------" );
+    msg_Dbg( p_obj, "families_lookup_lru" );
+    msg_Dbg( p_obj, "-----------------" );
+    vlc_lru_Apply( fs->families_lookup_lru, DumpLRUElement, p_obj );
     msg_Dbg( p_obj, "-------------------" );
     msg_Dbg( p_obj, "fallback_map" );
     msg_Dbg( p_obj, "-------------------" );
-    DumpDictionary( p_obj, &fs->fallback_map, true, -1 );
+    DumpDictionary( p_obj, &fs->fallback_map, false, -1 );
 }
 #endif
 
@@ -575,7 +587,7 @@ static void AddSingleFamily( const char *psz_start,
     {
         char *psz = strndup( psz_start, psz_end - psz_start );
         if( psz )
-            vlc_vector_push( families, psz );
+            vlc_vector_push( &families->vec, psz );
     }
 }
 
@@ -612,9 +624,8 @@ static char* SelectFontWithFamilyFallback( vlc_font_select_t *fs,
          * Try regular face of the same family first.
          * It usually has the best coverage.
          */
-        vlc_vector_foreach( psz_lcname, families )
+        vlc_vector_foreach( psz_lcname, &families->vec )
         {
-            assert(IsLowercase(psz_lcname));
             Debug( fs->p_obj, "Looking for family \"%s\"", psz_lcname );
 
             p_fallbacks = vlc_dictionary_value_for_key( &fs->fallback_map,
@@ -627,18 +638,19 @@ static char* SelectFontWithFamilyFallback( vlc_font_select_t *fs,
                     break;
             }
 
-            p_family = FontSelectGetFamily( fs, psz_lcname );
-            if( p_family && p_family->p_fonts )
+            p_family = NULL;
+        }
+
+        p_family = FontSelectAmongFamilies( fs, families );
+        if( p_family )
+        {
+            if( p_family->p_fonts &&
+                CheckFace( fs, p_family->p_fonts, codepoint ) )
             {
-                if( CheckFace( fs, p_family->p_fonts, codepoint ) )
-                {
-                    Debug( fs->p_obj, "Found family \"%s\" for codepoint %x",
-                           psz_lcname, codepoint );
-                    break;
-                }
+                Debug( fs->p_obj, "Found family \"%s\" for codepoint %x",
+                       psz_lcname, codepoint );
             }
-
-            p_family = NULL;
+            else p_family = NULL;
         }
 
         /* Try font attachments if not available locally */
@@ -661,21 +673,18 @@ static char* SelectFontWithFamilyFallback( vlc_font_select_t *fs,
         /* Try system fallbacks */
         if( !p_family )
         {
-            vlc_vector_foreach( psz_lcname, families )
+            p_fallbacks = FontFallbacksAmongFamilies( fs, families, codepoint );
+            if( p_fallbacks )
             {
-                Debug( fs->p_obj, "Looking for family \"%s\" in system fallbacks cp %x", psz_lcname, codepoint );
-                p_fallbacks = FontSelectGetFallbacks( fs, psz_lcname, codepoint );
-                if( p_fallbacks )
+                Debug( fs->p_obj, "Looking for families \"%s\" in system fallbacks cp %x",
+                                   families->psz_key, codepoint );
+                p_family = SearchFallbacks( fs, p_fallbacks, codepoint );
+                if( p_family && p_family->p_fonts )
                 {
-                    p_family = SearchFallbacks( fs, p_fallbacks, codepoint );
-                    if( p_family && p_family->p_fonts )
-                    {
-                        Debug( fs->p_obj, "Selected family \"%s\" in system fallbacks",
-                               p_family->psz_name );
-                        break;
-                    }
+                    Debug( fs->p_obj, "Selected family \"%s\" in system fallbacks",
+                           p_family->psz_name );
                 }
-                p_family = NULL;
+                else p_family = NULL;
             }
         }
 
@@ -701,7 +710,7 @@ static char* SelectFontWithFamilyFallback( vlc_font_select_t *fs,
     {
         Debug( fs->p_obj, "Looking for DEFAULT_FAMILY \"%s\" as a last resort", DEFAULT_FAMILY );
         char *lc = LowercaseDup(DEFAULT_FAMILY);
-        p_family = FontSelectGetFamily( fs, lc );
+        p_family = FontSelectFamily( fs, lc );
         free(lc);
     }
 
@@ -731,11 +740,12 @@ SelectAndLoadFace( filter_t *p_filter, const text_style_t *p_style, uni_char_t c
         psz_fontname = psz_alloc;
 
     fontfamilies_t families;
-    vlc_vector_init( &families );
+    families.psz_key = psz_fontname;
+    vlc_vector_init( &families.vec );
     SplitIntoSingleFamily( psz_fontname, &families );
-    if( families.size == 0 )
+    if( families.vec.size == 0 )
     {
-        vlc_vector_clear( &families );
+        vlc_vector_clear( &families.vec );
         free(psz_alloc);
         return NULL;
     }
@@ -768,9 +778,9 @@ SelectAndLoadFace( filter_t *p_filter, const text_style_t *p_style, uni_char_t c
     }
 
     char *psz_temp;
-    vlc_vector_foreach( psz_temp, &families )
+    vlc_vector_foreach( psz_temp, &families.vec )
         free( psz_temp );
-    vlc_vector_clear( &families );
+    vlc_vector_clear( &families.vec );
     free( psz_fontfile );
     free(psz_alloc);
 
@@ -778,8 +788,8 @@ SelectAndLoadFace( filter_t *p_filter, const text_style_t *p_style, uni_char_t c
 }
 
 #ifndef HAVE_GET_FONT_BY_FAMILY_NAME
-static const vlc_family_t * StaticMap_GetFamily( vlc_font_select_t *fs,
-                                                 const char *psz_lcname )
+static int StaticMap_GetFamily( vlc_font_select_t *fs, const char *psz_lcname,
+                                vlc_family_t **pp_result )
 {
     filter_t *p_filter = fs->p_filter;
     filter_sys_t *p_sys = p_filter->p_sys;
@@ -787,7 +797,10 @@ static const vlc_family_t * StaticMap_GetFamily( vlc_font_select_t *fs,
     vlc_family_t *p_family =
             vlc_dictionary_value_for_key( &fs->family_map, psz_lcname );
     if( p_family )
-        return p_family;
+    {
+        *pp_result = p_family;
+        return VLC_SUCCESS;
+    }
 
     const char *psz_file = NULL;
     if( !strcasecmp( psz_lcname, DEFAULT_FAMILY ) )
@@ -802,20 +815,24 @@ static const vlc_family_t * StaticMap_GetFamily( vlc_font_select_t *fs,
     }
 
     if( !psz_file )
-        return NULL;
+    {
+        *pp_result = NULL;
+        return VLC_SUCCESS;
+    }
 
     /* Create new entry */
     p_family = NewFamily( fs, psz_lcname, &fs->p_families,
                           &fs->family_map, psz_lcname );
 
     if( unlikely( !p_family ) )
-        return NULL;
+        return VLC_EGENERIC;
 
     char *psz_font_file = MakeFilePath( fs, psz_file );
     if( psz_font_file )
         NewFont( psz_font_file, 0, false, false, p_family );
 
-    return p_family;
+    *pp_result = p_family;
+    return VLC_SUCCESS;
 }
 #endif
 
@@ -851,25 +868,30 @@ vlc_font_select_t * FontSelectNew( filter_t *p_filter )
     fs->p_obj = VLC_OBJECT(p_filter);
 
     /* Dictionnaries for families */
-    vlc_dictionary_init( &fs->family_map, 50 );
-    vlc_dictionary_init( &fs->fallback_map, 20 );
+    vlc_dictionary_init( &fs->family_map, 53 );
+    vlc_dictionary_init( &fs->fallback_map, 23 );
+
+    fs->families_lookup_lru = vlc_lru_New( 23, NULL, NULL );
+    if( !fs->families_lookup_lru )
+        goto error;
 
 #ifdef HAVE_FONTCONFIG
-    fs->pf_get_family = FontConfig_GetFamily;
-    fs->pf_get_fallbacks = FontConfig_GetFallbacks;
+    fs->pf_select_family = FontConfig_GetFamily;
+    fs->pf_select_among_families = FontConfig_SelectAmongFamilies;
+    fs->pf_get_fallbacks_among_families = FontConfig_GetFallbacksAmongFamilies;
     if( FontConfig_Prepare( fs ) )
     {
-        fs->pf_get_family = NULL;
+        fs->pf_select_family = NULL;
         goto error;
     }
 
 #elif defined( __APPLE__ )
-    fs->pf_get_family = CoreText_GetFamily;
+    fs->pf_select_family = CoreText_GetFamily;
     fs->pf_get_fallbacks = CoreText_GetFallbacks;
 #elif defined( _WIN32 )
     if( InitDWrite( fs ) == VLC_SUCCESS )
     {
-        fs->pf_get_family = DWrite_GetFamily;
+        fs->pf_select_family = DWrite_GetFamily;
         fs->pf_get_fallbacks = DWrite_GetFallbacks;
     }
     else
@@ -881,20 +903,20 @@ vlc_font_select_t * FontSelectNew( filter_t *p_filter )
         msg_Warn( p_filter, "DirectWrite initialization failed. Falling back to GDI/Uniscribe" );
         const char *const ppsz_default[] =
             { "tahoma", "fangsong", "simhei", "kaiti" };
-        fs->pf_get_family = Win32_GetFamily;
+        fs->pf_select_family = Win32_GetFamily;
         fs->pf_get_fallbacks = Win32_GetFallbacks;
         if( InitDefaultList( fs, ppsz_default, ARRAY_SIZE(ppsz_default) ) == NULL )
             goto error;
 #endif
     }
 #elif defined( __ANDROID__ )
-    fs->pf_get_family = Android_GetFamily;
+    fs->pf_select_family = Android_GetFamily;
     fs->pf_get_fallbacks = Android_GetFallbacks;
 
     if( Android_Prepare( fs ) == VLC_ENOMEM )
         goto error;
 #else
-    fs->pf_get_family = StaticMap_GetFamily;
+    fs->pf_select_family = StaticMap_GetFamily;
     fs->pf_get_fallbacks = NULL;
     /* The default static fonts are also fallback fonts */
     const char *const ppsz_default[] =
@@ -913,14 +935,17 @@ error:
 void FontSelectDelete( vlc_font_select_t *fs )
 {
 #ifdef HAVE_FONTCONFIG
-    if( fs->pf_get_family == FontConfig_GetFamily )
+    if( fs->pf_select_family == FontConfig_GetFamily )
         FontConfig_Unprepare( fs );
 
 #elif defined( _WIN32 )
-    if( fs->pf_get_family == DWrite_GetFamily )
+    if( fs->pf_select_family == DWrite_GetFamily )
         ReleaseDWrite( fs );
 #endif
 
+    if( fs->families_lookup_lru )
+        vlc_lru_Release( fs->families_lookup_lru );
+
     /* Dicts */
     vlc_dictionary_clear( &fs->fallback_map, FreeFamilies, fs );
     vlc_dictionary_clear( &fs->family_map, NULL, NULL );
@@ -930,13 +955,57 @@ void FontSelectDelete( vlc_font_select_t *fs )
     free( fs );
 }
 
-const vlc_family_t * FontSelectGetFamily( vlc_font_select_t *fs, const char *psz_lcname )
+const vlc_family_t * FontSelectFamily( vlc_font_select_t *fs, const char *psz_lcname )
 {
-    return fs->pf_get_family ? fs->pf_get_family( fs, psz_lcname ) : NULL;
+    const vlc_family_t *p_family = NULL;
+    if( fs->pf_select_family )
+        fs->pf_select_family( fs, psz_lcname, &p_family );
+    return p_family;
+}
+
+const vlc_family_t * FontSelectAmongFamilies( vlc_font_select_t *fs, const fontfamilies_t *families )
+{
+    /* We return empty NULL matches, so we check if key exists, not value */
+    if( vlc_lru_HasKey( fs->families_lookup_lru, families->psz_key ) )
+        return vlc_lru_Get( fs->families_lookup_lru, families->psz_key );
+
+    const vlc_family_t *p_family = NULL;
+    if( fs->pf_select_among_families )
+    {
+        if( fs->pf_select_among_families( fs, families, &p_family ) != VLC_SUCCESS )
+            p_family = NULL;
+    }
+    else if( fs->pf_select_family )
+    {
+        const char *psz_name;
+        vlc_vector_foreach( psz_name, &families->vec )
+        {
+            fs->pf_select_family( fs, psz_name, &p_family );
+            if( p_family )
+                break;
+        }
+    }
+    vlc_lru_Insert( fs->families_lookup_lru, families->psz_key, (void *) p_family );
+    return p_family;
 }
 
-vlc_family_t * FontSelectGetFallbacks( vlc_font_select_t *fs, const char *psz_family,
-                                       uni_char_t codepoint )
+vlc_family_t * FontFallbacksAmongFamilies( vlc_font_select_t *fs, const fontfamilies_t *families,
+                                           uni_char_t codepoint )
 {
-    return fs->pf_get_fallbacks ? fs->pf_get_fallbacks( fs, psz_family, codepoint ) : NULL;
+    vlc_family_t *p_res = NULL;
+    if ( fs->pf_get_fallbacks_among_families )
+    {
+        fs->pf_get_fallbacks_among_families( fs, families, codepoint, &p_res );
+    }
+    else if( fs->pf_get_fallbacks )
+    {
+        const char *psz_name;
+        vlc_vector_foreach( psz_name, &families->vec )
+        {
+            fs->pf_get_fallbacks( fs, psz_name, codepoint, &p_res );
+            if( p_res )
+                break;
+        }
+    }
+    return p_res;
 }
diff --git a/modules/text_renderer/freetype/platform_fonts.h b/modules/text_renderer/freetype/platform_fonts.h
index 3ab71f9268..3d93ad0d59 100644
--- a/modules/text_renderer/freetype/platform_fonts.h
+++ b/modules/text_renderer/freetype/platform_fonts.h
@@ -155,6 +155,12 @@ struct vlc_family_t
     vlc_font_t   *p_fonts; /**< fonts matching this family */
 };
 
+typedef struct
+{
+    const char *psz_key;
+    struct VLC_VECTOR(char *) vec;
+} fontfamilies_t;
+
 #define FB_LIST_ATTACHMENTS "attachments"
 #define FB_LIST_DEFAULT     "default"
 #define FB_NAME             "fallback"
@@ -166,18 +172,18 @@ void FontSelectDelete( vlc_font_select_t * );
  * Get a pointer to the vlc_family_t in the master list that matches \p psz_family.
  * Add this family to the list if it hasn't been added yet.
  */
-const vlc_family_t * FontSelectGetFamily( vlc_font_select_t *, const char *psz_family );
+const vlc_family_t * FontSelectFamily( vlc_font_select_t *, const char *psz_family );
+const vlc_family_t * FontSelectAmongFamilies( vlc_font_select_t *, const fontfamilies_t * );
 
 /**
- * Get the fallback list for \p psz_family from the system and cache
+ * Get the fallback list for \p fontfamilies_t from the system and cache
  * it in \ref fallback_map.
  * On Windows fallback lists are populated progressively as required
  * using Uniscribe, so we need the codepoint here.
  */
-vlc_family_t * FontSelectGetFallbacks( vlc_font_select_t *, const char *psz_family,
+vlc_family_t * FontFallbacksAmongFamilies( vlc_font_select_t *, const fontfamilies_t *,
                                        uni_char_t codepoint );
 
-
 /* ******************
  * Family and fonts *
  ********************/




More information about the vlc-commits mailing list