gdi32: Fix the GdiGetCodePage() support ANSI_CHARSET font associated charset

Byeongsik Jeon bsjeon at hanmail.net
Mon Feb 25 19:42:14 CST 2013


Thank you.
Review again before submitting a patch to wine-patches, please.

On 02/26/13 00:08, Akihiro Sagawa wrote:
> On Sun, 24 Feb 2013 09:55:59 +0900, Byeongsik Jeon wrote:
> 
>> @@ -3615,6 +3675,10 @@ 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 */
>> +    if (strcmp(buf, cpbuf))
>> +        update_font_association_info(ansi_cp);
>>  }
>>  
>>  static BOOL init_freetype(void)
> 
> This condition should be rewritten. buf is not initialized when
> RegQueryValueExA is failed in line 3542. And strcmp(buf, cpbuf) has
> already done in line 3544.
> 
I wanted to update in registry when codepages changed, not logpixels. When
logpixels has been changed, MS-Windows does not update the font associated
charset registry. "memset(buf, 0, sizeof(buf))" has been added.

>> diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c
>> index 943f584..9d57806 100644
>> --- a/dlls/gdi32/tests/font.c
>> +++ b/dlls/gdi32/tests/font.c
> 
> Why are there no tests against OEM_CHARSET and SYMBOL_CHARSET?
> 
In the current Wine code, if lfCharset == OEM_CHARSET then GetTextCharset()
return a wrong value. This problem can be found in the test_oemcharset(). At
this point, I wanted to concentrate on the ANSI_CHARSET association problem.
-------------- next part --------------
>From 9be98fc85ee685f93ba61e208ceb7d9cd6662854 Mon Sep 17 00:00:00 2001
From: Byeongsik Jeon <bsjeon at hanmail.net>
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



More information about the wine-devel mailing list