[PATCH v5 0/2] MR9514: gdi32: Fix font creation with invaild bits.
Black Squad's launcher creates a font like ```c font = CreateFontW(12, 0, 0, 0, 0, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0x80 /* ??? */ | FF_ROMAN, L""); ``` This confuses Wine and causes it to pick a sans serif font instead of a serif one. -- v5: win32u: Mask highest font family bit to zero. https://gitlab.winehq.org/wine/wine/-/merge_requests/9514
From: Bernhard Kölbl <bkoelbl@codeweavers.com> --- dlls/gdi32/tests/font.c | 82 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index c56180b1ce6..c641316a609 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -8007,6 +8007,87 @@ static void test_add_font_path(void) SetCurrentDirectoryW( cwd ); } +static void test_font_family(void) +{ + static const struct + { + LONG font_height; + BYTE charset; + BYTE family; + const WCHAR *expected_font; + BYTE todo; + } td[] = + { + { 6, DEFAULT_CHARSET, FF_SWISS, L"Small Fonts" }, + { 12, DEFAULT_CHARSET, FF_SWISS, L"Small Fonts" }, + { 16, DEFAULT_CHARSET, FF_SWISS, L"MS Sans Serif" }, + { 24, DEFAULT_CHARSET, FF_SWISS, L"MS Sans Serif" }, + { 32, DEFAULT_CHARSET, FF_SWISS, L"Arial" }, + { 96, DEFAULT_CHARSET, FF_SWISS, L"Arial" }, + + { 6, DEFAULT_CHARSET, FF_ROMAN, L"Times New Roman" }, + { 12, DEFAULT_CHARSET, FF_ROMAN, L"Times New Roman" }, + { 16, DEFAULT_CHARSET, FF_ROMAN, L"MS Serif" }, + { 24, DEFAULT_CHARSET, FF_ROMAN, L"Times New Roman" }, + { 32, DEFAULT_CHARSET, FF_ROMAN, L"Times New Roman" }, + { 96, DEFAULT_CHARSET, FF_ROMAN, L"Times New Roman" }, + + /* Test font family with invalid bit */ + { 6, DEFAULT_CHARSET, 0x80 | FF_ROMAN, L"Times New Roman", 1 }, + { 12, DEFAULT_CHARSET, 0x80 | FF_SWISS, L"Small Fonts", 0 }, + { 16, DEFAULT_CHARSET, 0x80 | FF_ROMAN, L"MS Serif" , 1 }, + { 24, DEFAULT_CHARSET, 0x80 | FF_ROMAN, L"Times New Roman", 1 }, + { 32, DEFAULT_CHARSET, 0x80 | FF_SWISS, L"Arial", 0 }, + { 48, DEFAULT_CHARSET, 0x80 | FF_MODERN, L"Courier New", 1 }, + { 96, DEFAULT_CHARSET, 0x80 | FF_SWISS, L"Arial", 0 }, + }; + WCHAR font_name[1024] = { 0 }; + TEXTMETRICW metric; + HFONT hfont, old; + LOGFONTW lf; + HDC hdc; + INT i; + + if (system_lang_id != LANG_ENGLISH) + { + winetest_skip("Skipping font family tests on non English setups\n"); + return; + } + + hdc = GetDC(NULL); + + memset(&lf, 0, sizeof(lf)); + + for (i = 0; i < ARRAY_SIZE(td); ++i) + { + lf.lfPitchAndFamily = td[i].family; + lf.lfHeight = td[i].font_height; + lf.lfCharSet = td[i].charset; + + hfont = CreateFontIndirectW(&lf); + ok(!!hfont, "Failed to create font.\n"); + + old = SelectObject(hdc, hfont); + + memset(&metric, 0, sizeof(metric)); + GetTextMetricsW(hdc, &metric); + + todo_wine_if(td[i].todo) ok((metric.tmPitchAndFamily & 0xf0) == (td[i].family & 0x70), + "got unexpected font family %2x, needed %2x\n", metric.tmPitchAndFamily & 0xf0, td[i].family & 0x70); + + memset(font_name, 0, sizeof(font_name)); + GetTextFaceW(hdc, ARRAY_SIZE(font_name), font_name); + + todo_wine ok(!wcscmp(font_name, td[i].expected_font), + "Got unexpected font %s for height %lu, expected %s\n", debugstr_w(font_name), td[i].font_height, debugstr_w(td[i].expected_font)); + + SelectObject(hdc, old); + DeleteObject(hfont); + } + + ReleaseDC(0, hdc); +} + START_TEST(font) { static const char *test_names[] = @@ -8098,6 +8179,7 @@ START_TEST(font) test_select_object(); test_font_weight(); test_add_font_path(); + test_font_family(); /* These tests should be last test until RemoveFontResource * is properly implemented. -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9514
From: Bernhard Kölbl <bkoelbl@codeweavers.com> --- dlls/gdi32/tests/font.c | 14 +++++++------- dlls/win32u/font.c | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index c641316a609..a5d8d6d3d82 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -8033,13 +8033,13 @@ static void test_font_family(void) { 96, DEFAULT_CHARSET, FF_ROMAN, L"Times New Roman" }, /* Test font family with invalid bit */ - { 6, DEFAULT_CHARSET, 0x80 | FF_ROMAN, L"Times New Roman", 1 }, - { 12, DEFAULT_CHARSET, 0x80 | FF_SWISS, L"Small Fonts", 0 }, - { 16, DEFAULT_CHARSET, 0x80 | FF_ROMAN, L"MS Serif" , 1 }, - { 24, DEFAULT_CHARSET, 0x80 | FF_ROMAN, L"Times New Roman", 1 }, - { 32, DEFAULT_CHARSET, 0x80 | FF_SWISS, L"Arial", 0 }, - { 48, DEFAULT_CHARSET, 0x80 | FF_MODERN, L"Courier New", 1 }, - { 96, DEFAULT_CHARSET, 0x80 | FF_SWISS, L"Arial", 0 }, + { 6, DEFAULT_CHARSET, 0x80 | FF_ROMAN, L"Times New Roman" }, + { 12, DEFAULT_CHARSET, 0x80 | FF_SWISS, L"Small Fonts" }, + { 16, DEFAULT_CHARSET, 0x80 | FF_ROMAN, L"MS Serif" }, + { 24, DEFAULT_CHARSET, 0x80 | FF_ROMAN, L"Times New Roman" }, + { 32, DEFAULT_CHARSET, 0x80 | FF_SWISS, L"Arial" }, + { 48, DEFAULT_CHARSET, 0x80 | FF_MODERN, L"Courier New" }, + { 96, DEFAULT_CHARSET, 0x80 | FF_SWISS, L"Arial" }, }; WCHAR font_name[1024] = { 0 }; TEXTMETRICW metric; diff --git a/dlls/win32u/font.c b/dlls/win32u/font.c index 511f01f371c..e4d7b8ab121 100644 --- a/dlls/win32u/font.c +++ b/dlls/win32u/font.c @@ -1019,9 +1019,9 @@ static BOOL enum_fallbacks( DWORD pitch_and_family, int index, WCHAR buffer[LF_F { const char * const *defaults; - if ((pitch_and_family & FIXED_PITCH) || (pitch_and_family & 0xf0) == FF_MODERN) + if ((pitch_and_family & FIXED_PITCH) || (pitch_and_family & 0x70) == FF_MODERN) defaults = default_fixed_list; - else if ((pitch_and_family & 0xf0) == FF_ROMAN) + else if ((pitch_and_family & 0x70) == FF_ROMAN) defaults = default_serif_list; else defaults = default_sans_list; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9514
On Wed Mar 4 13:20:45 2026 +0000, Bernhard Kölbl wrote:
changed this line in [version 4 of the diff](/wine/wine/-/merge_requests/9514/diffs?diff_id=248410&start_sha=9fc983e1c145e2bd5093842c80df185a283ac390#5a89ffa87018ebd407cb0b64202a300fa91397f9_1022_1022) Right, I've replaced it with 0x70;
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/9514#note_131262
participants (2)
-
Bernhard Kölbl -
Bernhard Kölbl (@besentv)