[vlc-devel] [PATCH 1/1] freetype: handle non-English family and style names in Windows
Salah-Eddin Shaban
salah at videolan.org
Mon Nov 16 22:39:00 CET 2015
Close #6350
---
modules/text_renderer/fonts/win32.c | 186 +++++++++++++++++++++++++++++++++++-
1 file changed, 184 insertions(+), 2 deletions(-)
diff --git a/modules/text_renderer/fonts/win32.c b/modules/text_renderer/fonts/win32.c
index 228eb3f..a8494ad 100644
--- a/modules/text_renderer/fonts/win32.c
+++ b/modules/text_renderer/fonts/win32.c
@@ -30,6 +30,12 @@
* Preamble
*****************************************************************************/
+/** \ingroup freetype_fonts
+ * @{
+ * \file
+ * Win32 font management
+ */
+
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
@@ -37,6 +43,9 @@
#include <vlc_common.h>
#include <vlc_filter.h>
+#include <ft2build.h>
+#include FT_SFNT_NAMES_H
+
/* Win32 GDI */
#ifdef _WIN32
# include <windows.h>
@@ -166,6 +175,166 @@ static char* GetWindowsFontPath()
return FromWide( wdir );
}
+/**
+ * Get an SFNT name entry from an SFNT name table.
+ *
+ * \param p_name_data the start position of the name entry within the table [IN]
+ * \param p_storage_start the start position of the string storage area in the table [IN]
+ * \param p_table_end the position after the last byte of the table [IN]
+ * \param p_sfnt_name pointer to a \ref FT_SfntName to fill [OUT]
+ *
+ * \return \ref VLC_SUCCESS or \ref VLC_EGENERIC
+ */
+static int GetSfntNameEntry( FT_Byte *p_name_data, FT_Byte *p_storage_start,
+ FT_Byte *p_table_end, FT_SfntName *p_sfnt_name )
+{
+ uint16_t i_string_len = U16_AT( p_name_data + 8 );
+ uint16_t i_string_offset = U16_AT( p_name_data + 10 );
+ if( i_string_len == 0
+ || p_storage_start + i_string_offset + i_string_len > p_table_end )
+ return VLC_EGENERIC;
+
+ p_sfnt_name->platform_id = U16_AT( p_name_data + 0 );
+ p_sfnt_name->encoding_id = U16_AT( p_name_data + 2 );
+ p_sfnt_name->language_id = U16_AT( p_name_data + 4 );
+ p_sfnt_name->name_id = U16_AT( p_name_data + 6 );
+ p_sfnt_name->string_len = i_string_len;
+ p_sfnt_name->string = p_storage_start + i_string_offset;
+
+ return VLC_SUCCESS;
+}
+
+/**
+ * Get the SFNT name string matching the specified platform, encoding, name, and language IDs.
+ *
+ *\param p_table the SFNT table [IN]
+ *\param i_size table size in bytes [IN]
+ *\param i_platform_id platform ID as specified in the TrueType spec [IN]
+ *\param i_encoding_id encoding ID as specified in the TrueType spec [IN]
+ *\param i_name_id name ID as specified in the TrueType spec [IN]
+ *\param i_language_id language ID as specified in the TrueType spec [IN]
+ *\param pp_name the requested name.
+ * This is not null terminated. And can have different encodings
+ * based on the specified platform/encoding IDs [OUT]
+ *\param i_name_length the length in bytes of the returned name [OUT]
+ *
+ *\return \ref VLC_SUCCESS or \ref VLC_EGENERIC
+ */
+static int GetSfntNameString( FT_Byte *p_table, FT_UInt i_size, FT_UShort i_platform_id,
+ FT_UShort i_encoding_id, FT_UShort i_name_id, FT_UShort i_language_id,
+ FT_Byte **pp_name, FT_UInt *i_name_length )
+{
+ uint16_t i_name_count = U16_AT( p_table + 2 );
+ uint16_t i_storage_offset = U16_AT( p_table + 4 );
+ FT_Byte *p_storage = p_table + i_storage_offset;
+ FT_Byte *p_names = p_table + 6;
+
+ const int i_entry_size = 12;
+
+ for(int i = 0; i < i_name_count; ++i)
+ {
+ FT_SfntName sfnt_name;
+
+ if( GetSfntNameEntry( p_names + i * i_entry_size, p_storage, p_table + i_size, &sfnt_name ) )
+ return VLC_EGENERIC;
+
+ if( sfnt_name.platform_id == i_platform_id && sfnt_name.encoding_id == i_encoding_id
+ && sfnt_name.name_id == i_name_id && sfnt_name.language_id == i_language_id )
+ {
+ *i_name_length = sfnt_name.string_len;
+ *pp_name = sfnt_name.string;
+
+ return VLC_SUCCESS;
+ }
+ }
+
+ return VLC_EGENERIC;
+}
+
+/**
+ * Get the font's full English name.
+ *
+ * If the font has a family name or style name that matches the
+ * system's locale, EnumFontCallback() will be called with a \ref ENUMLOGFONTEX
+ * that has the localized name.
+ *
+ * We have to get the English name because that's what the Windows registry uses
+ * for name to file mapping.
+ */
+static TCHAR *GetFullEnglishName( const ENUMLOGFONTEX *lpelfe )
+{
+
+ HFONT hFont = NULL;
+ HDC hDc = NULL;
+ FT_Byte *p_table = NULL;
+ TCHAR *psz_result = NULL;
+
+ hFont = CreateFontIndirect( &lpelfe->elfLogFont );
+
+ if( !hFont )
+ return NULL;
+
+ hDc = CreateCompatibleDC( NULL );
+
+ if( !hDc )
+ {
+ DeleteObject( hFont );
+ return NULL;
+ }
+
+ HFONT hOriginalFont = ( HFONT ) SelectObject( hDc, hFont );
+
+ const uint32_t i_name_tag = ntoh32( ( uint32_t ) 'n' << 24
+ | ( uint32_t ) 'a' << 16
+ | ( uint32_t ) 'm' << 8
+ | ( uint32_t ) 'e' << 0 );
+
+ int i_size = GetFontData( hDc, i_name_tag, 0, 0, 0 );
+
+ if( i_size <= 0 )
+ goto done;
+
+ p_table = malloc( i_size );
+
+ if( !p_table )
+ goto done;
+
+ if( GetFontData( hDc, i_name_tag, 0, p_table, i_size ) <= 0 )
+ goto done;
+
+ FT_Byte *p_name = NULL;
+ FT_UInt i_name_length = 0;
+
+ /* FIXME: Try other combinations of platform/encoding/language IDs if necessary */
+ if( GetSfntNameString( p_table, i_size, 3, 1, 4, 0x409, &p_name, &i_name_length) )
+ goto done;
+
+ int i_length_in_wchars = i_name_length / 2;
+ wchar_t *psz_name = malloc( ( i_length_in_wchars + 1 ) * sizeof( *psz_name ) );
+
+ if( !psz_name )
+ goto done;
+
+ for( int i = 0; i < i_length_in_wchars; ++i )
+ psz_name[ i ] = U16_AT( p_name + i * 2 );
+ psz_name[ i_length_in_wchars ] = 0;
+
+#ifdef UNICODE
+ psz_result = psz_name;
+#else
+ psz_result = FromWide( psz_name );
+ free( psz_name );
+#endif
+
+done:
+ free( p_table );
+ SelectObject( hDc, hOriginalFont );
+ DeleteObject( hFont );
+ DeleteDC( hDc );
+
+ return psz_result;
+}
+
static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *lpelfe, const NEWTEXTMETRICEX *metric,
DWORD type, LPARAM lParam)
{
@@ -191,7 +360,20 @@ static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *lpelfe, const NEWTEXTM
int i_index = 0;
if( GetFileFontByName( (LPCTSTR)lpelfe->elfFullName, &psz_filename, &i_index ) )
- return 1;
+ {
+ TCHAR *psz_english_name = GetFullEnglishName( lpelfe );
+
+ if( !psz_english_name )
+ return 1;
+
+ if( GetFileFontByName( psz_english_name, &psz_filename, &i_index ) )
+ {
+ free( psz_english_name );
+ return 1;
+ }
+
+ free( psz_english_name );
+ }
if( strchr( psz_filename, DIR_SEP_CHAR ) )
psz_fontfile = psz_filename;
@@ -269,7 +451,7 @@ static int CALLBACK MetaFileEnumProc( HDC hdc, HANDLETABLE* table,
return 1;
}
-/*
+/**
* 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.
*/
--
1.9.1
More information about the vlc-devel
mailing list