[vlc-commits] freetype: rework and split font management code

Francois Cartegnie git at videolan.org
Tue Jul 21 16:07:21 CEST 2020


vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Wed Jul  1 20:46:21 2020 +0200| [5f7909edfcc83de7529993c18302ebde70517ca1] | committer: Francois Cartegnie

freetype: rework and split font management code

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

 modules/text_renderer/Makefile.am                 |   3 +-
 modules/text_renderer/freetype/fonts/android.c    |  84 +++---
 modules/text_renderer/freetype/fonts/backends.h   |  99 +++++++
 modules/text_renderer/freetype/fonts/darwin.c     |  36 ++-
 modules/text_renderer/freetype/fonts/dwrite.cpp   | 107 ++++----
 modules/text_renderer/freetype/fonts/fontconfig.c |  34 +--
 modules/text_renderer/freetype/fonts/win32.c      |  35 ++-
 modules/text_renderer/freetype/freetype.c         | 156 +----------
 modules/text_renderer/freetype/freetype.h         |  42 +--
 modules/text_renderer/freetype/platform_fonts.c   | 317 +++++++++++++++++-----
 modules/text_renderer/freetype/platform_fonts.h   |  83 +++---
 11 files changed, 536 insertions(+), 460 deletions(-)

diff --git a/modules/text_renderer/Makefile.am b/modules/text_renderer/Makefile.am
index d3cdf754aa..ef521d4c53 100644
--- a/modules/text_renderer/Makefile.am
+++ b/modules/text_renderer/Makefile.am
@@ -6,7 +6,8 @@ text_LTLIBRARIES = libtdummy_plugin.la
 libfreetype_plugin_la_SOURCES = \
 	text_renderer/freetype/platform_fonts.c text_renderer/freetype/platform_fonts.h \
 	text_renderer/freetype/freetype.c text_renderer/freetype/freetype.h \
-	text_renderer/freetype/text_layout.c text_renderer/freetype/text_layout.h
+	text_renderer/freetype/text_layout.c text_renderer/freetype/text_layout.h \
+        text_renderer/freetype/fonts/backends.h
 
 libfreetype_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) $(FREETYPE_CFLAGS)
 libfreetype_plugin_la_LIBADD = $(AM_LIBADD) $(LIBM)
diff --git a/modules/text_renderer/freetype/fonts/android.c b/modules/text_renderer/freetype/fonts/android.c
index 57555cdd80..6e73643a76 100644
--- a/modules/text_renderer/freetype/fonts/android.c
+++ b/modules/text_renderer/freetype/fonts/android.c
@@ -40,13 +40,14 @@
 # include <vlc_stream.h>
 
 #include "../platform_fonts.h"
+#include "backends.h"
 
 #define ANDROID_SYSTEM_FONTS_NOUGAT  "file:///system/etc/fonts.xml"
 #define ANDROID_SYSTEM_FONTS_LEGACY  "file:///system/etc/system_fonts.xml"
 #define ANDROID_FALLBACK_FONTS       "file:///system/etc/fallback_fonts.xml"
 #define ANDROID_VENDOR_FONTS         "file:///vendor/etc/fallback_fonts.xml"
 
