Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v2: The first two patches are mostly unrelated to the optimization goal, and are there to test and fix the face lookup logic wrt non-english names.
Then, change of plans, although the series doesn't change much from the previous patches, I now intend to do the font parsing by hand, getting rid of freetype when possible, and not relying on fontconfig anymore. This makes the font face listing faster for all platforms and cases.
In order to achieve that, as previously, I need to first invert the creation order between FT_Face and gdi32 Face. Making face creation independent of freetype first, and make it provide all required data to then create FT_Face from it.
Next I intend to send patches that iteratively add font info parsing with a FreeType fallback to support other font formats. Ultimately it will also allow us to start using FreeType cache manager instead of creating the faces manually. It shouldn't change much for the initial listing --as in any case we should avoid using FreeType at that point-- but it could also benefit to the GdiFont logic too.
Last in the future patches, I'm planning on improving the font family indexation performance, reducing the registry load once re-parsing the system fonts is faster than caching them, listing fontconfig fonts directly from its caches, and possibly then implementing some kind of lazy initialization.
Overall I think it can achieve ~30% to ~50% prefix startup time reduction, as well as good improvements on process startup time (with the prefix already started).
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..bfcfad30e24 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(GetUserDefaultLangID()) != LANG_ENGLISH && PRIMARYLANGID(GetUserDefaultLangID()) != 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(GetUserDefaultLangID()) == 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(GetUserDefaultLangID()) == 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(GetUserDefaultLangID()) == 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(GetUserDefaultLangID()) == 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(GetUserDefaultLangID()) == 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(GetUserDefaultLangID()) == 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(GetUserDefaultLangID()) == 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 bfcfad30e24..02a685ecb43 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(GetUserDefaultLangID()) == 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)" );
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=78872
Your paranoid android.
=== w10pro64_ja (32 bit report) ===
gdi32: font.c:7138: Test failed: 0: EnumFontFamiliesExA unexpected count 1. font.c:7156: Test failed: 0: EnumFontFamiliesExW unexpected count 0. font.c:7173: Test failed: 0: EnumFontFamiliesExA unexpected count 1. font.c:7211: Test failed: 0: EnumFontFamiliesExA unexpected count 0. font.c:7138: Test failed: 1: EnumFontFamiliesExA unexpected count 2. font.c:7156: Test failed: 1: EnumFontFamiliesExW unexpected count 0. font.c:7173: Test failed: 1: EnumFontFamiliesExA unexpected count 1. font.c:7183: Test failed: 1: (0) unexpected lfFaceName L"\30d5\30a9\30f3\30c8\540d Cond (ja)" font.c:7188: Test failed: 1: (0) unexpected elfStyle L"Reg (ja)" font.c:7211: Test failed: 1: EnumFontFamiliesExA unexpected count 0. font.c:7138: Test failed: 2: EnumFontFamiliesExA unexpected count 2. font.c:7156: Test failed: 2: EnumFontFamiliesExW unexpected count 0. font.c:7173: Test failed: 2: EnumFontFamiliesExA unexpected count 1. font.c:7183: Test failed: 2: (0) unexpected lfFaceName L"\30d5\30a9\30f3\30c8\540d Cond (ja)" font.c:7188: Test failed: 2: (0) unexpected elfStyle L"Reg (ja)" font.c:7211: Test failed: 2: EnumFontFamiliesExA unexpected count 0.
=== w10pro64_ja (64 bit report) ===
gdi32: font.c:7138: Test failed: 0: EnumFontFamiliesExA unexpected count 1. font.c:7156: Test failed: 0: EnumFontFamiliesExW unexpected count 0. font.c:7173: Test failed: 0: EnumFontFamiliesExA unexpected count 1. font.c:7211: Test failed: 0: EnumFontFamiliesExA unexpected count 0. font.c:7138: Test failed: 1: EnumFontFamiliesExA unexpected count 2. font.c:7156: Test failed: 1: EnumFontFamiliesExW unexpected count 0. font.c:7173: Test failed: 1: EnumFontFamiliesExA unexpected count 1. font.c:7183: Test failed: 1: (0) unexpected lfFaceName L"\30d5\30a9\30f3\30c8\540d Cond (ja)" font.c:7188: Test failed: 1: (0) unexpected elfStyle L"Reg (ja)" font.c:7211: Test failed: 1: EnumFontFamiliesExA unexpected count 0. font.c:7138: Test failed: 2: EnumFontFamiliesExA unexpected count 2. font.c:7156: Test failed: 2: EnumFontFamiliesExW unexpected count 0. font.c:7173: Test failed: 2: EnumFontFamiliesExA unexpected count 1. font.c:7183: Test failed: 2: (0) unexpected lfFaceName L"\30d5\30a9\30f3\30c8\540d Cond (ja)" font.c:7188: Test failed: 2: (0) unexpected elfStyle L"Reg (ja)" font.c:7211: Test failed: 2: EnumFontFamiliesExA unexpected count 0.
On 2020-09-17 18:48, Marvin wrote:
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=78872
Your paranoid android.
=== w10pro64_ja (32 bit report) ===
gdi32: font.c:7138: Test failed: 0: EnumFontFamiliesExA unexpected count 1. font.c:7156: Test failed: 0: EnumFontFamiliesExW unexpected count 0. font.c:7173: Test failed: 0: EnumFontFamiliesExA unexpected count 1. font.c:7211: Test failed: 0: EnumFontFamiliesExA unexpected count 0. font.c:7138: Test failed: 1: EnumFontFamiliesExA unexpected count 2. font.c:7156: Test failed: 1: EnumFontFamiliesExW unexpected count 0. font.c:7173: Test failed: 1: EnumFontFamiliesExA unexpected count 1. font.c:7183: Test failed: 1: (0) unexpected lfFaceName L"\30d5\30a9\30f3\30c8\540d Cond (ja)" font.c:7188: Test failed: 1: (0) unexpected elfStyle L"Reg (ja)" font.c:7211: Test failed: 1: EnumFontFamiliesExA unexpected count 0. font.c:7138: Test failed: 2: EnumFontFamiliesExA unexpected count 2. font.c:7156: Test failed: 2: EnumFontFamiliesExW unexpected count 0. font.c:7173: Test failed: 2: EnumFontFamiliesExA unexpected count 1. font.c:7183: Test failed: 2: (0) unexpected lfFaceName L"\30d5\30a9\30f3\30c8\540d Cond (ja)" font.c:7188: Test failed: 2: (0) unexpected elfStyle L"Reg (ja)" font.c:7211: Test failed: 2: EnumFontFamiliesExA unexpected count 0.
=== w10pro64_ja (64 bit report) ===
gdi32: font.c:7138: Test failed: 0: EnumFontFamiliesExA unexpected count 1. font.c:7156: Test failed: 0: EnumFontFamiliesExW unexpected count 0. font.c:7173: Test failed: 0: EnumFontFamiliesExA unexpected count 1. font.c:7211: Test failed: 0: EnumFontFamiliesExA unexpected count 0. font.c:7138: Test failed: 1: EnumFontFamiliesExA unexpected count 2. font.c:7156: Test failed: 1: EnumFontFamiliesExW unexpected count 0. font.c:7173: Test failed: 1: EnumFontFamiliesExA unexpected count 1. font.c:7183: Test failed: 1: (0) unexpected lfFaceName L"\30d5\30a9\30f3\30c8\540d Cond (ja)" font.c:7188: Test failed: 1: (0) unexpected elfStyle L"Reg (ja)" font.c:7211: Test failed: 1: EnumFontFamiliesExA unexpected count 0. font.c:7138: Test failed: 2: EnumFontFamiliesExA unexpected count 2. font.c:7156: Test failed: 2: EnumFontFamiliesExW unexpected count 0. font.c:7173: Test failed: 2: EnumFontFamiliesExA unexpected count 1. font.c:7183: Test failed: 2: (0) unexpected lfFaceName L"\30d5\30a9\30f3\30c8\540d Cond (ja)" font.c:7188: Test failed: 2: (0) unexpected elfStyle L"Reg (ja)" font.c:7211: Test failed: 2: EnumFontFamiliesExA unexpected count 0.
Damn, I've run that test multiple times, but I did it on the vm_w1064v1809_ja VM. It seems to be configured differently and this VM runs the test that are guarded by:
if (PRIMARYLANGID(GetUserDefaultLangID()) == LANG_ENGLISH)
I guess maybe only the GetSystemDefaultLangID() returns LANG_JAPANESE there? I'll fix the tests but is this actually expected?
I'll cancel the whole series anyway, as it doesn't seem to be liked very much, I'll resend another one, probably without the controversial unix paths thing :).
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;
The conversion is only temporary as we will store the path on faces.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/gdi32/freetype.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 3298b31ab74..960c2dc745c 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -592,7 +592,7 @@ static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0}; static const WCHAR face_flags_value[] = {'F','l','a','g','s',0}; static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0}; static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0}; -static const WCHAR face_file_name_value[] = {'F','i','l','e',' ','N','a','m','e','\0'}; +static const WCHAR face_unix_name_value[] = {'U','n','i','x',' ','N','a','m','e','\0'}; static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
@@ -1683,7 +1683,7 @@ static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *bu /* If we have a File Name key then this is a real font, not just the parent key of a bunch of non-scalable strikes */ needed = buffer_size; - if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS) + if (RegQueryValueExW( hkey_face, face_unix_name_value, NULL, NULL, buffer, &needed ) == ERROR_SUCCESS) { Face *face; face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face)); @@ -1691,7 +1691,7 @@ static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *bu face->family = NULL;
face->refcount = 1; - face->file = strdupW( buffer ); + face->file = towstr( CP_UNIXCP, buffer ); face->style_name = strdupW( face_name );
needed = buffer_size; @@ -1870,6 +1870,7 @@ static void add_face_to_cache(Face *face) { HKEY hkey_family, hkey_face; WCHAR *face_key_name; + char *unix_name;
RegCreateKeyExW( hkey_font_cache, face->family->family_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL ); @@ -1889,8 +1890,10 @@ static void add_face_to_cache(Face *face) if(!face->scalable) HeapFree(GetProcessHeap(), 0, face_key_name);
- RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file, - (strlenW(face->file) + 1) * sizeof(WCHAR)); + unix_name = strWtoA( CP_UNIXCP, face->file ); + RegSetValueExW( hkey_face, face_unix_name_value, 0, REG_BINARY, (BYTE *)unix_name, strlen( unix_name ) + 1 ); + HeapFree( GetProcessHeap(), 0, unix_name ); + RegSetValueExW( hkey_face, face_full_name_value, 0, REG_SZ, (BYTE *)face->full_name, (strlenW( face->full_name ) + 1) * sizeof(WCHAR) );
Make it not depend on FreeType so we can also use it for face creation from registry cache.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/gdi32/freetype.c | 120 +++++++++++++++++++++--------------------- 1 file changed, 60 insertions(+), 60 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 960c2dc745c..6ed4e52c70e 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 *face_create( 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 )) 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; @@ -1677,21 +1719,18 @@ static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size) { - DWORD needed, strike_index = 0; + DWORD face_index, flags, needed, strike_index = 0; HKEY hkey_strike; + Face *face;
/* If we have a File Name key then this is a real font, not just the parent key of a bunch of non-scalable strikes */ needed = buffer_size; - if (RegQueryValueExW( hkey_face, face_unix_name_value, NULL, NULL, buffer, &needed ) == ERROR_SUCCESS) + if (RegQueryValueExW( hkey_face, face_unix_name_value, NULL, NULL, buffer, &needed ) == ERROR_SUCCESS && + reg_load_dword( hkey_face, face_index_value, &face_index ) == ERROR_SUCCESS && + reg_load_dword( hkey_face, face_flags_value, &flags ) == ERROR_SUCCESS && + (face = face_create( buffer, face_index, NULL, 0, flags ))) { - Face *face; - face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face)); - face->cached_enum_data = NULL; - face->family = NULL; - - face->refcount = 1; - face->file = towstr( CP_UNIXCP, buffer ); face->style_name = strdupW( face_name );
needed = buffer_size; @@ -1704,22 +1743,16 @@ static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *bu } face->full_name = strdupW( buffer );
- reg_load_ftlong(hkey_face, face_index_value, &face->face_index); reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags); reg_load_ftlong(hkey_face, face_version_value, &face->font_version); - reg_load_dword(hkey_face, face_flags_value, &face->flags);
needed = sizeof(face->fs); RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
if(reg_load_ftshort(hkey_face, face_height_value, &face->size.height) != ERROR_SUCCESS) - { face->scalable = TRUE; - memset(&face->size, 0, sizeof(face->size)); - } else { - face->scalable = FALSE; reg_load_ftshort(hkey_face, face_width_value, &face->size.width); reg_load_ftlong(hkey_face, face_size_value, &face->size.size); reg_load_ftlong(hkey_face, face_x_ppem_value, &face->size.x_ppem); @@ -2115,57 +2148,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 *face_create_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 = face_create( 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], @@ -2181,9 +2180,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 = face_create_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) @@ -3527,7 +3527,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 = face_create_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 );
So we can then more easily invert the creation order between faces and ft_face, and eventually use FreeType cache with Face* as FTC_FaceID.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/gdi32/freetype.c | 64 ++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 40 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 6ed4e52c70e..d2c47b0a263 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -272,6 +272,7 @@ typedef struct tagFace { WCHAR *style_name; WCHAR *full_name; WCHAR *file; + const char *unix_name; dev_t dev; ino_t ino; void *font_data_ptr; @@ -290,7 +291,7 @@ typedef struct tagFace {
static inline const char *debugstr_face( Face *face ) { - if (face->file) return wine_dbg_sprintf( "%s (%ld)", debugstr_w(face->file), face->face_index ); + if (face->unix_name) return wine_dbg_sprintf( "%s (%ld)", debugstr_a(face->unix_name), 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 ); }
@@ -1177,14 +1178,6 @@ static WCHAR *towstr(UINT cp, const char *str) return wstr; }
-static char *strWtoA(UINT cp, const WCHAR *str) -{ - int len = WideCharToMultiByte( cp, 0, str, -1, NULL, 0, NULL, NULL ); - char *ret = HeapAlloc( GetProcessHeap(), 0, len ); - WideCharToMultiByte( cp, 0, str, -1, ret, len, NULL, NULL ); - return ret; -} - static void split_subst_info(NameCs *nc, LPSTR str) { CHAR *p = strrchr(str, ','); @@ -1546,6 +1539,7 @@ static Face *face_create( const char *unix_name, DWORD face_index, void *font_da DWORD font_data_size, DWORD flags ) { struct stat st; + DWORD length = 0; Face *face; int fd;
@@ -1554,19 +1548,23 @@ static Face *face_create( const char *unix_name, DWORD face_index, void *font_da
if (unix_name) { + length = strlen( unix_name ) + 1; if ((fd = open( unix_name, O_RDONLY )) == -1) return NULL; if (fstat( fd, &st )) return NULL; close( fd ); }
- if (!(face = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*face) ))) return NULL; + if (!(face = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*face) + length ))) + return NULL; face->refcount = 1;
list_init( &face->entry );
if (unix_name) { - face->file = towstr( CP_UNIXCP, unix_name ); + face->unix_name = (char *)(face + 1); + strcpy( (char *)face->unix_name, unix_name ); + face->file = towstr( CP_UNIXCP, face->unix_name ); face->dev = st.st_dev; face->ino = st.st_ino; } @@ -1630,7 +1628,7 @@ static BOOL insert_face_in_family_list( Face *face, Family *family ) debugstr_w(face->full_name), debugstr_w(family->family_name), cursor->font_version, face->font_version );
- if (face->file && face->dev == cursor->dev && face->ino == cursor->ino) + if (face->unix_name && face->dev == cursor->dev && face->ino == cursor->ino) { cursor->refcount++; TRACE( "face %s already in list, refcount now %d\n", debugstr_face(face), cursor->refcount ); @@ -1903,7 +1901,6 @@ static void add_face_to_cache(Face *face) { HKEY hkey_family, hkey_face; WCHAR *face_key_name; - char *unix_name;
RegCreateKeyExW( hkey_font_cache, face->family->family_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL ); @@ -1923,9 +1920,8 @@ static void add_face_to_cache(Face *face) if(!face->scalable) HeapFree(GetProcessHeap(), 0, face_key_name);
- unix_name = strWtoA( CP_UNIXCP, face->file ); - RegSetValueExW( hkey_face, face_unix_name_value, 0, REG_BINARY, (BYTE *)unix_name, strlen( unix_name ) + 1 ); - HeapFree( GetProcessHeap(), 0, unix_name ); + RegSetValueExW( hkey_face, face_unix_name_value, 0, REG_BINARY, (BYTE *)face->unix_name, + strlen( face->unix_name ) + 1 );
RegSetValueExW( hkey_face, face_full_name_value, 0, REG_SZ, (BYTE *)face->full_name, (strlenW( face->full_name ) + 1) * sizeof(WCHAR) ); @@ -2358,7 +2354,7 @@ static int remove_font_resource( const WCHAR *file, DWORD flags ) family->refcount++; LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, Face, entry ) { - if (!face->file) continue; + if (!face->unix_name) continue; if (LOWORD(face->flags) != LOWORD(flags)) continue; if (st.st_dev == face->dev && st.st_ino == face->ino) { @@ -3218,7 +3214,6 @@ static void update_reg_entries(void)
LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) { LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) { - char *buffer; if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
len = strlenW( face->full_name ) + 1; @@ -3231,11 +3226,7 @@ static void update_reg_entries(void) if (face->scalable) strcatW(valueW, TrueType);
- buffer = strWtoA( CP_UNIXCP, face->file ); - path = wine_get_dos_file_name( buffer ); - HeapFree( GetProcessHeap(), 0, buffer ); - - if (path) + if ((path = wine_get_dos_file_name( face->unix_name ))) { if ((full_path = get_full_path_name(path))) { @@ -4604,11 +4595,9 @@ static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
TRACE( "%s, %d x %d\n", debugstr_face(face), width, height );
- if (face->file) + if (face->unix_name) { - char *filename = strWtoA( CP_UNIXCP, face->file ); - font->mapping = map_font_file( filename ); - HeapFree( GetProcessHeap(), 0, filename ); + font->mapping = map_font_file( face->unix_name ); if (!font->mapping) { WARN( "failed to map %s\n", debugstr_face(face) ); @@ -5529,25 +5518,20 @@ static const VOID * get_GSUB_vert_feature(const GdiFont *font) static void fill_fileinfo_from_face( GdiFont *font, Face *face ) { WIN32_FILE_ATTRIBUTE_DATA info; - int len; + SIZE_T path_size; + WCHAR *path = NULL;
- if (!face->file) - { - font->fileinfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*font->fileinfo)); - font->fileinfo->size.QuadPart = face->font_data_size; - return; - } + if (!face->unix_name || !(path = wine_get_dos_file_name( face->unix_name ))) path_size = 0; + else path_size = strlenW( path ) * sizeof(WCHAR);
- len = strlenW(face->file); - font->fileinfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*font->fileinfo) + len * sizeof(WCHAR)); - if (GetFileAttributesExW(face->file, GetFileExInfoStandard, &info)) + font->fileinfo = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*font->fileinfo) + path_size ); + if (!face->unix_name) font->fileinfo->size.QuadPart = face->font_data_size; + else if (path && GetFileAttributesExW( path, GetFileExInfoStandard, &info )) { font->fileinfo->writetime = info.ftLastWriteTime; font->fileinfo->size.QuadPart = (LONGLONG)info.nFileSizeHigh << 32 | info.nFileSizeLow; - strcpyW(font->fileinfo->path, face->file); + strcpyW( font->fileinfo->path, path ); } - else - memset(font->fileinfo, 0, sizeof(*font->fileinfo) + len * sizeof(WCHAR)); }
/*************************************************************
Rémi Bernon rbernon@codeweavers.com writes:
So we can then more easily invert the creation order between faces and ft_face, and eventually use FreeType cache with Face* as FTC_FaceID.
I'm not sure this is going in the right direction either, particularly with the view of moving to PE. I would think we'd want to keep as much as possible of the GDI internal structures independent of the backend, and not need to be aware of things like Unix paths.
On 2020-09-17 17:50, Alexandre Julliard wrote:
Rémi Bernon rbernon@codeweavers.com writes:
So we can then more easily invert the creation order between faces and ft_face, and eventually use FreeType cache with Face* as FTC_FaceID.
I'm not sure this is going in the right direction either, particularly with the view of moving to PE. I would think we'd want to keep as much as possible of the GDI internal structures independent of the backend, and not need to be aware of things like Unix paths.
Well, it's not strictly required to be unix paths for FreeType integration, especially if we think about having a PE freetype as some point (where it would use NT paths directly).
What the Face needs to store is the path that will be then used by FreeType, in order to save conversions.
Now, there's a potential issue on Face creation, as I was intending to open and mmap the font files directly. As create_face was already calling stat, it seemed like a good place to do this too.
If the idea is to completely get rid of unix paths somehow, and use Win32 file access instead, then the quick test I did lately tells me that it has an overhead that makes the whole optimization a bit useless.
Instead of keeping the full NT path and computing it later.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/gdi32/freetype.c | 40 +++++++++++++--------------------------- 1 file changed, 13 insertions(+), 27 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index d2c47b0a263..39775b6ff5a 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -271,7 +271,7 @@ typedef struct tagFace { unsigned int refcount; WCHAR *style_name; WCHAR *full_name; - WCHAR *file; + WCHAR *file_name; const char *unix_name; dev_t dev; ino_t ino; @@ -1040,7 +1040,6 @@ static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_n { Family *family; Face *face; - const WCHAR *file;
TRACE("looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(face_name));
@@ -1051,14 +1050,8 @@ static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_n face_list = get_face_list_from_family(family); LIST_FOR_EACH_ENTRY(face, face_list, Face, entry) { - if (!face->file) - continue; - file = strrchrW(face->file, '/'); - if(!file) - file = face->file; - else - file++; - if(strcmpiW(file, file_name)) continue; + if (!face->file_name) continue; + if (strcmpiW( face->file_name, file_name )) continue; face->refcount++; return face; } @@ -1540,6 +1533,7 @@ static Face *face_create( const char *unix_name, DWORD face_index, void *font_da { struct stat st; DWORD length = 0; + const char *file_name; Face *face; int fd;
@@ -1564,7 +1558,11 @@ static Face *face_create( const char *unix_name, DWORD face_index, void *font_da { face->unix_name = (char *)(face + 1); strcpy( (char *)face->unix_name, unix_name ); - face->file = towstr( CP_UNIXCP, face->unix_name ); + + if ((file_name = strrchr( face->unix_name, '/' ))) file_name++; + else file_name = face->unix_name; + face->file_name = towstr( CP_UNIXCP, file_name ); + face->dev = st.st_dev; face->ino = st.st_ino; } @@ -1591,7 +1589,7 @@ static void release_face( Face *face ) list_remove( &face->entry ); release_family( face->family ); } - HeapFree( GetProcessHeap(), 0, face->file ); + HeapFree( GetProcessHeap(), 0, face->file_name ); HeapFree( GetProcessHeap(), 0, face->style_name ); HeapFree( GetProcessHeap(), 0, face->full_name ); HeapFree( GetProcessHeap(), 0, face->cached_enum_data ); @@ -2602,13 +2600,8 @@ static void populate_system_links(const WCHAR *name, const WCHAR *const *values) face_list = get_face_list_from_family(family); LIST_FOR_EACH_ENTRY(face, face_list, Face, entry) { - if (!face->file) - continue; - file = strrchrW(face->file, '/'); - if (!file) - file = face->file; - else - file++; + if (!face->file_name) continue; + file = face->file_name; break; } if (!file) @@ -3235,14 +3228,7 @@ static void update_reg_entries(void) } file = path; } - else if ((file = strrchrW(face->file, '/'))) - { - file++; - } - else - { - file = face->file; - } + else file = face->file_name;
len = strlenW(file) + 1; RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=78871
Your paranoid android.
=== w10pro64_ja (32 bit report) ===
gdi32: font.c:7138: Test failed: 0: EnumFontFamiliesExA unexpected count 1. font.c:7156: Test failed: 0: EnumFontFamiliesExW unexpected count 0. font.c:7173: Test failed: 0: EnumFontFamiliesExA unexpected count 1. font.c:7211: Test failed: 0: EnumFontFamiliesExA unexpected count 0. font.c:7138: Test failed: 1: EnumFontFamiliesExA unexpected count 2. font.c:7156: Test failed: 1: EnumFontFamiliesExW unexpected count 0. font.c:7173: Test failed: 1: EnumFontFamiliesExA unexpected count 1. font.c:7183: Test failed: 1: (0) unexpected lfFaceName L"\30d5\30a9\30f3\30c8\540d Cond (ja)" font.c:7188: Test failed: 1: (0) unexpected elfStyle L"Reg (ja)" font.c:7211: Test failed: 1: EnumFontFamiliesExA unexpected count 0. font.c:7138: Test failed: 2: EnumFontFamiliesExA unexpected count 2. font.c:7156: Test failed: 2: EnumFontFamiliesExW unexpected count 0. font.c:7173: Test failed: 2: EnumFontFamiliesExA unexpected count 1. font.c:7183: Test failed: 2: (0) unexpected lfFaceName L"\30d5\30a9\30f3\30c8\540d Cond (ja)" font.c:7188: Test failed: 2: (0) unexpected elfStyle L"Reg (ja)" font.c:7211: Test failed: 2: EnumFontFamiliesExA unexpected count 0.
=== w10pro64_ja (64 bit report) ===
gdi32: font.c:7138: Test failed: 0: EnumFontFamiliesExA unexpected count 1. font.c:7156: Test failed: 0: EnumFontFamiliesExW unexpected count 0. font.c:7173: Test failed: 0: EnumFontFamiliesExA unexpected count 1. font.c:7211: Test failed: 0: EnumFontFamiliesExA unexpected count 0. font.c:7138: Test failed: 1: EnumFontFamiliesExA unexpected count 2. font.c:7156: Test failed: 1: EnumFontFamiliesExW unexpected count 0. font.c:7173: Test failed: 1: EnumFontFamiliesExA unexpected count 1. font.c:7183: Test failed: 1: (0) unexpected lfFaceName L"\30d5\30a9\30f3\30c8\540d Cond (ja)" font.c:7188: Test failed: 1: (0) unexpected elfStyle L"Reg (ja)" font.c:7211: Test failed: 1: EnumFontFamiliesExA unexpected count 0. font.c:7138: Test failed: 2: EnumFontFamiliesExA unexpected count 2. font.c:7156: Test failed: 2: EnumFontFamiliesExW unexpected count 0. font.c:7173: Test failed: 2: EnumFontFamiliesExA unexpected count 1. font.c:7183: Test failed: 2: (0) unexpected lfFaceName L"\30d5\30a9\30f3\30c8\540d Cond (ja)" font.c:7188: Test failed: 2: (0) unexpected elfStyle L"Reg (ja)" font.c:7211: Test failed: 2: EnumFontFamiliesExA unexpected count 0.