[vlc-devel] [PATCH 2/4] freetype: font fallback for Linux

Salah-Eddin Shaban salshaaban at gmail.com
Thu Oct 22 13:53:48 CEST 2015


---
 modules/text_renderer/freetype.c       |   4 +-
 modules/text_renderer/platform_fonts.c | 217 +++++++++++++++++++++++++--------
 modules/text_renderer/platform_fonts.h |   7 +-
 modules/text_renderer/text_layout.c    |   5 +
 4 files changed, 178 insertions(+), 55 deletions(-)

diff --git a/modules/text_renderer/freetype.c b/modules/text_renderer/freetype.c
index 95b045e..61b3ec5 100644
--- a/modules/text_renderer/freetype.c
+++ b/modules/text_renderer/freetype.c
@@ -1259,7 +1259,9 @@ static int Create( vlc_object_t *p_this )
         goto error;
 
 #ifdef HAVE_FONTCONFIG
-    p_sys->pf_select = FontConfig_Select;
+    p_sys->pf_select = Generic_Select;
+    p_sys->pf_get_family = FontConfig_GetFamily;
+    p_sys->pf_get_fallbacks = FontConfig_GetFallbacks;
     FontConfig_BuildCache( p_filter );
 #elif defined( __APPLE__ )
 #if !TARGET_OS_IPHONE
diff --git a/modules/text_renderer/platform_fonts.c b/modules/text_renderer/platform_fonts.c
index 1195272..93ccdf1 100644
--- a/modules/text_renderer/platform_fonts.c
+++ b/modules/text_renderer/platform_fonts.c
@@ -461,73 +461,190 @@ void FontConfig_BuildCache( filter_t *p_filter )
     msg_Dbg( p_filter, "Took %ld microseconds", (long)((t2 - t1)) );
 }
 
