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);