>From 9be98fc85ee685f93ba61e208ceb7d9cd6662854 Mon Sep 17 00:00:00 2001 From: Byeongsik Jeon Date: Tue, 26 Feb 2013 10:31:20 +0900 Subject: [PATCH] gdi32: Fix the GdiGetCodePage() support ANSI_CHARSET font associated charset --- dlls/gdi32/font.c | 64 +++++++++++++++++++++++++++++++++++++ dlls/gdi32/freetype.c | 50 +++++++++++++++++++++++++++++ dlls/gdi32/tests/font.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 199 insertions(+) diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c index b274b83..3a99d35 100644 --- a/dlls/gdi32/font.c +++ b/dlls/gdi32/font.c @@ -590,11 +590,75 @@ HFONT WINAPI CreateFontW( INT height, INT width, INT esc, return CreateFontIndirectW( &logfont ); } +#define ASSOC_CHARSET_OEM (1) +#define ASSOC_CHARSET_ANSI (2) +#define ASSOC_CHARSET_SYMBOL (4) +static DWORD get_associated_charset_info(void) +{ + static DWORD associated_charset = -1; + + if (associated_charset == -1) + { + static const WCHAR assoc_charset_reg_keyW[] = {'S','y','s','t','e','m','\\', + 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', + 'C','o','n','t','r','o','l','\\','F','o','n','t','A','s','s','o','c','\\', + 'A','s','s','o','c','i','a','t','e','d',' ','C','h','a','r','s','e','t','\0'}; + static const WCHAR ansiW[] = {'A','N','S','I','(','0','0',')','\0'}; + static const WCHAR oemW[] = {'O','E','M','(','F','F',')','\0'}; + static const WCHAR symbolW[] = {'S','Y','M','B','O','L','(','0','2',')','\0'}; + static const WCHAR yesW[] = {'Y','E','S','\0'}; + HKEY hkey; + WCHAR *dataW; + DWORD type, data_len, max_data_len; + + associated_charset = 0; + + if (RegOpenKeyW(HKEY_LOCAL_MACHINE, + assoc_charset_reg_keyW, &hkey) != ERROR_SUCCESS) + return 0; + + if (RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + &max_data_len, NULL, NULL) != ERROR_SUCCESS) + return 0; + + dataW = HeapAlloc(GetProcessHeap(), 0, max_data_len); + + memset(dataW, 0, max_data_len); + data_len = max_data_len; + RegQueryValueExW(hkey, ansiW, NULL, &type, (LPBYTE)dataW, &data_len); + if (type == REG_SZ && !strcmpiW(dataW, yesW)) + associated_charset |= ASSOC_CHARSET_ANSI; + + memset(dataW, 0, max_data_len); + data_len = max_data_len; + RegQueryValueExW(hkey, oemW, NULL, &type, (LPBYTE)dataW, &data_len); + if (type == REG_SZ && !strcmpiW(dataW, yesW)) + associated_charset |= ASSOC_CHARSET_OEM; + + memset(dataW, 0, max_data_len); + data_len = max_data_len; + RegQueryValueExW(hkey, symbolW, NULL, &type, (LPBYTE)dataW, &data_len); + if (type == REG_SZ && !strcmpiW(dataW, yesW)) + associated_charset |= ASSOC_CHARSET_SYMBOL; + + HeapFree(GetProcessHeap(), 0, dataW); + RegCloseKey(hkey); + + TRACE("associated_charset = %d\n", associated_charset); + } + + return associated_charset; +} + static void update_font_code_page( DC *dc ) { CHARSETINFO csi; int charset = GetTextCharsetInfo( dc->hSelf, NULL, 0 ); + if (charset == ANSI_CHARSET && + get_associated_charset_info() & ASSOC_CHARSET_ANSI) + charset = DEFAULT_CHARSET; + /* Hmm, nicely designed api this one! */ if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET) ) dc->font_code_page = csi.ciACP; diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index b977b0d..bfcddc4 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -3505,6 +3505,50 @@ static void set_value_key(HKEY hkey, const char *name, const char *value) RegDeleteValueA(hkey, name); } +static void update_font_association_info(UINT current_ansi_codepage) +{ + static const char *font_assoc_reg_key = "System\\CurrentControlSet\\Control\\FontAssoc"; + static const char *assoc_charset_subkey = "Associated Charset"; + + if (is_dbcs_ansi_cp(current_ansi_codepage)) + { + HKEY hkey; + if (RegCreateKeyA(HKEY_LOCAL_MACHINE, font_assoc_reg_key, &hkey) == ERROR_SUCCESS) + { + HKEY hsubkey; + if (RegCreateKeyA(hkey, assoc_charset_subkey, &hsubkey) == ERROR_SUCCESS) + { + switch (current_ansi_codepage) + { + case 932: + set_value_key(hsubkey, "ANSI(00)", "NO"); + set_value_key(hsubkey, "OEM(FF)", "NO"); + set_value_key(hsubkey, "SYMBOL(02)", "NO"); + break; + case 936: + case 949: + case 950: + set_value_key(hsubkey, "ANSI(00)", "YES"); + set_value_key(hsubkey, "OEM(FF)", "YES"); + set_value_key(hsubkey, "SYMBOL(02)", "NO"); + break; + default: + break; + } + RegCloseKey(hsubkey); + } + + /* TODO: http://www.winehq.org/pipermail/wine-bugs/2011-April/272975.html + 2. Font Associated DefaultFonts + */ + + RegCloseKey(hkey); + } + } + else + RegDeleteTreeA(HKEY_LOCAL_MACHINE, font_assoc_reg_key); +} + static void update_font_info(void) { static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 }; @@ -3538,6 +3582,7 @@ static void update_font_info(void) if (is_dbcs_ansi_cp(ansi_cp)) use_default_fallback = TRUE; + memset(buf, 0, sizeof(buf)); len = sizeof(buf); if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ) { @@ -3615,6 +3660,11 @@ static void update_font_info(void) } if (!done) FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp); + + /* update locale dependent font association info in registry. + update only when codepages changed, not logpixels. */ + if (strcmp(buf, cpbuf) != 0) + update_font_association_info(ansi_cp); } static BOOL init_freetype(void) diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index 943f584..b72a423 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -2083,6 +2083,90 @@ static void test_font_charset(void) skip("Symbol or Wingdings is not installed\n"); } +static void test_GdiGetCodePage(void) +{ + static const struct _matching_data + { + UINT current_codepage; + LPCSTR lfFaceName; + UCHAR lfCharSet; + UINT expected_codepage; + } matching_data[] = { + {1251, "Arial", ANSI_CHARSET, 1252}, + {1251, "Tahoma", ANSI_CHARSET, 1252}, + + {1252, "Arial", ANSI_CHARSET, 1252}, + {1252, "Tahoma", ANSI_CHARSET, 1252}, + + {1253, "Arial", ANSI_CHARSET, 1252}, + {1253, "Tahoma", ANSI_CHARSET, 1252}, + + { 932, "Arial", ANSI_CHARSET, 1252}, /* Japanese Windows returns 1252, not 932 */ + { 932, "Tahoma", ANSI_CHARSET, 1252}, + { 932, "MS UI Gothic", ANSI_CHARSET, 1252}, + + { 936, "Arial", ANSI_CHARSET, 936}, + { 936, "Tahoma", ANSI_CHARSET, 936}, + { 936, "Simsun", ANSI_CHARSET, 936}, + + { 949, "Arial", ANSI_CHARSET, 949}, + { 949, "Tahoma", ANSI_CHARSET, 949}, + { 949, "Gulim", ANSI_CHARSET, 949}, + + { 950, "Arial", ANSI_CHARSET, 950}, + { 950, "Tahoma", ANSI_CHARSET, 950}, + { 950, "PMingLiU", ANSI_CHARSET, 950}, + }; + HDC hdc; + LOGFONT lf; + HFONT hfont; + UINT charset, acp; + DWORD codepage; + int i; + + if (!pGdiGetCodePage) + { + skip("GdiGetCodePage not available on this platform\n"); + return; + } + + acp = GetACP(); + + for (i = 0; i < sizeof(matching_data) / sizeof(struct _matching_data); i++) + { + /* only test data matched current locale codepage */ + if (matching_data[i].current_codepage != acp) + continue; + + if (!is_font_installed(matching_data[i].lfFaceName)) + { + skip("%s is not installed\n", matching_data[i].lfFaceName); + continue; + } + + hdc = GetDC(0); + + memset(&lf, 0, sizeof(lf)); + lf.lfHeight = -16; + lf.lfCharSet = matching_data[i].lfCharSet; + lstrcpyA(lf.lfFaceName, matching_data[i].lfFaceName); + hfont = CreateFontIndirectA(&lf); + ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError()); + + hfont = SelectObject(hdc, hfont); + charset = GetTextCharset(hdc); + codepage = pGdiGetCodePage(hdc); + trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d, expected codepage=%d\n", + acp, lf.lfFaceName, lf.lfCharSet, charset, codepage, matching_data[i].expected_codepage); + ok(codepage == matching_data[i].expected_codepage, + "GdiGetCodePage should have returned %d, got %d\n", matching_data[i].expected_codepage, codepage); + + hfont = SelectObject(hdc, hfont); + DeleteObject(hfont); + ReleaseDC(NULL, hdc); + } +} + static void test_GetFontUnicodeRanges(void) { LOGFONTA lf; @@ -4902,6 +4986,7 @@ START_TEST(font) test_GetOutlineTextMetrics(); test_SetTextJustification(); test_font_charset(); + test_GdiGetCodePage(); test_GetFontUnicodeRanges(); test_nonexistent_font(); test_orientation(); -- 1.8.1.4