-/***
- * \brief Selects a font matching family, bold, italic provided
- ***/
-char* FontConfig_Select( filter_t *p_filter, const char* family,
-                         bool b_bold, bool b_italic,
-                         int *i_idx, uni_char_t codepoint )
+const vlc_family_t *FontConfig_GetFamily( filter_t *p_filter, const char *psz_family )
 {
-    FcResult result = FcResultMatch;
-    FcPattern *pat, *p_pat;
-    FcChar8* val_s;
-    FcBool val_b;
-    char *ret = NULL;
-    FcConfig* config = NULL;
-    VLC_UNUSED(p_filter);
-    VLC_UNUSED(codepoint);
+    filter_sys_t *p_sys = p_filter->p_sys;
 
-    /* Create a pattern and fills it */
-    pat = FcPatternCreate();
-    if (!pat) return NULL;
+    char *psz_lc = ToLower( psz_family );
 
-    /* */
-    FcPatternAddString( pat, FC_FAMILY, (const FcChar8*)family );
-    FcPatternAddBool( pat, FC_OUTLINE, FcTrue );
-    FcPatternAddInteger( pat, FC_SLANT, b_italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
-    FcPatternAddInteger( pat, FC_WEIGHT, b_bold ? FC_WEIGHT_EXTRABOLD : FC_WEIGHT_NORMAL );
+    if( unlikely( !psz_lc ) )
+        return NULL;
 
-    /* */
-    FcDefaultSubstitute( pat );
-    if( !FcConfigSubstitute( config, pat, FcMatchPattern ) )
+    vlc_family_t *p_family =
+            vlc_dictionary_value_for_key( &p_sys->family_map, psz_lc );
+
+    if( p_family != kVLCDictionaryNotFound )
     {
-        FcPatternDestroy( pat );
-        return NULL;
+        free( psz_lc );
+        return p_family;
     }
 
-    /* Find the best font for the pattern, destroy the pattern */
-    p_pat = FcFontMatch( config, pat, &result );
-    FcPatternDestroy( pat );
-    if( !p_pat || result == FcResultNoMatch ) return NULL;
+    p_family = NewFamily( p_filter, psz_lc, &p_sys->p_families,
+                          &p_sys->family_map, psz_lc );
+
+    free( psz_lc );
+    if( !p_family )
+        return NULL;
+
+    bool b_bold, b_italic;
 
-    /* Check the new pattern */
-    if( ( FcResultMatch != FcPatternGetBool( p_pat, FC_OUTLINE, 0, &val_b ) )
-        || ( val_b != FcTrue ) )
+    for( int i = 0; i < 4; ++i )
     {
+        switch( i )
+        {
+        case 0:
+            b_bold = false;
+            b_italic = false;
+            break;
+        case 1:
+            b_bold = true;
+            b_italic = false;
+            break;
+        case 2:
+            b_bold = false;
+            b_italic = true;
+            break;
+        case 3:
+            b_bold = true;
+            b_italic = true;
+            break;
+        }
+
+        int i_index = 0;
+        FcResult result = FcResultMatch;
+        FcPattern *pat, *p_pat;
+        FcChar8* val_s;
+        FcBool val_b;
+        char *psz_fontfile = NULL;
+        FcConfig* config = NULL;
+
+        /* Create a pattern and fill it */
+        pat = FcPatternCreate();
+        if (!pat) continue;
+
+        /* */
+        FcPatternAddString( pat, FC_FAMILY, (const FcChar8*) psz_family );
+        FcPatternAddBool( pat, FC_OUTLINE, FcTrue );
+        FcPatternAddInteger( pat, FC_SLANT, b_italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
+        FcPatternAddInteger( pat, FC_WEIGHT, b_bold ? FC_WEIGHT_EXTRABOLD : FC_WEIGHT_NORMAL );
+
+        /* */
+        FcDefaultSubstitute( pat );
+        if( !FcConfigSubstitute( config, pat, FcMatchPattern ) )
+        {
+            FcPatternDestroy( pat );
+            continue;
+        }
+
+        /* Find the best font for the pattern, destroy the pattern */
+        p_pat = FcFontMatch( config, pat, &result );
+        FcPatternDestroy( pat );
+        if( !p_pat || result == FcResultNoMatch ) continue;
+
+        /* Check the new pattern */
+        if( ( FcResultMatch != FcPatternGetBool( p_pat, FC_OUTLINE, 0, &val_b ) )
+            || ( val_b != FcTrue ) )
+        {
+            FcPatternDestroy( p_pat );
+            continue;
+        }
+        if( FcResultMatch != FcPatternGetInteger( p_pat, FC_INDEX, 0, &i_index ) )
+        {
+            i_index = 0;
+        }
+
+        if( FcResultMatch != FcPatternGetString( p_pat, FC_FAMILY, 0, &val_s ) )
+        {
+            FcPatternDestroy( p_pat );
+            continue;
+        }
+
+        if( FcResultMatch == FcPatternGetString( p_pat, FC_FILE, 0, &val_s ) )
+            psz_fontfile = strdup( (const char*)val_s );
+
         FcPatternDestroy( p_pat );
-        return NULL;
+
+        if( !psz_fontfile )
+            continue;
+
+        NewFont( psz_fontfile, i_index, b_bold, b_italic, p_family );
     }
-    if( FcResultMatch != FcPatternGetInteger( p_pat, FC_INDEX, 0, i_idx ) )
+
+    return p_family;
+}
+
+vlc_family_t *FontConfig_GetFallbacks( filter_t *p_filter, 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 );
+
+    if( p_family != kVLCDictionaryNotFound )
     {
-        *i_idx = 0;
+        free( psz_lc );
+        return p_family;
     }
-
-    if( FcResultMatch != FcPatternGetString( p_pat, FC_FAMILY, 0, &val_s ) )
+    else
+        p_family = NULL;
+
+    const char *psz_last_name = "";
+    FcPattern  *p_pattern = FcPatternCreate();
+    FcValue     family;
+    family.type = FcTypeString;
+    family.u.s = ( const FcChar8* ) psz_family;
+    FcPatternAdd( p_pattern, FC_FAMILY, family, FcFalse );
+    if( FcConfigSubstitute( NULL, p_pattern, FcMatchPattern ) == FcTrue )
     {
-        FcPatternDestroy( p_pat );
-        return NULL;
+        FcDefaultSubstitute( p_pattern );
+        FcResult result;
+        FcFontSet* p_font_set = FcFontSort( NULL, p_pattern, FcTrue, NULL, &result );
+        if( p_font_set )
+        {
+            for( int i = 0; i < p_font_set->nfont; ++i )
+            {
+                char* psz_name = NULL;
+                FcPatternGetString( p_font_set->fonts[i],
+                                    FC_FAMILY, 0, ( FcChar8** )( &psz_name ) );
+
+                /* Avoid duplicate family names */
+                if( strcasecmp( psz_last_name, psz_name ) )
+                {
+                    vlc_family_t *p_temp = NewFamily( p_filter, psz_name,
+                                                      &p_family, NULL, NULL );
+
+                    if( unlikely( !p_temp ) )
+                    {
+                        FcFontSetDestroy( p_font_set );
+                        FcPatternDestroy( p_pattern );
+                        if( p_family )
+                            FreeFamilies( p_family, NULL );
+                        free( psz_lc );
+                        return NULL;
+                    }
+
+                    psz_last_name = p_temp->psz_name;
+                }
+            }
+            FcFontSetDestroy( p_font_set );
+        }
     }
+    FcPatternDestroy( p_pattern );
 
-    /* if( strcasecmp((const char*)val_s, family ) != 0 )
-        msg_Warn( p_filter, "fontconfig: selected font family is not"
-                            "the requested one: '%s' != '%s'\n",
-                            (const char*)val_s, family );   */
-
-    if( FcResultMatch == FcPatternGetString( p_pat, FC_FILE, 0, &val_s ) )
-        ret = strdup( (const char*)val_s );
+    if( p_family )
+        vlc_dictionary_insert( &p_sys->fallback_map, psz_lc, p_family );
 
-    FcPatternDestroy( p_pat );
-    return ret;
+    free( psz_lc );
+    return p_family;
 }
 #endif
 
diff --git a/modules/text_renderer/platform_fonts.h b/modules/text_renderer/platform_fonts.h
index ce788ec..9748ce4 100644
--- a/modules/text_renderer/platform_fonts.h
+++ b/modules/text_renderer/platform_fonts.h
@@ -120,13 +120,12 @@ struct vlc_family_t
 #define FB_NAME             "fallback"
 
 #ifdef HAVE_FONTCONFIG
-char* FontConfig_Select( filter_t *p_filter, const char* family,
-                         bool b_bold, bool b_italic,
-                         int *i_idx, uni_char_t codepoint );
+const vlc_family_t *FontConfig_GetFamily( filter_t *p_filter, const char *psz_family );
+vlc_family_t *FontConfig_GetFallbacks( filter_t *p_filter, const char *psz_family,
+                                       uni_char_t codepoint );
 void FontConfig_BuildCache( filter_t *p_filter );
 #endif
 
-
 #if defined( _WIN32 ) && !VLC_WINSTORE_APP
 char* Win32_Select( filter_t *p_filter, const char* family,
                     bool b_bold, bool b_italic,
diff --git a/modules/text_renderer/text_layout.c b/modules/text_renderer/text_layout.c
index a3386f9..bd6a62e 100644
--- a/modules/text_renderer/text_layout.c
+++ b/modules/text_renderer/text_layout.c
@@ -58,6 +58,11 @@
 #include "text_layout.h"
 #include "freetype.h"
 
+/* FontConfig */
+#ifdef HAVE_FONTCONFIG
+# define HAVE_FONT_FALLBACK
+#endif
+
 /*
  * Within a paragraph, run_desc_t represents a run of characters
  * having the same font face, size, and style, Unicode script
-- 
1.9.1



More information about the vlc-devel mailing list