From: Qian Hong Subject: [PATCH] gdi32/tests: Improve font name localization tests by not requiring a strict language match. Message-Id: <53BE1DA1.5070108@codeweavers.com> Date: Thu, 10 Jul 2014 12:59:13 +0800 Hello, - Sync the matching algorithm from gdi32/freetype.c:match_name_table_language() to gdi32/tests/font.c according to the following commit: commit b05b637c9179b7b01f21f5fd80e46cf405c04419 Author: Alexandre Julliard Date: Thu Jun 20 13:36:34 2013 +0200 gdi32: Improve font name localization by not requiring a strict language match. - Fixed http://bugs.winehq.org/show_bug.cgi?id=36867 - Test failures are not related to this patch. See https://testbot.winehq.org/JobDetails.pl?Key=7899 --- dlls/gdi32/tests/font.c | 251 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 218 insertions(+), 33 deletions(-) diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index 245fd56..852c858 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -3357,7 +3357,12 @@ end: return r; } +#define TT_PLATFORM_APPLE_UNICODE 0 +#define TT_PLATFORM_MACINTOSH 1 #define TT_PLATFORM_MICROSOFT 3 +#define TT_APPLE_ID_DEFAULT 0 +#define TT_APPLE_ID_ISO_10646 2 +#define TT_APPLE_ID_UNICODE_2_0 3 #define TT_MS_ID_SYMBOL_CS 0 #define TT_MS_ID_UNICODE_CS 1 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409 @@ -3365,6 +3370,194 @@ end: #define TT_NAME_ID_FONT_SUBFAMILY 2 #define TT_NAME_ID_UNIQUE_ID 3 #define TT_NAME_ID_FULL_NAME 4 +#define TT_MAC_ID_SIMPLIFIED_CHINESE 25 + +typedef struct sfnt_name +{ + USHORT platform_id; + USHORT encoding_id; + USHORT language_id; + USHORT name_id; + USHORT length; + USHORT offset; +} sfnt_name; + +static const LANGID mac_langid_table[] = +{ + MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */ + MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */ + MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */ + MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */ + MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */ + MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */ + MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */ + MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */ + MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */ + MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */ + MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */ + MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */ + MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */ + MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */ + MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */ + MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */ + MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */ + MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */ + MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */ + MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */ + MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */ + MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */ + MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */ + MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */ + MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */ + MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */ + MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */ + MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */ + MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */ + MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */ + MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */ + MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */ + MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */ + MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */ + MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */ + MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */ + MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */ + MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */ + MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */ + MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */ + MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */ + 0, /* TT_MAC_LANGID_YIDDISH */ + MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */ + MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */ + MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */ + MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */ + MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */ + MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */ + MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */ + MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */ + 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */ + MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */ + MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */ + 0, /* TT_MAC_LANGID_MOLDAVIAN */ + MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */ + MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */ + MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */ + MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */ + MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */ + MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */ + 0, /* TT_MAC_LANGID_KURDISH */ + MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */ + MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */ + MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */ + MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */ + MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */ + MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */ + MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */ + MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */ + MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */ + MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */ + MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */ + MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */ + MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */ + MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */ + MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */ + MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */ + 0, /* TT_MAC_LANGID_BURMESE */ + MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */ + MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */ + MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */ + MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */ + 0, /* TT_MAC_LANGID_TAGALOG */ + MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */ + 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */ + MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */ + MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */ + 0, /* TT_MAC_LANGID_GALLA */ + 0, /* TT_MAC_LANGID_SOMALI */ + MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */ + 0, /* TT_MAC_LANGID_RUANDA */ + 0, /* TT_MAC_LANGID_RUNDI */ + 0, /* TT_MAC_LANGID_CHEWA */ + MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */ + MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */ + MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */ + MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */ + MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */ + 0, /* TT_MAC_LANGID_LATIN */ + MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */ + 0, /* TT_MAC_LANGID_GUARANI */ + 0, /* TT_MAC_LANGID_AYMARA */ + MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */ + MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */ + 0, /* TT_MAC_LANGID_DZONGKHA */ + 0, /* TT_MAC_LANGID_JAVANESE */ + 0, /* TT_MAC_LANGID_SUNDANESE */ + MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */ + MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */ + MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */ + MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */ + MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */ + MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */ + MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */ + 0, /* TT_MAC_LANGID_TONGAN */ + 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */ + MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */ + MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */ +}; + +static inline WORD get_mac_code_page( const sfnt_name *name ) +{ + if (GET_BE_WORD(name->encoding_id) == TT_MAC_ID_SIMPLIFIED_CHINESE) return 10008; /* special case */ + return 10000 + GET_BE_WORD(name->encoding_id); +} + +static int match_name_table_language( const sfnt_name *name, LANGID lang ) +{ + LANGID name_lang; + int res = 0; + + switch (GET_BE_WORD(name->platform_id)) + { + case TT_PLATFORM_MICROSOFT: + res += 5; /* prefer the Microsoft name */ + switch (GET_BE_WORD(name->encoding_id)) + { + case TT_MS_ID_UNICODE_CS: + case TT_MS_ID_SYMBOL_CS: + name_lang = GET_BE_WORD(name->language_id); + break; + default: + return 0; + } + break; + case TT_PLATFORM_MACINTOSH: + if (!IsValidCodePage( get_mac_code_page( name ))) return 0; + if (GET_BE_WORD(name->language_id) >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0; + name_lang = mac_langid_table[GET_BE_WORD(name->language_id)]; + break; + case TT_PLATFORM_APPLE_UNICODE: + res += 2; /* prefer Unicode encodings */ + switch (GET_BE_WORD(name->encoding_id)) + { + case TT_APPLE_ID_DEFAULT: + case TT_APPLE_ID_ISO_10646: + case TT_APPLE_ID_UNICODE_2_0: + if (GET_BE_WORD(name->language_id) >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0; + name_lang = mac_langid_table[GET_BE_WORD(name->language_id)]; + break; + default: + return 0; + } + break; + default: + return 0; + } + if (name_lang == lang) res += 30; + else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20; + else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10; + return res; +} static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, WCHAR *out_buf, SIZE_T out_size, LCID language_id) { @@ -3374,21 +3567,14 @@ static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, WCHAR *out_buf, SIZE_ USHORT number_of_record; USHORT storage_offset; } *header; - struct sfnt_name - { - USHORT platform_id; - USHORT encoding_id; - USHORT language_id; - USHORT name_id; - USHORT length; - USHORT offset; - } *entry; + sfnt_name *entry; BOOL r = FALSE; LONG size, offset, length; LONG c, ret; WCHAR *name; BYTE *data; USHORT i; + int res, best_lang = 0, best_index = -1; size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0); ok(size != GDI_ERROR, "no name table found\n"); @@ -3421,35 +3607,34 @@ static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, WCHAR *out_buf, SIZE_ entry = (void *)&header[1]; for (i = 0; i < header->number_of_record; i++) { - if (GET_BE_WORD(entry[i].platform_id) != TT_PLATFORM_MICROSOFT || - (GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_UNICODE_CS && GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_SYMBOL_CS) || - GET_BE_WORD(entry[i].language_id) != language_id || - GET_BE_WORD(entry[i].name_id) != name_id) + if (GET_BE_WORD(entry[i].name_id) != name_id) continue; + res = match_name_table_language( &entry[i], language_id); + if (res > best_lang) { - continue; + best_lang = res; + best_index = i; } + } - offset = header->storage_offset + GET_BE_WORD(entry[i].offset); - length = GET_BE_WORD(entry[i].length); - if (offset + length > size) - { - trace("entry %d is out of range\n", i); - break; - } - if (length >= out_size) - { - trace("buffer too small for entry %d\n", i); - break; - } + offset = header->storage_offset + GET_BE_WORD(entry[best_index].offset); + length = GET_BE_WORD(entry[best_index].length); + if (offset + length > size) + { + trace("entry %d is out of range\n", best_index); + goto out; + } + if (length >= out_size) + { + trace("buffer too small for entry %d\n", best_index); + goto out; + } - name = (WCHAR *)(data + offset); - for (c = 0; c < length / 2; c++) - out_buf[c] = GET_BE_WORD(name[c]); - out_buf[c] = 0; + name = (WCHAR *)(data + offset); + for (c = 0; c < length / 2; c++) + out_buf[c] = GET_BE_WORD(name[c]); + out_buf[c] = 0; - r = TRUE; - break; - } + r = TRUE; out: HeapFree(GetProcessHeap(), 0, data);