-static int Android_ParseFont( filter_t *p_filter, xml_reader_t *p_xml,
+static int Android_ParseFont( vlc_font_select_t *fs, xml_reader_t *p_xml,
                               vlc_family_t *p_family )
 {
     bool              b_bold      = false;
@@ -72,7 +73,7 @@ static int Android_ParseFont( filter_t *p_filter, xml_reader_t *p_xml,
 
     if( i_type != XML_READER_TEXT || !psz_val || !*psz_val )
     {
-        msg_Warn( p_filter, "Android_ParseFont: no file name" );
+        msg_Warn( fs->p_obj, "Android_ParseFont: no file name" );
         return VLC_EGENERIC;
     }
 
@@ -89,10 +90,9 @@ static int Android_ParseFont( filter_t *p_filter, xml_reader_t *p_xml,
     return VLC_SUCCESS;
 }
 
-static int Android_Nougat_ParseFamily( filter_t *p_filter, xml_reader_t *p_xml )
+static int Android_Nougat_ParseFamily( vlc_font_select_t *fs, xml_reader_t *p_xml )
 {
-    filter_sys_t     *p_sys       = p_filter->p_sys;
-    vlc_dictionary_t *p_dict      = &p_sys->family_map;
+    vlc_dictionary_t *p_dict      = &fs->family_map;
     vlc_family_t     *p_family    = NULL;
     const char       *psz_val     = NULL;
     const char       *psz_attr    = NULL;
@@ -127,13 +127,13 @@ static int Android_Nougat_ParseFamily( filter_t *p_filter, xml_reader_t *p_xml )
     {
         /*
          * We are either parsing a nameless family, or a named family that
-         * was not previously added to p_sys->family_map.
+         * was not previously added to fs->family_map.
          *
          * Create a new family with the given name or, if psz_name is NULL,
          * with the name fallback-xxxx
          */
-        p_family = NewFamily( p_filter, psz_name, &p_sys->p_families,
-                              &p_sys->family_map, NULL );
+        p_family = NewFamily( fs, psz_name, &fs->p_families,
+                              &fs->family_map, NULL );
 
         if( unlikely( !p_family ) )
             return VLC_ENOMEM;
@@ -145,7 +145,7 @@ static int Android_Nougat_ParseFamily( filter_t *p_filter, xml_reader_t *p_xml )
         {
         case XML_READER_STARTELEM:
             if( !strcasecmp( "font", psz_val ) )
-                if( Android_ParseFont( p_filter, p_xml, p_family ) == VLC_ENOMEM )
+                if( Android_ParseFont( fs, p_xml, p_family ) == VLC_ENOMEM )
                     return VLC_ENOMEM;
             break;
 
@@ -159,8 +159,8 @@ static int Android_Nougat_ParseFamily( filter_t *p_filter, xml_reader_t *p_xml )
                      * default fallback list.
                      */
                     vlc_family_t *p_fallback =
-                        NewFamily( p_filter, p_family->psz_name,
-                                   NULL, &p_sys->fallback_map, FB_LIST_DEFAULT );
+                        NewFamily( fs, p_family->psz_name,
+                                   NULL, &fs->fallback_map, FB_LIST_DEFAULT );
 
                     if( unlikely( !p_fallback ) )
                         return VLC_ENOMEM;
@@ -174,14 +174,13 @@ static int Android_Nougat_ParseFamily( filter_t *p_filter, xml_reader_t *p_xml )
         }
     }
 
-    msg_Warn( p_filter, "Android_ParseFamily: Corrupt font configuration file" );
+    msg_Warn( fs->p_obj, "Android_ParseFamily: Corrupt font configuration file" );
     return VLC_EGENERIC;
 }
 
-static int Android_ParseAlias( filter_t *p_filter, xml_reader_t *p_xml )
+static int Android_ParseAlias( vlc_font_select_t *fs, xml_reader_t *p_xml )
 {
-    filter_sys_t     *p_sys       = p_filter->p_sys;
-    vlc_dictionary_t *p_dict      = &p_sys->family_map;
+    vlc_dictionary_t *p_dict      = &fs->family_map;
     vlc_family_t     *p_dest      = NULL;
     char             *psz_name    = NULL;
     char             *psz_dest    = NULL;
@@ -218,10 +217,9 @@ done:
     return i_ret;
 }
 
-static int Android_Legacy_ParseFamily( filter_t *p_filter, xml_reader_t *p_xml )
+static int Android_Legacy_ParseFamily( vlc_font_select_t *fs, xml_reader_t *p_xml )
 {
-    filter_sys_t     *p_sys       = p_filter->p_sys;
-    vlc_dictionary_t *p_dict      = &p_sys->family_map;
+    vlc_dictionary_t *p_dict      = &fs->family_map;
     vlc_family_t     *p_family    = NULL;
     char             *psz_lc      = NULL;
     int               i_counter   = 0;
@@ -250,7 +248,7 @@ static int Android_Legacy_ParseFamily( filter_t *p_filter, xml_reader_t *p_xml )
 
                 if( i_type != XML_READER_TEXT || !p_node || !*p_node )
                 {
-                    msg_Warn( p_filter, "Android_ParseFamily: empty name" );
+                    msg_Warn( fs->p_obj, "Android_ParseFamily: empty name" );
                     continue;
                 }
 
@@ -264,7 +262,7 @@ static int Android_Legacy_ParseFamily( filter_t *p_filter, xml_reader_t *p_xml )
                     if( p_family == kVLCDictionaryNotFound )
                     {
                         p_family =
-                            NewFamily( p_filter, psz_lc, &p_sys->p_families, NULL, NULL );
+                            NewFamily( fs, psz_lc, &fs->p_families, NULL, NULL );
 
                         if( unlikely( !p_family ) )
                         {
@@ -296,8 +294,8 @@ static int Android_Legacy_ParseFamily( filter_t *p_filter, xml_reader_t *p_xml )
                 }
 
                 if( !p_family )
-                    p_family = NewFamily( p_filter, NULL, &p_sys->p_families,
-                                          &p_sys->family_map, NULL );
+                    p_family = NewFamily( fs, NULL, &fs->p_families,
+                                          &fs->family_map, NULL );
 
                 if( unlikely( !p_family ) )
                     return VLC_ENOMEM;
@@ -321,7 +319,7 @@ static int Android_Legacy_ParseFamily( filter_t *p_filter, xml_reader_t *p_xml )
                     b_italic = true;
                     break;
                 default:
-                    msg_Warn( p_filter, "Android_ParseFamily: too many files" );
+                    msg_Warn( fs->p_obj, "Android_ParseFamily: too many files" );
                     return VLC_EGENERIC;
                 }
 
@@ -339,7 +337,7 @@ static int Android_Legacy_ParseFamily( filter_t *p_filter, xml_reader_t *p_xml )
             {
                 if( !p_family )
                 {
-                    msg_Warn( p_filter, "Android_ParseFamily: empty family" );
+                    msg_Warn( fs->p_obj, "Android_ParseFamily: empty family" );
                     return VLC_EGENERIC;
                 }
 
@@ -350,8 +348,8 @@ static int Android_Legacy_ParseFamily( filter_t *p_filter, xml_reader_t *p_xml )
                 if( strcasestr( p_family->psz_name, FB_NAME ) )
                 {
                     vlc_family_t *p_fallback =
-                        NewFamily( p_filter, p_family->psz_name,
-                                   NULL, &p_sys->fallback_map, FB_LIST_DEFAULT );
+                        NewFamily( fs, p_family->psz_name,
+                                   NULL, &fs->fallback_map, FB_LIST_DEFAULT );
 
                     if( unlikely( !p_fallback ) )
                         return VLC_ENOMEM;
@@ -365,20 +363,20 @@ static int Android_Legacy_ParseFamily( filter_t *p_filter, xml_reader_t *p_xml )
         }
     }
 
-    msg_Warn( p_filter, "Android_ParseOldFamily: Corrupt font configuration file" );
+    msg_Warn( fs->p_obj, "Android_ParseOldFamily: Corrupt font configuration file" );
     return VLC_EGENERIC;
 }
 
-static int Android_ParseSystemFonts( filter_t *p_filter, const char *psz_path,
+static int Android_ParseSystemFonts( vlc_font_select_t *fs, const char *psz_path,
                                      bool b_new_format )
 {
     int i_ret = VLC_SUCCESS;
-    stream_t *p_stream = vlc_stream_NewURL( p_filter, psz_path );
+    stream_t *p_stream = vlc_stream_NewURL( fs->p_obj, psz_path );
 
     if( !p_stream )
         return VLC_EGENERIC;
 
-    xml_reader_t *p_xml = xml_ReaderCreate( p_filter, p_stream );
+    xml_reader_t *p_xml = xml_ReaderCreate( fs->p_obj, p_stream );
 
     if( !p_xml )
     {
@@ -392,17 +390,17 @@ static int Android_ParseSystemFonts( filter_t *p_filter, const char *psz_path,
     {
         if( i_type == XML_READER_STARTELEM && !strcasecmp( "family", p_node ) && b_new_format )
         {
-            if( ( i_ret = Android_Nougat_ParseFamily( p_filter, p_xml ) ) )
+            if( ( i_ret = Android_Nougat_ParseFamily( fs, p_xml ) ) )
                 break;
         }
         else if( i_type == XML_READER_STARTELEM && !strcasecmp( "family", p_node ) && !b_new_format )
         {
-            if( ( i_ret = Android_Legacy_ParseFamily( p_filter, p_xml ) ) )
+            if( ( i_ret = Android_Legacy_ParseFamily( fs, p_xml ) ) )
                 break;
         }
         else if( i_type == XML_READER_STARTELEM && !strcasecmp( "alias", p_node ) && b_new_format )
         {
-            if( ( i_ret = Android_ParseAlias( p_filter, p_xml ) ) )
+            if( ( i_ret = Android_ParseAlias( fs, p_xml ) ) )
                 break;
         }
     }
@@ -412,30 +410,29 @@ static int Android_ParseSystemFonts( filter_t *p_filter, const char *psz_path,
     return i_ret;
 }
 
-int Android_Prepare( filter_t *p_filter )
+int Android_Prepare( vlc_font_select_t *fs )
 {
-    if( Android_ParseSystemFonts( p_filter, ANDROID_SYSTEM_FONTS_NOUGAT, true ) != VLC_SUCCESS )
+    if( Android_ParseSystemFonts( fs, ANDROID_SYSTEM_FONTS_NOUGAT, true ) != VLC_SUCCESS )
     {
-        if( Android_ParseSystemFonts( p_filter, ANDROID_SYSTEM_FONTS_LEGACY, false ) == VLC_ENOMEM )
+        if( Android_ParseSystemFonts( fs, ANDROID_SYSTEM_FONTS_LEGACY, false ) == VLC_ENOMEM )
             return VLC_ENOMEM;
-        if( Android_ParseSystemFonts( p_filter, ANDROID_FALLBACK_FONTS, false ) == VLC_ENOMEM )
+        if( Android_ParseSystemFonts( fs, ANDROID_FALLBACK_FONTS, false ) == VLC_ENOMEM )
             return VLC_ENOMEM;
-        if( Android_ParseSystemFonts( p_filter, ANDROID_VENDOR_FONTS, false ) == VLC_ENOMEM )
+        if( Android_ParseSystemFonts( fs, ANDROID_VENDOR_FONTS, false ) == VLC_ENOMEM )
             return VLC_ENOMEM;
     }
 
     return VLC_SUCCESS;
 }
 
-const vlc_family_t *Android_GetFamily( filter_t *p_filter, const char *psz_family )
+const vlc_family_t *Android_GetFamily( vlc_font_select_t *fs, const char *psz_family )
 {
-    filter_sys_t *p_sys = p_filter->p_sys;
     char *psz_lc = ToLower( psz_family );
     if( unlikely( !psz_lc ) )
         return NULL;
 
     vlc_family_t *p_family =
-            vlc_dictionary_value_for_key( &p_sys->family_map, psz_lc );
+            vlc_dictionary_value_for_key( &fs->family_map, psz_lc );
 
     free( psz_lc );
 
@@ -445,18 +442,17 @@ const vlc_family_t *Android_GetFamily( filter_t *p_filter, const char *psz_famil
     return p_family;
 }
 
-vlc_family_t *Android_GetFallbacks( filter_t *p_filter, const char *psz_family,
+vlc_family_t *Android_GetFallbacks( vlc_font_select_t *fs, const char *psz_family,
                                     uni_char_t codepoint )
 {
     VLC_UNUSED( codepoint );
 
     vlc_family_t *p_fallbacks = NULL;
-    filter_sys_t *p_sys = p_filter->p_sys;
     char *psz_lc = ToLower( psz_family );
     if( unlikely( !psz_lc ) )
         return NULL;
 
-    p_fallbacks = vlc_dictionary_value_for_key( &p_sys->fallback_map, psz_lc );
+    p_fallbacks = vlc_dictionary_value_for_key( &fs->fallback_map, psz_lc );
 
     free( psz_lc );
 
diff --git a/modules/text_renderer/freetype/fonts/backends.h b/modules/text_renderer/freetype/fonts/backends.h
new file mode 100644
index 0000000000..88058b0449
--- /dev/null
+++ b/modules/text_renderer/freetype/fonts/backends.h
@@ -0,0 +1,99 @@
+/*****************************************************************************
+ * backends.h : freetype font configuration backends declarations
+ *****************************************************************************
+ * Copyright (C) 2002 - 2015 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+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 );
+
+    vlc_family_t * (*pf_get_fallbacks) ( vlc_font_select_t *, const char *psz_family,
+                     uni_char_t codepoint );
+
+    /**
+     * 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;
+
+    /**
+     * This maps a family name to a vlc_family_t within the master list
+     */
+    vlc_dictionary_t  family_map;
+
+    /**
+     * This maps a family name to a fallback list of vlc_family_t's.
+     * Fallback lists only reference the lists of vlc_font_t's within the
+     * master list, so they should be freed using FreeFamilies()
+     */
+    vlc_dictionary_t  fallback_map;
+
+    int               i_fallback_counter;
+
+#if defined( _WIN32 )
+    void *p_dw_sys;
+#endif
+};
+
+/***
+ * 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_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 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 );
+
+const vlc_family_t *Win32_GetFamily( vlc_font_select_t *, const char *psz_family );
+#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);
+#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_Prepare( vlc_font_select_t * );
+#endif /* __ANDROID__ */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/text_renderer/freetype/fonts/darwin.c b/modules/text_renderer/freetype/fonts/darwin.c
index 53fa28a3a4..9d99bea30a 100644
--- a/modules/text_renderer/freetype/fonts/darwin.c
+++ b/modules/text_renderer/freetype/fonts/darwin.c
@@ -38,6 +38,7 @@
 #include <CoreText/CoreText.h>
 
 #include "../platform_fonts.h"
+#include "backends.h"
 
 static char* getPathForFontDescription(CTFontDescriptorRef fontDescriptor)
 {
@@ -55,7 +56,7 @@ static char* getPathForFontDescription(CTFontDescriptorRef fontDescriptor)
     return retPath;
 }
 
-static void addNewFontToFamily(filter_t *p_filter, CTFontDescriptorRef iter, char *path, vlc_family_t *p_family)
+static void addNewFontToFamily(vlc_font_select_t *fs, CTFontDescriptorRef iter, char *path, vlc_family_t *p_family)
 {
     bool b_bold = false;
     bool b_italic = false;
@@ -70,19 +71,17 @@ static void addNewFontToFamily(filter_t *p_filter, CTFontDescriptorRef iter, cha
     b_italic = traitValue > 0.03;
 
 #ifndef NDEBUG
-    msg_Dbg(p_filter, "New font: bold %i italic %i path '%s'", b_bold, b_italic, path);
+    msg_Dbg(fs->p_obj, "New font: bold %i italic %i path '%s'", b_bold, b_italic, path);
 #else
-    VLC_UNUSED(p_filter);
+    VLC_UNUSED(fs);
 #endif
     NewFont(path, 0, b_bold, b_italic, p_family);
 
     CFRelease(fontTraits);
 }
 
-const vlc_family_t *CoreText_GetFamily(filter_t *p_filter, const char *psz_family)
+const vlc_family_t *CoreText_GetFamily(vlc_font_select_t *fs, const char *psz_family)
 {
-    filter_sys_t *p_sys = p_filter->p_sys;
-
     if (unlikely(psz_family == NULL)) {
         return NULL;
     }
@@ -93,7 +92,7 @@ const vlc_family_t *CoreText_GetFamily(filter_t *p_filter, const char *psz_famil
     }
 
     /* let's double check if we have parsed this family already */
-    vlc_family_t *p_family = vlc_dictionary_value_for_key(&p_sys->family_map, psz_lc);
+    vlc_family_t *p_family = vlc_dictionary_value_for_key(&fs->family_map, psz_lc);
     if (p_family) {
         free(psz_lc);
         return p_family;
@@ -113,7 +112,7 @@ const vlc_family_t *CoreText_GetFamily(filter_t *p_filter, const char *psz_famil
     };
 
 #ifndef NDEBUG
-    msg_Dbg(p_filter, "Creating new family for '%s'", psz_family);
+    msg_Dbg(fs->p_obj, "Creating new family for '%s'", psz_family);
 #endif
 
     CFStringRef familyName = CFStringCreateWithCString(kCFAllocatorDefault,
@@ -131,13 +130,13 @@ const vlc_family_t *CoreText_GetFamily(filter_t *p_filter, const char *psz_famil
 
     coreTextFontCollection = CTFontCollectionCreateWithFontDescriptors(coreTextFontDescriptorsArray, 0);
     if (coreTextFontCollection == NULL) {
-        msg_Warn(p_filter,"CTFontCollectionCreateWithFontDescriptors (1) failed!");
+        msg_Warn(fs->p_obj,"CTFontCollectionCreateWithFontDescriptors (1) failed!");
         goto end;
     }
 
     matchedFontDescriptions = CTFontCollectionCreateMatchingFontDescriptors(coreTextFontCollection);
     if (matchedFontDescriptions == NULL) {
-        msg_Warn(p_filter, "CTFontCollectionCreateMatchingFontDescriptors (2) failed!");
+        msg_Warn(fs->p_obj, "CTFontCollectionCreateMatchingFontDescriptors (2) failed!");
         goto end;
     }
 
@@ -146,7 +145,7 @@ const vlc_family_t *CoreText_GetFamily(filter_t *p_filter, const char *psz_famil
     char *path = NULL;
 
     /* create a new family object */
-    p_family = NewFamily(p_filter, psz_lc, &p_sys->p_families, &p_sys->family_map, psz_lc);
+    p_family = NewFamily(fs, psz_lc, &fs->p_families, &fs->family_map, psz_lc);
     if (unlikely(!p_family)) {
         goto end;
     }
@@ -161,7 +160,7 @@ const vlc_family_t *CoreText_GetFamily(filter_t *p_filter, const char *psz_famil
             continue;
         }
 
-        addNewFontToFamily(p_filter, iter, path, p_family);
+        addNewFontToFamily(fs, iter, path, p_family);
     }
 
 end:
@@ -184,9 +183,8 @@ end:
     return p_family;
 }
 
-vlc_family_t *CoreText_GetFallbacks(filter_t *p_filter, const char *psz_family, uni_char_t codepoint)
+vlc_family_t *CoreText_GetFallbacks(vlc_font_select_t *fs, const char *psz_family, uni_char_t codepoint)
 {
-    filter_sys_t *p_sys = p_filter->p_sys;
     if (unlikely(psz_family == NULL)) {
         return NULL;
     }
@@ -213,21 +211,21 @@ vlc_family_t *CoreText_GetFallbacks(filter_t *p_filter, const char *psz_family,
     /* create a new family object */
     char *psz_fallbackFamilyName = FromCFString(fallbackFontFamilyName, kCFStringEncodingUTF8);
     if (psz_fallbackFamilyName == NULL) {
-        msg_Warn(p_filter, "Failed to convert font family name CFString to C string");
+        msg_Warn(fs->p_obj, "Failed to convert font family name CFString to C string");
         goto done;
     }
 #ifndef NDEBUG
-    msg_Dbg(p_filter, "Will deploy fallback font '%s'", psz_fallbackFamilyName);
+    msg_Dbg(fs->p_obj, "Will deploy fallback font '%s'", psz_fallbackFamilyName);
 #endif
 
     psz_lc_fallback = ToLower(psz_fallbackFamilyName);
 
-    p_family = vlc_dictionary_value_for_key(&p_sys->family_map, psz_lc_fallback);
+    p_family = vlc_dictionary_value_for_key(&fs->family_map, psz_lc_fallback);
     if (p_family) {
         goto done;
     }
 
-    p_family = NewFamily(p_filter, psz_lc_fallback, &p_sys->p_families, &p_sys->family_map, psz_lc_fallback);
+    p_family = NewFamily(fs, psz_lc_fallback, &fs->p_families, &fs->family_map, psz_lc_fallback);
     if (unlikely(!p_family)) {
         goto done;
     }
@@ -241,7 +239,7 @@ vlc_family_t *CoreText_GetFallbacks(filter_t *p_filter, const char *psz_family,
         goto done;
     }
 
-    addNewFontToFamily(p_filter, fallbackFontDescriptor, strdup(psz_fontPath), p_family);
+    addNewFontToFamily(fs, fallbackFontDescriptor, strdup(psz_fontPath), p_family);
 
 done:
     CFRelease(familyName);
diff --git a/modules/text_renderer/freetype/fonts/dwrite.cpp b/modules/text_renderer/freetype/fonts/dwrite.cpp
index 1e4f168a02..950ae55f06 100644
--- a/modules/text_renderer/freetype/fonts/dwrite.cpp
+++ b/modules/text_renderer/freetype/fonts/dwrite.cpp
@@ -35,6 +35,7 @@
 #include <regex>
 
 #include "../platform_fonts.h"
+#include "backends.h"
 
 using Microsoft::WRL::ComPtr;
 using namespace std;
@@ -103,7 +104,7 @@ static inline void AppendFamily( vlc_family_t **pp_list, vlc_family_t *p_family
     *pp_list = p_family;
 }
 
-extern "C" int InitDWrite( filter_t *p_filter )
+extern "C" int InitDWrite( vlc_font_select_t *fs )
 {
     dw_sys_t *p_dw_sys;
     HMODULE p_dw_dll = NULL;
@@ -126,22 +127,20 @@ extern "C" int InitDWrite( filter_t *p_filter )
         FreeLibrary( p_dw_dll );
         (void)e;
 #else
-        msg_Err( p_filter, "InitDWrite(): %s", e.what() );
+        msg_Err( fs->p_obj, "InitDWrite(): %s", e.what() );
 #endif
 
         return VLC_EGENERIC;
     }
 
-    filter_sys_t *p_sys = reinterpret_cast<filter_sys_t *>( p_filter->p_sys );
-    p_sys->p_dw_sys = p_dw_sys;
-    msg_Dbg( p_filter, "Using DWrite backend" );
+    fs->p_dw_sys = p_dw_sys;
+    msg_Dbg( fs->p_obj, "Using DWrite backend" );
     return VLC_SUCCESS;
 }
 
-extern "C" int ReleaseDWrite( filter_t *p_filter )
+extern "C" int ReleaseDWrite( vlc_font_select_t *fs )
 {
-    filter_sys_t *p_sys = reinterpret_cast<filter_sys_t *>( p_filter->p_sys );
-    dw_sys_t *p_dw_sys = ( dw_sys_t * ) p_sys->p_dw_sys;
+    dw_sys_t *p_dw_sys = ( dw_sys_t * ) fs->p_dw_sys;
 
 #if VLC_WINSTORE_APP
     delete p_dw_sys;
@@ -157,10 +156,9 @@ extern "C" int ReleaseDWrite( filter_t *p_filter )
     return VLC_SUCCESS;
 }
 
-extern "C" int DWrite_GetFontStream( filter_t *p_filter, int i_index, FT_Stream *pp_stream )
+extern "C" int DWrite_GetFontStream( vlc_font_select_t *fs, int i_index, FT_Stream *pp_stream )
 {
-    filter_sys_t *p_sys = reinterpret_cast<filter_sys_t *>( p_filter->p_sys );
-    dw_sys_t *p_dw_sys = ( dw_sys_t * ) p_sys->p_dw_sys;
+    dw_sys_t *p_dw_sys = ( dw_sys_t * ) fs->p_dw_sys;
 
     if( i_index < 0 || i_index >= ( int ) p_dw_sys->streams.size() )
         return VLC_ENOITEM;
@@ -329,7 +327,7 @@ static wstring SanitizeName( const wstring &name )
  * Also used for face names, in which case Thin will match Thin,
  * Thin Italic, Thin Oblique...
  */
-static bool DWrite_PartialMatch( filter_t *p_filter, const wstring &full_name,
+static bool DWrite_PartialMatch( vlc_font_select_t *fs, const wstring &full_name,
                                  const wstring &partial_name, wstring *p_unmatched = nullptr )
 {
     auto pattern = wstring{ L"^" } + SanitizeName( partial_name ) + wstring{ L"\\s*(.*)$" };
@@ -340,7 +338,7 @@ static bool DWrite_PartialMatch( filter_t *p_filter, const wstring &full_name,
     if( !regex_match( full_name, match, rx ) )
         return false;
 
-    msg_Dbg( p_filter, "DWrite_PartialMatch(): %S matches %S", full_name.c_str(), partial_name.c_str() );
+    msg_Dbg( fs->p_obj, "DWrite_PartialMatch(): %S matches %S", full_name.c_str(), partial_name.c_str() );
 
     if( p_unmatched )
         *p_unmatched = match[ 1 ].str();
@@ -353,7 +351,7 @@ static bool DWrite_PartialMatch( filter_t *p_filter, const wstring &full_name,
  * The 3 locales tested are en-US and the user and system default locales. b_partial determines
  * which parameter has the partial string, p_names or name.
  */
-static bool DWrite_PartialMatch( filter_t *p_filter, ComPtr< IDWriteLocalizedStrings > &p_names,
+static bool DWrite_PartialMatch( vlc_font_select_t *fs, ComPtr< IDWriteLocalizedStrings > &p_names,
                                  const wstring &name, bool b_partial, wstring *p_unmatched = nullptr )
 {
     wchar_t buff_sys[ LOCALE_NAME_MAX_LENGTH ] = {};
@@ -389,9 +387,9 @@ static bool DWrite_PartialMatch( filter_t *p_filter, ComPtr< IDWriteLocalizedStr
                     {
                         bool b_result;
                         if( b_partial )
-                            b_result = DWrite_PartialMatch( p_filter, locale_name, name, p_unmatched );
+                            b_result = DWrite_PartialMatch( fs, locale_name, name, p_unmatched );
                         else
-                            b_result = DWrite_PartialMatch( p_filter, name, locale_name, p_unmatched );
+                            b_result = DWrite_PartialMatch( fs, name, locale_name, p_unmatched );
 
                         if( b_result )
                             return true;
@@ -407,7 +405,7 @@ static bool DWrite_PartialMatch( filter_t *p_filter, ComPtr< IDWriteLocalizedStr
     return false;
 }
 
-static vector< ComPtr< IDWriteFont > > DWrite_GetFonts( filter_t *p_filter, IDWriteFontFamily *p_dw_family,
+static vector< ComPtr< IDWriteFont > > DWrite_GetFonts( vlc_font_select_t *fs, IDWriteFontFamily *p_dw_family,
                                                         const wstring &face_name )
 {
     vector< ComPtr< IDWriteFont > > result;
@@ -426,7 +424,7 @@ static vector< ComPtr< IDWriteFont > > DWrite_GetFonts( filter_t *p_filter, IDWr
             if( FAILED( p_dw_font->GetFaceNames( p_dw_names.GetAddressOf() ) ) )
                 throw runtime_error( "GetFaceNames() failed" );
 
-            if( DWrite_PartialMatch( p_filter, p_dw_names, face_name, true ) )
+            if( DWrite_PartialMatch( fs, p_dw_names, face_name, true ) )
                 result.push_back( p_dw_font );
         }
     }
@@ -464,10 +462,10 @@ static vector< ComPtr< IDWriteFont > > DWrite_GetFonts( filter_t *p_filter, IDWr
     return result;
 }
 
-static void DWrite_ParseFamily( filter_t *p_filter, IDWriteFontFamily *p_dw_family, const wstring &face_name,
+static void DWrite_ParseFamily( vlc_font_select_t *fs, IDWriteFontFamily *p_dw_family, const wstring &face_name,
                                 vlc_family_t *p_family, vector< FT_Stream > &streams )
 {
-    vector< ComPtr< IDWriteFont > > fonts = DWrite_GetFonts( p_filter, p_dw_family, face_name );
+    vector< ComPtr< IDWriteFont > > fonts = DWrite_GetFonts( fs, p_dw_family, face_name );
 
     /*
      * We select at most 4 fonts to add to p_family, one for each style. So in case of
@@ -495,14 +493,14 @@ static void DWrite_ParseFamily( filter_t *p_filter, IDWriteFontFamily *p_dw_fami
             int i_weight = b_bold ? 700 : 400;
             if( abs( ( *pp_font )->GetWeight() - i_weight ) > abs( p_dw_font->GetWeight() - i_weight ) )
             {
-                msg_Dbg( p_filter, "DWrite_ParseFamily(): using font at index %u with weight %u for bold: %d, italic: %d",
+                msg_Dbg( fs->p_obj, "DWrite_ParseFamily(): using font at index %u with weight %u for bold: %d, italic: %d",
                          ( unsigned ) i, p_dw_font->GetWeight(), b_bold, b_italic );
                 *pp_font = p_dw_font.Get();
             }
         }
         else
         {
-            msg_Dbg( p_filter, "DWrite_ParseFamily(): using font at index %u with weight %u for bold: %d, italic: %d",
+            msg_Dbg( fs->p_obj, "DWrite_ParseFamily(): using font at index %u with weight %u for bold: %d, italic: %d",
                      ( unsigned ) i, p_dw_font->GetWeight(), b_bold, b_italic );
             *pp_font = p_dw_font.Get();
         }
@@ -571,10 +569,9 @@ static void DWrite_ParseFamily( filter_t *p_filter, IDWriteFontFamily *p_dw_fami
     }
 }
 
-extern "C" const vlc_family_t *DWrite_GetFamily( filter_t *p_filter, const char *psz_family )
+extern "C" const vlc_family_t *DWrite_GetFamily( vlc_font_select_t *fs, const char *psz_family )
 {
-    filter_sys_t *p_sys = reinterpret_cast<filter_sys_t *>( p_filter->p_sys );
-    dw_sys_t                     *p_dw_sys     = ( dw_sys_t * ) p_sys->p_dw_sys;
+    dw_sys_t                     *p_dw_sys     = ( dw_sys_t * ) fs->p_dw_sys;
     ComPtr< IDWriteFontFamily >   p_dw_family;
 
     UINT32 i_index;
@@ -585,20 +582,20 @@ extern "C" const vlc_family_t *DWrite_GetFamily( filter_t *p_filter, const char
         return NULL;
 
     vlc_family_t *p_family =
-        ( vlc_family_t * ) vlc_dictionary_value_for_key( &p_sys->family_map, psz_lc );
+        ( vlc_family_t * ) vlc_dictionary_value_for_key( &fs->family_map, psz_lc );
 
     free( psz_lc );
 
     if( p_family )
         return p_family;
 
-    p_family = NewFamily( p_filter, psz_family, &p_sys->p_families,
-                          &p_sys->family_map, psz_family );
+    p_family = NewFamily( fs, psz_family, &fs->p_families,
+                          &fs->family_map, psz_family );
 
     if( unlikely( !p_family ) )
         return NULL;
 
-    msg_Dbg( p_filter, "DWrite_GetFamily(): family name: %s", psz_family );
+    msg_Dbg( fs->p_obj, "DWrite_GetFamily(): family name: %s", psz_family );
 
     wchar_t *pwsz_family = ToWide( psz_family );
     if( unlikely( !pwsz_family ) )
@@ -609,17 +606,17 @@ extern "C" const vlc_family_t *DWrite_GetFamily( filter_t *p_filter, const char
     {
         if( FAILED( p_dw_sys->p_dw_system_fonts->GetFontFamily( i_index, p_dw_family.GetAddressOf() ) ) )
         {
-            msg_Err( p_filter, "DWrite_GetFamily: GetFontFamily() failed" );
+            msg_Err( fs->p_obj, "DWrite_GetFamily: GetFontFamily() failed" );
             goto done;
         }
 
         try
         {
-            DWrite_ParseFamily( p_filter, p_dw_family.Get(), wstring{}, p_family, p_dw_sys->streams );
+            DWrite_ParseFamily( fs, p_dw_family.Get(), wstring{}, p_family, p_dw_sys->streams );
         }
         catch( const exception &e )
         {
-            msg_Err( p_filter, "DWrite_GetFamily(): %s", e.what() );
+            msg_Err( fs->p_obj, "DWrite_GetFamily(): %s", e.what() );
             goto done;
         }
     }
@@ -645,26 +642,26 @@ extern "C" const vlc_family_t *DWrite_GetFamily( filter_t *p_filter, const char
             ComPtr< IDWriteFontFamily > p_cur_family;
             if( FAILED( p_dw_sys->p_dw_system_fonts->GetFontFamily( i_index, p_cur_family.GetAddressOf() ) ) )
             {
-                msg_Err( p_filter, "DWrite_GetFamily: GetFontFamily() failed" );
+                msg_Err( fs->p_obj, "DWrite_GetFamily: GetFontFamily() failed" );
                 continue;
             }
 
             if( FAILED( p_cur_family->GetFamilyNames( p_names.GetAddressOf() ) ) )
             {
-                msg_Err( p_filter, "DWrite_GetFamily: GetFamilyNames() failed" );
+                msg_Err( fs->p_obj, "DWrite_GetFamily: GetFamilyNames() failed" );
                 continue;
             }
 
-            if( !DWrite_PartialMatch( p_filter, p_names, wstring{ pwsz_family }, false, &face_name ) )
+            if( !DWrite_PartialMatch( fs, p_names, wstring{ pwsz_family }, false, &face_name ) )
                 continue;
 
             try
             {
-                DWrite_ParseFamily( p_filter, p_cur_family.Get(), face_name, p_family, p_dw_sys->streams );
+                DWrite_ParseFamily( fs, p_cur_family.Get(), face_name, p_family, p_dw_sys->streams );
             }
             catch( const exception &e )
             {
-                msg_Err( p_filter, "DWrite_GetFamily(): %s", e.what() );
+                msg_Err( fs->p_obj, "DWrite_GetFamily(): %s", e.what() );
             }
 
             /*
@@ -684,11 +681,10 @@ done:
     return p_family;
 }
 
-static char *DWrite_Fallback( filter_t *p_filter, const char *psz_family,
+static char *DWrite_Fallback( vlc_font_select_t *fs, const char *psz_family,
                               uni_char_t codepoint )
 {
-    filter_sys_t *p_sys = reinterpret_cast<filter_sys_t *>( p_filter->p_sys );
-    dw_sys_t                         *p_dw_sys          = ( dw_sys_t * ) p_sys->p_dw_sys;
+    dw_sys_t                         *p_dw_sys          = ( dw_sys_t * ) fs->p_dw_sys;
     wchar_t                          *pwsz_buffer       = NULL;
     char                             *psz_result        = NULL;
     UINT32                            i_string_length   = 0;
@@ -698,7 +694,7 @@ static char *DWrite_Fallback( filter_t *p_filter, const char *psz_family,
     ComPtr< IDWriteFontFamily >       p_dw_family;
     ComPtr< IDWriteLocalizedStrings > p_names;
 
-    msg_Dbg( p_filter, "DWrite_Fallback(): family: %s, codepoint: 0x%x", psz_family, codepoint );
+    msg_Dbg( fs->p_obj, "DWrite_Fallback(): family: %s, codepoint: 0x%x", psz_family, codepoint );
 
     wchar_t p_text[2];
     UINT32  i_text_length;
@@ -716,25 +712,25 @@ static char *DWrite_Fallback( filter_t *p_filter, const char *psz_family,
                                   &i_mapped_length, p_dw_font.GetAddressOf(), &f_scale )
      || !p_dw_font )
     {
-        msg_Warn( p_filter, "DWrite_Fallback(): MapCharacters() failed" );
+        msg_Warn( fs->p_obj, "DWrite_Fallback(): MapCharacters() failed" );
         goto done;
     }
 
     if( p_dw_font->GetFontFamily( p_dw_family.GetAddressOf() ) )
     {
-        msg_Err( p_filter, "DWrite_Fallback(): GetFontFamily() failed" );
+        msg_Err( fs->p_obj, "DWrite_Fallback(): GetFontFamily() failed" );
         goto done;
     }
 
     if( p_dw_family->GetFamilyNames( p_names.GetAddressOf() ) )
     {
-        msg_Err( p_filter, "DWrite_Fallback(): GetFamilyNames() failed" );
+        msg_Err( fs->p_obj, "DWrite_Fallback(): GetFamilyNames() failed" );
         goto done;
     }
 
     if( p_names->GetStringLength( 0, &i_string_length ) )
     {
-        msg_Err( p_filter, "DWrite_Fallback(): GetStringLength() failed" );
+        msg_Err( fs->p_obj, "DWrite_Fallback(): GetStringLength() failed" );
         goto done;
     }
 
@@ -744,12 +740,12 @@ static char *DWrite_Fallback( filter_t *p_filter, const char *psz_family,
 
     if( p_names->GetString( 0, pwsz_buffer, i_string_length + 1 ) )
     {
-        msg_Err( p_filter, "DWrite_Fallback(): GetString() failed" );
+        msg_Err( fs->p_obj, "DWrite_Fallback(): GetString() failed" );
         goto done;
     }
 
     psz_result = FromWide( pwsz_buffer );
-    msg_Dbg( p_filter, "DWrite_Fallback(): returning %s", psz_result );
+    msg_Dbg( fs->p_obj, "DWrite_Fallback(): returning %s", psz_result );
 
 done:
     free( pwsz_buffer );
@@ -757,10 +753,9 @@ done:
     return psz_result;
 }
 
-extern "C" vlc_family_t *DWrite_GetFallbacks( filter_t *p_filter, const char *psz_family,
+extern "C" vlc_family_t *DWrite_GetFallbacks( vlc_font_select_t *fs, const char *psz_family,
                                               uni_char_t codepoint )
 {
-    filter_sys_t  *p_sys = reinterpret_cast<filter_sys_t *>( p_filter->p_sys );
     vlc_family_t  *p_family      = NULL;
     vlc_family_t  *p_fallbacks   = NULL;
     char          *psz_fallback  = NULL;
@@ -771,10 +766,10 @@ extern "C" vlc_family_t *DWrite_GetFallbacks( filter_t *p_filter, const char *ps
     if( unlikely( !psz_lc ) )
         return NULL;
 
-    p_fallbacks = ( vlc_family_t * ) vlc_dictionary_value_for_key( &p_sys->fallback_map, psz_lc );
+    p_fallbacks = ( vlc_family_t * ) vlc_dictionary_value_for_key( &fs->fallback_map, psz_lc );
 
     if( p_fallbacks )
-        p_family = SearchFallbacks( p_filter, p_fallbacks, codepoint );
+        p_family = SearchFallbacks( fs, p_fallbacks, codepoint );
 
     /*
      * If the fallback list of psz_family has no family which contains the requested
@@ -784,19 +779,19 @@ extern "C" vlc_family_t *DWrite_GetFallbacks( filter_t *p_filter, const char *ps
      */
     if( !p_family )
     {
-        psz_fallback = DWrite_Fallback( p_filter, psz_lc, codepoint );
+        psz_fallback = DWrite_Fallback( fs, psz_lc, codepoint );
 
         if( !psz_fallback )
             goto done;
 
-        const vlc_family_t *p_fallback = DWrite_GetFamily( p_filter, psz_fallback );
+        const vlc_family_t *p_fallback = DWrite_GetFamily( fs, psz_fallback );
         if( !p_fallback || !p_fallback->p_fonts )
             goto done;
 
-        if( !GetFace( p_filter, p_fallback->p_fonts, codepoint ) )
+        if( !GetFace( fs, p_fallback->p_fonts, codepoint ) )
             goto done;
 
-        p_family = NewFamily( p_filter, psz_fallback, NULL, NULL, NULL );
+        p_family = NewFamily( fs, psz_fallback, NULL, NULL, NULL );
 
         if( unlikely( !p_family ) )
             goto done;
@@ -806,7 +801,7 @@ extern "C" vlc_family_t *DWrite_GetFallbacks( filter_t *p_filter, const char *ps
         if( p_fallbacks )
             AppendFamily( &p_fallbacks, p_family );
         else
-            vlc_dictionary_insert( &p_sys->fallback_map,
+            vlc_dictionary_insert( &fs->fallback_map,
                                    psz_lc, p_family );
     }
 
diff --git a/modules/text_renderer/freetype/fonts/fontconfig.c b/modules/text_renderer/freetype/fonts/fontconfig.c
index 5a6e7fc6cb..d37b02fa4a 100644
--- a/modules/text_renderer/freetype/fonts/fontconfig.c
+++ b/modules/text_renderer/freetype/fonts/fontconfig.c
@@ -43,12 +43,13 @@
 #include <fontconfig/fontconfig.h>
 
 #include "../platform_fonts.h"
+#include "backends.h"
 
 static FcConfig *config;
 static uintptr_t refs;
 static vlc_mutex_t lock = VLC_STATIC_MUTEX;
 
-int FontConfig_Prepare( filter_t *p_filter )
+int FontConfig_Prepare( vlc_font_select_t *fs )
 {
     vlc_tick_t ts;
 
@@ -59,7 +60,7 @@ int FontConfig_Prepare( filter_t *p_filter )
         return VLC_SUCCESS;
     }
 
-    msg_Dbg( p_filter, "Building font databases.");
+    msg_Dbg( fs->p_obj, "Building font databases.");
     ts = vlc_tick_now();
 
 #ifndef _WIN32
@@ -73,7 +74,7 @@ int FontConfig_Prepare( filter_t *p_filter )
     config = FcInitLoadConfig();
 
     int i_ret =
-        vlc_dialog_display_progress( p_filter, true, 0.0, NULL,
+        vlc_dialog_display_progress( fs->p_obj, true, 0.0, NULL,
                                      _("Building font cache"),
                                      _("Please wait while your font cache is rebuilt.\n"
                                      "This should take less than a few minutes.") );
@@ -84,18 +85,19 @@ int FontConfig_Prepare( filter_t *p_filter )
         return VLC_ENOMEM;
 
     if( i_dialog_id != 0 )
-        vlc_dialog_cancel( p_filter, i_dialog_id );
+        vlc_dialog_cancel( fs->p_obj, i_dialog_id );
 
 #endif
 
     vlc_mutex_unlock( &lock );
-    msg_Dbg( p_filter, "Took %" PRId64 " microseconds", vlc_tick_now() - ts );
+    msg_Dbg( fs->p_obj, "Took %" PRId64 " microseconds", vlc_tick_now() - ts );
 
     return (config != NULL) ? VLC_SUCCESS : VLC_EGENERIC;
 }
 
-void FontConfig_Unprepare(void)
+void FontConfig_Unprepare( vlc_font_select_t *fs )
 {
+    VLC_UNUSED(fs);
     vlc_mutex_lock( &lock );
     assert( refs > 0 );
     if( --refs == 0 )
@@ -104,17 +106,15 @@ void FontConfig_Unprepare(void)
     vlc_mutex_unlock( &lock );
 }
 
-const vlc_family_t *FontConfig_GetFamily( filter_t *p_filter, const char *psz_family )
+const vlc_family_t *FontConfig_GetFamily( vlc_font_select_t *fs, const char *psz_family )
 {
-    filter_sys_t *p_sys = p_filter->p_sys;
-
     char *psz_lc = ToLower( psz_family );
 
     if( unlikely( !psz_lc ) )
         return NULL;
 
     vlc_family_t *p_family =
-            vlc_dictionary_value_for_key( &p_sys->family_map, psz_lc );
+            vlc_dictionary_value_for_key( &fs->family_map, psz_lc );
 
     if( p_family != kVLCDictionaryNotFound )
     {
@@ -122,8 +122,8 @@ const vlc_family_t *FontConfig_GetFamily( filter_t *p_filter, const char *psz_fa
         return p_family;
     }
 
-    p_family = NewFamily( p_filter, psz_lc, &p_sys->p_families,
-                          &p_sys->family_map, psz_lc );
+    p_family = NewFamily( fs, psz_lc, &fs->p_families,
+                          &fs->family_map, psz_lc );
 
     free( psz_lc );
     if( !p_family )
@@ -171,6 +171,7 @@ const vlc_family_t *FontConfig_GetFamily( filter_t *p_filter, const char *psz_fa
             FcPatternDestroy( p_pat );
             continue;
         }
+
         if( FcResultMatch != FcPatternGetInteger( p_pat, FC_INDEX, 0, &i_index ) )
         {
             i_index = 0;
@@ -196,21 +197,20 @@ const vlc_family_t *FontConfig_GetFamily( filter_t *p_filter, const char *psz_fa
     return p_family;
 }
 
-vlc_family_t *FontConfig_GetFallbacks( filter_t *p_filter, const char *psz_family,
+vlc_family_t *FontConfig_GetFallbacks( vlc_font_select_t *fs, const char *psz_family,
                                        uni_char_t codepoint )
 {
 
     VLC_UNUSED( codepoint );
 
     vlc_family_t *p_family = NULL;
-    filter_sys_t *p_sys    = p_filter->p_sys;
 
     char *psz_lc = ToLower( psz_family );
 
     if( unlikely( !psz_lc ) )
         return NULL;
 
-    p_family = vlc_dictionary_value_for_key( &p_sys->fallback_map, psz_lc );
+    p_family = vlc_dictionary_value_for_key( &fs->fallback_map, psz_lc );
 
     if( p_family != kVLCDictionaryNotFound )
     {
@@ -242,7 +242,7 @@ vlc_family_t *FontConfig_GetFallbacks( filter_t *p_filter, const char *psz_famil
                 /* Avoid duplicate family names */
                 if( strcasecmp( psz_last_name, psz_name ) )
                 {
-                    vlc_family_t *p_temp = NewFamily( p_filter, psz_name,
+                    vlc_family_t *p_temp = NewFamily( fs, psz_name,
                                                       &p_family, NULL, NULL );
 
                     if( unlikely( !p_temp ) )
@@ -264,7 +264,7 @@ vlc_family_t *FontConfig_GetFallbacks( filter_t *p_filter, const char *psz_famil
     FcPatternDestroy( p_pattern );
 
     if( p_family )
-        vlc_dictionary_insert( &p_sys->fallback_map, psz_lc, p_family );
+        vlc_dictionary_insert( &fs->fallback_map, psz_lc, p_family );
 
     free( psz_lc );
     return p_family;
diff --git a/modules/text_renderer/freetype/fonts/win32.c b/modules/text_renderer/freetype/fonts/win32.c
index 9dbe120a4f..bed26294c1 100644
--- a/modules/text_renderer/freetype/fonts/win32.c
+++ b/modules/text_renderer/freetype/fonts/win32.c
@@ -55,6 +55,7 @@
 #endif
 
 #include "../platform_fonts.h"
+#include "backends.h"
 
 #if !VLC_WINSTORE_APP
 #define FONT_DIR_NT  TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts")
@@ -331,7 +332,7 @@ done:
 
 struct enumFontCallbackContext
 {
-    filter_t *p_filter;
+    vlc_font_select_t *fs;
     vlc_family_t *p_family;
 };
 
@@ -380,7 +381,7 @@ static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *lpelfe, const NEWTEXTM
         psz_fontfile = psz_filename;
     else
     {
-        psz_fontfile = MakeFilePath( ctx->p_filter, psz_filename );
+        psz_fontfile = MakeFilePath( ctx->fs, psz_filename );
         free( psz_filename );
         if( !psz_fontfile )
             return 1;
@@ -391,24 +392,23 @@ static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *lpelfe, const NEWTEXTM
     return 1;
 }
 
-const vlc_family_t *Win32_GetFamily( filter_t *p_filter, const char *psz_family )
+const vlc_family_t *Win32_GetFamily( vlc_font_select_t *fs, const char *psz_family )
 {
-    filter_sys_t *p_sys = p_filter->p_sys;
     char *psz_lc = ToLower( psz_family );
 
     if( unlikely( !psz_lc ) )
         return NULL;
 
     vlc_family_t *p_family =
-        vlc_dictionary_value_for_key( &p_sys->family_map, psz_lc );
+        vlc_dictionary_value_for_key( &fs->family_map, psz_lc );
 
     free( psz_lc );
 
     if( p_family )
         return p_family;
 
-    p_family = NewFamily( p_filter, psz_family, &p_sys->p_families,
-                          &p_sys->family_map, psz_family );
+    p_family = NewFamily( fs, psz_family, &fs->p_families,
+                          &fs->family_map, psz_family );
 
     if( unlikely( !p_family ) )
         return NULL;
@@ -423,7 +423,7 @@ const vlc_family_t *Win32_GetFamily( filter_t *p_filter, const char *psz_family
     /* */
     HDC hDC = GetDC( NULL );
     struct enumFontCallbackContext ctx;
-    ctx.p_filter = p_filter;
+    ctx.fs = fs;
     ctx.p_family = NULL;
     EnumFontFamiliesEx(hDC, &lf, (FONTENUMPROC)&EnumFontCallback, (LPARAM)&ctx, 0);
     ReleaseDC(NULL, hDC);
@@ -520,12 +520,11 @@ error:
     return NULL;
 }
 
-vlc_family_t *Win32_GetFallbacks( filter_t *p_filter, const char *psz_family,
+vlc_family_t *Win32_GetFallbacks( vlc_font_select_t *fs, const char *psz_family,
                                   uni_char_t codepoint )
 {
     vlc_family_t  *p_family      = NULL;
     vlc_family_t  *p_fallbacks   = NULL;
-    filter_sys_t  *p_sys         = p_filter->p_sys;
     char          *psz_uniscribe = NULL;
 
 
@@ -534,10 +533,10 @@ vlc_family_t *Win32_GetFallbacks( filter_t *p_filter, const char *psz_family,
     if( unlikely( !psz_lc ) )
         return NULL;
 
-    p_fallbacks = vlc_dictionary_value_for_key( &p_sys->fallback_map, psz_lc );
+    p_fallbacks = vlc_dictionary_value_for_key( &fs->fallback_map, psz_lc );
 
     if( p_fallbacks )
-        p_family = SearchFallbacks( p_filter, p_fallbacks, codepoint );
+        p_family = SearchFallbacks( fs, p_fallbacks, codepoint );
 
     /*
      * If the fallback list of psz_family has no family which contains the requested
@@ -552,14 +551,14 @@ vlc_family_t *Win32_GetFallbacks( filter_t *p_filter, const char *psz_family,
         if( !psz_uniscribe )
             goto done;
 
-        const vlc_family_t *p_uniscribe = Win32_GetFamily( p_filter, psz_uniscribe );
+        const vlc_family_t *p_uniscribe = Win32_GetFamily( fs, psz_uniscribe );
         if( !p_uniscribe || !p_uniscribe->p_fonts )
             goto done;
 
-        if( !GetFace( p_filter, p_uniscribe->p_fonts, codepoint ) );
+        if( !GetFace( fs, p_uniscribe->p_fonts, codepoint ) )
             goto done;
 
-        p_family = NewFamily( p_filter, psz_uniscribe, NULL, NULL, NULL );
+        p_family = NewFamily( fs, psz_uniscribe, NULL, NULL, NULL );
 
         if( unlikely( !p_family ) )
             goto done;
@@ -569,7 +568,7 @@ vlc_family_t *Win32_GetFallbacks( filter_t *p_filter, const char *psz_family,
         if( p_fallbacks )
             AppendFamily( &p_fallbacks, p_family );
         else
-            vlc_dictionary_insert( &p_sys->fallback_map,
+            vlc_dictionary_insert( &fs->fallback_map,
                                    psz_lc, p_family );
     }
 
@@ -579,9 +578,9 @@ done:
     return p_family;
 }
 
-char * MakeFilePath( filter_t *p_filter, const char *psz_filename )
+char * MakeFilePath( vlc_font_select_t *fs, const char *psz_filename )
 {
-    VLC_UNUSED(p_filter);
+    VLC_UNUSED(fs);
 
     if( !psz_filename )
         return NULL;
diff --git a/modules/text_renderer/freetype/freetype.c b/modules/text_renderer/freetype/freetype.c
index 813a4f86dd..882aa925f7 100644
--- a/modules/text_renderer/freetype/freetype.c
+++ b/modules/text_renderer/freetype/freetype.c
@@ -42,28 +42,6 @@
 #include <vlc_text_style.h>                                   /* text_style_t*/
 #include <vlc_charset.h>
 
-/* apple stuff */
-#ifdef __APPLE__
-# undef HAVE_FONTCONFIG
-# define HAVE_GET_FONT_BY_FAMILY_NAME
-#endif
-
-/* Win32 */
-#ifdef _WIN32
-# undef HAVE_FONTCONFIG
-# define HAVE_GET_FONT_BY_FAMILY_NAME
-#endif
-
-/* FontConfig */
-#ifdef HAVE_FONTCONFIG
-# define HAVE_GET_FONT_BY_FAMILY_NAME
-#endif
-
-/* Android */
-#ifdef __ANDROID__
-# define HAVE_GET_FONT_BY_FAMILY_NAME
-#endif
-
 #include <assert.h>
 
 #include "platform_fonts.h"
@@ -299,7 +277,6 @@ static int LoadFontsFromAttachments( filter_t *p_filter )
     input_attachment_t  **pp_attachments;
     int                   i_attachments_cnt;
     FT_Face               p_face = NULL;
-    char                 *psz_lc = NULL;
 
     if( filter_GetInputAttachments( p_filter, &pp_attachments, &i_attachments_cnt ) )
         return VLC_EGENERIC;
@@ -336,31 +313,10 @@ static int LoadFontsFromAttachments( filter_t *p_filter )
                 bool b_bold = p_face->style_flags & FT_STYLE_FLAG_BOLD;
                 bool b_italic = p_face->style_flags & FT_STYLE_FLAG_ITALIC;
 
-                if( p_face->family_name )
-                    psz_lc = ToLower( p_face->family_name );
-                else
-                    if( asprintf( &psz_lc, FB_NAME"-%04d",
-                                  p_sys->i_fallback_counter++ ) < 0 )
-                        psz_lc = NULL;
-
-                if( unlikely( !psz_lc ) )
+                vlc_family_t *p_family = DeclareNewFamily( p_sys->fs, p_face->family_name );
+                if( unlikely( !p_family ) )
                     goto error;
 
-                vlc_family_t *p_family =
-                    vlc_dictionary_value_for_key( &p_sys->family_map, psz_lc );
-
-                if( p_family == kVLCDictionaryNotFound )
-                {
-                    p_family = NewFamily( p_filter, psz_lc, &p_sys->p_families,
-                                          &p_sys->family_map, psz_lc );
-
-                    if( unlikely( !p_family ) )
-                        goto error;
-                }
-
-                free( psz_lc );
-                psz_lc = NULL;
-
                 char *psz_fontfile;
                 if( asprintf( &psz_fontfile, ":/%d",
                               p_sys->i_font_attachments - 1 ) < 0
@@ -370,6 +326,9 @@ static int LoadFontsFromAttachments( filter_t *p_filter )
                 FT_Done_Face( p_face );
                 p_face = NULL;
 
+                /* Add font attachment to the "attachments" fallback list */
+                DeclareFamilyAsAttachMenFallback( p_sys->fs, p_family );
+
                 i_font_idx++;
             }
         }
@@ -381,36 +340,12 @@ static int LoadFontsFromAttachments( filter_t *p_filter )
 
     free( pp_attachments );
 
-    /* Add font attachments to the "attachments" fallback list */
-    vlc_family_t *p_attachments = NULL;
-
-    for( vlc_family_t *p_family = p_sys->p_families; p_family;
-         p_family = p_family->p_next )
-    {
-        vlc_family_t *p_temp = NewFamily( p_filter, p_family->psz_name, &p_attachments,
-                                          NULL, NULL );
-        if( unlikely( !p_temp ) )
-        {
-            if( p_attachments )
-                FreeFamilies( p_attachments, NULL );
-            return VLC_ENOMEM;
-        }
-        else
-            p_temp->p_fonts = p_family->p_fonts;
-    }
-
-    if( p_attachments )
-        vlc_dictionary_insert( &p_sys->fallback_map, FB_LIST_ATTACHMENTS, p_attachments );
-
     return VLC_SUCCESS;
 
 error:
     if( p_face )
         FT_Done_Face( p_face );
 
-    if( psz_lc )
-        free( psz_lc );
-
     for( int i = k + 1; i < i_attachments_cnt; ++i )
         vlc_input_attachment_Delete( pp_attachments[ i ] );
 
@@ -1444,10 +1379,8 @@ static int Create( vlc_object_t *p_this )
         p_sys->p_stroker = NULL;
     }
 
-    /* Dictionnaries for fonts and families */
+    /* Dictionnaries for fonts */
     vlc_dictionary_init( &p_sys->face_map, 50 );
-    vlc_dictionary_init( &p_sys->family_map, 50 );
-    vlc_dictionary_init( &p_sys->fallback_map, 20 );
 
     p_sys->i_scale = 100;
 
@@ -1482,57 +1415,12 @@ static int Create( vlc_object_t *p_this )
     p_sys->f_shadow_vector_x   = f_shadow_distance * cosf((float)(2. * M_PI) * f_shadow_angle / 360);
     p_sys->f_shadow_vector_y   = f_shadow_distance * sinf((float)(2. * M_PI) * f_shadow_angle / 360);
 
-    if( LoadFontsFromAttachments( p_filter ) == VLC_ENOMEM )
-        goto error;
-
-#ifdef HAVE_FONTCONFIG
-    p_sys->pf_get_family = FontConfig_GetFamily;
-    p_sys->pf_get_fallbacks = FontConfig_GetFallbacks;
-    if( FontConfig_Prepare( p_filter ) )
-    {
-        p_sys->pf_get_family = NULL;
-        goto error;
-    }
-
-#elif defined( __APPLE__ )
-    p_sys->pf_get_family = CoreText_GetFamily;
-    p_sys->pf_get_fallbacks = CoreText_GetFallbacks;
-#elif defined( _WIN32 )
-    if( InitDWrite( p_filter ) == VLC_SUCCESS )
-    {
-        p_sys->pf_get_family = DWrite_GetFamily;
-        p_sys->pf_get_fallbacks = DWrite_GetFallbacks;
-    }
-    else
-    {
-#if VLC_WINSTORE_APP
-        msg_Err( p_filter, "Error initializing DirectWrite" );
+    p_sys->fs = FontSelectNew( p_filter  );
+    if( !p_sys->fs )
         goto error;
-#else
-        msg_Warn( p_filter, "DirectWrite initialization failed. Falling back to GDI/Uniscribe" );
-        const char *const ppsz_win32_default[] =
-            { "Tahoma", "FangSong", "SimHei", "KaiTi" };
-        p_sys->pf_get_family = Win32_GetFamily;
-        p_sys->pf_get_fallbacks = Win32_GetFallbacks;
-        InitDefaultList( p_filter, ppsz_win32_default,
-                         sizeof( ppsz_win32_default ) / sizeof( *ppsz_win32_default ) );
-#endif
-    }
-#elif defined( __ANDROID__ )
-    p_sys->pf_get_family = Android_GetFamily;
-    p_sys->pf_get_fallbacks = Android_GetFallbacks;
 
-    if( Android_Prepare( p_filter ) == VLC_ENOMEM )
+    if( LoadFontsFromAttachments( p_filter ) == VLC_ENOMEM )
         goto error;
-#else
-    p_sys->pf_get_family = StaticMap_GetFamily;
-    p_sys->pf_get_fallbacks = NULL;
-    /* The default static fonts are also fallback fonts */
-    const char *const ppsz_default[] =
-        { DEFAULT_FAMILY, DEFAULT_MONOSPACE_FAMILY };
-    InitDefaultList( p_filter, ppsz_default,
-                     sizeof( ppsz_default ) / sizeof( *ppsz_default ) );
-#endif
 
     p_sys->p_face = SelectAndLoadFace( p_filter, p_sys->p_default_style, ' ' );
     if( !p_sys->p_face )
@@ -1562,18 +1450,7 @@ static void Destroy( vlc_object_t *p_this )
     filter_sys_t *p_sys = p_filter->p_sys;
 
 #ifdef DEBUG_PLATFORM_FONTS
-    msg_Dbg( p_filter, "------------------" );
-    msg_Dbg( p_filter, "p_sys->p_families:" );
-    msg_Dbg( p_filter, "------------------" );
-    DumpFamily( p_filter, p_sys->p_families, true, -1 );
-    msg_Dbg( p_filter, "-----------------" );
-    msg_Dbg( p_filter, "p_sys->family_map" );
-    msg_Dbg( p_filter, "-----------------" );
-    DumpDictionary( p_filter, &p_sys->family_map, false, 1 );
-    msg_Dbg( p_filter, "-------------------" );
-    msg_Dbg( p_filter, "p_sys->fallback_map" );
-    msg_Dbg( p_filter, "-------------------" );
-    DumpDictionary( p_filter, &p_sys->fallback_map, true, -1 );
+    DumpFamilies( p_sys->fs );
 #endif
 
     free( p_sys->psz_fontfile );
@@ -1584,11 +1461,7 @@ static void Destroy( vlc_object_t *p_this )
     text_style_Delete( p_sys->p_forced_style );
 
     /* Fonts dicts */
-    vlc_dictionary_clear( &p_sys->fallback_map, FreeFamilies, p_filter );
     vlc_dictionary_clear( &p_sys->face_map, FreeFace, p_filter );
-    vlc_dictionary_clear( &p_sys->family_map, NULL, NULL );
-    if( p_sys->p_families )
-        FreeFamiliesAndFonts( p_sys->p_families );
 
     /* Attachments */
     if( p_sys->pp_font_attachments )
@@ -1599,14 +1472,7 @@ static void Destroy( vlc_object_t *p_this )
         free( p_sys->pp_font_attachments );
     }
 
-#ifdef HAVE_FONTCONFIG
-    if( p_sys->pf_get_family == FontConfig_GetFamily )
-        FontConfig_Unprepare();
-
-#elif defined( _WIN32 )
-    if( p_sys->pf_get_family == DWrite_GetFamily )
-        ReleaseDWrite( p_filter );
-#endif
+    FontSelectDelete( p_sys->fs );
 
     /* Freetype */
     if( p_sys->p_stroker )
diff --git a/modules/text_renderer/freetype/freetype.h b/modules/text_renderer/freetype/freetype.h
index 0e9eaa1860..f0ed9d8d7f 100644
--- a/modules/text_renderer/freetype/freetype.h
+++ b/modules/text_renderer/freetype/freetype.h
@@ -66,6 +66,8 @@ typedef uint32_t uni_char_t;
 # endif
 #endif
 
+typedef struct vlc_font_select_t vlc_font_select_t;
+
 /*****************************************************************************
  * filter_sys_t: freetype local data
  *****************************************************************************
@@ -94,50 +96,14 @@ typedef struct
     input_attachment_t **pp_font_attachments;
     int                  i_font_attachments;
 
-    /**
-     * 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;
-
-    /**
-     * This maps a family name to a vlc_family_t within the master list
-     */
-    vlc_dictionary_t  family_map;
-
-    /**
-     * This maps a family name to a fallback list of vlc_family_t's.
-     * Fallback lists only reference the lists of vlc_font_t's within the
-     * master list, so they should be freed using FreeFamilies()
-     */
-    vlc_dictionary_t  fallback_map;
-
     /** Font face cache */
     vlc_dictionary_t  face_map;
 
-    int               i_fallback_counter;
-
     /* Current scaling of the text, default is 100 (%) */
     int               i_scale;
 
-    /**
-     * 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 * (*pf_get_family) ( filter_t *p_filter, const char *psz_family );
-
-    /**
-     * Get the fallback list for \p psz_family 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 * (*pf_get_fallbacks) ( filter_t *p_filter, const char *psz_family,
-                                         uni_char_t codepoint );
-
-#if defined( _WIN32 )
-    void *p_dw_sys;
-#endif
+    vlc_font_select_t *fs;
+
 } filter_sys_t;
 
 /**
diff --git a/modules/text_renderer/freetype/platform_fonts.c b/modules/text_renderer/freetype/platform_fonts.c
index 5b70833311..084b011e23 100644
--- a/modules/text_renderer/freetype/platform_fonts.c
+++ b/modules/text_renderer/freetype/platform_fonts.c
@@ -47,6 +47,7 @@
 
 #include "platform_fonts.h"
 #include "freetype.h"
+#include "fonts/backends.h"
 
 static FT_Face LoadFace( filter_t *p_filter, const char *psz_fontfile, int i_idx,
                   const text_style_t *p_style )
@@ -89,7 +90,7 @@ static FT_Face LoadFace( filter_t *p_filter, const char *psz_fontfile, int i_idx
     {
         int i_index = atoi( psz_fontfile + 4 );
         FT_Stream p_stream;
-        if( DWrite_GetFontStream( p_filter, i_index, &p_stream ) != VLC_SUCCESS )
+        if( DWrite_GetFontStream( p_sys->fs, i_index, &p_stream ) != VLC_SUCCESS )
             msg_Err( p_filter, "LoadFace: Invalid font stream index" );
         else
         {
@@ -136,12 +137,12 @@ done:
     return p_face;
 }
 
-FT_Face GetFace( filter_t *p_filter, vlc_font_t *p_font, uni_char_t codepoint )
+FT_Face GetFace( vlc_font_select_t *fs, vlc_font_t *p_font, uni_char_t codepoint )
 {
-    filter_sys_t *p_sys = p_filter->p_sys;
+    filter_sys_t *p_sys = fs->p_filter->p_sys;
 
     if( !p_font->p_face )
-        p_font->p_face = LoadFace( p_filter, p_font->psz_fontfile,
+        p_font->p_face = LoadFace( fs->p_filter, p_font->psz_fontfile,
                                    p_font->i_index,
                                    p_sys->p_default_style );
 
@@ -162,7 +163,7 @@ FT_Face GetFace( filter_t *p_filter, vlc_font_t *p_font, uni_char_t codepoint )
  * containing an Arabic codepoint is requested from the Arial family, the regular font will
  * be returned, because the italic font of Arial has no Arabic support.
  */
-static vlc_font_t *GetBestFont( filter_t *p_filter, const vlc_family_t *p_family,
+static vlc_font_t *GetBestFont( vlc_font_select_t *fs, const vlc_family_t *p_family,
                                 bool b_bold, bool b_italic, uni_char_t codepoint )
 {
     int i_best_score = 0;
@@ -172,7 +173,7 @@ static vlc_font_t *GetBestFont( filter_t *p_filter, const vlc_family_t *p_family
     {
         int i_score = 0;
 
-        if( codepoint && GetFace( p_filter, p_font, codepoint ) )
+        if( codepoint && GetFace( fs, p_font, codepoint ) )
             i_score += 1000;
 
         if( !!p_font->b_bold == !!b_bold )
@@ -190,10 +191,9 @@ static vlc_font_t *GetBestFont( filter_t *p_filter, const vlc_family_t *p_family
     return p_best_font;
 }
 
-vlc_family_t *SearchFallbacks( filter_t *p_filter, vlc_family_t *p_fallbacks,
+vlc_family_t *SearchFallbacks( vlc_font_select_t *fs, vlc_family_t *p_fallbacks,
                                       uni_char_t codepoint )
 {
-    filter_sys_t *p_sys = p_filter->p_sys;
     vlc_family_t *p_family = NULL;
 
     for( vlc_family_t *p_fallback = p_fallbacks; p_fallback;
@@ -201,14 +201,13 @@ vlc_family_t *SearchFallbacks( filter_t *p_filter, vlc_family_t *p_fallbacks,
     {
         if( !p_fallback->p_fonts )
         {
-            const vlc_family_t *p_temp =
-                    p_sys->pf_get_family( p_filter, p_fallback->psz_name );
+            const vlc_family_t *p_temp = FontSelectGetFamily( fs, p_fallback->psz_name );
             if( !p_temp || !p_temp->p_fonts )
                 continue;
             p_fallback->p_fonts = p_temp->p_fonts;
         }
 
-        if( !GetFace( p_filter, p_fallback->p_fonts, codepoint ) )
+        if( !GetFace( fs, p_fallback->p_fonts, codepoint ) )
             continue;
 
         p_family = p_fallback;
@@ -218,7 +217,7 @@ vlc_family_t *SearchFallbacks( filter_t *p_filter, vlc_family_t *p_fallbacks,
     return p_family;
 }
 
-static vlc_family_t *SearchFontByFamilyName( filter_t *p_filter,
+static vlc_family_t *SearchFontByFamilyName( vlc_font_select_t *fs,
                                              vlc_family_t *p_list,
                                              const char *psz_familyname,
                                              uni_char_t codepoint )
@@ -227,7 +226,7 @@ static vlc_family_t *SearchFontByFamilyName( filter_t *p_filter,
     {
         if( !strcasecmp( p->psz_name, psz_familyname ) &&
             p->p_fonts &&
-            GetFace( p_filter, p->p_fonts, codepoint ) )
+            GetFace( fs, p->p_fonts, codepoint ) )
             return p;
     }
     return NULL;
@@ -249,12 +248,10 @@ static inline void AppendFamily( vlc_family_t **pp_list, vlc_family_t *p_family
     *pp_list = p_family;
 }
 
-vlc_family_t *NewFamily( filter_t *p_filter, const char *psz_family,
+vlc_family_t *NewFamily( vlc_font_select_t *fs, const char *psz_family,
                          vlc_family_t **pp_list, vlc_dictionary_t *p_dict,
                          const char *psz_key )
 {
-    filter_sys_t *p_sys = p_filter->p_sys;
-
     vlc_family_t *p_family = calloc( 1, sizeof( *p_family ) );
     if( unlikely(!p_family) )
         return NULL;
@@ -263,9 +260,7 @@ vlc_family_t *NewFamily( filter_t *p_filter, const char *psz_family,
     if( psz_family && *psz_family )
         psz_name = ToLower( psz_family );
     else
-        if( asprintf( &psz_name, FB_NAME"-%04d",
-                      p_sys->i_fallback_counter++ ) < 0 )
-            psz_name = NULL;
+        psz_name = CreateUniqueFamilyKey( fs );
 
     char *psz_lc = NULL;
     if( likely( psz_name ) )
@@ -302,6 +297,58 @@ vlc_family_t *NewFamily( filter_t *p_filter, const char *psz_family,
     return p_family;
 }
 
+char *CreateUniqueFamilyKey( vlc_font_select_t *fs )
+{
+    char *psz_key;
+    if( asprintf( &psz_key, FB_NAME"-%04d",
+                  fs->i_fallback_counter++ ) < 0 )
+        return NULL;
+    return psz_key;
+}
+
+vlc_family_t * DeclareNewFamily( vlc_font_select_t *fs, const char *psz_family )
+{
+    char *psz_lc;
+
+    if( psz_family )
+        psz_lc = ToLower( psz_family );
+    else
+        psz_lc = CreateUniqueFamilyKey( fs );
+
+    if( unlikely( !psz_lc ) )
+        return NULL;
+
+    vlc_family_t *p_family = vlc_dictionary_value_for_key( &fs->family_map, psz_lc );
+    if( p_family == kVLCDictionaryNotFound )
+    {
+        p_family = NewFamily( fs, psz_lc, &fs->p_families,
+                              &fs->family_map, psz_lc );
+    }
+
+    free( psz_lc );
+
+    return p_family;
+}
+
+int DeclareFamilyAsAttachMenFallback( vlc_font_select_t *fs, vlc_family_t *p_family )
+{
+    vlc_family_t *p_decl = NewFamily( fs, p_family->psz_name,
+                                      NULL, NULL, NULL );
+    if( unlikely(!p_decl) )
+        return VLC_EGENERIC;
+
+    p_decl->p_fonts = p_family->p_fonts;
+
+    vlc_family_t *p_list =
+            vlc_dictionary_value_for_key( &fs->fallback_map, FB_LIST_ATTACHMENTS );
+    if( p_list )
+        AppendFamily( &p_list, p_decl );
+    else
+        vlc_dictionary_insert( &fs->fallback_map, FB_LIST_ATTACHMENTS, p_decl );
+
+    return VLC_SUCCESS;
+}
+
 vlc_font_t *NewFont( char *psz_fontfile, int i_index,
                      bool b_bold, bool b_italic,
                      vlc_family_t *p_parent )
@@ -364,22 +411,20 @@ void FreeFamilies( void *p_families, void *p_obj )
     free( p_family );
 }
 
-vlc_family_t *InitDefaultList( filter_t *p_filter, const char *const *ppsz_default,
+vlc_family_t *InitDefaultList( vlc_font_select_t *fs, const char *const *ppsz_default,
                                int i_size )
 {
 
     vlc_family_t  *p_default  = NULL;
-    filter_sys_t  *p_sys = p_filter->p_sys;
 
     for( int i = 0; i < i_size; ++i )
     {
-        const vlc_family_t *p_family =
-                p_sys->pf_get_family( p_filter, ppsz_default[ i ] );
+        const vlc_family_t *p_family = FontSelectGetFamily( fs, ppsz_default[ i ] );
 
         if( p_family )
         {
             vlc_family_t *p_temp =
-                NewFamily( p_filter, ppsz_default[ i ], &p_default, NULL, NULL );
+                NewFamily( fs, ppsz_default[ i ], &p_default, NULL, NULL );
 
             if( unlikely( !p_temp ) )
                 goto error;
@@ -389,7 +434,7 @@ vlc_family_t *InitDefaultList( filter_t *p_filter, const char *const *ppsz_defau
     }
 
     if( p_default )
-        vlc_dictionary_insert( &p_sys->fallback_map, FB_LIST_DEFAULT, p_default );
+        vlc_dictionary_insert( &fs->fallback_map, FB_LIST_DEFAULT, p_default );
 
     return p_default;
 
@@ -399,8 +444,8 @@ error:
 }
 
 #ifdef DEBUG_PLATFORM_FONTS
-void DumpFamily( filter_t *p_filter, const vlc_family_t *p_family,
-                 bool b_dump_fonts, int i_max_families )
+static void DumpFamily( vlc_object_t *p_obj, const vlc_family_t *p_family,
+                        bool b_dump_fonts, int i_max_families )
 {
 
     if( i_max_families < 0 )
@@ -408,7 +453,7 @@ void DumpFamily( filter_t *p_filter, const vlc_family_t *p_family,
 
     for( int i = 0; p_family && i < i_max_families ; p_family = p_family->p_next, ++i )
     {
-        msg_Dbg( p_filter, "\t[%p] %s", (void *)p_family, p_family->psz_name );
+        msg_Dbg( p_obj, "\t[%p] %s", (void *)p_family, p_family->psz_name );
 
         if( b_dump_fonts )
         {
@@ -424,7 +469,7 @@ void DumpFamily( filter_t *p_filter, const vlc_family_t *p_family,
                 else if( p_font->b_bold && p_font->b_italic )
                     psz_style = "Bold Italic";
 
-                msg_Dbg( p_filter, "\t\t[%p] (%s): %s - %d", (void *)p_font,
+                msg_Dbg( p_obj, "\t\t[%p] (%s): %s - %d", (void *)p_font,
                          psz_style, p_font->psz_fontfile, p_font->i_index );
             }
 
@@ -432,8 +477,8 @@ void DumpFamily( filter_t *p_filter, const vlc_family_t *p_family,
     }
 }
 
-void DumpDictionary( filter_t *p_filter, const vlc_dictionary_t *p_dict,
-                     bool b_dump_fonts, int i_max_families )
+static void DumpDictionary( vlc_object_t *p_obj, const vlc_dictionary_t *p_dict,
+                            bool b_dump_fonts, int i_max_families )
 {
     char **ppsz_keys = vlc_dictionary_all_keys( p_dict );
 
@@ -443,13 +488,30 @@ void DumpDictionary( filter_t *p_filter, const vlc_dictionary_t *p_dict,
     for( int i = 0; ppsz_keys[ i ]; ++i )
     {
         vlc_family_t *p_family = vlc_dictionary_value_for_key( p_dict, ppsz_keys[ i ] );
-        msg_Dbg( p_filter, "Key: %s", ppsz_keys[ i ] );
+        msg_Dbg( p_obj, "Key: %s", ppsz_keys[ i ] );
         if( p_family )
-            DumpFamily( p_filter, p_family, b_dump_fonts, i_max_families );
+            DumpFamily( p_obj, p_family, b_dump_fonts, i_max_families );
         free( ppsz_keys[ i ] );
     }
     free( ppsz_keys );
 }
+
+void DumpFamilies( vlc_font_select_t *fs )
+{
+    vlc_object_t *p_obj = fs->p_obj;
+    msg_Dbg( p_obj, "------------------" );
+    msg_Dbg( p_obj, "p_families:" );
+    msg_Dbg( p_obj, "------------------" );
+    DumpFamily( p_obj, fs->p_families, true, -1 );
+    msg_Dbg( p_obj, "-----------------" );
+    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, "fallback_map" );
+    msg_Dbg( p_obj, "-------------------" );
+    DumpDictionary( p_obj, &fs->fallback_map, true, -1 );
+}
 #endif
 
 char* ToLower( const char *psz_src )
@@ -532,13 +594,11 @@ static void SplitIntoSingleFamily( const char *psz_spec, fontfamilies_t *familie
     free( dup );
 }
 
-static char* SelectFontWithFamilyFallback( filter_t *p_filter,
+static char* SelectFontWithFamilyFallback( vlc_font_select_t *fs,
                                     const fontfamilies_t *families,
                                     const text_style_t *p_style,
                                     int *pi_idx, uni_char_t codepoint )
 {
-    filter_sys_t *p_sys = p_filter->p_sys;
-
     const bool b_bold = p_style->i_style_flags & STYLE_BOLD;
     const bool b_italic = p_style->i_style_flags & STYLE_ITALIC;
     const vlc_family_t *p_family = NULL;
@@ -553,25 +613,27 @@ static char* SelectFontWithFamilyFallback( filter_t *p_filter,
          */
         vlc_vector_foreach( psz_name, families )
         {
-            Debug( p_filter, "Looking for family \"%s\"", psz_name );
+            Debug( fs->p_obj, "Looking for family \"%s\"", psz_name );
 
-            p_fallbacks = vlc_dictionary_value_for_key( &p_sys->fallback_map,
+            p_fallbacks = vlc_dictionary_value_for_key( &fs->fallback_map,
                                                         FB_LIST_ATTACHMENTS );
             if( p_fallbacks )
             {
-                p_family = SearchFontByFamilyName( p_filter, p_fallbacks,
+                p_family = SearchFontByFamilyName( fs, p_fallbacks,
                                                    psz_name, codepoint );
                 if( p_family )
                     break;
             }
 
-            p_family = p_sys->pf_get_family( p_filter, psz_name );
-            if( p_family && p_family->p_fonts &&
-                GetFace( p_filter, p_family->p_fonts, codepoint ) )
+            p_family = FontSelectGetFamily( fs, psz_name );
+            if( p_family && p_family->p_fonts )
             {
-                Debug( p_filter, "Found family \"%s\" for codepoint %x",
-                       psz_name, codepoint );
-                break;
+                if( GetFace( fs, p_family->p_fonts, codepoint ) )
+                {
+                    Debug( fs->p_obj, "Found family \"%s\" for codepoint %x",
+                           psz_name, codepoint );
+                    break;
+                }
             }
 
             p_family = NULL;
@@ -580,33 +642,33 @@ static char* SelectFontWithFamilyFallback( filter_t *p_filter,
         /* Try font attachments if not available locally */
         if( !p_family )
         {
-            Debug( p_filter, "Looking for family \"%s\" in attachments", psz_name );
-
-            p_fallbacks = vlc_dictionary_value_for_key( &p_sys->fallback_map,
+            Debug( fs->p_obj, "Looking for family \"%s\" in attachments", psz_name );
+            p_fallbacks = vlc_dictionary_value_for_key( &fs->fallback_map,
                                                         FB_LIST_ATTACHMENTS );
             if( p_fallbacks )
-                p_family = SearchFallbacks( p_filter, p_fallbacks, codepoint );
-
-            if( p_family && p_family->p_fonts )
             {
-                Debug( p_filter, "Selected family \"%s\" in attachments",
-                       p_family->psz_name );
+                p_family = SearchFallbacks( fs, p_fallbacks, codepoint );
+                if( p_family )
+                {
+                    Debug( fs->p_obj, "Selected family \"%s\" in attachments",
+                           p_family->psz_name );
+                }
             }
         }
 
         /* Try system fallbacks */
-        if( !p_family && p_sys->pf_get_fallbacks )
+        if( !p_family )
         {
             vlc_vector_foreach( psz_name, families )
             {
-                Debug( p_filter, "Looking for family \"%s\" in system fallbacks", psz_name );
-                p_fallbacks = p_sys->pf_get_fallbacks( p_filter, psz_name, codepoint );
+                Debug( fs->p_obj, "Looking for family \"%s\" in system fallbacks", psz_name );
+                p_fallbacks = FontSelectGetFallbacks( fs, psz_name, codepoint );
                 if( p_fallbacks )
                 {
-                    p_family = SearchFallbacks( p_filter, p_fallbacks, codepoint );
+                    p_family = SearchFallbacks( fs, p_fallbacks, codepoint );
                     if( p_family && p_family->p_fonts )
                     {
-                        Debug( p_filter, "Selected family \"%s\" in system fallbacks",
+                        Debug( fs->p_obj, "Selected family \"%s\" in system fallbacks",
                                p_family->psz_name );
                         break;
                     }
@@ -618,13 +680,15 @@ static char* SelectFontWithFamilyFallback( filter_t *p_filter,
         /* Try the default fallback list, if any */
         if( !p_family )
         {
-            p_fallbacks = vlc_dictionary_value_for_key( &p_sys->fallback_map,
+            p_fallbacks = vlc_dictionary_value_for_key( &fs->fallback_map,
                                                         FB_LIST_DEFAULT );
             if( p_fallbacks )
-                p_family = SearchFallbacks( p_filter, p_fallbacks, codepoint );
+                p_family = SearchFallbacks( fs, p_fallbacks, codepoint );
             if( p_family )
-                Debug( p_filter, "Selected family \"%s\" in default fallback list",
+            {
+                Debug( fs->p_obj, "Selected family \"%s\" in default fallback list",
                        p_family->psz_name );
+            }
         }
 
         if( !p_family )
@@ -633,20 +697,20 @@ static char* SelectFontWithFamilyFallback( filter_t *p_filter,
 
     if( !p_family || !p_family->p_fonts )
     {
-        Debug( p_filter, "Looking for DEFAULT_FAMILY \"%s\" as a last resort", DEFAULT_FAMILY );
-        p_family = p_sys->pf_get_family( p_filter, DEFAULT_FAMILY );
+        Debug( fs->p_obj, "Looking for DEFAULT_FAMILY \"%s\" as a last resort", DEFAULT_FAMILY );
+        p_family = FontSelectGetFamily( fs, DEFAULT_FAMILY );
     }
 
     vlc_font_t *p_font;
-    if( p_family && ( p_font = GetBestFont( p_filter, p_family, b_bold,
+    if( p_family && ( p_font = GetBestFont( fs, p_family, b_bold,
                                             b_italic, codepoint ) ) )
     {
-        Debug( p_filter, "Selected best font file \"%s\"", p_font->psz_fontfile );
+        Debug( fs->p_obj, "Selected best font file \"%s\"", p_font->psz_fontfile );
         *pi_idx = p_font->i_index;
         return strdup( p_font->psz_fontfile );
     }
 
-    Debug( p_filter, "Could not match any family or font : that should not happen" );
+    Debug( fs->p_obj, "Could not match any family or font : that should not happen" );
 
     return NULL;
 }
@@ -654,6 +718,7 @@ static char* SelectFontWithFamilyFallback( filter_t *p_filter,
 FT_Face SelectAndLoadFace( filter_t *p_filter, const text_style_t *p_style,
                            uni_char_t codepoint )
 {
+    filter_sys_t *p_sys = p_filter->p_sys;
     const char *psz_fontname = (p_style->i_style_flags & STYLE_MONOSPACED)
                                ? p_style->psz_monofontname : p_style->psz_fontname;
 
@@ -670,7 +735,7 @@ FT_Face SelectAndLoadFace( filter_t *p_filter, const text_style_t *p_style,
 
     int  i_idx = 0;
     char *psz_fontfile =
-            SelectFontWithFamilyFallback( p_filter, &families, p_style,
+            SelectFontWithFamilyFallback( p_sys->fs, &families, p_style,
                                           &i_idx, codepoint );
     if( psz_fontfile && *psz_fontfile != '\0' )
     {
@@ -692,9 +757,10 @@ FT_Face SelectAndLoadFace( filter_t *p_filter, const text_style_t *p_style,
 }
 
 #ifndef HAVE_GET_FONT_BY_FAMILY_NAME
-const vlc_family_t * StaticMap_GetFamily( filter_t *p_filter,
-                                          const char *psz_family )
+static const vlc_family_t * StaticMap_GetFamily( vlc_font_select_t *fs,
+                                                 const char *psz_family )
 {
+    filter_t *p_filter = fs->p_filter;
     filter_sys_t *p_sys = p_filter->p_sys;
     char *psz_lc = ToLower( psz_family );
 
@@ -702,7 +768,8 @@ const vlc_family_t * StaticMap_GetFamily( filter_t *p_filter,
         return NULL;
 
     vlc_family_t *p_family =
-        vlc_dictionary_value_for_key( &p_sys->family_map, psz_lc );
+        vlc_dictionary_value_for_key( &fs->family_map, psz_lc );
+
     if( p_family )
     {
         free( psz_lc );
@@ -728,15 +795,15 @@ const vlc_family_t * StaticMap_GetFamily( filter_t *p_filter,
     }
 
     /* Create new entry */
-    p_family = NewFamily( p_filter, psz_lc, &p_sys->p_families,
-                          &p_sys->family_map, psz_lc );
+    p_family = NewFamily( fs, psz_lc, &fs->p_families,
+                          &fs->family_map, psz_lc );
 
     free( psz_lc );
 
     if( unlikely( !p_family ) )
         return NULL;
 
-    char *psz_font_file = MakeFilePath( p_filter, psz_file );
+    char *psz_font_file = MakeFilePath( fs, psz_file );
     if( psz_font_file )
         NewFont( psz_font_file, 0, false, false, p_family );
 
@@ -746,9 +813,9 @@ const vlc_family_t * StaticMap_GetFamily( filter_t *p_filter,
 
 #if !defined(_WIN32) || VLC_WINSTORE_APP
 
-char * MakeFilePath( filter_t *p_filter, const char *psz_filename )
+char * MakeFilePath( vlc_font_select_t *fs, const char *psz_filename )
 {
-    VLC_UNUSED(p_filter);
+    VLC_UNUSED(fs);
 
     if( !psz_filename )
         return NULL;
@@ -765,3 +832,103 @@ char * MakeFilePath( filter_t *p_filter, const char *psz_filename )
     return psz_filepath;
 }
 #endif
+
+vlc_font_select_t * FontSelectNew( filter_t *p_filter )
+{
+    vlc_font_select_t *fs = calloc( 1, sizeof(*fs) );
+    if( !fs )
+        return fs;
+
+    fs->p_filter = 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 );
+
+#ifdef HAVE_FONTCONFIG
+    fs->pf_get_family = FontConfig_GetFamily;
+    fs->pf_get_fallbacks = FontConfig_GetFallbacks;
+    if( FontConfig_Prepare( fs ) )
+    {
+        fs->pf_get_family = NULL;
+        goto error;
+    }
+
+#elif defined( __APPLE__ )
+    fs->pf_get_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_get_fallbacks = DWrite_GetFallbacks;
+    }
+    else
+    {
+#if VLC_WINSTORE_APP
+        msg_Err( p_filter, "Error initializing DirectWrite" );
+        goto error;
+#else
+        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_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_get_fallbacks = Android_GetFallbacks;
+
+    if( Android_Prepare( fs ) == VLC_ENOMEM )
+        goto error;
+#else
+    fs->pf_get_family = StaticMap_GetFamily;
+    fs->pf_get_fallbacks = NULL;
+    /* The default static fonts are also fallback fonts */
+    const char *const ppsz_default[] =
+        { DEFAULT_FAMILY, DEFAULT_MONOSPACE_FAMILY };
+    if( InitDefaultList( fs, ppsz_default, ARRAY_SIZE(ppsz_default) ) == NULL )
+        goto error;
+#endif
+
+    return fs;
+
+error:
+    FontSelectDelete( fs );
+    return NULL;
+}
+
+void FontSelectDelete( vlc_font_select_t *fs )
+{
+#ifdef HAVE_FONTCONFIG
+    if( fs->pf_get_family == FontConfig_GetFamily )
+        FontConfig_Unprepare( fs );
+
+#elif defined( _WIN32 )
+    if( fs->pf_get_family == DWrite_GetFamily )
+        ReleaseDWrite( fs );
+#endif
+
+    /* Dicts */
+    vlc_dictionary_clear( &fs->fallback_map, FreeFamilies, fs );
+    vlc_dictionary_clear( &fs->family_map, NULL, NULL );
+    if( fs->p_families )
+        FreeFamiliesAndFonts( fs->p_families );
+
+    free( fs );
+}
+
+const vlc_family_t * FontSelectGetFamily( vlc_font_select_t *fs, const char *psz_family )
+{
+    return fs->pf_get_family ? fs->pf_get_family( fs, psz_family ) : NULL;
+}
+
+vlc_family_t * FontSelectGetFallbacks( vlc_font_select_t *fs, const char *psz_family,
+                                       uni_char_t codepoint )
+{
+    return fs->pf_get_fallbacks ? fs->pf_get_fallbacks( fs, psz_family, codepoint ) : NULL;
+}
diff --git a/modules/text_renderer/freetype/platform_fonts.h b/modules/text_renderer/freetype/platform_fonts.h
index dc3be45372..feb03078ba 100644
--- a/modules/text_renderer/freetype/platform_fonts.h
+++ b/modules/text_renderer/freetype/platform_fonts.h
@@ -66,12 +66,16 @@ extern "C" {
 # define SYSTEM_DEFAULT_FAMILY              "Helvetica Neue"
 # define SYSTEM_DEFAULT_MONOSPACE_FONT_FILE "Monaco.dfont"
 # define SYSTEM_DEFAULT_MONOSPACE_FAMILY    "Monaco"
+# define HAVE_GET_FONT_BY_FAMILY_NAME
+# undef  HAVE_FONTCONFIG
 #elif defined( _WIN32 )
 # define SYSTEM_FONT_PATH                   "" /* Default path font found at run-time */
 # define SYSTEM_DEFAULT_FONT_FILE           "arial.ttf"
 # define SYSTEM_DEFAULT_FAMILY              "Arial"
 # define SYSTEM_DEFAULT_MONOSPACE_FONT_FILE "cour.ttf"
 # define SYSTEM_DEFAULT_MONOSPACE_FAMILY    "Courier New"
+# define HAVE_GET_FONT_BY_FAMILY_NAME
+# undef  HAVE_FONTCONFIG
 #elif defined( __OS2__ )
 # define SYSTEM_FONT_PATH                   "/psfonts"
 # define SYSTEM_DEFAULT_FONT_FILE           "tnrwt_k.ttf"
@@ -84,6 +88,7 @@ extern "C" {
 # define SYSTEM_DEFAULT_FAMILY              "sans-serif"
 # define SYSTEM_DEFAULT_MONOSPACE_FONT_FILE "DroidSansMono.ttf"
 # define SYSTEM_DEFAULT_MONOSPACE_FAMILY    "Monospace"
+# define HAVE_GET_FONT_BY_FAMILY_NAME
 #else
 # define SYSTEM_FONT_PATH                   "/usr/share/fonts/truetype/freefont"
 # define SYSTEM_DEFAULT_FONT_FILE           "FreeSerifBold.ttf"
@@ -92,6 +97,10 @@ extern "C" {
 # define SYSTEM_DEFAULT_MONOSPACE_FAMILY    "Monospace"
 #endif
 
+#if defined(HAVE_FONTCONFIG) && !defined(HAVE_GET_FONT_BY_FAMILY_NAME)
+# define HAVE_GET_FONT_BY_FAMILY_NAME
+#endif
+
 #ifndef DEFAULT_FONT_FILE
 # define DEFAULT_FONT_FILE SYSTEM_DEFAULT_FONT_FILE
 #endif
@@ -150,45 +159,24 @@ struct vlc_family_t
 #define FB_LIST_DEFAULT     "default"
 #define FB_NAME             "fallback"
 
-/***
- * PLATFORM SPECIFIC SELECTORS
- **/
-#ifdef HAVE_FONTCONFIG
-vlc_family_t *FontConfig_GetFallbacks( filter_t *p_filter, const char *psz_family,
-                                       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 )
-const vlc_family_t *DWrite_GetFamily( filter_t *p_filter, const char *psz_family );
-vlc_family_t *DWrite_GetFallbacks( filter_t *p_filter, const char *psz_family,
-                                  uni_char_t codepoint );
-int InitDWrite( filter_t *p_filter );
-int ReleaseDWrite( filter_t *p_filter );
-int DWrite_GetFontStream( filter_t *p_filter, int i_index, FT_Stream *pp_stream );
-#if !VLC_WINSTORE_APP
-vlc_family_t *Win32_GetFallbacks( filter_t *p_filter, const char *psz_family,
-                                  uni_char_t codepoint );
-
-const vlc_family_t *Win32_GetFamily( filter_t *p_filter, const char *psz_family );
-#endif /* !VLC_WINSTORE_APP */
-#endif /* _WIN32 */
+vlc_font_select_t * FontSelectNew( filter_t * );
+void FontSelectDelete( vlc_font_select_t * );
 
-#ifdef __APPLE__
-vlc_family_t *CoreText_GetFallbacks(filter_t *p_filter, const char *psz_family, uni_char_t codepoint);
-const vlc_family_t *CoreText_GetFamily(filter_t *p_filter, const char *psz_family);
-#endif /* __APPLE__ */
+/**
+ * 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 );
 
-#ifdef __ANDROID__
-const vlc_family_t *Android_GetFamily( filter_t *p_filter, const char *psz_family );
-vlc_family_t *Android_GetFallbacks( filter_t *p_filter, const char *psz_family,
-                                    uni_char_t codepoint );
-int Android_Prepare( filter_t *p_filter );
-#endif /* __ANDROID__ */
+/**
+ * Get the fallback list for \p psz_family 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,
+                                       uni_char_t codepoint );
 
-const vlc_family_t * StaticMap_GetFamily( filter_t *p_filter, const char *psz_family );
 
 /* ******************
  * Family and fonts *
@@ -212,10 +200,15 @@ const vlc_family_t * StaticMap_GetFamily( filter_t *p_filter, const char *psz_fa
  *
  * \return the new family representation
  */
-vlc_family_t *NewFamily( filter_t *p_filter, const char *psz_family,
+vlc_family_t *NewFamily( vlc_font_select_t *, const char *psz_family,
                          vlc_family_t **pp_list, vlc_dictionary_t *p_dict,
                          const char *psz_key );
 
+vlc_family_t * DeclareNewFamily( vlc_font_select_t *, const char *psz_family );
+int DeclareFamilyAsAttachMenFallback( vlc_font_select_t *, vlc_family_t * );
+
+char *CreateUniqueFamilyKey( vlc_font_select_t * );
+
 /**
  * Creates a new font.
  *
@@ -264,22 +257,18 @@ void FreeFamilies( void *p_families, void *p_obj );
  * of that function, where each family is added to the default list if
  * its name has "fallback" in it. So InitDefaultList() is not called on Android.
  *
- * \param p_filter the freetype module object [IN]
+ * \param fs the vlc_font_select_t handle [IN]
  * \param ppsz_default the table default fonts [IN]
  * \param i_size the size of the supplied table [IN]
  *
  * \return the default fallback list
  */
-vlc_family_t *InitDefaultList( filter_t *p_filter, const char *const *ppsz_default,
+vlc_family_t *InitDefaultList( vlc_font_select_t *fs, const char *const *ppsz_default,
                                int i_size );
 
 /* Debug Helpers */
 #ifdef DEBUG_PLATFORM_FONTS
-void DumpFamily( filter_t *p_filter, const vlc_family_t *p_family,
-                 bool b_dump_fonts, int i_max_families );
-
-void DumpDictionary( filter_t *p_filter, const vlc_dictionary_t *p_dict,
-                     bool b_dump_fonts, int i_max_families );
+void DumpFamilies( vlc_font_select_t * );
 #endif
 
 /* String helpers */
@@ -290,11 +279,11 @@ int ConvertToLiveSize( filter_t *p_filter, const text_style_t *p_style );
 
 
 /* Only for fonts implementors */
-vlc_family_t *SearchFallbacks( filter_t *p_filter, vlc_family_t *p_fallbacks,
+vlc_family_t *SearchFallbacks( vlc_font_select_t *, vlc_family_t *p_fallbacks,
                                       uni_char_t codepoint );
-FT_Face GetFace( filter_t *p_filter, vlc_font_t *p_font, uni_char_t codepoint );
+FT_Face GetFace( vlc_font_select_t *, vlc_font_t *p_font, uni_char_t codepoint );
 
-char * MakeFilePath( filter_t *p_filter, const char *psz_filename );
+char * MakeFilePath( vlc_font_select_t *, const char *psz_filename );
 
 #ifdef __cplusplus
 }




More information about the vlc-commits mailing list