Commit fd07f90e authored by Salah-Eddin Shaban's avatar Salah-Eddin Shaban Committed by Jean-Baptiste Kempf
Browse files

freetype: font fallback for Windows


Signed-off-by: Jean-Baptiste Kempf's avatarJean-Baptiste Kempf <jb@videolan.org>
parent 195da069
...@@ -62,7 +62,7 @@ libwin32text_plugin_la_LIBADD = -lgdi32 ...@@ -62,7 +62,7 @@ libwin32text_plugin_la_LIBADD = -lgdi32
if HAVE_WIN32 if HAVE_WIN32
libfreetype_plugin_la_LIBADD += -liconv -lz libfreetype_plugin_la_LIBADD += -liconv -lz
if !HAVE_WINSTORE if !HAVE_WINSTORE
libfreetype_plugin_la_LIBADD += -lgdi32 libfreetype_plugin_la_LIBADD += -lgdi32 -lusp10
text_LTLIBRARIES += libwin32text_plugin.la text_LTLIBRARIES += libwin32text_plugin.la
endif endif
endif endif
...@@ -1273,7 +1273,13 @@ static int Create( vlc_object_t *p_this ) ...@@ -1273,7 +1273,13 @@ static int Create( vlc_object_t *p_this )
p_sys->pf_select = MacLegacy_Select; p_sys->pf_select = MacLegacy_Select;
#endif #endif
#elif defined( _WIN32 ) && defined( HAVE_GET_FONT_BY_FAMILY_NAME ) #elif defined( _WIN32 ) && defined( HAVE_GET_FONT_BY_FAMILY_NAME )
p_sys->pf_select = Win32_Select; const char *const ppsz_win32_default[] =
{ "Tahoma", "FangSong", "SimHei", "KaiTi" };
p_sys->pf_get_family = Win32_GetFamily;
p_sys->pf_get_fallbacks = Win32_GetFallbacks;
p_sys->pf_select = Generic_Select;
InitDefaultList( p_filter, ppsz_win32_default,
sizeof( ppsz_win32_default ) / sizeof( *ppsz_win32_default ) );
#elif defined( __ANDROID__ ) #elif defined( __ANDROID__ )
p_sys->pf_get_family = Android_GetFamily; p_sys->pf_get_family = Android_GetFamily;
p_sys->pf_get_fallbacks = Android_GetFallbacks; p_sys->pf_get_fallbacks = Android_GetFallbacks;
......
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
#ifdef _WIN32 #ifdef _WIN32
# include <windows.h> # include <windows.h>
# include <shlobj.h> # include <shlobj.h>
# include <usp10.h>
# include <vlc_charset.h> /* FromT */ # include <vlc_charset.h> /* FromT */
#endif #endif
...@@ -656,7 +657,54 @@ vlc_family_t *FontConfig_GetFallbacks( filter_t *p_filter, const char *psz_famil ...@@ -656,7 +657,54 @@ vlc_family_t *FontConfig_GetFallbacks( filter_t *p_filter, const char *psz_famil
#if defined( _WIN32 ) && !VLC_WINSTORE_APP #if defined( _WIN32 ) && !VLC_WINSTORE_APP
#define FONT_DIR_NT _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts") #define FONT_DIR_NT _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts")
static int GetFileFontByName( LPCTSTR font_name, char **psz_filename ) static char *Trim( char *psz_text )
{
int i_first_char = -1;
int i_last_char = -1;
int i_len = strlen( psz_text );
for( int i = 0; i < i_len; ++i )
{
if( psz_text[i] != ' ')
{
if( i_first_char == -1 )
i_first_char = i;
i_last_char = i;
}
}
psz_text[ i_last_char + 1 ] = 0;
if( i_first_char != -1 ) psz_text = psz_text + i_first_char;
return psz_text;
}
static int ConcatenatedIndex( char *psz_haystack, const char *psz_needle )
{
char *psz_family = psz_haystack;
char *psz_terminator = psz_haystack + strlen( psz_haystack );
int i_index = 0;
while( psz_family < psz_terminator )
{
char *psz_amp = strchr( psz_family, '&' );
if( !psz_amp ) psz_amp = psz_terminator;
*psz_amp = 0;
psz_family = Trim( psz_family );
if( !strcasecmp( psz_family, psz_needle ) )
return i_index;
psz_family = psz_amp + 1;
++i_index;
}
return -1;
}
static int GetFileFontByName( LPCTSTR font_name, char **psz_filename, int *i_index )
{ {
HKEY hKey; HKEY hKey;
TCHAR vbuffer[MAX_PATH]; TCHAR vbuffer[MAX_PATH];
...@@ -667,7 +715,6 @@ static int GetFileFontByName( LPCTSTR font_name, char **psz_filename ) ...@@ -667,7 +715,6 @@ static int GetFileFontByName( LPCTSTR font_name, char **psz_filename )
return 1; return 1;
char *font_name_temp = FromT( font_name ); char *font_name_temp = FromT( font_name );
size_t fontname_len = strlen( font_name_temp );
for( int index = 0;; index++ ) for( int index = 0;; index++ )
{ {
...@@ -678,6 +725,7 @@ static int GetFileFontByName( LPCTSTR font_name, char **psz_filename ) ...@@ -678,6 +725,7 @@ static int GetFileFontByName( LPCTSTR font_name, char **psz_filename )
NULL, NULL, (LPBYTE)dbuffer, &dbuflen); NULL, NULL, (LPBYTE)dbuffer, &dbuflen);
if( i_result != ERROR_SUCCESS ) if( i_result != ERROR_SUCCESS )
{ {
free( font_name_temp );
RegCloseKey( hKey ); RegCloseKey( hKey );
return i_result; return i_result;
} }
...@@ -687,41 +735,23 @@ static int GetFileFontByName( LPCTSTR font_name, char **psz_filename ) ...@@ -687,41 +735,23 @@ static int GetFileFontByName( LPCTSTR font_name, char **psz_filename )
char *s = strchr( psz_value,'(' ); char *s = strchr( psz_value,'(' );
if( s != NULL && s != psz_value ) s[-1] = '\0'; if( s != NULL && s != psz_value ) s[-1] = '\0';
/* Manage concatenated font names */ int i_concat_idx = 0;
if( strchr( psz_value, '&') ) { if( ( i_concat_idx = ConcatenatedIndex( psz_value, font_name_temp ) ) != -1 )
if( strcasestr( psz_value, font_name_temp ) != NULL ) {
{ *i_index = i_concat_idx;
free( psz_value ); *psz_filename = FromT( dbuffer );
break; free( psz_value );
} break;
}
else {
if( strncasecmp( psz_value, font_name_temp, fontname_len ) == 0 )
{
free( psz_value );
break;
}
} }
free( psz_value ); free( psz_value );
} }
*psz_filename = FromT( dbuffer );
free( font_name_temp ); free( font_name_temp );
RegCloseKey( hKey ); RegCloseKey( hKey );
return 0; return 0;
} }
static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *lpelfe, const NEWTEXTMETRICEX *metric,
DWORD type, LPARAM lParam)
{
VLC_UNUSED( metric );
if( (type & RASTER_FONTTYPE) ) return 1;
// if( lpelfe->elfScript ) FIXME
return GetFileFontByName( (LPCTSTR)lpelfe->elfFullName, (char **)lParam );
}
static char* GetWindowsFontPath() static char* GetWindowsFontPath()
{ {
wchar_t wdir[MAX_PATH]; wchar_t wdir[MAX_PATH];
...@@ -733,71 +763,229 @@ static char* GetWindowsFontPath() ...@@ -733,71 +763,229 @@ static char* GetWindowsFontPath()
return FromWide( wdir ); return FromWide( wdir );
} }
char* Win32_Select( filter_t *p_filter, const char* family, static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *lpelfe, const NEWTEXTMETRICEX *metric,
bool b_bold, bool b_italic, DWORD type, LPARAM lParam)
int *i_idx, uni_char_t codepoint )
{ {
VLC_UNUSED( codepoint ); VLC_UNUSED( metric );
VLC_UNUSED( i_idx ); if( (type & RASTER_FONTTYPE) ) return 1;
VLC_UNUSED( p_filter );
if( !family || strlen( family ) < 1 ) vlc_family_t *p_family = ( vlc_family_t * ) lParam;
goto fail;
bool b_bold = ( lpelfe->elfLogFont.lfWeight == FW_BOLD );
bool b_italic = ( lpelfe->elfLogFont.lfItalic != 0 );
for( vlc_font_t *p_font = p_family->p_fonts; p_font; p_font = p_font->p_next )
if( !!p_font->b_bold == !!b_bold && !!p_font->b_italic == !!b_italic )
return 1;
char *psz_filename = NULL;
char *psz_fontfile = NULL;
int i_index = 0;
if( GetFileFontByName( (LPCTSTR)lpelfe->elfFullName, &psz_filename, &i_index ) )
return 1;
if( strchr( psz_filename, DIR_SEP_CHAR ) )
psz_fontfile = psz_filename;
else
{
/* Get Windows Font folder */
char *psz_win_fonts_path = GetWindowsFontPath();
if( asprintf( &psz_fontfile, "%s\\%s", psz_win_fonts_path, psz_filename ) == -1 )
{
free( psz_filename );
free( psz_win_fonts_path );
return 1;
}
free( psz_filename );
free( psz_win_fonts_path );
}
NewFont( psz_fontfile, i_index, b_bold, b_italic, p_family );
return 1;
}
const vlc_family_t *Win32_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 )
return p_family;
p_family = NewFamily( p_filter, psz_family, &p_sys->p_families,
&p_sys->family_map, psz_family );
if( unlikely( !p_family ) )
return NULL;
/* */
LOGFONT lf; LOGFONT lf;
lf.lfCharSet = DEFAULT_CHARSET; lf.lfCharSet = DEFAULT_CHARSET;
if( b_italic )
lf.lfItalic = true;
if( b_bold )
lf.lfWeight = FW_BOLD;
LPTSTR psz_fbuffer = ToT( family ); LPTSTR psz_fbuffer = ToT( psz_family );
_tcsncpy( (LPTSTR)&lf.lfFaceName, psz_fbuffer, LF_FACESIZE ); _tcsncpy( (LPTSTR)&lf.lfFaceName, psz_fbuffer, LF_FACESIZE );
free( psz_fbuffer ); free( psz_fbuffer );
/* */ /* */
char *psz_filename = NULL;
HDC hDC = GetDC( NULL ); HDC hDC = GetDC( NULL );
EnumFontFamiliesEx(hDC, &lf, (FONTENUMPROC)&EnumFontCallback, (LPARAM)&psz_filename, 0); EnumFontFamiliesEx(hDC, &lf, (FONTENUMPROC)&EnumFontCallback, (LPARAM)p_family, 0);
ReleaseDC(NULL, hDC); ReleaseDC(NULL, hDC);
/* */ return p_family;
if( psz_filename != NULL ) }
static int CALLBACK MetaFileEnumProc( HDC hdc, HANDLETABLE* table,
CONST ENHMETARECORD* record,
int table_entries, LPARAM log_font )
{
VLC_UNUSED( hdc );
VLC_UNUSED( table );
VLC_UNUSED( table_entries );
if( record->iType == EMR_EXTCREATEFONTINDIRECTW )
{ {
/* FIXME: increase i_idx, when concatenated strings */ const EMREXTCREATEFONTINDIRECTW* create_font_record =
i_idx = 0; ( const EMREXTCREATEFONTINDIRECTW * ) record;
/* Prepend the Windows Font path, when only a filename was provided */ *( ( LOGFONT * ) log_font ) = create_font_record->elfw.elfLogFont;
if( strchr( psz_filename, DIR_SEP_CHAR ) ) }
return psz_filename; return 1;
else }
{
/* Get Windows Font folder */
char *psz_win_fonts_path = GetWindowsFontPath();
char *psz_tmp;
if( asprintf( &psz_tmp, "%s\\%s", psz_win_fonts_path, psz_filename ) == -1 )
{
free( psz_filename );
free( psz_win_fonts_path );
return NULL;
}
free( psz_filename );
free( psz_win_fonts_path );
return psz_tmp; /*
} * This is a hack used by Chrome and WebKit to expose the fallback font used
* by Uniscribe for some given text for use with custom shapers / font engines.
*/
static char *UniscribeFallback( const char *psz_family, uni_char_t codepoint )
{
HDC hdc = NULL;
HDC meta_file_dc = NULL;
HENHMETAFILE meta_file = NULL;
LPTSTR psz_fbuffer = NULL;
char *psz_result = NULL;
hdc = CreateCompatibleDC( NULL );
if( !hdc )
return NULL;
meta_file_dc = CreateEnhMetaFile( hdc, NULL, NULL, NULL );
if( !meta_file_dc )
goto error;
LOGFONT lf;
memset( &lf, 0, sizeof( lf ) );
psz_fbuffer = ToT( psz_family );
if( !psz_fbuffer )
goto error;
_tcsncpy( ( LPTSTR ) &lf.lfFaceName, psz_fbuffer, LF_FACESIZE );
free( psz_fbuffer );
lf.lfCharSet = DEFAULT_CHARSET;
HFONT hFont = CreateFontIndirect( &lf );
if( !hFont )
goto error;
HFONT hOriginalFont = SelectObject( meta_file_dc, hFont );
TCHAR text = codepoint;
SCRIPT_STRING_ANALYSIS script_analysis;
HRESULT hresult = ScriptStringAnalyse( meta_file_dc, &text, 1, 0, -1,
SSA_METAFILE | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK,
0, NULL, NULL, NULL, NULL, NULL, &script_analysis );
if( SUCCEEDED( hresult ) )
{
hresult = ScriptStringOut( script_analysis, 0, 0, 0, NULL, 0, 0, FALSE );
ScriptStringFree( &script_analysis );
} }
else /* Let's take any font we can */
fail: SelectObject( meta_file_dc, hOriginalFont );
DeleteObject( hFont );
meta_file = CloseEnhMetaFile( meta_file_dc );
if( SUCCEEDED( hresult ) )
{ {
char *psz_win_fonts_path = GetWindowsFontPath(); LOGFONT log_font;
char *psz_tmp; log_font.lfFaceName[ 0 ] = 0;
if( asprintf( &psz_tmp, "%s\\%s", psz_win_fonts_path, SYSTEM_DEFAULT_FONT_FILE ) == -1 ) EnumEnhMetaFile( 0, meta_file, MetaFileEnumProc, &log_font, NULL );
return NULL; if( log_font.lfFaceName[ 0 ] )
psz_result = FromT( log_font.lfFaceName );
}
DeleteEnhMetaFile(meta_file);
DeleteDC( hdc );
return psz_result;
error:
if( meta_file_dc ) DeleteEnhMetaFile( CloseEnhMetaFile( meta_file_dc ) );
if( hdc ) DeleteDC( hdc );
return NULL;
}
vlc_family_t *Win32_GetFallbacks( filter_t *p_filter, 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;
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 );
if( p_fallbacks )
p_family = SearchFallbacks( p_filter, p_fallbacks, codepoint );
if( !p_family )
{
psz_uniscribe = UniscribeFallback( psz_lc, codepoint );
if( !psz_uniscribe )
goto done;
const vlc_family_t *p_uniscribe = Win32_GetFamily( p_filter, psz_uniscribe );
if( !p_uniscribe || !p_uniscribe->p_fonts )
goto done;
FT_Face p_face = GetFace( p_filter, p_uniscribe->p_fonts );
if( !p_face || !FT_Get_Char_Index( p_face, codepoint ) )
goto done;
p_family = NewFamily( p_filter, psz_uniscribe, NULL, NULL, NULL );
if( unlikely( !p_family ) )
goto done;
p_family->p_fonts = p_uniscribe->p_fonts;
if( p_fallbacks )
AppendFamily( &p_fallbacks, p_family );
else else
return psz_tmp; vlc_dictionary_insert( &p_sys->fallback_map,
psz_lc, p_family );
} }
done:
free( psz_lc );
free( psz_uniscribe );
return p_family;
} }
#endif /* _WIN32 */ #endif /* _WIN32 */
......
...@@ -127,10 +127,10 @@ void FontConfig_BuildCache( filter_t *p_filter ); ...@@ -127,10 +127,10 @@ void FontConfig_BuildCache( filter_t *p_filter );
#endif #endif
#if defined( _WIN32 ) && !VLC_WINSTORE_APP #if defined( _WIN32 ) && !VLC_WINSTORE_APP
char* Win32_Select( filter_t *p_filter, const char* family, vlc_family_t *Win32_GetFallbacks( filter_t *p_filter, const char *psz_family,
bool b_bold, bool b_italic, uni_char_t codepoint );
int *i_idx, uni_char_t codepoint );
const vlc_family_t *Win32_GetFamily( filter_t *p_filter, const char *psz_family );
#endif /* _WIN32 */ #endif /* _WIN32 */
#ifdef __APPLE__ #ifdef __APPLE__
......
...@@ -58,6 +58,14 @@ ...@@ -58,6 +58,14 @@
#include "text_layout.h" #include "text_layout.h"
#include "freetype.h" #include "freetype.h"
/* Win32 */
#ifdef _WIN32
# undef HAVE_FONTCONFIG
# if !VLC_WINSTORE_APP
# define HAVE_FONT_FALLBACK
# endif
#endif
/* FontConfig */ /* FontConfig */
#ifdef HAVE_FONTCONFIG #ifdef HAVE_FONTCONFIG
# define HAVE_FONT_FALLBACK # define HAVE_FONT_FALLBACK
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment