[vlc-devel] [RFC PATCH] freetype: font fallback using fontconfig
Salah-Eddin Shaban
salshaaban at gmail.com
Wed Jul 8 23:46:21 CEST 2015
---
modules/text_renderer/freetype.c | 237 ++++++++++++++++++++++++++-------
modules/text_renderer/freetype.h | 29 ++--
modules/text_renderer/platform_fonts.c | 41 +++++-
modules/text_renderer/platform_fonts.h | 16 ++-
modules/text_renderer/text_layout.c | 210 ++++++++++++++++++++++++++++-
5 files changed, 454 insertions(+), 79 deletions(-)
diff --git a/modules/text_renderer/freetype.c b/modules/text_renderer/freetype.c
index 2773779..3958c89 100644
--- a/modules/text_renderer/freetype.c
+++ b/modules/text_renderer/freetype.c
@@ -67,12 +67,13 @@
/* FontConfig */
#ifdef HAVE_FONTCONFIG
+# include <fontconfig/fontconfig.h>
+# include <fontconfig/fcfreetype.h>
# define HAVE_GET_FONT_BY_FAMILY_NAME
#endif
#include <assert.h>
-#include "text_renderer.h"
#include "platform_fonts.h"
#include "freetype.h"
#include "text_layout.h"
@@ -297,6 +298,35 @@ static int LoadFontsFromAttachments( filter_t *p_filter )
p_attach->i_data > 0 && p_attach->p_data )
{
p_sys->pp_font_attachments[ p_sys->i_font_attachments++ ] = p_attach;
+
+#ifdef HAVE_FONTCONFIG
+ char buffer[ 10 ];
+ FT_Face p_face;
+ int i_num_faces = 0;
+ int i_index = 0;
+ snprintf( buffer, sizeof( buffer ), ":/%d", p_sys->i_font_attachments - 1 );
+
+ do {
+ if( FT_New_Memory_Face( p_sys->p_library, p_attach->p_data,
+ p_attach->i_data, i_index, &p_face ) )
+ continue;
+
+ i_num_faces = p_face->num_faces;
+
+ FcPattern *p_pattern =
+ FcFreeTypeQueryFace( p_face,
+ ( const FcChar8* )buffer, i_index,
+ FcConfigGetBlanks( p_sys->p_config ) );
+
+ FcFontSet *p_set = FcConfigGetFonts( p_sys->p_config, FcSetSystem );
+
+ if( !p_pattern || !p_set || !FcFontSetAdd( p_set, p_pattern ) )
+ msg_Err( p_filter,
+ "Error adding font attachment to font database" );
+
+ FT_Done_Face( p_face );
+ } while( ++i_index < i_num_faces );
+#endif
}
else
{
@@ -863,6 +893,7 @@ static inline int RenderAXYZ( filter_t *p_filter,
+#ifndef HAVE_FONTCONFIG
static FT_Face LoadEmbeddedFace( filter_sys_t *p_sys, const text_style_t *p_style )
{
for( int k = 0; k < p_sys->i_font_attachments; k++ )
@@ -894,6 +925,7 @@ static FT_Face LoadEmbeddedFace( filter_sys_t *p_sys, const text_style_t *p_styl
}
return NULL;
}
+#endif
static xml_reader_t *GetXMLReader( filter_t *p_filter, stream_t *p_sub )
{
@@ -1275,6 +1307,7 @@ static int Create( vlc_object_t *p_this )
p_sys->style.psz_monofontname = psz_monofontfamily;
#ifdef HAVE_FONTCONFIG
+ p_sys->p_config = FcInitLoadConfigAndFonts();
p_sys->pf_select = FontConfig_Select;
FontConfig_BuildCache( p_filter );
#elif defined( __APPLE__ )
@@ -1289,10 +1322,11 @@ static int Create( vlc_object_t *p_this )
/* */
psz_fontfile = p_sys->pf_select( p_filter, psz_fontname, false, false,
- p_sys->i_default_font_size, &fontindex );
+ p_sys->i_default_font_size, &fontindex,
+ NULL, 0 );
psz_monofontfile = p_sys->pf_select( p_filter, psz_monofontfamily, false,
- false, p_sys->i_default_font_size,
- &monofontindex );
+ false, p_sys->i_default_font_size,
+ &monofontindex, NULL, 0 );
msg_Dbg( p_filter, "Using %s as font from file %s", psz_fontname, psz_fontfile );
msg_Dbg( p_filter, "Using %s as mono-font from file %s", psz_monofontfamily, psz_monofontfile );
@@ -1305,11 +1339,7 @@ static int Create( vlc_object_t *p_this )
if( Init_FT( p_this, psz_fontfile, fontindex, f_outline_thickness ) != VLC_SUCCESS )
goto error;
- int i_faces_size = 20;
- p_sys->faces_cache.p_faces = malloc( i_faces_size * sizeof( *p_sys->faces_cache.p_faces ) );
- p_sys->faces_cache.p_styles = malloc( i_faces_size * sizeof( *p_sys->faces_cache.p_styles ) );
- p_sys->faces_cache.i_cache_size = i_faces_size;
- p_sys->faces_cache.i_faces_count = 0;
+ vlc_dictionary_init( &p_sys->faces_cache, 20 );
p_sys->pp_font_attachments = NULL;
p_sys->i_font_attachments = 0;
@@ -1346,6 +1376,17 @@ static void Destroy_FT( vlc_object_t *p_this )
FT_Done_FreeType( p_sys->p_library );
}
+static void FreeFace( void *p_face, void *p_obj )
+{
+
+ VLC_UNUSED( p_obj );
+
+ //filter_t *p_filter = ( filter_t * ) p_obj;
+ //msg_Dbg( p_filter, "FT_Done_Face: 0x%lx", ( long ) p_face );
+
+ FT_Done_Face( ( FT_Face ) p_face );
+}
+
/*****************************************************************************
* Destroy: destroy Clone video thread output method
*****************************************************************************
@@ -1356,14 +1397,7 @@ static void Destroy( vlc_object_t *p_this )
filter_t *p_filter = (filter_t *)p_this;
filter_sys_t *p_sys = p_filter->p_sys;
- faces_cache_t *p_cache = &p_sys->faces_cache;
- for( int i = 0; i < p_cache->i_faces_count; ++i )
- {
- FT_Done_Face( p_cache->p_faces[ i ] );
- free( p_cache->p_styles[ i ].psz_fontname );
- }
- free( p_sys->faces_cache.p_faces );
- free( p_sys->faces_cache.p_styles );
+ vlc_dictionary_clear( &p_sys->faces_cache, FreeFace, p_filter );
if( p_sys->pp_font_attachments )
{
@@ -1378,23 +1412,43 @@ static void Destroy( vlc_object_t *p_this )
free( p_sys->style.psz_monofontname );
Destroy_FT( p_this );
+
+#ifdef HAVE_FONTCONFIG
+ FcConfigDestroy( p_sys->p_config );
+#endif
+
free( p_sys );
}
+#ifndef HAVE_FONTCONFIG
FT_Face LoadFace( filter_t *p_filter,
- const text_style_t *p_style )
+ const text_style_t *p_style,
+ const char *language,
+ uni_char_t codepoint )
{
+ VLC_UNUSED(language);
+ VLC_UNUSED(codepoint);
+
filter_sys_t *p_sys = p_filter->p_sys;
+ char buffer[ 128 ];
+
+ const char *p_bold = (p_style->i_style_flags & STYLE_BOLD) ? " Bold" : "";
+ const char *p_italic = (p_style->i_style_flags & STYLE_ITALIC) ? " Italic" : "";
+ int i_font_width = (p_style->i_style_flags & STYLE_HALFWIDTH) ?
+ p_style->i_font_size / 2 : p_style->i_font_size;
+ snprintf( buffer, sizeof( buffer ), "%s%s%s - %d - %d",
+ p_style->psz_fontname,
+ p_bold, p_italic,
+ p_style->i_font_size, i_font_width );
+
+ FT_Face p_face = vlc_dictionary_value_for_key( &p_sys->faces_cache,
+ buffer );
+ if( p_face != kVLCDictionaryNotFound )
+ return p_face;
- faces_cache_t *p_cache = &p_sys->faces_cache;
- for( int i = 0; i < p_cache->i_faces_count; ++i )
- if( FaceStyleEquals( &p_cache->p_styles[ i ], p_style )
- && p_cache->p_styles[ i ].i_font_size == p_style->i_font_size
- && !( ( p_cache->p_styles[ i ].i_style_flags ^ p_style->i_style_flags ) & STYLE_HALFWIDTH ) )
- return p_cache->p_faces[ i ];
/* Look for a match amongst our attachments first */
- FT_Face p_face = LoadEmbeddedFace( p_sys, p_style );
+ p_face = LoadEmbeddedFace( p_sys, p_style );
/* Load system wide font otheriwse */
if( !p_face )
@@ -1407,7 +1461,8 @@ FT_Face LoadFace( filter_t *p_filter,
(p_style->i_style_flags & STYLE_BOLD) != 0,
(p_style->i_style_flags & STYLE_ITALIC) != 0,
-1,
- &i_idx );
+ &i_idx,
+ NULL, 0 );
else
psz_fontfile = NULL;
@@ -1443,9 +1498,6 @@ FT_Face LoadFace( filter_t *p_filter,
return NULL;
}
- int i_font_width = p_style->i_style_flags & STYLE_HALFWIDTH
- ? p_style->i_font_size / 2 : p_style->i_font_size;
-
if( FT_Set_Pixel_Sizes( p_face, i_font_width, p_style->i_font_size ) )
{
msg_Err( p_filter,
@@ -1454,36 +1506,119 @@ FT_Face LoadFace( filter_t *p_filter,
return NULL;
}
- if( p_cache->i_faces_count == p_cache->i_cache_size )
+ //msg_Dbg( p_filter, "LoadFace: adding face to cache: 0x%lx %s", ( long ) p_face, buffer );
+
+ vlc_dictionary_insert( &p_sys->faces_cache, buffer, p_face );
+
+ return p_face;
+}
+
+#else
+
+FT_Face LoadFace( filter_t *p_filter,
+ const text_style_t *p_style,
+ const char *language,
+ uni_char_t codepoint )
+{
+ //msg_Dbg( p_filter, "LoadFace: font requested: %s, language: %s, codepoint: %x",
+ // p_style->psz_fontname, language, codepoint );
+
+ filter_sys_t *p_sys = p_filter->p_sys;
+ char buffer[ 128 ];
+
+ int i_idx = 0;
+ char *psz_fontfile = NULL;
+ if( p_sys->pf_select )
+ psz_fontfile = p_sys->pf_select( p_filter,
+ p_style->psz_fontname,
+ (p_style->i_style_flags & STYLE_BOLD) != 0,
+ (p_style->i_style_flags & STYLE_ITALIC) != 0,
+ -1,
+ &i_idx,
+ language, codepoint );
+ else
+ psz_fontfile = NULL;
+
+ if( !psz_fontfile )
+ return NULL;
+
+ if( *psz_fontfile == '\0' )
{
- FT_Face *p_new_faces =
- realloc( p_cache->p_faces, p_cache->i_cache_size * 2 * sizeof( *p_cache->p_faces ) );
- if( !p_new_faces )
- {
- FT_Done_Face( p_face );
- return NULL;
- }
+ msg_Warn( p_filter,
+ "We were not able to find a matching font: \"%s\" (%s %s),"
+ " so using default font",
+ p_style->psz_fontname,
+ (p_style->i_style_flags & STYLE_BOLD) ? "Bold" : "",
+ (p_style->i_style_flags & STYLE_ITALIC) ? "Italic" : "" );
+ free( psz_fontfile );
+ return NULL;
+ }
+
+ //msg_Dbg( p_filter, "LoadFace: font returned: %s, face index: %d",
+ // psz_fontfile, i_idx );
- p_cache->p_faces = p_new_faces;
+ int i_font_width = (p_style->i_style_flags & STYLE_HALFWIDTH) ?
+ p_style->i_font_size / 2 : p_style->i_font_size;
+ snprintf( buffer, sizeof( buffer ), "%s - %d - %d - %d",
+ psz_fontfile,
+ i_idx,
+ p_style->i_font_size, i_font_width );
- text_style_t *p_new_styles =
- realloc( p_cache->p_styles, p_cache->i_cache_size * 2 * sizeof( *p_cache->p_styles ) ) ;
- if( !p_new_styles )
+ FT_Face p_face = vlc_dictionary_value_for_key( &p_sys->faces_cache,
+ buffer );
+ if( p_face != kVLCDictionaryNotFound )
+ {
+ free( psz_fontfile );
+ return p_face;
+ }
+
+ if( psz_fontfile[0] == ':' && psz_fontfile[1] == '/' )
+ {
+ int i_attach = atoi( psz_fontfile + 2 );
+ if( i_attach < 0 || i_attach >= p_sys->i_font_attachments )
{
- FT_Done_Face( p_face );
- return NULL;
+ msg_Err( p_filter, "Invalid font attachment index" );
+ p_face = NULL;
+ }
+ else
+ {
+ input_attachment_t *p_attach = p_sys->pp_font_attachments[ i_attach ];
+ if( FT_New_Memory_Face( p_sys->p_library, p_attach->p_data,
+ p_attach->i_data, i_idx, &p_face ) )
+ p_face = NULL;
}
+ }
+ else
+ if( FT_New_Face( p_sys->p_library, psz_fontfile, i_idx, &p_face ) )
+ p_face = NULL;
+
+ free( psz_fontfile );
- p_cache->p_styles = p_new_styles;
- p_cache->i_cache_size *= 2;
+ if( !p_face )
+ return NULL;
+
+ if( FT_Select_Charmap( p_face, ft_encoding_unicode ) )
+ {
+ /* We've loaded a font face which is unhelpful for actually
+ * rendering text - fallback to the default one.
+ */
+ FT_Done_Face( p_face );
+ return NULL;
}
- text_style_t *p_face_style = p_cache->p_styles + p_cache->i_faces_count;
- p_face_style->i_font_size = p_style->i_font_size;
- p_face_style->i_style_flags = p_style->i_style_flags;
- p_face_style->psz_fontname = strdup( p_style->psz_fontname );
- p_cache->p_faces[ p_cache->i_faces_count ] = p_face;
- ++p_cache->i_faces_count;
+ if( FT_Set_Pixel_Sizes( p_face, i_font_width, p_style->i_font_size ) )
+ {
+ msg_Err( p_filter,
+ "Failed to set font size to %d", p_style->i_font_size );
+ FT_Done_Face( p_face );
+ return NULL;
+ }
+
+ //msg_Dbg( p_filter, "LoadFace: adding face to cache: 0x%lx %s", ( long ) p_face, buffer );
+
+ vlc_dictionary_insert( &p_sys->faces_cache, buffer, p_face );
return p_face;
}
+
+#endif
diff --git a/modules/text_renderer/freetype.h b/modules/text_renderer/freetype.h
index d486773..beb1489 100644
--- a/modules/text_renderer/freetype.h
+++ b/modules/text_renderer/freetype.h
@@ -25,13 +25,15 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
-typedef struct faces_cache_t
-{
- FT_Face *p_faces;
- text_style_t *p_styles;
- int i_faces_count;
- int i_cache_size;
-} faces_cache_t;
+#include <vlc_arrays.h>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_STROKER_H
+
+#ifdef HAVE_FONTCONFIG
+#include <fontconfig/fontconfig.h>
+#endif
/*****************************************************************************
* filter_sys_t: freetype local data
@@ -59,12 +61,16 @@ struct filter_sys_t
int i_font_attachments;
/* Font faces cache */
- faces_cache_t faces_cache;
+ vlc_dictionary_t faces_cache;
char * (*pf_select) (filter_t *, const char* family,
- bool bold, bool italic, int size,
- int *index);
+ bool bold, bool italic, int size,
+ int *index, const char *language,
+ uni_char_t codepoint);
+#ifdef HAVE_FONTCONFIG
+ FcConfig *p_config;
+#endif
};
#define FT_FLOOR(X) ((X & -64) >> 6)
@@ -73,4 +79,5 @@ struct filter_sys_t
#define FT_MulFix(v, s) (((v)*(s))>>16)
#endif
-FT_Face LoadFace( filter_t *p_filter, const text_style_t *p_style );
+FT_Face LoadFace( filter_t *p_filter, const text_style_t *p_style,
+ const char *language, uni_char_t codepoint );
diff --git a/modules/text_renderer/platform_fonts.c b/modules/text_renderer/platform_fonts.c
index 7869dba..543466b 100644
--- a/modules/text_renderer/platform_fonts.c
+++ b/modules/text_renderer/platform_fonts.c
@@ -49,6 +49,7 @@
/* Win32 GDI */
#ifdef _WIN32
+# undef HAVE_FONTCONFIG
# include <windows.h>
# include <shlobj.h>
# include <vlc_charset.h> /* FromT */
@@ -60,6 +61,7 @@
#endif
#include "platform_fonts.h"
+#include "freetype.h"
#ifdef HAVE_FONTCONFIG
void FontConfig_BuildCache( filter_t *p_filter )
@@ -110,22 +112,37 @@ void FontConfig_BuildCache( filter_t *p_filter )
* \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_size, int *i_idx )
+ bool b_bold, bool b_italic, int i_size, int *i_idx,
+ const char *language, uni_char_t codepoint )
{
FcResult result = FcResultMatch;
FcPattern *pat, *p_pat;
FcChar8* val_s;
FcBool val_b;
char *ret = NULL;
- FcConfig* config = NULL;
- VLC_UNUSED(p_filter);
+
+ filter_sys_t *p_sys = p_filter->p_sys;
+ FcConfig* config = p_sys->p_config;
/* Create a pattern and fills it */
pat = FcPatternCreate();
if (!pat) return NULL;
/* */
- FcPatternAddString( pat, FC_FAMILY, (const FcChar8*)family );
+ if ( language )
+ FcPatternAddString( pat, FC_LANG, ( const FcChar8* ) language );
+ if ( codepoint )
+ {
+ FcCharSet *cs = FcCharSetCreate();
+ FcCharSetAddChar( cs, codepoint );
+ FcPatternAddCharSet( pat, FC_CHARSET, cs );
+ FcCharSetDestroy( cs );
+ }
+ FcValue value;
+ value.type = FcTypeString;
+ value.u.s = (const FcChar8*) family;
+ FcPatternAddWeak( pat, FC_FAMILY, value, true );
+
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 );
@@ -259,11 +276,14 @@ static char* GetWindowsFontPath()
}
char* Win32_Select( filter_t *p_filter, const char* family,
- bool b_bold, bool b_italic, int i_size, int *i_idx )
+ bool b_bold, bool b_italic, int i_size, int *i_idx,
+ const char *language, uni_char_t codepoint )
{
VLC_UNUSED( i_size );
VLC_UNUSED( i_idx );
VLC_UNUSED( p_filter );
+ VLC_UNUSED( language );
+ VLC_UNUSED( codepoint );
if( !family || strlen( family ) < 1 )
goto fail;
@@ -328,11 +348,15 @@ fail:
#ifdef __APPLE__
#if !TARGET_OS_IPHONE
char* MacLegacy_Select( filter_t *p_filter, const char* psz_fontname,
- bool b_bold, bool b_italic, int i_size, int *i_idx )
+ bool b_bold, bool b_italic, int i_size, int *i_idx,
+ const char *language, uni_char_t codepoint )
{
VLC_UNUSED( b_bold );
VLC_UNUSED( b_italic );
VLC_UNUSED( i_size );
+ VLC_UNUSED( language );
+ VLC_UNUSED( codepoint );
+
FSRef ref;
unsigned char path[MAXPATHLEN];
char * psz_path;
@@ -409,13 +433,16 @@ char* MacLegacy_Select( filter_t *p_filter, const char* psz_fontname,
#endif
char* Dummy_Select( filter_t *p_filter, const char* psz_font,
- bool b_bold, bool b_italic, int i_size, int *i_idx )
+ bool b_bold, bool b_italic, int i_size, int *i_idx,
+ const char *language, uni_char_t codepoint )
{
VLC_UNUSED(p_filter);
VLC_UNUSED(b_bold);
VLC_UNUSED(b_italic);
VLC_UNUSED(i_size);
VLC_UNUSED(i_idx);
+ VLC_UNUSED(language);
+ VLC_UNUSED(codepoint);
char *psz_fontname;
# if defined( _WIN32 ) && !VLC_WINSTORE_APP
diff --git a/modules/text_renderer/platform_fonts.h b/modules/text_renderer/platform_fonts.h
index cff52b1..de58f71 100644
--- a/modules/text_renderer/platform_fonts.h
+++ b/modules/text_renderer/platform_fonts.h
@@ -33,6 +33,8 @@
# include "config.h"
#endif
+#include "text_renderer.h"
+
/* Default fonts */
#ifdef __APPLE__
# define SYSTEM_DEFAULT_FONT_FILE "/Library/Fonts/Arial Unicode.ttf"
@@ -80,25 +82,29 @@
#ifdef HAVE_FONTCONFIG
char* FontConfig_Select( filter_t *p_filter, const char* family,
- bool b_bold, bool b_italic, int i_size, int *i_idx );
+ bool b_bold, bool b_italic, int i_size, int *i_idx,
+ const char *language, 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, int i_size, int *i_idx );
+ bool b_bold, bool b_italic, int i_size, int *i_idx,
+ const char *language, uni_char_t codepoint );
#endif /* _WIN32 */
#ifdef __APPLE__
#if !TARGET_OS_IPHONE
char* MacLegacy_Select( filter_t *p_filter, const char* psz_fontname,
- bool b_bold, bool b_italic, int i_size, int *i_idx );
+ bool b_bold, bool b_italic, int i_size, int *i_idx,
+ const char *language, uni_char_t codepoint );
#endif
#endif
char* Dummy_Select( filter_t *p_filter, const char* family,
- bool b_bold, bool b_italic, int i_size, int *i_idx );
+ bool b_bold, bool b_italic, int i_size, int *i_idx,
+ const char *language, uni_char_t codepoint );
-#define File_Select(a) Dummy_Select(NULL, a, 0, 0, 0, NULL)
+#define File_Select(a) Dummy_Select(NULL, a, 0, 0, 0, NULL, NULL, 0)
diff --git a/modules/text_renderer/text_layout.c b/modules/text_renderer/text_layout.c
index bb6019b..da0b981 100644
--- a/modules/text_renderer/text_layout.c
+++ b/modules/text_renderer/text_layout.c
@@ -55,6 +55,10 @@
# include <hb-ft.h>
#endif
+#if defined(__APPLE__) || defined(_WIN32)
+# undef HAVE_FONTCONFIG
+#endif
+
#include "text_renderer.h"
#include "text_layout.h"
#include "freetype.h"
@@ -105,6 +109,7 @@ typedef struct paragraph_t
uni_char_t *p_code_points; //Unicode code points
int *pi_glyph_indices; //Glyph index values within the run's font face
text_style_t **pp_styles;
+ FT_Face *pp_faces;
int *pi_run_ids; //The run to which each glyph belongs
glyph_bitmaps_t *p_glyph_bitmaps;
uint8_t *pi_karaoke_bar;
@@ -223,6 +228,8 @@ static paragraph_t *NewParagraph( filter_t *p_filter,
malloc( i_size * sizeof( *p_paragraph->pi_glyph_indices ) );
p_paragraph->pp_styles =
malloc( i_size * sizeof( *p_paragraph->pp_styles ) );
+ p_paragraph->pp_faces =
+ calloc( i_size, sizeof( *p_paragraph->pp_faces ) );
p_paragraph->pi_run_ids =
calloc( i_size, sizeof( *p_paragraph->pi_run_ids ) );
p_paragraph->p_glyph_bitmaps =
@@ -235,9 +242,9 @@ static paragraph_t *NewParagraph( filter_t *p_filter,
p_paragraph->i_runs_count = 0;
if( !p_paragraph->p_code_points || !p_paragraph->pi_glyph_indices
- || !p_paragraph->pp_styles || !p_paragraph->pi_run_ids
- || !p_paragraph->p_glyph_bitmaps || !p_paragraph->pi_karaoke_bar
- || !p_paragraph->p_runs )
+ || !p_paragraph->pp_styles || !p_paragraph->pp_faces
+ || !p_paragraph->pi_run_ids|| !p_paragraph->p_glyph_bitmaps
+ || !p_paragraph->pi_karaoke_bar || !p_paragraph->p_runs )
goto error;
if( p_code_points )
@@ -286,6 +293,7 @@ error:
if( p_paragraph->p_code_points ) free( p_paragraph->p_code_points );
if( p_paragraph->pi_glyph_indices ) free( p_paragraph->pi_glyph_indices );
if( p_paragraph->pp_styles ) free( p_paragraph->pp_styles );
+ if( p_paragraph->pp_faces ) free( p_paragraph->pp_faces );
if( p_paragraph->pi_run_ids ) free( p_paragraph->pi_run_ids );
if( p_paragraph->p_glyph_bitmaps ) free( p_paragraph->p_glyph_bitmaps );
if (p_paragraph->pi_karaoke_bar ) free( p_paragraph->pi_karaoke_bar );
@@ -310,6 +318,7 @@ static void FreeParagraph( paragraph_t *p_paragraph )
free( p_paragraph->p_glyph_bitmaps );
free( p_paragraph->pi_karaoke_bar );
free( p_paragraph->pi_run_ids );
+ free( p_paragraph->pp_faces );
free( p_paragraph->pp_styles );
free( p_paragraph->p_code_points );
@@ -431,6 +440,193 @@ static int AddRun( filter_t *p_filter,
}
/*
+ * This is based on the list in Qt's qfontconfigdatabase.cpp
+ */
+#if defined( HAVE_HARFBUZZ ) && defined( HAVE_FONTCONFIG )
+static const char * languageFromScript( hb_script_t script )
+{
+ switch( script )
+ {
+ case HB_SCRIPT_LATIN: return "en";
+ case HB_SCRIPT_GREEK: return "el";
+ case HB_SCRIPT_CYRILLIC: return "ru";
+ case HB_SCRIPT_ARMENIAN: return "hy";
+ case HB_SCRIPT_HEBREW: return "he";
+ case HB_SCRIPT_ARABIC: return "ar";
+ case HB_SCRIPT_SYRIAC: return "syr";
+ case HB_SCRIPT_THAANA: return "dv";
+ case HB_SCRIPT_DEVANAGARI: return "hi";
+ case HB_SCRIPT_BENGALI: return "bn";
+ case HB_SCRIPT_GURMUKHI: return "pa";
+ case HB_SCRIPT_GUJARATI: return "gu";
+ case HB_SCRIPT_ORIYA: return "or";
+ case HB_SCRIPT_TAMIL: return "ta";
+ case HB_SCRIPT_TELUGU: return "te";
+ case HB_SCRIPT_KANNADA: return "kn";
+ case HB_SCRIPT_MALAYALAM: return "ml";
+ case HB_SCRIPT_SINHALA: return "si";
+ case HB_SCRIPT_THAI: return "th";
+ case HB_SCRIPT_LAO: return "lo";
+ case HB_SCRIPT_TIBETAN: return "bo";
+ case HB_SCRIPT_MYANMAR: return "my";
+ case HB_SCRIPT_GEORGIAN: return "ka";
+ case HB_SCRIPT_HANGUL: return "ko";
+ case HB_SCRIPT_ETHIOPIC: return "am";
+ case HB_SCRIPT_CHEROKEE: return "chr";
+ case HB_SCRIPT_CANADIAN_ABORIGINAL: return "cr";
+ case HB_SCRIPT_OGHAM: return "sga";
+ case HB_SCRIPT_RUNIC: return "non";
+ case HB_SCRIPT_KHMER: return "km";
+ case HB_SCRIPT_MONGOLIAN: return "mn";
+ case HB_SCRIPT_HIRAGANA: return "ja";
+ case HB_SCRIPT_KATAKANA: return "ja";
+ case HB_SCRIPT_BOPOMOFO: return "zh-TW";
+ //case HB_SCRIPT_HAN:
+ case HB_SCRIPT_YI: return "ii";
+ case HB_SCRIPT_OLD_ITALIC: return "ett";
+ case HB_SCRIPT_GOTHIC: return "got";
+ case HB_SCRIPT_DESERET: return "en";
+ case HB_SCRIPT_TAGALOG: return "fil";
+ case HB_SCRIPT_HANUNOO: return "hnn";
+ case HB_SCRIPT_BUHID: return "bku";
+ case HB_SCRIPT_TAGBANWA: return "tbw";
+ case HB_SCRIPT_COPTIC: return "cop";
+ case HB_SCRIPT_LIMBU: return "lif";
+ case HB_SCRIPT_TAI_LE: return "tdd";
+ case HB_SCRIPT_LINEAR_B: return "grc";
+ case HB_SCRIPT_UGARITIC: return "uga";
+ case HB_SCRIPT_SHAVIAN: return "en";
+ case HB_SCRIPT_OSMANYA: return "so";
+ case HB_SCRIPT_CYPRIOT: return "grc";
+ //case HB_SCRIPT_BRAILLE
+ case HB_SCRIPT_BUGINESE: return "bug";
+ case HB_SCRIPT_NEW_TAI_LUE: return "khb";
+ case HB_SCRIPT_GLAGOLITIC: return "cu";
+ case HB_SCRIPT_TIFINAGH: return "shi";
+ case HB_SCRIPT_SYLOTI_NAGRI: return "syl";
+ case HB_SCRIPT_OLD_PERSIAN: return "peo";
+ case HB_SCRIPT_KHAROSHTHI: return "pra";
+ case HB_SCRIPT_BALINESE: return "ban";
+ case HB_SCRIPT_CUNEIFORM: return "akk";
+ case HB_SCRIPT_PHOENICIAN: return "phn";
+ case HB_SCRIPT_PHAGS_PA: return "lzh";
+ case HB_SCRIPT_NKO: return "man";
+ case HB_SCRIPT_SUNDANESE: return "su";
+ case HB_SCRIPT_LEPCHA: return "lep";
+ case HB_SCRIPT_OL_CHIKI: return "sat";
+ case HB_SCRIPT_VAI: return "vai";
+ case HB_SCRIPT_SAURASHTRA: return "saz";
+ case HB_SCRIPT_KAYAH_LI: return "eky";
+ case HB_SCRIPT_REJANG: return "rej";
+ case HB_SCRIPT_LYCIAN: return "xlc";
+ case HB_SCRIPT_CARIAN: return "xcr";
+ case HB_SCRIPT_LYDIAN: return "xld";
+ case HB_SCRIPT_CHAM: return "cjm";
+ case HB_SCRIPT_TAI_THAM: return "nod";
+ case HB_SCRIPT_TAI_VIET: return "blt";
+ case HB_SCRIPT_AVESTAN: return "ae";
+ case HB_SCRIPT_EGYPTIAN_HIEROGLYPHS: return "egy";
+ case HB_SCRIPT_SAMARITAN: return "smp";
+ case HB_SCRIPT_LISU: return "lis";
+ case HB_SCRIPT_BAMUM: return "bax";
+ case HB_SCRIPT_JAVANESE: return "jv";
+ case HB_SCRIPT_MEETEI_MAYEK: return "mni";
+ case HB_SCRIPT_IMPERIAL_ARAMAIC: return "arc";
+ case HB_SCRIPT_OLD_SOUTH_ARABIAN: return "xsa";
+ case HB_SCRIPT_INSCRIPTIONAL_PARTHIAN: return "xpr";
+ case HB_SCRIPT_INSCRIPTIONAL_PAHLAVI: return "pal";
+ case HB_SCRIPT_OLD_TURKIC: return "otk";
+ case HB_SCRIPT_KAITHI: return "bh";
+ case HB_SCRIPT_BATAK: return "bbc";
+ case HB_SCRIPT_BRAHMI: return "pra";
+ case HB_SCRIPT_MANDAIC: return "myz";
+ case HB_SCRIPT_CHAKMA: return "ccp";
+ case HB_SCRIPT_MEROITIC_CURSIVE: return "xmr";
+ case HB_SCRIPT_MEROITIC_HIEROGLYPHS: return "xmr";
+ case HB_SCRIPT_MIAO: return "hmd";
+ case HB_SCRIPT_SHARADA: return "sa";
+ case HB_SCRIPT_SORA_SOMPENG: return "srb";
+ case HB_SCRIPT_TAKRI: return "doi";
+
+ default: return NULL;
+ }
+}
+#endif
+
+/*
+ * Add a run with font fallback, possibly breaking the run further
+ * into runs of glyphs that end up having the same font face.
+ */
+#ifdef HAVE_FONTCONFIG
+static int AddRunWithFallback( filter_t *p_filter, paragraph_t *p_paragraph,
+ int i_start_offset, int i_end_offset )
+{
+ if( i_start_offset >= i_end_offset
+ || i_start_offset < 0 || i_start_offset >= p_paragraph->i_size
+ || i_end_offset <= 0 || i_end_offset > p_paragraph->i_size )
+ {
+ msg_Err( p_filter,
+ "AddRunWithFallback() invalid parameters. Paragraph size: %d, "
+ "Start offset: %d, End offset: %d",
+ p_paragraph->i_size, i_start_offset, i_end_offset );
+ return VLC_EGENERIC;
+ }
+
+ text_style_t *p_style = p_paragraph->pp_styles[ i_start_offset ];
+
+ /* Maximum number of faces to try for each run */
+ #define MAX_FACES 5
+ FT_Face pp_faces[ MAX_FACES ] = {0};
+
+#ifdef HAVE_HARFBUZZ
+ pp_faces[ 0 ] =
+ LoadFace( p_filter, p_style,
+ languageFromScript( p_paragraph->p_scripts[ i_start_offset ] ),
+ 0 );
+#else
+ pp_faces[ 0 ] = LoadFace( p_filter, p_style, NULL, 0 );
+#endif
+
+ for( int i = i_start_offset; i < i_end_offset; ++i )
+ {
+ int i_index = 0;
+ int i_glyph_index = 0;
+ FT_Face p_face = NULL;
+ do {
+ p_face = pp_faces[ i_index ];
+ if( !p_face )
+ p_face = pp_faces[ i_index ] =
+ LoadFace( p_filter, p_style, NULL,
+ p_paragraph->p_code_points[ i ] );
+ if( !p_face )
+ continue;
+ i_glyph_index = FT_Get_Char_Index( p_face,
+ p_paragraph->p_code_points[ i ] );
+ if( i_glyph_index )
+ p_paragraph->pp_faces[ i ] = p_face;
+
+ } while( i_glyph_index == 0 && ++i_index < MAX_FACES );
+ }
+
+ int i_run_start = i_start_offset;
+ for( int i = i_start_offset; i <= i_end_offset; ++i )
+ {
+ if( i == i_end_offset
+ || p_paragraph->pp_faces[ i_run_start ] != p_paragraph->pp_faces[ i ] )
+ {
+ if( AddRun( p_filter, p_paragraph, i_run_start, i,
+ p_paragraph->pp_faces[ i_run_start ] ) )
+ return VLC_EGENERIC;
+
+ i_run_start = i;
+ }
+ }
+
+ return VLC_SUCCESS;
+}
+#endif
+
+/*
* Segment a paragraph into runs
*/
static int ItemizeParagraph( filter_t *p_filter, paragraph_t *p_paragraph )
@@ -464,7 +660,11 @@ static int ItemizeParagraph( filter_t *p_filter, paragraph_t *p_paragraph )
& STYLE_HALFWIDTH )
||!FaceStyleEquals( p_last_style, p_paragraph->pp_styles[ i ] ) )
{
+#ifdef HAVE_FONTCONFIG
+ int i_ret = AddRunWithFallback( p_filter, p_paragraph, i_last_run_start, i );
+#else
int i_ret = AddRun( p_filter, p_paragraph, i_last_run_start, i, 0 );
+#endif
if( i_ret )
return i_ret;
@@ -520,7 +720,7 @@ static int ShapeParagraphHarfBuzz( filter_t *p_filter,
FT_Face p_face = 0;
if( !p_run->p_face )
{
- p_face = LoadFace( p_filter, p_style );
+ p_face = LoadFace( p_filter, p_style, NULL, 0 );
if( !p_face )
{
p_face = p_sys->p_face;
@@ -776,7 +976,7 @@ static int LoadGlyphs( filter_t *p_filter, paragraph_t *p_paragraph,
FT_Face p_face = 0;
if( !p_run->p_face )
{
- p_face = LoadFace( p_filter, p_style );
+ p_face = LoadFace( p_filter, p_style, NULL, 0 );
if( !p_face )
{
p_face = p_sys->p_face;
--
1.9.1
More information about the vlc-devel
mailing list