Previously, map_font() could return a font that does not directly support the requested codepage but has a child font that does. By enumerating fonts for the specific charset, as well as checking each candidate font's signature, the returned font now directly supports the codepage.
-- v2: mlang: Use EnumFontFamiliesEx() in map_font().
From: Danyil Blyschak dblyschak@codeweavers.com
Previously, map_font() could return a font that does not directly support the requested codepage but has a child font that does. By enumerating fonts for the specific charset, as well as checking each candidate font's signature, the returned font now directly supports the codepage. --- dlls/mlang/mlang.c | 66 +++++++++++++++++++++++++++++++--------- dlls/mlang/tests/mlang.c | 9 ++++++ 2 files changed, 61 insertions(+), 14 deletions(-)
diff --git a/dlls/mlang/mlang.c b/dlls/mlang/mlang.c index e340a5f57c7..9f7d1159e57 100644 --- a/dlls/mlang/mlang.c +++ b/dlls/mlang/mlang.c @@ -1311,20 +1311,61 @@ HRESULT WINAPI Rfc1766ToLcidA(LCID *lcid, LPCSTR rfc1766A) return Rfc1766ToLcidW(lcid, rfc1766W); }
+struct map_font_enum_data +{ + HDC hdc; + LOGFONTW src_lf; + HFONT font; + UINT charset; + DWORD mask; +}; + +static INT CALLBACK map_font_enum_proc(const LOGFONTW *lf, const TEXTMETRICW *ntm, DWORD type, LPARAM lParam) +{ + HFONT new_font, old_font; + FONTSIGNATURE fs; + UINT charset; + struct map_font_enum_data *data = (struct map_font_enum_data *)lParam; + + data->src_lf.lfCharSet = lf->lfCharSet; + wcscpy(data->src_lf.lfFaceName, lf->lfFaceName); + + new_font = CreateFontIndirectW(&data->src_lf); + if (new_font == NULL) return 1; + + old_font = SelectObject(data->hdc, new_font); + charset = GetTextCharsetInfo(data->hdc, &fs, 0); + SelectObject(data->hdc, old_font); + + /* check that the font directly supports the codepage as well (not just through a child font) */ + if (charset == data->charset && fs.fsCsb[0] & data->mask) + { + data->font = new_font; + return 0; + } + DeleteObject(new_font); + return 1; +} + static HRESULT map_font(HDC hdc, DWORD codepages, HFONT src_font, HFONT *dst_font) { struct font_list *font_list_entry; CHARSETINFO charset_info; - HFONT new_font, old_font; LOGFONTW font_attr; DWORD mask, Csb[2]; BOOL found_cached; - UINT charset; BOOL ret; UINT i; + struct map_font_enum_data enum_data;
if (hdc == NULL || src_font == NULL) return E_FAIL;
+ enum_data.hdc = hdc; + enum_data.font = NULL; + + GetObjectW(src_font, sizeof(enum_data.src_lf), &enum_data.src_lf); + enum_data.src_lf.lfWidth = 0; + for (i = 0; i < 32; i++) { mask = (DWORD)(1 << i); @@ -1351,36 +1392,33 @@ static HRESULT map_font(HDC hdc, DWORD codepages, HFONT src_font, HFONT *dst_fon LeaveCriticalSection(&font_cache_critical); if (found_cached) return S_OK;
- GetObjectW(src_font, sizeof(font_attr), &font_attr); font_attr.lfCharSet = (BYTE)charset_info.ciCharset; - font_attr.lfWidth = 0; font_attr.lfFaceName[0] = 0; - new_font = CreateFontIndirectW(&font_attr); - if (new_font == NULL) continue; + font_attr.lfPitchAndFamily = 0;
- old_font = SelectObject(hdc, new_font); - charset = GetTextCharset(hdc); - SelectObject(hdc, old_font); - if (charset == charset_info.ciCharset) + enum_data.charset = charset_info.ciCharset; + enum_data.mask = mask; + + if (!EnumFontFamiliesExW(hdc, &font_attr, map_font_enum_proc, (LPARAM)&enum_data, 0)) { font_list_entry = malloc(sizeof(*font_list_entry)); if (font_list_entry == NULL) return E_OUTOFMEMORY;
font_list_entry->base_font = src_font; - font_list_entry->font = new_font; - font_list_entry->charset = charset; + font_list_entry->font = enum_data.font; + font_list_entry->charset = enum_data.charset;
EnterCriticalSection(&font_cache_critical); list_add_tail(&font_cache, &font_list_entry->list_entry); LeaveCriticalSection(&font_cache_critical);
if (dst_font != NULL) - *dst_font = new_font; + *dst_font = enum_data.font; return S_OK; } } } - + WARN("couldn't create an appropriate mapped font...\n"); return E_FAIL; }
diff --git a/dlls/mlang/tests/mlang.c b/dlls/mlang/tests/mlang.c index d104d4d5184..42847406eb8 100644 --- a/dlls/mlang/tests/mlang.c +++ b/dlls/mlang/tests/mlang.c @@ -2720,6 +2720,8 @@ static void test_MapFont(IMLangFontLink *font_link, IMLangFontLink2 *font_link2) HRESULT ret; HDC hdc; WCHAR ch; + UINT charset; + FONTSIGNATURE fs;
hdc = GetDC(NULL); codepages = FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC | FS_GREEK | FS_TURKISH | @@ -2781,6 +2783,13 @@ static void test_MapFont(IMLangFontLink *font_link, IMLangFontLink2 *font_link2) ret = IMLangFontLink2_MapFont(font_link2, hdc, codepages, 0, &new_font); ok(ret == S_OK && new_font == last_font, "IMLangFontLink2_MapFont: expected S_OK/%p, got %08lx/%p\n", last_font, ret, new_font);
+ /* check that the returned font can directly handle the codepage (instead of relying on a child font) */ + ret = IMLangFontLink2_MapFont(font_link2, hdc, FS_JISJAPAN, 0, &new_font); + old_font = SelectObject(hdc, new_font); + charset = GetTextCharsetInfo(hdc, &fs, 0); + SelectObject(hdc, old_font); + ok(ret == S_OK && charset == SHIFTJIS_CHARSET && !!(fs.fsCsb[0] & FS_JISJAPAN), "IMLangFontLink2_MapFont: expected S_OK/%u/1, got %08lx/%u/0\n", SHIFTJIS_CHARSET, ret, charset); + ret = IMLangFontLink2_ReleaseFont(font_link2, NULL); ok(ret == E_FAIL, "IMLangFontLink2_ReleaseFont: expected E_FAIL, got %08lx\n", ret); ret = IMLangFontLink2_ReleaseFont(font_link2, new_font);
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=148322
Your paranoid android.
=== w1064v1507 (32 bit report) ===
mlang: mlang.c:2791: Test failed: IMLangFontLink2_MapFont: expected S_OK/128/1, got 8a1503e9/0/0 mlang.c:2796: Test failed: IMLangFontLink2_ReleaseFont: expected S_OK, got 80004005 mlang.c:2802: Test failed: MapFont() failed, hr 0x80004005. mlang.c:2805: Test failed: expected !NULL/!NULL, got 00000000/250A0529 mlang.c:2806: Test failed: expected equal, got not equal mlang.c:2809: Test failed: code pages of font is incorrect
=== w1064v1507 (64 bit report) ===
mlang: mlang.c:2791: Test failed: IMLangFontLink2_MapFont: expected S_OK/128/1, got 8a1503e9/0/0 mlang.c:2796: Test failed: IMLangFontLink2_ReleaseFont: expected S_OK, got 80004005 mlang.c:2802: Test failed: MapFont() failed, hr 0x80004005. mlang.c:2805: Test failed: expected !NULL/!NULL, got 0000000000000000/00000000250A0529 mlang.c:2806: Test failed: expected equal, got not equal mlang.c:2809: Test failed: code pages of font is incorrect
=== debian11b (64 bit WoW report) ===
user32: input.c:4305: Test succeeded inside todo block: button_down_hwnd_todo 1: got MSG_TEST_WIN hwnd 0000000001CE00F4, msg WM_LBUTTONDOWN, wparam 0x1, lparam 0x320032
This merge request was approved by Huw Davies.