Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v3: * Fix the test, using GetSystemDefaultLangID() instead of GetUserDefaultLangID(), as the system language is what dictates font lookup logic.
* Remove the dreadful unix path patches. We won't be using FreeType so much in the end so we can probably affort a path conversion there.
dlls/gdi32/tests/Makefile.in | 3 + dlls/gdi32/tests/font.c | 265 +++++++++++++++++++++++++++ dlls/gdi32/tests/resource.rc | 9 + dlls/gdi32/tests/wine_langnames.sfd | 138 ++++++++++++++ dlls/gdi32/tests/wine_langnames.ttf | Bin 0 -> 2792 bytes dlls/gdi32/tests/wine_langnames2.sfd | 80 ++++++++ dlls/gdi32/tests/wine_langnames2.ttf | Bin 0 -> 2016 bytes dlls/gdi32/tests/wine_langnames3.sfd | 78 ++++++++ dlls/gdi32/tests/wine_langnames3.ttf | Bin 0 -> 2048 bytes 9 files changed, 573 insertions(+) create mode 100644 dlls/gdi32/tests/wine_langnames.sfd create mode 100644 dlls/gdi32/tests/wine_langnames.ttf create mode 100644 dlls/gdi32/tests/wine_langnames2.sfd create mode 100644 dlls/gdi32/tests/wine_langnames2.ttf create mode 100644 dlls/gdi32/tests/wine_langnames3.sfd create mode 100644 dlls/gdi32/tests/wine_langnames3.ttf
diff --git a/dlls/gdi32/tests/Makefile.in b/dlls/gdi32/tests/Makefile.in index 8b722cfe5d2..975750886e4 100644 --- a/dlls/gdi32/tests/Makefile.in +++ b/dlls/gdi32/tests/Makefile.in @@ -24,6 +24,9 @@ FONT_SRCS = \ wine_test.sfd \ wine_ttfnames.sfd \ wine_ttfnames_bold.sfd \ + wine_langnames.sfd \ + wine_langnames2.sfd \ + wine_langnames3.sfd \ wine_vdmx.sfd
RC_SRCS = resource.rc diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index f5c8d4dac3b..33dcc3b31ac 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -2757,6 +2757,12 @@ struct enum_fullname_data ENUMLOGFONTA *elf; };
+struct enum_fullname_data_w +{ + int total, size; + ENUMLOGFONTW *elf; +}; + struct enum_font_dataW { int total, size; @@ -3110,6 +3116,23 @@ static INT CALLBACK enum_fullname_data_proc(const LOGFONTA *lf, const TEXTMETRIC return 1; }
+static INT CALLBACK enum_fullname_data_proc_w( const LOGFONTW *lf, const TEXTMETRICW *ntm, DWORD type, LPARAM lParam ) +{ + struct enum_fullname_data_w *efnd = (struct enum_fullname_data_w *)lParam; + + if (type != TRUETYPE_FONTTYPE) return 1; + + if (efnd->total >= efnd->size) + { + efnd->size = max( (efnd->total + 1) * 2, 256 ); + efnd->elf = heap_realloc( efnd->elf, efnd->size * sizeof(*efnd->elf) ); + if (!efnd->elf) return 0; + } + efnd->elf[efnd->total++] = *(ENUMLOGFONTW *)lf; + + return 1; +} + static void test_EnumFontFamiliesEx_default_charset(void) { struct enum_font_data efd; @@ -7007,6 +7030,247 @@ static void test_ttf_names(void) ReleaseDC(NULL, dc); }
+static void test_lang_names(void) +{ + static const WCHAR name_cond_ja_w[] = {0x30d5,0x30a9,0x30f3,0x30c8,0x540d,' ','C','o','n','d',' ','(','j','a',')',0}; + static const WCHAR name_cond_ja_reg_w[] = {0x30d5,0x30a9,0x30f3,0x30c8,0x540d,' ','C','o','n','d',' ','(','j','a',')',' ','R','e','g',0}; + static const WCHAR name_cond_ja_reg_ja_w[] = {0x30d5,0x30a9,0x30f3,0x30c8,0x540d,' ','C','o','n','d',' ','(','j','a',')',' ','R','e','g',' ','(','j','a',')',0}; + static const WCHAR name_wws_ja_w[] = {0x30d5,0x30a9,0x30f3,0x30c8,0x540d,' ','W','W','S',' ','(','j','a',')',0}; + + struct enum_fullname_data efnd; + struct enum_fullname_data_w efnd_w; + char ttf_name[MAX_PATH], ttf_name2[MAX_PATH], ttf_name3[MAX_PATH]; + LOGFONTA font = {0}; + LOGFONTW font_w = {0}; + int ret, i; + HDC dc; + const WCHAR *primary_family, *primary_fullname; + + if (PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH && PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_JAPANESE) + { + skip( "Primary language is neither English nor Japanese, skipping test\n" ); + return; + } + + if (!write_ttf_file( "wine_langnames.ttf", ttf_name )) + { + skip( "Failed to create ttf file for testing\n" ); + return; + } + + if (!write_ttf_file( "wine_langnames2.ttf", ttf_name2 )) + { + skip( "Failed to create ttf file for testing\n" ); + DeleteFileA( ttf_name ); + return; + } + + if (!write_ttf_file( "wine_langnames3.ttf", ttf_name3 )) + { + skip( "Failed to create ttf file for testing\n" ); + DeleteFileA( ttf_name2 ); + DeleteFileA( ttf_name ); + return; + } + + ret = AddFontResourceExA( ttf_name, FR_PRIVATE, 0 ); + ok( ret, "AddFontResourceEx() failed\n" ); + + dc = GetDC( NULL ); + + if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH) + { + primary_family = L"Wine Lang Cond (en)"; + primary_fullname = L"Wine Lang Cond Reg (en)"; + } + else + { + primary_family = name_cond_ja_w; + primary_fullname = name_cond_ja_reg_w; + } + + for (i = 0; i < 3; ++i) + { + /* check that lookup by preferred or WWS family / full names or postscript FontName doesn't work */ + + strcpy( font.lfFaceName, "Wine Lang (en)" ); + memset( &efnd, 0, sizeof(efnd) ); + EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 ); + ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total ); + + strcpy( font.lfFaceName, "Wine Lang Condensed Bold (ko)" ); + memset( &efnd, 0, sizeof(efnd) ); + EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 ); + ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total ); + + wcscpy( font_w.lfFaceName, name_wws_ja_w ); + memset( &efnd_w, 0, sizeof(efnd_w) ); + EnumFontFamiliesExW( dc, &font_w, enum_fullname_data_proc_w, (LPARAM)&efnd_w, 0 ); + ok( efnd_w.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd_w.total ); + + strcpy( font.lfFaceName, "Reg WWS (zh-tw)" ); + memset( &efnd, 0, sizeof(efnd) ); + EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 ); + ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total ); + + strcpy( font.lfFaceName, "Wine Lang (en) Reg WWS (en)" ); + memset( &efnd, 0, sizeof(efnd) ); + EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 ); + ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total ); + + strcpy( font.lfFaceName, "WineLangNamesRegular" ); + memset( &efnd, 0, sizeof(efnd) ); + EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 ); + ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total ); + + /* then, the primary ttf family name always works */ + + wcscpy( font_w.lfFaceName, primary_family ); + memset( &efnd_w, 0, sizeof(efnd_w) ); + EnumFontFamiliesExW( dc, &font_w, enum_fullname_data_proc_w, (LPARAM)&efnd_w, 0 ); + ok( efnd_w.total == min( 2, i + 1 ), "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd_w.total ); + + if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH) + { + wcscpy( font_w.lfFaceName, name_cond_ja_w ); + memset( &efnd_w, 0, sizeof(efnd_w) ); + EnumFontFamiliesExW( dc, &font_w, enum_fullname_data_proc_w, (LPARAM)&efnd_w, 0 ); + ok( efnd_w.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd_w.total ); + } + + /* if there is no primary ttf family name, the english ttf name, or postscript FamilyName are used instead */ + + strcpy( font.lfFaceName, "Wine_Lang_Names" ); + memset( &efnd, 0, sizeof(efnd) ); + EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 ); + if (i == 2) + ok( efnd.total == 1, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total ); + else + ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total ); + + /* same goes for ttf full names */ + + wcscpy( font_w.lfFaceName, primary_fullname ); + memset( &efnd_w, 0, sizeof(efnd_w) ); + EnumFontFamiliesExW( dc, &font_w, enum_fullname_data_proc_w, (LPARAM)&efnd_w, 0 ); + ok( efnd_w.total == 1, "%d: EnumFontFamiliesExW unexpected count %u.\n", i, efnd_w.total ); + + if (efnd_w.total >= 1) + { + ok( !wcscmp( (WCHAR *)efnd_w.elf[0].elfLogFont.lfFaceName, primary_family ), + "%d: (%d) unexpected lfFaceName %s\n", i, efnd_w.total, debugstr_w((WCHAR *)efnd_w.elf[0].elfLogFont.lfFaceName) ); + ok( !wcscmp( (WCHAR *)efnd_w.elf[0].elfFullName, primary_fullname ), + "%d: (%d) unexpected elfFullName %s\n", i, efnd_w.total, debugstr_w((WCHAR *)efnd_w.elf[0].elfFullName) ); + ok( !wcscmp( (WCHAR *)efnd_w.elf[0].elfStyle, PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH ? L"Reg (en)" : L"Reg (ja)" ), + "%d: (%d) unexpected elfStyle %s\n", i, efnd_w.total, debugstr_w((WCHAR *)efnd_w.elf[0].elfStyle) ); + } + + if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH) + { + wcscpy( font_w.lfFaceName, name_cond_ja_reg_w ); + memset( &efnd_w, 0, sizeof(efnd_w) ); + EnumFontFamiliesExW( dc, &font_w, enum_fullname_data_proc_w, (LPARAM)&efnd_w, 0 ); + ok( efnd_w.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd_w.total ); + } + + wcscpy( font_w.lfFaceName, L"Wine_Lang_Names_Regular" ); + memset( &efnd_w, 0, sizeof(efnd_w) ); + EnumFontFamiliesExW( dc, &font_w, enum_fullname_data_proc_w, (LPARAM)&efnd_w, 0 ); + ok( efnd_w.total == i, "%d: EnumFontFamiliesExW unexpected count %u.\n", i, efnd_w.total ); + + while (efnd_w.total--) + { + ok( !wcscmp( (WCHAR *)efnd_w.elf[efnd_w.total].elfLogFont.lfFaceName, efnd_w.total == 1 ? L"Wine_Lang_Names" : primary_family ), + "%d: (%d) unexpected lfFaceName %s\n", i, efnd_w.total, debugstr_w((WCHAR *)efnd_w.elf[efnd_w.total].elfLogFont.lfFaceName) ); + ok( !wcscmp( (WCHAR *)efnd_w.elf[efnd_w.total].elfFullName, L"Wine_Lang_Names_Regular" ), + "%d: (%d) unexpected elfFullName %s\n", i, efnd_w.total, debugstr_w((WCHAR *)efnd_w.elf[efnd_w.total].elfFullName) ); + if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH) + ok( !wcscmp( (WCHAR *)efnd_w.elf[efnd_w.total].elfStyle, efnd_w.total == 1 ? L"Regular" : L"Reg (en)" ), + "%d: (%d) unexpected elfStyle %s\n", i, efnd_w.total, debugstr_w((WCHAR *)efnd_w.elf[efnd_w.total].elfStyle) ); + else + ok( !wcscmp( (WCHAR *)efnd_w.elf[0].elfStyle, L"Reg (ja)" ), + "%d: (%d) unexpected elfStyle %s\n", i, efnd_w.total, debugstr_w((WCHAR *)efnd_w.elf[0].elfStyle) ); + } + + if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH) + { + wcscpy( font_w.lfFaceName, name_cond_ja_reg_ja_w ); + memset( &efnd_w, 0, sizeof(efnd_w) ); + EnumFontFamiliesExW( dc, &font_w, enum_fullname_data_proc_w, (LPARAM)&efnd_w, 0 ); + ok( efnd_w.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd_w.total ); + } + + /* another language can also be used for lookup, if the primary langid isn't english, then + english seems to have priority, otherwise or if english is already the primary langid, + the family name with the smallest langid is used as secondary lookup language. */ + + strcpy( font.lfFaceName, "Wine Lang Cond (zh-tw)" ); + memset( &efnd, 0, sizeof(efnd) ); + EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 ); + if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH) + todo_wine ok( efnd.total == min( 2, i + 1 ), "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total ); + else /* (zh-tw) doesn't match here probably because there's an (en) name too */ + ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total ); + + strcpy( font.lfFaceName, "Wine Lang Cond (en)" ); + memset( &efnd, 0, sizeof(efnd) ); + EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 ); + /* either because it's the primary language, or because it's a secondary */ + ok( efnd.total == min( 2, i + 1 ), "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total ); + + strcpy( font.lfFaceName, "Wine Lang Cond (fr)" ); + memset( &efnd, 0, sizeof(efnd) ); + EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 ); + /* as wine_langnames3.sfd does not specify (en) name, (fr) is preferred */ + if (i == 2) todo_wine ok( efnd.total == 1, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total ); + else ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total ); + + strcpy( font.lfFaceName, "Wine Lang Cond (ko)" ); + memset( &efnd, 0, sizeof(efnd) ); + EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 ); + ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total ); + + /* that doesn't apply to full names */ + + strcpy( font.lfFaceName, "Wine Lang Cond Reg (zh-tw)" ); + memset( &efnd, 0, sizeof(efnd) ); + EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 ); + ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total ); + + strcpy( font.lfFaceName, "Wine Lang Cond Reg (fr)" ); + memset( &efnd, 0, sizeof(efnd) ); + EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 ); + ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total ); + + if (i == 0) + { + ret = AddFontResourceExA( ttf_name2, FR_PRIVATE, 0 ); + ok( ret, "AddFontResourceEx() failed\n" ); + } + else if (i == 1) + { + ret = AddFontResourceExA( ttf_name3, FR_PRIVATE, 0 ); + ok( ret, "AddFontResourceEx() failed\n" ); + } + } + + ret = RemoveFontResourceExA( ttf_name3, FR_PRIVATE, 0 ); + ok( ret, "RemoveFontResourceEx() failed\n" ); + + DeleteFileA( ttf_name3 ); + + ret = RemoveFontResourceExA( ttf_name2, FR_PRIVATE, 0 ); + ok( ret, "RemoveFontResourceEx() failed\n" ); + + DeleteFileA( ttf_name2 ); + + ret = RemoveFontResourceExA( ttf_name, FR_PRIVATE, 0 ); + ok( ret, "RemoveFontResourceEx() failed\n" ); + + DeleteFileA( ttf_name ); + ReleaseDC( NULL, dc ); +} + typedef struct { USHORT majorVersion; @@ -7419,6 +7683,7 @@ START_TEST(font) test_GetCharWidthI(); test_long_names(); test_ttf_names(); + test_lang_names(); test_char_width();
/* These tests should be last test until RemoveFontResource diff --git a/dlls/gdi32/tests/resource.rc b/dlls/gdi32/tests/resource.rc index b5a6107a987..6cbe789880b 100644 --- a/dlls/gdi32/tests/resource.rc +++ b/dlls/gdi32/tests/resource.rc @@ -37,3 +37,12 @@ wine_ttfnames.ttf RCDATA wine_ttfnames.ttf
/* @makedep: wine_ttfnames_bold.ttf */ wine_ttfnames_bold.ttf RCDATA wine_ttfnames_bold.ttf + +/* @makedep: wine_langnames.ttf */ +wine_langnames.ttf RCDATA wine_langnames.ttf + +/* @makedep: wine_langnames2.ttf */ +wine_langnames2.ttf RCDATA wine_langnames2.ttf + +/* @makedep: wine_langnames3.ttf */ +wine_langnames3.ttf RCDATA wine_langnames3.ttf diff --git a/dlls/gdi32/tests/wine_langnames.sfd b/dlls/gdi32/tests/wine_langnames.sfd new file mode 100644 index 00000000000..4ce1e70baca --- /dev/null +++ b/dlls/gdi32/tests/wine_langnames.sfd @@ -0,0 +1,138 @@ +SplineFontDB: 3.2 +FontName: WineLangNamesRegular +FullName: Wine_Lang_Names_Regular +FamilyName: Wine_Lang_Names +Weight: Regular +Copyright: Copyright (c) 2020, Remi Bernon for CodeWeavers +UComments: "2017-11-17: Created with FontForge (http://fontforge.org)" +Version: 001.000 +ItalicAngle: 0 +UnderlinePosition: -102 +UnderlineWidth: 51 +Ascent: 819 +Descent: 205 +InvalidEm: 0 +LayerCount: 2 +Layer: 0 0 "Back" 1 +Layer: 1 0 "Fore" 0 +XUID: [1021 48 28337276 3092883] +OS2Version: 0 +OS2_WeightWidthSlopeOnly: 0 +OS2_UseTypoMetrics: 1 +CreationTime: 1510948643 +ModificationTime: 1599738445 +OS2TypoAscent: 0 +OS2TypoAOffset: 1 +OS2TypoDescent: 0 +OS2TypoDOffset: 1 +OS2TypoLinegap: 0 +OS2WinAscent: 0 +OS2WinAOffset: 1 +OS2WinDescent: 0 +OS2WinDOffset: 1 +HheadAscent: 0 +HheadAOffset: 1 +HheadDescent: 0 +HheadDOffset: 1 +OS2Vendor: 'PfEd' +MarkAttachClasses: 1 +DEI: 91125 +LangName: 1033 \ + "" \ + "Wine Lang Cond (en)" \ + "Reg (en)" \ + "" \ + "Wine Lang Cond Reg (en)" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "Wine Lang (en)" \ + "Wine Lang Condensed Reg (en)" \ + "" \ + "" \ + "" \ + "Wine Lang WWS (en)" \ + "Reg WWS (en)" +LangName: 1041 \ + "" \ + "+MNUwqTDzMMhUDQAA Cond (ja)" \ + "Reg (ja)" \ + "" \ + "+MNUwqTDzMMhUDQAA Cond (ja) Reg" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "+MNUwqTDzMMhUDQAA (ja)" \ + "+MNUwqTDzMMhUDQAA Condensed Reg (ja)" \ + "" \ + "" \ + "" \ + "+MNUwqTDzMMhUDQAA WWS (ja)" \ + "Reg WWS (ja)" +LangName: 1028 \ + "" \ + "Wine Lang Cond (zh-tw)" \ + "Reg (zh-tw)" \ + "" \ + "Wine Lang Cond Reg (zh-tw)" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "Wine Lang (zh-tw)" \ + "Wine Lang Condensed Reg (zh-tw)" \ + "" \ + "" \ + "" \ + "Wine Lang WWS (zh-tw)" \ + "Reg WWS (zh-tw)" +Encoding: ISO8859-1 +UnicodeInterp: none +NameList: AGL For New Fonts +DisplaySize: -48 +AntiAlias: 1 +FitToEm: 0 +WinInfo: 64 16 4 +BeginPrivate: 0 +EndPrivate +BeginChars: 256 1 + +StartChar: at +Encoding: 64 64 0 +Width: 1024 +VWidth: 0 +Flags: HW +LayerCount: 2 +Fore +SplineSet +259 332 m 29 + 468 664 l 29 + 514 332 l 29 + 259 332 l 29 +EndSplineSet +EndChar +EndChars +EndSplineFont diff --git a/dlls/gdi32/tests/wine_langnames.ttf b/dlls/gdi32/tests/wine_langnames.ttf new file mode 100644 index 0000000000000000000000000000000000000000..674fd1bc7e42c5051eaa3870bd097e5579e981d4 GIT binary patch literal 2792 zcmdT`OKcle6g_Wd>@*>?c1cnsqB2cGNveD%c2%{NK_Q{0i_oGZiWgKkCYjhN@z}E6 zqyZ$5*swsN>_D)C1(Xd56=H{=LaIbqAOu1bD#50U5?COz;FECf_}R|KG;5yq=AC=r z{om`+Kmpi`7hz&D9v^@FmG_q%plOBN_QxJQ9Y-r#NPi&oxv~DpL?E>Qs0``Jscb5b zeZkwLzvCX7nlIVtFkS}CcHUd*R58D?LCa`*m-L?W+~UmVOUtxx_K?nJ+|=~`wY3Ap zzi=PVkP&FK0<_ghx-*k4U22AUfb@0Jp}E{t3QuF4`ZnpNZ0b@TXK<4DXGq&#D(l`K zjs48~w}9Y}`CPHIaTCWW`aJKCLUQFUJ@fVH<i6M+xXU5~`1aUuZ_9b(h0nf32VfY+ z6_R^k2$zdGKIeQ{-Y|Si<-79J@;O#jM>Lhs8$_QkVo~HWn49s2A=Q1ge5%`ssz!1V z;8QP&v$~#`IX%t(3}VoXZbWh3kHn9uDq=%1GDgm#`&+T*Qg?s1>u6)7#Bw`@Y@QZ> zLJzV>{&VA+mV^q{94N^}_U5%E!p#>oEbjm3%b#V=jr>k97ei{SBJ6;P2J|f{^v9MP zEUZSBf`K1m%cenyB~#b|VJ|lX)!(sYmT)x^4Ic_W7!4opP@!K}R*WnEOmrACG^b28 z!ijrbYOL-f`Bk49Q6uYDrFfm{qe@TEk4cRc?!m_z8=SeD8k?M@a~fMXpgz<%fRI|% zIEWUbOXCps8c%8*M!WHj#;w?I+|sxW&1Q>Cjtnq*%)c}?&}MaOY~h&oh{hpwSPL45 z@v!x##;rJN-O#uV2Lla0mYIKwTkJQ|{t;Z(*gyy?8k?BGEsZVosh2bkz*b*q97LB| z*Eqyn9@03B6UGINThVEJs&O0cHU9K*n0^nMhcu>Nvz$wq|BoZ)nC6GjVm_yF7>@ax z#;s^KuW3x1=1&+#4tXr1fLWxGL5csiE=-}DX9SMFdx%HjB1;(?Lqr95)bmKq@GS5Y zJJY;LaHlZu%M^j(Tz;`Io6eN%uBmQ2;zXPtd(_R&+Cy%^%X#)pu3!)6rrm^_ns*CS zNYIBzZ5t!B<1wbPZI9L^GMBt=ip_eiJ(BX$)b^(BF4rSdViftR)To=*S8+ew667pU zNE}4?vU7Nz;;y(&R^29XmH}ibSwvEszKA*UBwf)Npmr}`=)KiKA)fO}@mwM8+L1oT zK4nXoNeMG~maqF_k^x<uOBHxC;PjsCm3r)!@{XjorC!T%g0U7D?W~`x&FCD)C^^c{ z1}0eHSr*-K2KpSwA*YgdrPj5S%Wf+P`}LMQ{4{hHHTBKSsusT%XSq8SUz>$xYNWH$ z)gqtL<6RPVy`nqK8LD))p4kKw8>6W@u_O{>+oolQu-LAOIo~+%IlnvC$M2@SO1NVA z0w;kpw<%oB*+rw0AhyU=?QP*!{M9c{J%6=iw#T>gre5VL9wozP`8w$33t?efo?H2M zwo+^6?poVD-pO+PitO&AR)wvyl{o+Fo{iRD6&qI(C8fBxF8P>IlsfFQ6~9wzUtZ1p XE|q(+A(~}v|M~se`X{2X`Md64$O)6Q
literal 0 HcmV?d00001
diff --git a/dlls/gdi32/tests/wine_langnames2.sfd b/dlls/gdi32/tests/wine_langnames2.sfd new file mode 100644 index 00000000000..50199af9adf --- /dev/null +++ b/dlls/gdi32/tests/wine_langnames2.sfd @@ -0,0 +1,80 @@ +SplineFontDB: 3.2 +FontName: WineLangNamesRegular +FullName: Wine_Lang_Names_Regular +FamilyName: Wine_Lang_Names +Weight: Regular +Copyright: Copyright (c) 2020, Remi Bernon for CodeWeavers +UComments: "2017-11-17: Created with FontForge (http://fontforge.org)" +Version: 001.000 +ItalicAngle: 0 +UnderlinePosition: -102 +UnderlineWidth: 51 +Ascent: 819 +Descent: 205 +InvalidEm: 0 +LayerCount: 2 +Layer: 0 0 "Back" 1 +Layer: 1 0 "Fore" 0 +XUID: [1021 48 28337276 3092883] +OS2Version: 0 +OS2_WeightWidthSlopeOnly: 0 +OS2_UseTypoMetrics: 1 +CreationTime: 1510948643 +ModificationTime: 1599738445 +OS2TypoAscent: 0 +OS2TypoAOffset: 1 +OS2TypoDescent: 0 +OS2TypoDOffset: 1 +OS2TypoLinegap: 0 +OS2WinAscent: 0 +OS2WinAOffset: 1 +OS2WinDescent: 0 +OS2WinDOffset: 1 +HheadAscent: 0 +HheadAOffset: 1 +HheadDescent: 0 +HheadDOffset: 1 +OS2Vendor: 'PfEd' +MarkAttachClasses: 1 +DEI: 91125 +LangName: 1028 \ + "" \ + "Wine Lang Cond (zh-tw)" \ + "Reg (zh-tw)" \ + "" \ + "Wine Lang Cond Reg (zh-tw)" +LangName: 1041 \ + "" \ + "+MNUwqTDzMMhUDQAA Cond (ja)" \ + "Reg (ja)" +LangName: 1033 \ + "" \ + "Wine Lang Cond (en)" \ + "Reg (en)" +Encoding: ISO8859-1 +UnicodeInterp: none +NameList: AGL For New Fonts +DisplaySize: -48 +AntiAlias: 1 +FitToEm: 0 +WinInfo: 64 16 4 +BeginPrivate: 0 +EndPrivate +BeginChars: 256 1 + +StartChar: at +Encoding: 64 64 0 +Width: 1024 +VWidth: 0 +Flags: HW +LayerCount: 2 +Fore +SplineSet +259 332 m 29 + 468 664 l 29 + 514 332 l 29 + 259 332 l 29 +EndSplineSet +EndChar +EndChars +EndSplineFont diff --git a/dlls/gdi32/tests/wine_langnames2.ttf b/dlls/gdi32/tests/wine_langnames2.ttf new file mode 100644 index 0000000000000000000000000000000000000000..47082dbd67e117529574d83755fd19e969cd205f GIT binary patch literal 2016 zcmdT_O>A355dL=k>@-kl0)-xk(2^ENP~yDURYfZ!SqU{ggcgM;xl}lh<oTz>&(@2Z zHe9I0g+nEJ1c?I@7bqv29^h1oAE{EqfkP30$`y$cI3RL@m~Yn4b}SW%EBiFNGqW?Z z-^`BoK>>IWR}jN;F1PUF)sGu4Fz_X{BQHFEI)_JanDU1rpL=;KwHWs<0jflKd8Ojj za42z?@^_?}m5sW=sD2BGjd0&7dh4}Ti;*$#KIH?&wavm;jV9yACMefRzPI|&?(Pxt zzmiUrsE7|bamG4E`B<q^zkCqtNy@h<53N;KJiLkp`WwpkRlLhJoWV)%pP_65ui{@A zyqe|yd!#$H>UzDkjT1b-&i!W~xstYT&NlLgGJoQJhYH}^<G+6(>yK}I{xwDct@U+^ z2cSjEK_9C*-?rD<Mr!Z1XUA%su8(*stIHy3O&pqB19Q{w>Md&CZm;St(rS=e#5qSp zaCXN_h109Jf-JJJbSsVX7Kz2wH8D^`M&vBICB>Rc-7SqoXfu=~@(7I#SBIa-S>BPI zTVF($P>J3FN^%j}Kl%{v-{|pj{QrE|US{9O_bhYKQe&0k4a6{jWJ6&p(;RTHlWHX5 zKV_ORO%{!qsN<q;4kXlHnI=oPlS&UiG5mCT_~@t_`fY1VU;le?R2LXd#nc=-?j5PI zdW_;XNj0bD_HIb=9>y=7JHZr|BVJMeX~b*x+;+sr*h}Xk-oX*|NyNu7q;?`cfx~)C zIzbu|6Z*M`*LYOF7V!>_>o+YgJ^2br><4N86s|?Q#t^n5K86B*j(7)2)$xtPsN0b~ zfibmb`C-O+Tz?kvjHAEDEUKts6CuhdqJ%m-bPOvP=bD0RX@dMbd{k&-FhedxK)--e zfosTB;;eFKiR59!+N=Y!)!JrQE|%(MY-QY}+>|?E=KV_9%=lqY4NRdLn%U~AzvO!x zen^KUo)OU7V2*JDVrs_@7+sM0)Q!`u9QbC=3ySm(R?V0nP$?M2zH2q_7o)A5g<FTL zA&umK6dwqe>nT#_*nIccJkAn8g_i5cN1-objXFtJe5UC=$wzRqTPWnJK|NOui@r%E zU31C^%)G$NpXC#|o+qG-YhK8mX?ODEq|~FA@_#$qrhbo@z#_4RL|eAG8lrQFQF4^e z(0~;#v*@lnopfE7noioCTK7_J*RqqaJyi0rX+&A{-2d&eUS~s1vZXG`mF>HpetieT zy`%Ilwa?4F<9_7+;oe$!fSF12bsFRXZ>ayYj)oAT*R*v5X-bOJKjaZtv^r|litlsp ak8_a!W7(G&;@S4L^AEdwH^pQB|Lh+tiXH<1
literal 0 HcmV?d00001
diff --git a/dlls/gdi32/tests/wine_langnames3.sfd b/dlls/gdi32/tests/wine_langnames3.sfd new file mode 100644 index 00000000000..ea0dbff57d9 --- /dev/null +++ b/dlls/gdi32/tests/wine_langnames3.sfd @@ -0,0 +1,78 @@ +SplineFontDB: 3.2 +FontName: WineLangNamesRegular +FullName: Wine_Lang_Names_Regular +FamilyName: Wine_Lang_Names +Weight: Regular +Copyright: Copyright (c) 2020, Remi Bernon for CodeWeavers +UComments: "2017-11-17: Created with FontForge (http://fontforge.org)" +Version: 001.000 +ItalicAngle: 0 +UnderlinePosition: -102 +UnderlineWidth: 51 +Ascent: 819 +Descent: 205 +InvalidEm: 0 +LayerCount: 2 +Layer: 0 0 "Back" 1 +Layer: 1 0 "Fore" 0 +XUID: [1021 48 28337276 3092883] +OS2Version: 0 +OS2_WeightWidthSlopeOnly: 0 +OS2_UseTypoMetrics: 1 +CreationTime: 1510948643 +ModificationTime: 1599738445 +OS2TypoAscent: 0 +OS2TypoAOffset: 1 +OS2TypoDescent: 0 +OS2TypoDOffset: 1 +OS2TypoLinegap: 0 +OS2WinAscent: 0 +OS2WinAOffset: 1 +OS2WinDescent: 0 +OS2WinDOffset: 1 +HheadAscent: 0 +HheadAOffset: 1 +HheadDescent: 0 +HheadDOffset: 1 +OS2Vendor: 'PfEd' +MarkAttachClasses: 1 +DEI: 91125 +LangName: 1036 \ + "" \ + "Wine Lang Cond (fr)" \ + "Reg (fr)" \ + "" \ + "Wine Lang Cond Reg (fr)" +LangName: 1042 \ + "" \ + "Wine Lang Cond (ko)" \ + "Reg (ko)" \ + "" \ + "Wine Lang Cond Reg (ko)" +Encoding: ISO8859-1 +UnicodeInterp: none +NameList: AGL For New Fonts +DisplaySize: -48 +AntiAlias: 1 +FitToEm: 0 +WinInfo: 64 16 4 +BeginPrivate: 0 +EndPrivate +BeginChars: 256 1 + +StartChar: at +Encoding: 64 64 0 +Width: 1024 +VWidth: 0 +Flags: HW +LayerCount: 2 +Fore +SplineSet +259 332 m 29 + 468 664 l 29 + 514 332 l 29 + 259 332 l 29 +EndSplineSet +EndChar +EndChars +EndSplineFont diff --git a/dlls/gdi32/tests/wine_langnames3.ttf b/dlls/gdi32/tests/wine_langnames3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..dd76bd478bbb2546cfbbb7e9184cc7f602c59303 GIT binary patch literal 2048 zcmdT_O>7%Q6#iy*ZMRU79|cv22rX%W1SQU9jVfCCU?tS_U<xWxaw#}lXZ<7MwY70W zbD~EMNc6y=NZjC54q&U|ghT~GLMTX-1FBlo6Sq=&BI*HRzL_06i4Sc#GS=Jq-kbM7 zFB1p=Pv9aftmN~HuYK@&+XYg;Q#$_YD<|`K5@Y0lQ2gs}&U#A;|6M>-$*+{^eiK8< zJLGSW=1Utb2NUvrz#8YdUGdkO-7Y;Nb&dRi%Gzf6`*w%^t!eVjYT&PqZf_qZ{)2R^ zN<reFouIFy<d0VCtqX@Bo+Gc~53e;!KF(p0_73^S>i&f$PT@GuPmy;*zaD&H?a-I? z3F&^bvEJ(5#xchKi03at)k<3Y@vX0lL)pLZxJ?1@>r3}ORr{^?zWoUkfRyqI*#nSD z%0(M3IUDOssXfJK@z>T8yKkc`g_h-z)+#ntE`hblkL4C6AI7`5gN!&xDH8merSj~r zH_9hhaS=J>tV}n9vpN%<Q(wh_U}nsmP1hvYbJcfE<0jiIIpukrN)C6MKgH*GNBZ0S z&S*j;cLNAji=w@2Uxs@RcCiZoKVN#5IXCL}GHa2l$HL<cSV$q=7MRU;Qa0{-?PTJ& zY{!y>Xj@90P~uK1DgMrO*uuMBX5`tC7cwJ9CdBZcTU+wVKT8v`On1T(1y0;$)noBA z+3RUh5QUwqs(EAB?%fGyv0|{m5WX~6GLxSTwm3^UgKZoZpBbFMu()k-5@YfyH3_zw zx3@_#7I+4i43>Nmt{H5hj2i~qNQ;)i2{__wgOivP_cZ38E1s8WgC&OLlEJi<RgFir z&Sis@P8@5L^O%;uU;zy@v55#ZR8U2W(>jR~rnq}>HBA$rL4Z1S9Ly6%2x%9RD|3&y zD?h6|Stj||&^qhDLZi7E)hgANGg+E)JlAuloijnb=FA6C*a)3+BXSlRtHE;MZv+ty zmKh_YbrA*n37Jz7r-|y6spDE06bpV>DW2y0LxIYxg7a9TPDD1SoL}<^@;bkk-Xm%R z%+cfP;Br4fdT^ZLfZy0=j@C1L0cZN1LB0{T@{OnxI9}RyPB;Vk6-_=onR923&!`4G ztj59EgEjYj0!yqaVpnSBE?nj}r)yNmp#oc4W0zfbF73K5CB3qH&E0M7KqFNls?WO3 z{jT=Ro&N2_Hy`ru)!dYs&lIOTcD7gYV9WoiKZ$o(^ZrOZ$)iT<>6_QKdleaGE=c>A ndgKM)iz8Yr_<ryHM>@neL!B!h$}+ar-<#Vz-zbZ{|L^_<2BRY9
literal 0 HcmV?d00001
If english is the current locale, or if the primary langid does not have a name in the font (in which case the english name is used), look for another non-english name.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/gdi32/freetype.c | 60 +++++++++++++++++++++++------------------ dlls/gdi32/tests/font.c | 4 +-- 2 files changed, 36 insertions(+), 28 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index cf53f148ad1..86585882342 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -301,7 +301,7 @@ typedef struct tagFamily { struct list entry; unsigned int refcount; WCHAR family_name[LF_FACESIZE]; - WCHAR english_name[LF_FACESIZE]; + WCHAR second_name[LF_FACESIZE]; struct list faces; struct list *replacement; } Family; @@ -574,7 +574,7 @@ typedef struct tagFontSubst { static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\','W','i','n','e','\', 'F','o','n','t','s',0}; static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0}; -static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0}; +static const WCHAR second_name_value[] = {'S','e','c','o','n','d',' ','N','a','m','e',0}; static const WCHAR face_index_value[] = {'I','n','d','e','x',0}; static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0}; static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0}; @@ -1076,7 +1076,7 @@ static Family *find_family_from_any_name(const WCHAR *name) LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry) { if (!strncmpiW( family->family_name, name, LF_FACESIZE - 1 )) return family; - if (!strncmpiW( family->english_name, name, LF_FACESIZE - 1 )) return family; + if (!strncmpiW( family->second_name, name, LF_FACESIZE - 1 )) return family; }
return NULL; @@ -1415,6 +1415,7 @@ static int match_name_table_language( const FT_SfntName *name, LANGID lang ) if (name_lang == lang) res += 30; else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20; else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10; + else if (lang == MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL )) res += 5 * (0x100000 - name_lang); return res; }
@@ -1623,13 +1624,13 @@ static BOOL insert_face_in_family_list( Face *face, Family *family ) * NB This function stores the ptrs to the strings to save copying. * Don't free them after calling. */ -static Family *create_family( WCHAR *family_name, WCHAR *english_name ) +static Family *create_family( WCHAR *family_name, WCHAR *second_name ) { Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) ); family->refcount = 1; lstrcpynW( family->family_name, family_name, LF_FACESIZE ); - if (english_name) lstrcpynW( family->english_name, english_name, LF_FACESIZE ); - else family->english_name[0] = 0; + if (second_name) lstrcpynW( family->second_name, second_name, LF_FACESIZE ); + else family->second_name[0] = 0; list_init( &family->faces ); family->replacement = &family->faces; list_add_tail( &font_list, &family->entry ); @@ -1794,22 +1795,22 @@ static void load_font_list_from_cache(HKEY hkey_font_cache) size = sizeof(buffer); while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL)) { - WCHAR *english_name = NULL; + WCHAR *second_name = NULL; WCHAR *family_name = strdupW( buffer ); DWORD face_index = 0;
RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family); TRACE("opened family key %s\n", debugstr_w(family_name)); size = sizeof(buffer); - if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size)) - english_name = strdupW( buffer ); + if (!RegQueryValueExW( hkey_family, second_name_value, NULL, NULL, (BYTE *)buffer, &size )) + second_name = strdupW( buffer );
- family = create_family( family_name, english_name ); + family = create_family( family_name, second_name );
- if (english_name) + if (second_name) { FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst)); - subst->from.name = strdupW( english_name ); + subst->from.name = strdupW( second_name ); subst->from.charset = -1; subst->to.name = strdupW(family_name); subst->to.charset = -1; @@ -1832,7 +1833,7 @@ static void load_font_list_from_cache(HKEY hkey_font_cache) }
HeapFree( GetProcessHeap(), 0, family_name ); - HeapFree( GetProcessHeap(), 0, english_name ); + HeapFree( GetProcessHeap(), 0, second_name );
RegCloseKey(hkey_family); release_family( family ); @@ -1869,9 +1870,9 @@ static void add_face_to_cache(Face *face)
RegCreateKeyExW( hkey_font_cache, face->family->family_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL ); - if (face->family->english_name[0]) - RegSetValueExW( hkey_family, english_name_value, 0, REG_SZ, (BYTE *)face->family->english_name, - (strlenW( face->family->english_name ) + 1) * sizeof(WCHAR) ); + if (face->family->second_name[0]) + RegSetValueExW( hkey_family, second_name_value, 0, REG_SZ, (BYTE *)face->family->second_name, + (strlenW( face->family->second_name ) + 1) * sizeof(WCHAR) );
if (face->scalable) face_key_name = face->style_name; else @@ -1947,28 +1948,35 @@ static WCHAR *get_vertical_name( WCHAR *name ) static Family *get_family( FT_Face ft_face, BOOL vertical ) { Family *family; - WCHAR *family_name, *english_name; + WCHAR *family_name, *second_name;
family_name = ft_face_get_family_name( ft_face, GetSystemDefaultLCID() ); - english_name = ft_face_get_family_name( ft_face, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT) ); + second_name = ft_face_get_family_name( ft_face, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT) );
- if (!strcmpiW( family_name, english_name )) + /* try to find another secondary name, preferring the lowest langids */ + if (!strcmpiW( family_name, second_name )) { - HeapFree( GetProcessHeap(), 0, english_name ); - english_name = NULL; + HeapFree( GetProcessHeap(), 0, second_name ); + second_name = ft_face_get_family_name( ft_face, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) ); + } + + if (!strcmpiW( family_name, second_name )) + { + HeapFree( GetProcessHeap(), 0, second_name ); + second_name = NULL; }
if (vertical) { family_name = get_vertical_name( family_name ); - english_name = get_vertical_name( english_name ); + second_name = get_vertical_name( second_name ); }
if ((family = find_family_from_name( family_name ))) family->refcount++; - else if ((family = create_family( family_name, english_name )) && english_name) + else if ((family = create_family( family_name, second_name )) && second_name) { FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) ); - subst->from.name = strdupW( english_name ); + subst->from.name = strdupW( second_name ); subst->from.charset = -1; subst->to.name = strdupW( family_name ); subst->to.charset = -1; @@ -1976,7 +1984,7 @@ static Family *get_family( FT_Face ft_face, BOOL vertical ) }
HeapFree( GetProcessHeap(), 0, family_name ); - HeapFree( GetProcessHeap(), 0, english_name ); + HeapFree( GetProcessHeap(), 0, second_name );
return family; } @@ -2411,7 +2419,7 @@ static BOOL map_font_family(const WCHAR *orig, const WCHAR *repl) { TRACE("mapping %s to %s\n", debugstr_w(repl), debugstr_w(orig)); lstrcpynW( new_family->family_name, orig, LF_FACESIZE ); - new_family->english_name[0] = 0; + new_family->second_name[0] = 0; list_init(&new_family->faces); new_family->replacement = &family->faces; list_add_tail(&font_list, &new_family->entry); diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index 33dcc3b31ac..0ada22d95d5 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -7208,7 +7208,7 @@ static void test_lang_names(void) memset( &efnd, 0, sizeof(efnd) ); EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 ); if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH) - todo_wine ok( efnd.total == min( 2, i + 1 ), "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total ); + ok( efnd.total == min( 2, i + 1 ), "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total ); else /* (zh-tw) doesn't match here probably because there's an (en) name too */ ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
@@ -7222,7 +7222,7 @@ static void test_lang_names(void) memset( &efnd, 0, sizeof(efnd) ); EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 ); /* as wine_langnames3.sfd does not specify (en) name, (fr) is preferred */ - if (i == 2) todo_wine ok( efnd.total == 1, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total ); + if (i == 2) ok( efnd.total == 1, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total ); else ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
strcpy( font.lfFaceName, "Wine Lang Cond (ko)" );
Signed-off-by: Huw Davies huw@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/gdi32/freetype.c | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 86585882342..3298b31ab74 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -288,6 +288,12 @@ typedef struct tagFace { struct enum_data *cached_enum_data; } Face;
+static inline const char *debugstr_face( Face *face ) +{ + if (face->file) return wine_dbg_sprintf( "%s (%ld)", debugstr_w(face->file), face->face_index ); + else return wine_dbg_sprintf( "%p-%p (%ld)", face->font_data_ptr, (char *)face->font_data_ptr + face->font_data_size, face->face_index ); +} + #define FS_DBCS_MASK (FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD|FS_JOHAB)
#define ADDFONT_EXTERNAL_FONT 0x01 @@ -1585,20 +1591,17 @@ static BOOL insert_face_in_family_list( Face *face, Family *family ) if (face->file && face->dev == cursor->dev && face->ino == cursor->ino) { cursor->refcount++; - TRACE("Font %s already in list, refcount now %d\n", - debugstr_w(face->file), cursor->refcount); + TRACE( "face %s already in list, refcount now %d\n", debugstr_face(face), cursor->refcount ); return FALSE; } if (face->font_version <= cursor->font_version) { - TRACE("Original font %s is newer so skipping %s\n", - debugstr_w(cursor->file), debugstr_w(face->file)); + TRACE( "Original %s is newer so skipping %s\n", debugstr_face(cursor), debugstr_face(face) ); return FALSE; } else { - TRACE("Replacing original %s with %s\n", - debugstr_w(cursor->file), debugstr_w(face->file)); + TRACE( "Replacing original %s with %s\n", debugstr_face(cursor), debugstr_face(face) ); list_add_before( &cursor->entry, &face->entry ); face->family = family; family->refcount++; @@ -1612,7 +1615,7 @@ static BOOL insert_face_in_family_list( Face *face, Family *family ) }
TRACE( "Adding face %s in family %s from %s\n", debugstr_w(face->full_name), - debugstr_w(family->family_name), debugstr_w(face->file) ); + debugstr_w(family->family_name), debugstr_face(face) ); list_add_before( &cursor->entry, &face->entry ); face->family = family; family->refcount++; @@ -2356,7 +2359,7 @@ static int remove_font_resource( const WCHAR *file, DWORD flags ) if (LOWORD(face->flags) != LOWORD(flags)) continue; if (st.st_dev == face->dev && st.st_ino == face->ino) { - TRACE( "removing matching face %s refcount %d\n", debugstr_w(face->file), face->refcount ); + TRACE( "removing matching face %s refcount %d\n", debugstr_face(face), face->refcount ); release_face( face ); count++; } @@ -2623,8 +2626,7 @@ static void populate_system_links(const WCHAR *name, const WCHAR *const *values) child_font->font = NULL; font_link->fs.fsCsb[0] |= face->fs.fsCsb[0]; font_link->fs.fsCsb[1] |= face->fs.fsCsb[1]; - TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file), - child_font->face->face_index); + TRACE( "Adding %s\n", debugstr_face(child_font->face) ); list_add_tail(&font_link->links, &child_font->entry);
TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file)); @@ -2704,8 +2706,7 @@ static void init_system_links(void) child_font->font = NULL; font_link->fs.fsCsb[0] |= face->fs.fsCsb[0]; font_link->fs.fsCsb[1] |= face->fs.fsCsb[1]; - TRACE("Adding file %s index %ld\n", - debugstr_w(child_font->face->file), child_font->face->face_index); + TRACE( "Adding %s\n", debugstr_face(child_font->face) ); list_add_tail(&font_link->links, &child_font->entry); } list_add_tail(&system_links, &font_link->entry); @@ -2763,8 +2764,7 @@ skip_internal: child_font->font = NULL; system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0]; system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1]; - TRACE("Found Tahoma in %s index %ld\n", - debugstr_w(child_font->face->file), child_font->face->face_index); + TRACE( "Found Tahoma in %s\n", debugstr_face(child_font->face) ); list_add_tail(&system_font_link->links, &child_font->entry); } font_link = find_font_link(Tahoma); @@ -4599,7 +4599,7 @@ static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height) void *data_ptr; DWORD data_size;
- TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height); + TRACE( "%s, %d x %d\n", debugstr_face(face), width, height );
if (face->file) { @@ -4608,7 +4608,7 @@ static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height) HeapFree( GetProcessHeap(), 0, filename ); if (!font->mapping) { - WARN("failed to map %s\n", debugstr_w(face->file)); + WARN( "failed to map %s\n", debugstr_face(face) ); return 0; } data_ptr = font->mapping->data; @@ -4700,8 +4700,7 @@ static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp) } }
- FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n", - face->fs.fsCsb[0], debugstr_w(face->file)); + FIXME( "returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x %s\n", face->fs.fsCsb[0], debugstr_face(face) ); *cp = acp; return DEFAULT_CHARSET; } @@ -5134,7 +5133,7 @@ static BOOL create_child_font_list(GdiFont *font) new_child->font = NULL; new_child->face->refcount++; list_add_tail(&font->child_fonts, &new_child->entry); - TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index); + TRACE( "face %s\n", debugstr_face(new_child->face) ); } ret = TRUE; } @@ -5157,7 +5156,7 @@ static BOOL create_child_font_list(GdiFont *font) new_child->font = NULL; new_child->face->refcount++; list_add_tail(&font->child_fonts, &new_child->entry); - TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index); + TRACE( "face %s\n", debugstr_face(new_child->face) ); } ret = TRUE; } @@ -5894,8 +5893,7 @@ found_face: else ret->charset = get_nearest_charset( family->family_name, face, &ret->codepage );
- TRACE( "Chosen: %s (%s/%p:%ld)\n", debugstr_w(face->full_name), debugstr_w(face->file), - face->font_data_ptr, face->face_index ); + TRACE( "Chosen: %s from %s\n", debugstr_w(face->full_name), debugstr_face(face) );
ret->aveWidth = height ? lf.lfWidth : 0;
On Thu, Sep 17, 2020 at 07:30:44PM +0200, Rémi Bernon wrote:
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
dlls/gdi32/freetype.c | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 86585882342..3298b31ab74 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -288,6 +288,12 @@ typedef struct tagFace { struct enum_data *cached_enum_data; } Face;
+static inline const char *debugstr_face( Face *face ) +{
- if (face->file) return wine_dbg_sprintf( "%s (%ld)", debugstr_w(face->file), face->face_index );
- else return wine_dbg_sprintf( "%p-%p (%ld)", face->font_data_ptr, (char *)face->font_data_ptr + face->font_data_size, face->face_index );
+}
While this patch is fine in principle, I wonder whether the name of the helper is ideal. We might want a helper to dump the face's name, ppem, etc. at some point, so unless you're planning to extend this helper to do that, then something like debugstr_face_source() might be more appropriate.
Huw.
On 2020-09-21 11:01, Huw Davies wrote:
On Thu, Sep 17, 2020 at 07:30:44PM +0200, Rémi Bernon wrote:
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
dlls/gdi32/freetype.c | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 86585882342..3298b31ab74 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -288,6 +288,12 @@ typedef struct tagFace { struct enum_data *cached_enum_data; } Face;
+static inline const char *debugstr_face( Face *face ) +{
- if (face->file) return wine_dbg_sprintf( "%s (%ld)", debugstr_w(face->file), face->face_index );
- else return wine_dbg_sprintf( "%p-%p (%ld)", face->font_data_ptr, (char *)face->font_data_ptr + face->font_data_size, face->face_index );
+}
While this patch is fine in principle, I wonder whether the name of the helper is ideal. We might want a helper to dump the face's name, ppem, etc. at some point, so unless you're planning to extend this helper to do that, then something like debugstr_face_source() might be more appropriate.
Huw.
I wasn't planning on adding anything like that, but there's already a "DumpFontList" which is probably supposed to do that, and could perhaps be a bit more detailed. In the same way as FreeType has the "FaceID" notion for its cache (an abstract type that uniquely identifies a face), it could be debugstr_faceid, keeping it short. Would that work for you?
On Mon, Sep 21, 2020 at 11:11:23AM +0200, Rémi Bernon wrote:
On 2020-09-21 11:01, Huw Davies wrote:
On Thu, Sep 17, 2020 at 07:30:44PM +0200, Rémi Bernon wrote:
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
dlls/gdi32/freetype.c | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 86585882342..3298b31ab74 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -288,6 +288,12 @@ typedef struct tagFace { struct enum_data *cached_enum_data; } Face; +static inline const char *debugstr_face( Face *face ) +{
- if (face->file) return wine_dbg_sprintf( "%s (%ld)", debugstr_w(face->file), face->face_index );
- else return wine_dbg_sprintf( "%p-%p (%ld)", face->font_data_ptr, (char *)face->font_data_ptr + face->font_data_size, face->face_index );
+}
While this patch is fine in principle, I wonder whether the name of the helper is ideal. We might want a helper to dump the face's name, ppem, etc. at some point, so unless you're planning to extend this helper to do that, then something like debugstr_face_source() might be more appropriate.
Huw.
I wasn't planning on adding anything like that, but there's already a "DumpFontList" which is probably supposed to do that, and could perhaps be a bit more detailed. In the same way as FreeType has the "FaceID" notion for its cache (an abstract type that uniquely identifies a face), it could be debugstr_faceid, keeping it short. Would that work for you?
Sure, that works.
Huw.
Make it not depend on FreeType so we can also use it before creating FT_Face.
We also open and fstat the file first, checking for its existence and in preparation for mmaping it to parse the font info later.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/gdi32/freetype.c | 99 +++++++++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 45 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 3298b31ab74..8f4b0d075d7 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -1542,6 +1542,48 @@ static void release_family( Family *family ) HeapFree( GetProcessHeap(), 0, family ); }
+static Face *create_face( const char *unix_name, DWORD face_index, void *font_data_ptr, + DWORD font_data_size, DWORD flags ) +{ + struct stat st; + Face *face; + int fd; + + TRACE( "unix_name %s, face_index %u, font_data_ptr %p, font_data_size %u, flags %#x\n", + unix_name, face_index, font_data_ptr, font_data_size, flags ); + + if (unix_name) + { + if ((fd = open( unix_name, O_RDONLY )) == -1) return NULL; + if (fstat( fd, &st ) == -1) return NULL; + close( fd ); + } + + if (!(face = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*face) ))) return NULL; + face->refcount = 1; + + list_init( &face->entry ); + + if (unix_name) + { + face->file = towstr( CP_UNIXCP, unix_name ); + face->dev = st.st_dev; + face->ino = st.st_ino; + } + else + { + face->font_data_ptr = font_data_ptr; + face->font_data_size = font_data_size; + } + + face->face_index = face_index; + + if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags ); + face->flags = flags; + + return face; +} + static void release_face( Face *face ) { if (--face->refcount) return; @@ -2112,57 +2154,23 @@ static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs ) } }
-static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size, - DWORD flags ) +static Face *create_face_from_ft_face( FT_Face ft_face, FT_Long face_index, const char *file, + void *font_data_ptr, DWORD font_data_size, DWORD flags ) { - struct stat st; - Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) ); + Face *face; + + if (!(face = create_face( file, face_index, font_data_ptr, font_data_size, flags ))) + return NULL;
- face->refcount = 1; face->style_name = ft_face_get_style_name( ft_face, GetSystemDefaultLangID() ); face->full_name = ft_face_get_full_name( ft_face, GetSystemDefaultLangID() ); - if (flags & ADDFONT_VERTICAL_FONT) face->full_name = get_vertical_name( face->full_name ); + if (face->flags & ADDFONT_VERTICAL_FONT) face->full_name = get_vertical_name( face->full_name );
- face->dev = 0; - face->ino = 0; - if (file) - { - face->file = towstr( CP_UNIXCP, file ); - face->font_data_ptr = NULL; - face->font_data_size = 0; - if (!stat( file, &st )) - { - face->dev = st.st_dev; - face->ino = st.st_ino; - } - } - else - { - face->file = NULL; - face->font_data_ptr = font_data_ptr; - face->font_data_size = font_data_size; - } - - face->face_index = face_index; get_fontsig( ft_face, &face->fs ); face->ntmFlags = get_ntm_flags( ft_face ); face->font_version = get_font_version( ft_face );
- if (FT_IS_SCALABLE( ft_face )) - { - memset( &face->size, 0, sizeof(face->size) ); - face->scalable = TRUE; - } - else - { - get_bitmap_size( ft_face, &face->size ); - face->scalable = FALSE; - } - - if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags ); - face->flags = flags; - face->family = NULL; - face->cached_enum_data = NULL; + if (!(face->scalable = FT_IS_SCALABLE( ft_face ))) get_bitmap_size( ft_face, &face->size );
TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n", face->fs.fsCsb[0], face->fs.fsCsb[1], @@ -2178,9 +2186,10 @@ static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr Face *face; Family *family;
- face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags ); - family = get_family( ft_face, flags & ADDFONT_VERTICAL_FONT ); + if (!(face = create_face_from_ft_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags ))) + return;
+ family = get_family( ft_face, flags & ADDFONT_VERTICAL_FONT ); if (insert_face_in_family_list( face, family )) { if (flags & ADDFONT_ADD_TO_CACHE) @@ -3524,7 +3533,7 @@ static BOOL get_fontdir( const char *unix_name, struct fontdir *fd ) DWORD type;
if (!ft_face) return FALSE; - face = create_face( ft_face, 0, unix_name, NULL, 0, 0 ); + face = create_face_from_ft_face( ft_face, 0, unix_name, NULL, 0, 0 ); family_name = ft_face_get_family_name( ft_face, GetSystemDefaultLCID() ); pFT_Done_Face( ft_face );
On Thu, Sep 17, 2020 at 07:30:45PM +0200, Rémi Bernon wrote:
Make it not depend on FreeType so we can also use it before creating FT_Face.
We also open and fstat the file first, checking for its existence and in preparation for mmaping it to parse the font info later.
This is probably fine as it stands, but it would be good to see a bit more of where you're going before making this change.
Huw.
On 2020-09-21 11:02, Huw Davies wrote:
On Thu, Sep 17, 2020 at 07:30:45PM +0200, Rémi Bernon wrote:
Make it not depend on FreeType so we can also use it before creating FT_Face.
We also open and fstat the file first, checking for its existence and in preparation for mmaping it to parse the font info later.
This is probably fine as it stands, but it would be good to see a bit more of where you're going before making this change.
Huw.
Sure, here's where I currently intend to go:
https://gitlab.com/rbernon/wine/-/commits/wip/freetype/v3/
I'll probably also drop the FreeType cache manager usage, as it's not really useful anymore (since we won't be loading so many fonts with FreeType). I had some additional patches that use it for all FreeType code in gdi32 (including for GdiFont), but I need to sort out some issues related to font lifecycle and some internal cache first.
This supersedes the whole previous series (192832-192838).