diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 686f2b54682..521bf054e43 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -1092,6 +1092,86 @@ fail: return NULL; } +struct family_names_data +{ + LANGID primary_langid; + struct opentype_name family_name; + struct opentype_name second_name; + BOOL primary_seen; + BOOL english_seen; +}; + +static BOOL search_family_names_callback( LANGID langid, struct opentype_name *name, void *user ) +{ + struct family_names_data *data = user; + + if (langid == MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT)) + { + data->english_seen = TRUE; + if (data->primary_langid == langid) data->primary_seen = TRUE; + + if (!data->family_name.bytes) data->family_name = *name; + else if (data->primary_langid != langid) data->second_name = *name; + } + else if (data->primary_langid == langid) + { + data->primary_seen = TRUE; + if (!data->second_name.bytes) data->second_name = data->family_name; + data->family_name = *name; + } + else if (!data->second_name.bytes) data->second_name = *name; + + if (data->family_name.bytes && data->second_name.bytes && data->primary_seen && data->english_seen) + return TRUE; + return FALSE; +} + +struct face_name_data +{ + LANGID primary_langid; + struct opentype_name face_name; +}; + +static BOOL search_face_name_callback( LANGID langid, struct opentype_name *name, void *user ) +{ + struct face_name_data *data = user; + + if (langid == data->primary_langid || (langid == MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT) && !data->face_name.bytes)) + data->face_name = *name; + + return langid == data->primary_langid; +} + +static WCHAR *decode_opentype_name( struct opentype_name *name ) +{ + CPTABLEINFO codepage_info; + USHORT *codepage_ptr; + SIZE_T codepage_size; + WCHAR buffer[512]; + DWORD len; + + if (!name->codepage) + { + len = min( ARRAY_SIZE(buffer), name->length / sizeof(WCHAR) ); + while (len--) buffer[len] = GET_BE_WORD( ((WORD *)name->bytes)[len] ); + len = min( ARRAY_SIZE(buffer), name->length / sizeof(WCHAR) ); + } + else + { + NtGetNlsSectionPtr( 11, name->codepage, NULL, (void **)&codepage_ptr, &codepage_size ); + RtlInitCodePageTable( codepage_ptr, &codepage_info ); + RtlCustomCPToUnicodeN( &codepage_info, buffer, sizeof(buffer), &len, name->bytes, name->length ); + len /= sizeof(WCHAR); + NtUnmapViewOfSection( GetCurrentProcess(), codepage_ptr ); + } + + buffer[ARRAY_SIZE(buffer) - 1] = 0; + if (len == ARRAY_SIZE(buffer)) WARN("Truncated font name %s -> %s\n", debugstr_an(name->bytes, name->length), debugstr_w(buffer)); + else buffer[len] = 0; + + return strdupW( buffer ); +} + struct unix_face { FT_Face ft_face; @@ -1110,11 +1190,14 @@ struct unix_face static struct unix_face *unix_face_create( const char *unix_name, void *data_ptr, DWORD data_size, UINT face_index, DWORD flags ) { + static const WCHAR space_w[] = {' ',0}; + const struct ttc_sfnt_v1 *ttc_sfnt_v1; + const struct tt_name_v0 *tt_name_v0; struct unix_face *This; struct stat st; DWORD face_count; - int fd; + int fd, length; TRACE( "unix_name %s, face_index %u, data_ptr %p, data_size %u, flags %#x\n", unix_name, face_index, data_ptr, data_size, flags ); @@ -1140,20 +1223,55 @@ static struct unix_face *unix_face_create( const char *unix_name, void *data_ptr RtlFreeHeap( GetProcessHeap(), 0, This ); This = NULL; } - else if (opentype_get_ttc_sfnt_v1( data_ptr, data_size, face_index, &face_count, &ttc_sfnt_v1 )) + else if (opentype_get_ttc_sfnt_v1( data_ptr, data_size, face_index, &face_count, &ttc_sfnt_v1 ) && + opentype_get_tt_name_v0( data_ptr, data_size, ttc_sfnt_v1, &tt_name_v0 )) { + struct family_names_data family_names; + struct face_name_data style_name; + struct face_name_data full_name; + LANGID primary_langid = system_lcid; + This->scalable = TRUE; This->num_faces = face_count; + + memset( &family_names, 0, sizeof(family_names) ); + family_names.primary_langid = primary_langid; + opentype_enum_family_names( tt_name_v0, search_family_names_callback, &family_names ); + This->family_name = decode_opentype_name( &family_names.family_name ); + This->second_name = decode_opentype_name( &family_names.second_name ); + + memset( &style_name, 0, sizeof(style_name) ); + style_name.primary_langid = primary_langid; + opentype_enum_style_names( tt_name_v0, search_face_name_callback, &style_name ); + This->style_name = decode_opentype_name( &style_name.face_name ); + + memset( &full_name, 0, sizeof(full_name) ); + style_name.primary_langid = primary_langid; + opentype_enum_full_names( tt_name_v0, search_face_name_callback, &full_name ); + This->full_name = decode_opentype_name( &full_name.face_name ); + + TRACE( "parsed font names family_name %s, second_name %s, primary_seen %d, english_seen %d, " + "full_name %s, style_name %s\n", + debugstr_w(This->family_name), debugstr_w(This->second_name), + family_names.primary_seen, family_names.english_seen, + debugstr_w(This->full_name), debugstr_w(This->style_name) ); + + if (!This->full_name && This->family_name && This->style_name) + { + length = lstrlenW( This->family_name ) + lstrlenW( space_w ) + lstrlenW( This->style_name ) + 1; + This->full_name = RtlAllocateHeap( GetProcessHeap(), 0, length * sizeof(WCHAR) ); + lstrcpyW( This->full_name, This->family_name ); + lstrcatW( This->full_name, space_w ); + lstrcatW( This->full_name, This->style_name ); + WARN( "full name not found, using %s instead\n", debugstr_w(This->full_name) ); + } } else { WARN( "unable to parse font, falling back to FreeType\n" ); This->scalable = FT_IS_SCALABLE( This->ft_face ); This->num_faces = This->ft_face->num_faces; - } - if (This) - { This->family_name = ft_face_get_family_name( This->ft_face, system_lcid ); This->second_name = ft_face_get_family_name( This->ft_face, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT) ); @@ -1173,7 +1291,10 @@ static struct unix_face *unix_face_create( const char *unix_name, void *data_ptr This->style_name = ft_face_get_style_name( This->ft_face, system_lcid ); This->full_name = ft_face_get_full_name( This->ft_face, system_lcid ); + } + if (This) + { This->ntm_flags = get_ntm_flags( This->ft_face ); This->font_version = get_font_version( This->ft_face ); if (!This->scalable) get_bitmap_size( This->ft_face, &This->size ); diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h index a529cb0890c..9a988d08d7e 100644 --- a/dlls/gdi32/gdi_private.h +++ b/dlls/gdi32/gdi_private.h @@ -417,9 +417,27 @@ extern void font_init(void) DECLSPEC_HIDDEN; /* opentype.c */ struct ttc_sfnt_v1; +struct tt_name_v0; + +struct opentype_name +{ + DWORD codepage; + DWORD length; + const void *bytes; +}; extern BOOL opentype_get_ttc_sfnt_v1( const void *data, size_t size, DWORD index, DWORD *count, const struct ttc_sfnt_v1 **ttc_sfnt_v1 ) DECLSPEC_HIDDEN; +extern BOOL opentype_get_tt_name_v0( const void *data, size_t size, const struct ttc_sfnt_v1 *ttc_sfnt_v1, + const struct tt_name_v0 **tt_name_v0 ) DECLSPEC_HIDDEN; + +typedef BOOL ( *opentype_enum_names_cb )( LANGID langid, struct opentype_name *name, void *user ); +extern BOOL opentype_enum_family_names( const struct tt_name_v0 *tt_name_v0, + opentype_enum_names_cb callback, void *user ) DECLSPEC_HIDDEN; +extern BOOL opentype_enum_style_names( const struct tt_name_v0 *tt_name_v0, + opentype_enum_names_cb callback, void *user ) DECLSPEC_HIDDEN; +extern BOOL opentype_enum_full_names( const struct tt_name_v0 *tt_name_v0, + opentype_enum_names_cb callback, void *user ) DECLSPEC_HIDDEN; /* gdiobj.c */ extern HGDIOBJ alloc_gdi_handle( void *obj, WORD type, const struct gdi_obj_funcs *funcs ) DECLSPEC_HIDDEN; diff --git a/dlls/gdi32/opentype.c b/dlls/gdi32/opentype.c index 2363439cdc5..4200b08d318 100644 --- a/dlls/gdi32/opentype.c +++ b/dlls/gdi32/opentype.c @@ -26,6 +26,7 @@ #include "windef.h" #include "winbase.h" +#include "winnls.h" #include "wine/debug.h" @@ -40,6 +41,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(font); #define MS_EBSC_TAG MS_MAKE_TAG('E','B','S','C') #define MS_EBDT_TAG MS_MAKE_TAG('E','B','D','T') #define MS_CBDT_TAG MS_MAKE_TAG('C','B','D','T') +#define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e') #ifdef WORDS_BIGENDIAN #define GET_BE_WORD(x) (x) @@ -115,8 +117,125 @@ struct tt_os2_v1 ULONG ulCodePageRange1; ULONG ulCodePageRange2; }; + +struct tt_namerecord +{ + WORD platformID; + WORD encodingID; + WORD languageID; + WORD nameID; + WORD length; + WORD offset; +}; + +struct tt_name_v0 +{ + WORD format; + WORD count; + WORD stringOffset; + struct tt_namerecord nameRecord[1]; +}; #include "poppack.h" +enum OPENTYPE_PLATFORM_ID +{ + OPENTYPE_PLATFORM_UNICODE = 0, + OPENTYPE_PLATFORM_MAC, + OPENTYPE_PLATFORM_ISO, + OPENTYPE_PLATFORM_WIN, + OPENTYPE_PLATFORM_CUSTOM +}; + +enum TT_NAME_WIN_ENCODING_ID +{ + TT_NAME_WIN_ENCODING_SYMBOL = 0, + TT_NAME_WIN_ENCODING_UNICODE_BMP, + TT_NAME_WIN_ENCODING_SJIS, + TT_NAME_WIN_ENCODING_PRC, + TT_NAME_WIN_ENCODING_BIG5, + TT_NAME_WIN_ENCODING_WANSUNG, + TT_NAME_WIN_ENCODING_JOHAB, + TT_NAME_WIN_ENCODING_RESERVED1, + TT_NAME_WIN_ENCODING_RESERVED2, + TT_NAME_WIN_ENCODING_RESERVED3, + TT_NAME_WIN_ENCODING_UNICODE_FULL +}; + +enum TT_NAME_UNICODE_ENCODING_ID +{ + TT_NAME_UNICODE_ENCODING_1_0 = 0, + TT_NAME_UNICODE_ENCODING_1_1, + TT_NAME_UNICODE_ENCODING_ISO_10646, + TT_NAME_UNICODE_ENCODING_2_0_BMP, + TT_NAME_UNICODE_ENCODING_2_0_FULL, + TT_NAME_UNICODE_ENCODING_VAR, + TT_NAME_UNICODE_ENCODING_FULL, +}; + +enum TT_NAME_MAC_ENCODING_ID +{ + TT_NAME_MAC_ENCODING_ROMAN = 0, + TT_NAME_MAC_ENCODING_JAPANESE, + TT_NAME_MAC_ENCODING_TRAD_CHINESE, + TT_NAME_MAC_ENCODING_KOREAN, + TT_NAME_MAC_ENCODING_ARABIC, + TT_NAME_MAC_ENCODING_HEBREW, + TT_NAME_MAC_ENCODING_GREEK, + TT_NAME_MAC_ENCODING_RUSSIAN, + TT_NAME_MAC_ENCODING_RSYMBOL, + TT_NAME_MAC_ENCODING_DEVANAGARI, + TT_NAME_MAC_ENCODING_GURMUKHI, + TT_NAME_MAC_ENCODING_GUJARATI, + TT_NAME_MAC_ENCODING_ORIYA, + TT_NAME_MAC_ENCODING_BENGALI, + TT_NAME_MAC_ENCODING_TAMIL, + TT_NAME_MAC_ENCODING_TELUGU, + TT_NAME_MAC_ENCODING_KANNADA, + TT_NAME_MAC_ENCODING_MALAYALAM, + TT_NAME_MAC_ENCODING_SINHALESE, + TT_NAME_MAC_ENCODING_BURMESE, + TT_NAME_MAC_ENCODING_KHMER, + TT_NAME_MAC_ENCODING_THAI, + TT_NAME_MAC_ENCODING_LAOTIAN, + TT_NAME_MAC_ENCODING_GEORGIAN, + TT_NAME_MAC_ENCODING_ARMENIAN, + TT_NAME_MAC_ENCODING_SIMPL_CHINESE, + TT_NAME_MAC_ENCODING_TIBETAN, + TT_NAME_MAC_ENCODING_MONGOLIAN, + TT_NAME_MAC_ENCODING_GEEZ, + TT_NAME_MAC_ENCODING_SLAVIC, + TT_NAME_MAC_ENCODING_VIETNAMESE, + TT_NAME_MAC_ENCODING_SINDHI, + TT_NAME_MAC_ENCODING_UNINTERPRETED +}; + +enum OPENTYPE_NAME_ID +{ + OPENTYPE_NAME_COPYRIGHT_NOTICE = 0, + OPENTYPE_NAME_FAMILY, + OPENTYPE_NAME_SUBFAMILY, + OPENTYPE_NAME_UNIQUE_IDENTIFIER, + OPENTYPE_NAME_FULLNAME, + OPENTYPE_NAME_VERSION_STRING, + OPENTYPE_NAME_POSTSCRIPT, + OPENTYPE_NAME_TRADEMARK, + OPENTYPE_NAME_MANUFACTURER, + OPENTYPE_NAME_DESIGNER, + OPENTYPE_NAME_DESCRIPTION, + OPENTYPE_NAME_VENDOR_URL, + OPENTYPE_NAME_DESIGNER_URL, + OPENTYPE_NAME_LICENSE_DESCRIPTION, + OPENTYPE_NAME_LICENSE_INFO_URL, + OPENTYPE_NAME_RESERVED_ID15, + OPENTYPE_NAME_TYPOGRAPHIC_FAMILY, + OPENTYPE_NAME_TYPOGRAPHIC_SUBFAMILY, + OPENTYPE_NAME_COMPATIBLE_FULLNAME, + OPENTYPE_NAME_SAMPLE_TEXT, + OPENTYPE_NAME_POSTSCRIPT_CID, + OPENTYPE_NAME_WWS_FAMILY, + OPENTYPE_NAME_WWS_SUBFAMILY +}; + static BOOL opentype_get_table_ptr( const void *data, size_t size, const struct ttc_sfnt_v1 *ttc_sfnt_v1, UINT32 table_tag, const void **table_ptr, UINT32 *table_size ) { @@ -151,6 +270,306 @@ static BOOL opentype_get_tt_os2_v1( const void *data, size_t size, const struct return opentype_get_table_ptr( data, size, ttc_sfnt_v1, MS_OS_2_TAG, (const void **)tt_os2_v1, &table_size ); } +static UINT get_name_record_codepage( enum OPENTYPE_PLATFORM_ID platform, USHORT encoding ) +{ + switch (platform) + { + case OPENTYPE_PLATFORM_UNICODE: + return 0; + case OPENTYPE_PLATFORM_MAC: + switch (encoding) + { + case TT_NAME_MAC_ENCODING_ROMAN: + return 10000; + case TT_NAME_MAC_ENCODING_JAPANESE: + return 10001; + case TT_NAME_MAC_ENCODING_TRAD_CHINESE: + return 10002; + case TT_NAME_MAC_ENCODING_KOREAN: + return 10003; + case TT_NAME_MAC_ENCODING_ARABIC: + return 10004; + case TT_NAME_MAC_ENCODING_HEBREW: + return 10005; + case TT_NAME_MAC_ENCODING_GREEK: + return 10006; + case TT_NAME_MAC_ENCODING_RUSSIAN: + return 10007; + case TT_NAME_MAC_ENCODING_SIMPL_CHINESE: + return 10008; + case TT_NAME_MAC_ENCODING_THAI: + return 10021; + default: + FIXME( "encoding %u not handled, platform %d.\n", encoding, platform ); + break; + } + break; + case OPENTYPE_PLATFORM_WIN: + switch (encoding) + { + case TT_NAME_WIN_ENCODING_SYMBOL: + case TT_NAME_WIN_ENCODING_UNICODE_BMP: + case TT_NAME_WIN_ENCODING_UNICODE_FULL: + return 0; + case TT_NAME_WIN_ENCODING_SJIS: + return 932; + case TT_NAME_WIN_ENCODING_PRC: + return 936; + case TT_NAME_WIN_ENCODING_BIG5: + return 950; + case TT_NAME_WIN_ENCODING_WANSUNG: + return 20949; + case TT_NAME_WIN_ENCODING_JOHAB: + return 1361; + default: + FIXME( "encoding %u not handled, platform %d.\n", encoding, platform ); + break; + } + break; + default: + FIXME( "unknown platform %d\n", platform ); + break; + } + + return 0; +} + +static const LANGID mac_langid_table[] = +{ + MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), + MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), + MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_ITALIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_DUTCH, SUBLANG_DEFAULT), + MAKELANGID(LANG_SWEDISH, SUBLANG_DEFAULT), + MAKELANGID(LANG_SPANISH, SUBLANG_DEFAULT), + MAKELANGID(LANG_DANISH, SUBLANG_DEFAULT), + MAKELANGID(LANG_PORTUGUESE, SUBLANG_DEFAULT), + MAKELANGID(LANG_NORWEGIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT), + MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT), + MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), + MAKELANGID(LANG_FINNISH, SUBLANG_DEFAULT), + MAKELANGID(LANG_GREEK, SUBLANG_DEFAULT), + MAKELANGID(LANG_ICELANDIC, SUBLANG_DEFAULT), + MAKELANGID(LANG_MALTESE, SUBLANG_DEFAULT), + MAKELANGID(LANG_TURKISH, SUBLANG_DEFAULT), + MAKELANGID(LANG_CROATIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_CHINESE_TRADITIONAL, SUBLANG_DEFAULT), + MAKELANGID(LANG_URDU, SUBLANG_DEFAULT), + MAKELANGID(LANG_HINDI, SUBLANG_DEFAULT), + MAKELANGID(LANG_THAI, SUBLANG_DEFAULT), + MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_LITHUANIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), + MAKELANGID(LANG_HUNGARIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_ESTONIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_LATVIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_SAMI, SUBLANG_DEFAULT), + MAKELANGID(LANG_FAEROESE, SUBLANG_DEFAULT), + MAKELANGID(LANG_FARSI, SUBLANG_DEFAULT), + MAKELANGID(LANG_RUSSIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_CHINESE_SIMPLIFIED, SUBLANG_DEFAULT), + MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH_BELGIAN), + MAKELANGID(LANG_IRISH, SUBLANG_DEFAULT), + MAKELANGID(LANG_ALBANIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_ROMANIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_CZECH, SUBLANG_DEFAULT), + MAKELANGID(LANG_SLOVAK, SUBLANG_DEFAULT), + MAKELANGID(LANG_SLOVENIAN, SUBLANG_DEFAULT), + 0, + MAKELANGID(LANG_SERBIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_MACEDONIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_BULGARIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_UKRAINIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_BELARUSIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_UZBEK, SUBLANG_DEFAULT), + MAKELANGID(LANG_KAZAK, SUBLANG_DEFAULT), + MAKELANGID(LANG_AZERI, SUBLANG_AZERI_CYRILLIC), + 0, + MAKELANGID(LANG_ARMENIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_GEORGIAN, SUBLANG_DEFAULT), + 0, + MAKELANGID(LANG_KYRGYZ, SUBLANG_DEFAULT), + MAKELANGID(LANG_TAJIK, SUBLANG_DEFAULT), + MAKELANGID(LANG_TURKMEN, SUBLANG_DEFAULT), + MAKELANGID(LANG_MONGOLIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_MONGOLIAN, SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), + MAKELANGID(LANG_PASHTO, SUBLANG_DEFAULT), + 0, + MAKELANGID(LANG_KASHMIRI, SUBLANG_DEFAULT), + MAKELANGID(LANG_SINDHI, SUBLANG_DEFAULT), + MAKELANGID(LANG_TIBETAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_NEPALI, SUBLANG_DEFAULT), + MAKELANGID(LANG_SANSKRIT, SUBLANG_DEFAULT), + MAKELANGID(LANG_MARATHI, SUBLANG_DEFAULT), + MAKELANGID(LANG_BENGALI, SUBLANG_DEFAULT), + MAKELANGID(LANG_ASSAMESE, SUBLANG_DEFAULT), + MAKELANGID(LANG_GUJARATI, SUBLANG_DEFAULT), + MAKELANGID(LANG_PUNJABI, SUBLANG_DEFAULT), + MAKELANGID(LANG_ORIYA, SUBLANG_DEFAULT), + MAKELANGID(LANG_MALAYALAM, SUBLANG_DEFAULT), + MAKELANGID(LANG_KANNADA, SUBLANG_DEFAULT), + MAKELANGID(LANG_TAMIL, SUBLANG_DEFAULT), + MAKELANGID(LANG_TELUGU, SUBLANG_DEFAULT), + MAKELANGID(LANG_SINHALESE, SUBLANG_DEFAULT), + 0, + MAKELANGID(LANG_KHMER, SUBLANG_DEFAULT), + MAKELANGID(LANG_LAO, SUBLANG_DEFAULT), + MAKELANGID(LANG_VIETNAMESE, SUBLANG_DEFAULT), + MAKELANGID(LANG_INDONESIAN, SUBLANG_DEFAULT), + 0, + MAKELANGID(LANG_MALAY, SUBLANG_DEFAULT), + 0, + MAKELANGID(LANG_AMHARIC, SUBLANG_DEFAULT), + MAKELANGID(LANG_TIGRIGNA, SUBLANG_DEFAULT), + 0, + 0, + MAKELANGID(LANG_SWAHILI, SUBLANG_DEFAULT), + 0, + 0, + 0, + MAKELANGID(LANG_MALAGASY, SUBLANG_DEFAULT), + MAKELANGID(LANG_ESPERANTO, SUBLANG_DEFAULT), + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + MAKELANGID(LANG_WELSH, SUBLANG_DEFAULT), + MAKELANGID(LANG_BASQUE, SUBLANG_DEFAULT), + MAKELANGID(LANG_CATALAN, SUBLANG_DEFAULT), + 0, + MAKELANGID(LANG_QUECHUA, SUBLANG_DEFAULT), + 0, + 0, + MAKELANGID(LANG_TATAR, SUBLANG_DEFAULT), + MAKELANGID(LANG_UIGHUR, SUBLANG_DEFAULT), + 0, + 0, + 0, + MAKELANGID(LANG_GALICIAN, SUBLANG_DEFAULT), + MAKELANGID(LANG_AFRIKAANS, SUBLANG_DEFAULT), + MAKELANGID(LANG_BRETON, SUBLANG_DEFAULT), + MAKELANGID(LANG_INUKTITUT, SUBLANG_DEFAULT), + MAKELANGID(LANG_SCOTTISH_GAELIC, SUBLANG_DEFAULT), + MAKELANGID(LANG_MANX_GAELIC, SUBLANG_DEFAULT), + MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), + 0, + 0, + MAKELANGID(LANG_GREENLANDIC, SUBLANG_DEFAULT), + MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), +}; + +static LANGID get_name_record_langid( enum OPENTYPE_PLATFORM_ID platform, USHORT encoding, USHORT language ) +{ + switch (platform) + { + case OPENTYPE_PLATFORM_WIN: + return language; + case OPENTYPE_PLATFORM_MAC: + if (language < ARRAY_SIZE(mac_langid_table)) return mac_langid_table[language]; + WARN( "invalid mac lang id %d\n", language ); + break; + case OPENTYPE_PLATFORM_UNICODE: + switch (encoding) + { + case TT_NAME_UNICODE_ENCODING_1_0: + case TT_NAME_UNICODE_ENCODING_ISO_10646: + case TT_NAME_UNICODE_ENCODING_2_0_BMP: + if (language < ARRAY_SIZE(mac_langid_table)) return mac_langid_table[language]; + WARN( "invalid unicode lang id %d\n", language ); + break; + default: + break; + } + default: + FIXME( "unknown platform %d\n", platform ); + break; + } + + return MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL); +} + +static BOOL opentype_enum_font_names( const struct tt_name_v0 *header, enum OPENTYPE_PLATFORM_ID platform, + enum OPENTYPE_NAME_ID name, opentype_enum_names_cb callback, void *user ) +{ + const char *name_data; + USHORT i, name_count, encoding, language, length, offset; + USHORT platform_id = GET_BE_WORD( platform ), name_id = GET_BE_WORD( name ); + LANGID langid; + BOOL ret = FALSE; + + switch (GET_BE_WORD( header->format )) + { + case 0: + case 1: + break; + default: + FIXME( "unsupported name format %d\n", GET_BE_WORD( header->format ) ); + return FALSE; + } + + name_data = (const char *)header + GET_BE_WORD( header->stringOffset ); + name_count = GET_BE_WORD( header->count ); + for (i = 0; i < name_count; i++) + { + const struct tt_namerecord *record = &header->nameRecord[i]; + struct opentype_name opentype_name; + + if (record->nameID != name_id) continue; + if (record->platformID != platform_id) continue; + + language = GET_BE_WORD( record->languageID ); + if (language >= 0x8000) + { + FIXME( "handle name format 1\n" ); + continue; + } + + encoding = GET_BE_WORD( record->encodingID ); + offset = GET_BE_WORD( record->offset ); + length = GET_BE_WORD( record->length ); + langid = get_name_record_langid( platform, encoding, language ); + + opentype_name.codepage = get_name_record_codepage( platform, encoding ); + opentype_name.length = length; + opentype_name.bytes = name_data + offset; + + if ((ret = callback( langid, &opentype_name, user ))) break; + } + + return ret; +} + BOOL opentype_get_ttc_sfnt_v1( const void *data, size_t size, DWORD index, DWORD *count, const struct ttc_sfnt_v1 **ttc_sfnt_v1 ) { const struct ttc_header_v1 *ttc_header_v1 = data; @@ -218,3 +637,43 @@ BOOL opentype_get_ttc_sfnt_v1( const void *data, size_t size, DWORD index, DWORD return TRUE; } + +BOOL opentype_get_tt_name_v0( const void *data, size_t size, const struct ttc_sfnt_v1 *ttc_sfnt_v1, + const struct tt_name_v0 **tt_name_v0 ) +{ + UINT32 table_size = sizeof(**tt_name_v0); + return opentype_get_table_ptr( data, size, ttc_sfnt_v1, MS_NAME_TAG, (const void **)tt_name_v0, &table_size ); +} + +BOOL opentype_enum_family_names( const struct tt_name_v0 *header, opentype_enum_names_cb callback, void *user ) +{ + if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_WIN, OPENTYPE_NAME_FAMILY, callback, user )) + return TRUE; + if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_MAC, OPENTYPE_NAME_FAMILY, callback, user )) + return TRUE; + if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_UNICODE, OPENTYPE_NAME_FAMILY, callback, user )) + return TRUE; + return FALSE; +} + +BOOL opentype_enum_style_names( const struct tt_name_v0 *header, opentype_enum_names_cb callback, void *user ) +{ + if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_WIN, OPENTYPE_NAME_SUBFAMILY, callback, user )) + return TRUE; + if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_MAC, OPENTYPE_NAME_SUBFAMILY, callback, user )) + return TRUE; + if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_UNICODE, OPENTYPE_NAME_SUBFAMILY, callback, user )) + return TRUE; + return FALSE; +} + +BOOL opentype_enum_full_names( const struct tt_name_v0 *header, opentype_enum_names_cb callback, void *user ) +{ + if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_WIN, OPENTYPE_NAME_FULLNAME, callback, user )) + return TRUE; + if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_MAC, OPENTYPE_NAME_FULLNAME, callback, user )) + return TRUE; + if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_UNICODE, OPENTYPE_NAME_FULLNAME, callback, user )) + return TRUE; + return FALSE; +}