The offending font is NotoColorEmoji.ttf which is present in, e. g., google-noto-emoji-color-fonts or noto-fonts-emoji packages available in various distribution. Attempting to load this font on Windows 10 (with AddFontResourceA() or open it with default font viewer) fails while currently succeeds on Windows. fontforge also refuses to open this font. That is because the font is bitmap only but missing bitmap table.
Some apps (Glyph launcher is an example) try to GetOutlineTextMetrics() on this font and do not expect that to have an error return (as we currenly do), which leads to crash on unhandled division by zero exception.
I am attaching a bitmap-only ttf test font (with only one bitmap) which I created with fontforge to make sure that such font can still be loaded in Wine. This font also loads on Windows (both with AddFontResourceA() and with default font viewer).
There are other font types which can be legitimately missing EBDT table, but FT_Load_Sfnt_Table() returns a different error for those and my patch doesn't reject those fonts.
[test.ttf](/uploads/b41472180b80c2c53f9dcc06055990f0/test.ttf)
From: Paul Gofman pgofman@codeweavers.com
--- dlls/win32u/freetype.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/dlls/win32u/freetype.c b/dlls/win32u/freetype.c index f00df7ed86d..4514574ec42 100644 --- a/dlls/win32u/freetype.c +++ b/dlls/win32u/freetype.c @@ -254,6 +254,8 @@ MAKE_FUNCPTR(FcStrSetMember); #define GET_BE_DWORD(x) RtlUlongByteSwap(x) #endif
+#define MS_EBDT_TAG MS_MAKE_TAG('E','B','D','T') + /* 'gasp' flags */ #define GASP_GRIDFIT 0x01 #define GASP_DOGRAY 0x02 @@ -1177,6 +1179,8 @@ static struct unix_face *unix_face_create( const char *unix_name, void *data_ptr struct stat st; DWORD face_count; int fd, length; + FT_Error error; + FT_ULong len;
TRACE( "unix_name %s, face_index %u, data_ptr %p, data_size %u, flags %#x\n", unix_name, face_index, data_ptr, data_size, flags ); @@ -1268,7 +1272,20 @@ static struct unix_face *unix_face_create( const char *unix_name, void *data_ptr
This->ntm_flags = get_ntm_flags( This->ft_face ); This->font_version = get_font_version( This->ft_face ); - if (!This->scalable) get_bitmap_size( This->ft_face, &This->size ); + if (!This->scalable) + { + error = pFT_Load_Sfnt_Table( This->ft_face, RtlUlongByteSwap(MS_EBDT_TAG), 0, NULL, &len ); + if (error == FT_Err_Table_Missing) + { + WARN( "EBDT table is missing in bitmap only font %s.\n", + debugstr_w(ft_face_get_family_name( This->ft_face, system_lcid ))); + pFT_Done_Face( This->ft_face ); + free( This ); + This = NULL; + goto done; + } + get_bitmap_size( This->ft_face, &This->size ); + } get_fontsig( This->ft_face, &This->fs ); } else
I don't think we should reject such fonts. NotoColorEmoji.ttf does have bitmap data, in a form of CBDT table.
Do you think that maybe opentype path can be improved to support it? Or we can otherwise make GetOutLineGlyphMetrics() work? It seems to me that in current state such font, how we load it, is unusable, and can only break apps but not be really used.
Which one is the opentype path? Or rather, where exactly does GetOutlineTextMetrics() break when EBDT is missing? I didn't follow closely "recent" (year or two) changes in gdi32/win32u font handling. My guess is that freetype is capable to return grayscale bitmap for color png, rgba, or whatever format CBDT provides, is that correct? If it works this way, metrics data should be functionally equivalent between CBLC and EBLC tables.
On 7/9/22 13:05, Nikolay Sivov (@nsivov) wrote:
Which one is the opentype path? Or rather, where exactly does GetOutlineTextMetrics() break when EBDT is missing? I didn't follow closely "recent" (year or two) changes in gdi32/win32u font handling. My guess is that freetype is capable to return grayscale bitmap for color png, rgba, or whatever format CBDT provides, is that correct? If it works this way, metrics data should be functionally equivalent between CBLC and EBLC tables.
By "opentype path" I mean the path initialized in unix_face_create() (win32u/freetype.c) if opentype_get_ttc_sfnt_v1, opentype_get_tt_name_v0 and opentype_get_properties succeeds and when it doesn't use freetype library. GetOutlineTextMetrics() always return 0 for fonts marked as not scalable (happens for bitmap only fonts in "freetype" path). In fact, I guess it is possible that current handling of any bitmap-only ttf font is problematic, but those fonts seem to be exceptionally rare and in fact I could not immediately find just any public font like that.
With the font in question it is not just that GetOutlineTextMetrics() returns 0, I tried using this font for rendering emojis in Wine with static control and it doesn't display anything. My understanding that such a font is currently non-functional in Wine. I actually started this patch from trying to understand how to make it functional instead of rejecting, but I feel like I am missing the grounds on which I can test the behaviour to think of fixing it: this specific font doesn't load on Windows, doesn't load with fontforge on Linux and doesn't seem to work in Wine currently. Do you have any ideas what can be the basis for correct behaviour here? Or maybe it would still make sense not load the fonts we can't properly handle now anyway?
On Mon Jul 11 14:53:55 2022 +0000, Ghost User wrote:
Paul Gofman replied on the mailing list:
On 7/9/22 13:05, Nikolay Sivov (@nsivov) wrote: > Which one is the opentype path? Or rather, where exactly does GetOutlineTextMetrics() break when EBDT is missing? I didn't follow closely "recent" (year or two) changes in gdi32/win32u font handling. My guess is that freetype is capable to return grayscale bitmap for color png, rgba, or whatever format CBDT provides, is that correct? If it works this way, metrics data should be functionally equivalent between CBLC and EBLC tables. > By "opentype path" I mean the path initialized in unix_face_create() (win32u/freetype.c) if opentype_get_ttc_sfnt_v1, opentype_get_tt_name_v0 and opentype_get_properties succeeds and when it doesn't use freetype library. GetOutlineTextMetrics() always return 0 for fonts marked as not scalable (happens for bitmap only fonts in "freetype" path). In fact, I guess it is possible that current handling of any bitmap-only ttf font is problematic, but those fonts seem to be exceptionally rare and in fact I could not immediately find just any public font like that. With the font in question it is not just that GetOutlineTextMetrics() returns 0, I tried using this font for rendering emojis in Wine with static control and it doesn't display anything. My understanding that such a font is currently non-functional in Wine. I actually started this patch from trying to understand how to make it functional instead of rejecting, but I feel like I am missing the grounds on which I can test the behaviour to think of fixing it: this specific font doesn't load on Windows, doesn't load with fontforge on Linux and doesn't seem to work in Wine currently. Do you have any ideas what can be the basis for correct behaviour here? Or maybe it would still make sense not load the fonts we can't properly handle now anyway? _______________________________________________ wine-gitlab mailing list -- wine-gitlab@winehq.org To unsubscribe send an email to wine-gitlab-leave@winehq.org
Ok, so what would be a test program for this that imitates what application is doing? Do you know why application is using this font in a first place? Does it iterate over all of them? Freetype is indeed capable of handling it, both with or without color, as ftview shows.
On Wed Jul 27 16:19:20 2022 +0000, Nikolay Sivov wrote:
Ok, so what would be a test program for this that imitates what application is doing? Do you know why application is using this font in a first place? Does it iterate over all of them? Freetype is indeed capable of handling it, both with or without color, as ftview shows.
I didn't see application actually trying to use it, it just loads it along with a bunch of other fonts and breaks with division by zero exception when GetOutlineTextMetrics() is not working (probably just finding the font through some enumeration).
My test program tries to load that ttf file and that doesn't work on Windows, my initial understanding was that we shouldn't as well if it breaks things. This ttf apparently can't be used on Windows through Windows functions, if only an app will load and render it directly without using winapi for that.
An interesting test case would be to see how some real-life bitmap only or color bitmap only ttf behaves on Windows if it can be loaded, do you have such an example in mind? I was struggling to find one but could not. Maybe such ttf are not supported on Windows at all?
On Wed Jul 27 16:27:38 2022 +0000, Paul Gofman wrote:
I didn't see application actually trying to use it, it just loads it along with a bunch of other fonts and breaks with division by zero exception when GetOutlineTextMetrics() is not working (probably just finding the font through some enumeration). My test program tries to load that ttf file and that doesn't work on Windows, my initial understanding was that we shouldn't as well if it breaks things. This ttf apparently can't be used on Windows through Windows functions, if only an app will load and render it directly without using winapi for that. An interesting test case would be to see how some real-life bitmap only or color bitmap only ttf behaves on Windows if it can be loaded, do you have such an example in mind? I was struggling to find one but could not. Maybe such ttf are not supported on Windows at all?
Otherwise, we could probably just try to implement GetOutlineTextMetrics() somehow for bitmap only fonts if we need such fonts supported? And then there are probably more missing bits so that font can be actually rendered through gdi functions.
On Wed Jul 27 16:30:00 2022 +0000, Paul Gofman wrote:
Otherwise, we could probably just try to implement GetOutlineTextMetrics() somehow for bitmap only fonts if we need such fonts supported? And then there are probably more missing bits so that font can be actually rendered through gdi functions.
The trick to have it working on Windows might be to have empty glyf table, example of that is https://font.gohu.org/gohufont-2.1-otb.tar.gz . They call it OTB, but that's not a thing in itself, it's a regular sfnt container obviously. It's using EBDT, but still has glyf table with no outlines.
On Wed Jul 27 19:47:07 2022 +0000, Nikolay Sivov wrote:
The trick to have it working on Windows might be to have empty glyf table, example of that is https://font.gohu.org/gohufont-2.1-otb.tar.gz . They call it OTB, but that's not a thing in itself, it's a regular sfnt container obviously. It's using EBDT, but still has glyf table with no outlines.
Ah, I found now this https://github.com/googlefonts/noto-emoji/tree/main/fonts , they have _WindowsCompatible variant there, with same empty glyf table. Windows is likely to do some validation that's too strict in practice.
On Wed Jul 27 19:48:16 2022 +0000, Nikolay Sivov wrote:
Ah, I found now this https://github.com/googlefonts/noto-emoji/tree/main/fonts , they have _WindowsCompatible variant there, with same empty glyf table. Windows is likely to do some validation that's too strict in practice.
Thanks a lot. I loaded that font on Windows and saw that: - it fails GetOutlineTextMetrics() the same way as with Wine; - being installed, it is enumerated; moreso, it has TMPF_VECTOR, TMPF_TRUETYPE flags in text metrics structure during enumeration (GetTextMetrics() fails as well though);
The launcher still worked on Windows even with that font installed so I looked at it further. It turns out this font usage comes from Qt (so currently the font probably breaks many Qt apps). I looked at the source code here: https://download.qt.io/archive/qt/5.12/5.12.0/single/. Interesting things mostly happen in qtbase/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp.
After looking at the code I tested GetFontData('cmap' tag) and figured that it fails on Windows for the font (with the same ERROR_INVALID_HANDLE error code as GetOutlineTextMetrics, GetTextMertics), while GetFontData currently succeeds on Wine. That fails for other tables (which are present in the ttf) as well. Failing GetFontData in Wine helps the launcher.
So it seems to me that once text metrics can't be retrieved for font GetFontData() also fails. Should we maybe do that?
Is there an update on merging this change? One Qt app I use actually throws an ACCESS_VIOLATION exception before loading the main window without it :frog: