[vlc-devel] [PATCH 3/4] freetype: font fallback for Android
Salah-Eddin Shaban
salshaaban at gmail.com
Thu Oct 22 13:53:49 CEST 2015
---
modules/text_renderer/freetype.c | 16 +++
modules/text_renderer/platform_fonts.c | 225 +++++++++++++++++++++++++++++++++
modules/text_renderer/platform_fonts.h | 16 ++-
modules/text_renderer/text_layout.c | 5 +
4 files changed, 260 insertions(+), 2 deletions(-)
diff --git a/modules/text_renderer/freetype.c b/modules/text_renderer/freetype.c
index 61b3ec5..97d8ee1 100644
--- a/modules/text_renderer/freetype.c
+++ b/modules/text_renderer/freetype.c
@@ -64,6 +64,11 @@
# 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"
@@ -1269,6 +1274,17 @@ static int Create( vlc_object_t *p_this )
#endif
#elif defined( _WIN32 ) && defined( HAVE_GET_FONT_BY_FAMILY_NAME )
p_sys->pf_select = Win32_Select;
+#elif defined( __ANDROID__ )
+ p_sys->pf_get_family = Android_GetFamily;
+ p_sys->pf_get_fallbacks = Android_GetFallbacks;
+ p_sys->pf_select = Generic_Select;
+
+ if( Android_ParseSystemFonts( p_filter, ANDROID_SYSTEM_FONTS ) == VLC_ENOMEM )
+ goto error;
+ if( Android_ParseSystemFonts( p_filter, ANDROID_FALLBACK_FONTS ) == VLC_ENOMEM )
+ goto error;
+ if( Android_ParseSystemFonts( p_filter, ANDROID_VENDOR_FONTS ) == VLC_ENOMEM )
+ goto error;
#else
p_sys->pf_select = Dummy_Select;
#endif
diff --git a/modules/text_renderer/platform_fonts.c b/modules/text_renderer/platform_fonts.c
index 93ccdf1..df1a7d1 100644
--- a/modules/text_renderer/platform_fonts.c
+++ b/modules/text_renderer/platform_fonts.c
@@ -61,6 +61,11 @@
# include <fontconfig/fontconfig.h>
#endif
+#ifdef __ANDROID__
+#include <vlc_xml.h>
+#include <vlc_stream.h>
+#endif
+
#include "platform_fonts.h"
#include "freetype.h"
@@ -906,3 +911,223 @@ char* Dummy_Select( filter_t *p_filter, const char* psz_font,
return psz_fontname;
}
+
+#ifdef __ANDROID__
+static int Android_ParseFamily( filter_t *p_filter, xml_reader_t *p_xml )
+{
+ filter_sys_t *p_sys = p_filter->p_sys;
+ vlc_dictionary_t *p_dict = &p_sys->family_map;
+ vlc_family_t *p_family = NULL;
+ char *psz_lc = NULL;
+ int i_counter = 0;
+ bool b_bold = false;
+ bool b_italic = false;
+ const char *p_node = NULL;
+ int i_type = 0;
+
+ while( ( i_type = xml_ReaderNextNode( p_xml, &p_node ) ) > 0 )
+ {
+ switch( i_type )
+ {
+ case XML_READER_STARTELEM:
+ /*
+ * Multiple names can reference the same family in Android. When
+ * the first name is encountered we set p_family to the vlc_family_t
+ * in the master list matching this name, and if no such family
+ * exists we create a new one and add it to the master list.
+ * If the master list does contain a family with that name it's one
+ * of the font attachments, and the family will end up having embedded
+ * fonts and system fonts.
+ */
+ if( !strcasecmp( "name", p_node ) )
+ {
+ i_type = xml_ReaderNextNode( p_xml, &p_node );
+
+ if( i_type != XML_READER_TEXT || !p_node || !*p_node )
+ {
+ msg_Warn( p_filter, "Android_ParseFamily: empty name" );
+ continue;
+ }
+
+ psz_lc = ToLower( p_node );
+ if( unlikely( !psz_lc ) )
+ return VLC_ENOMEM;
+
+ if( !p_family )
+ {
+ p_family = vlc_dictionary_value_for_key( p_dict, psz_lc );
+ if( p_family == kVLCDictionaryNotFound )
+ {
+ p_family =
+ NewFamily( p_filter, psz_lc, &p_sys->p_families, NULL, NULL );
+
+ if( unlikely( !p_family ) )
+ {
+ free( psz_lc );
+ return VLC_ENOMEM;
+ }
+
+ }
+ }
+
+ if( vlc_dictionary_value_for_key( p_dict, psz_lc ) == kVLCDictionaryNotFound )
+ vlc_dictionary_insert( p_dict, psz_lc, p_family );
+ free( psz_lc );
+ }
+ /*
+ * If p_family has not been set by the time we encounter the first file,
+ * it means this family has no name, and should be used only as a fallback.
+ * We create a new family for it in the master list and later add it to
+ * the "default" fallback list.
+ */
+ else if( !strcasecmp( "file", p_node ) )
+ {
+ i_type = xml_ReaderNextNode( p_xml, &p_node );
+
+ if( i_type != XML_READER_TEXT || !p_node || !*p_node )
+ {
+ ++i_counter;
+ continue;
+ }
+
+ if( !p_family )
+ p_family = NewFamily( p_filter, NULL, &p_sys->p_families,
+ &p_sys->family_map, NULL );
+
+ if( unlikely( !p_family ) )
+ return VLC_ENOMEM;
+
+ switch( i_counter )
+ {
+ 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;
+ default:
+ msg_Warn( p_filter, "Android_ParseFamily: too many files" );
+ return VLC_EGENERIC;
+ }
+
+ char *psz_fontfile = NULL;
+ if( asprintf( &psz_fontfile, "%s/%s", ANDROID_FONT_PATH, p_node ) < 0
+ || !NewFont( psz_fontfile, 0, b_bold, b_italic, p_family ) )
+ return VLC_ENOMEM;
+
+ ++i_counter;
+ }
+ break;
+
+ case XML_READER_ENDELEM:
+ if( !strcasecmp( "family", p_node ) )
+ {
+ if( !p_family )
+ {
+ msg_Warn( p_filter, "Android_ParseFamily: empty family" );
+ return VLC_EGENERIC;
+ }
+
+ 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 );
+
+ if( unlikely( !p_fallback ) )
+ return VLC_ENOMEM;
+
+ p_fallback->p_fonts = p_family->p_fonts;
+ }
+
+ return VLC_SUCCESS;
+ }
+ break;
+ }
+ }
+
+ msg_Warn( p_filter, "Android_ParseFamily: Corrupt font configuration file" );
+ return VLC_EGENERIC;
+}
+
+int Android_ParseSystemFonts( filter_t *p_filter, const char *psz_path )
+{
+ int i_ret = VLC_SUCCESS;
+ stream_t *p_stream = stream_UrlNew( p_filter, psz_path );
+
+ if( !p_stream )
+ return VLC_EGENERIC;
+
+ xml_reader_t *p_xml = xml_ReaderCreate( p_filter, p_stream );
+
+ if( !p_xml )
+ {
+ stream_Delete( p_stream );
+ return VLC_EGENERIC;
+ }
+
+ const char *p_node;
+ int i_type;
+ while( ( i_type = xml_ReaderNextNode( p_xml, &p_node ) ) > 0 )
+ {
+ if( i_type == XML_READER_STARTELEM && !strcasecmp( "family", p_node ) )
+ {
+ if( ( i_ret = Android_ParseFamily( p_filter, p_xml ) ) )
+ break;
+ }
+ }
+
+ xml_ReaderDelete( p_xml );
+ stream_Delete( p_stream );
+ return i_ret;
+}
+
+const vlc_family_t *Android_GetFamily( filter_t *p_filter, 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 );
+
+ free( psz_lc );
+
+ if( p_family == kVLCDictionaryNotFound )
+ return NULL;
+
+ return p_family;
+}
+
+vlc_family_t *Android_GetFallbacks( filter_t *p_filter, 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 );
+
+ free( psz_lc );
+
+ if( p_fallbacks == kVLCDictionaryNotFound )
+ return NULL;
+
+ return p_fallbacks;
+}
+#endif
diff --git a/modules/text_renderer/platform_fonts.h b/modules/text_renderer/platform_fonts.h
index 9748ce4..b8fe25c 100644
--- a/modules/text_renderer/platform_fonts.h
+++ b/modules/text_renderer/platform_fonts.h
@@ -70,9 +70,9 @@ typedef uint32_t uni_char_t;
# define SYSTEM_DEFAULT_MONOSPACE_FAMILY "Monotype Sans Duospace WT K"
#elif defined( __ANDROID__ )
# define SYSTEM_DEFAULT_FONT_FILE "/system/fonts/DroidSans-Bold.ttf"
-# define SYSTEM_DEFAULT_FAMILY "Droid Sans Bold"
+# define SYSTEM_DEFAULT_FAMILY "Droid Sans"
# define SYSTEM_DEFAULT_MONOSPACE_FONT_FILE "/system/fonts/DroidSansMono.ttf"
-# define SYSTEM_DEFAULT_MONOSPACE_FAMILY "Droid Sans Mono"
+# define SYSTEM_DEFAULT_MONOSPACE_FAMILY "Monospace"
#else
# define SYSTEM_DEFAULT_FONT_FILE "/usr/share/fonts/truetype/freefont/FreeSerifBold.ttf"
# define SYSTEM_DEFAULT_FAMILY "Serif Bold"
@@ -141,6 +141,18 @@ char* MacLegacy_Select( filter_t *p_filter, const char* psz_fontname,
#endif
#endif
+#ifdef __ANDROID__
+#define ANDROID_SYSTEM_FONTS "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"
+#define ANDROID_FONT_PATH "/system/fonts"
+
+int Android_ParseSystemFonts( filter_t *p_filter, const char *psz_path );
+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 );
+#endif
+
char* Dummy_Select( filter_t *p_filter, const char* family,
bool b_bold, bool b_italic,
int *i_idx, uni_char_t codepoint );
diff --git a/modules/text_renderer/text_layout.c b/modules/text_renderer/text_layout.c
index bd6a62e..545568b 100644
--- a/modules/text_renderer/text_layout.c
+++ b/modules/text_renderer/text_layout.c
@@ -63,6 +63,11 @@
# define HAVE_FONT_FALLBACK
#endif
+/* Android */
+#ifdef __ANDROID__
+# 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