[PATCH v2 0/1] MR9480: win32u: Fix broken otmfsType flag generation.
Freetype uses a function to get the licensing flags, FT_Get_FSType_Flags(), and it's non-trivial. (See also: https://freetype.org/freetype2/docs/reference/ft2-information_retrieval.html...) Use FF's function to get the proper flags, and then set otmfsType based on them. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58987 -- v2: win32u: Fix broken otmfsType flag generation. https://gitlab.winehq.org/wine/wine/-/merge_requests/9480
From: Patrick Hibbs <hibbsncc1701(a)gmail.com> Freetype uses a function to get the licensing flags, FT_Get_FSType_Flags(), and it's non-trivial. (See also: https://freetype.org/freetype2/docs/reference/ft2-information_retrieval.html...) Use FF's function to get the proper flags, and then set otmfsType based on them. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58987 --- dlls/win32u/freetype.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/dlls/win32u/freetype.c b/dlls/win32u/freetype.c index aeae190bc46..97e802230be 100644 --- a/dlls/win32u/freetype.c +++ b/dlls/win32u/freetype.c @@ -92,6 +92,7 @@ static void *ft_handle = NULL; MAKE_FUNCPTR(FT_Done_Face); MAKE_FUNCPTR(FT_Get_Char_Index); MAKE_FUNCPTR(FT_Get_First_Char); +MAKE_FUNCPTR(FT_Get_FSType_Flags); MAKE_FUNCPTR(FT_Get_Next_Char); MAKE_FUNCPTR(FT_Get_Sfnt_Name); MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count); @@ -1470,6 +1471,7 @@ static BOOL init_freetype(void) LOAD_FUNCPTR(FT_Done_Face) LOAD_FUNCPTR(FT_Get_Char_Index) LOAD_FUNCPTR(FT_Get_First_Char) + LOAD_FUNCPTR(FT_Get_FSType_Flags) LOAD_FUNCPTR(FT_Get_Next_Char) LOAD_FUNCPTR(FT_Get_Sfnt_Name) LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count) @@ -3313,7 +3315,7 @@ static BOOL face_has_symbol_charmap(FT_Face ft_face) static BOOL freetype_set_outline_text_metrics( struct gdi_font *font ) { FT_Face ft_face = get_ft_face( font ); - UINT needed; + UINT needed, ff_fsflags; TT_OS2 *pOS2; TT_HoriHeader *pHori; TT_Postscript *pPost; @@ -3532,7 +3534,16 @@ static BOOL freetype_set_outline_text_metrics( struct gdi_font *font ) if (font->fake_bold) font->otm.otmfsSelection |= 1 << 5; /* Only return valid bits that define embedding and subsetting restrictions */ - font->otm.otmfsType = pOS2->fsType & 0x30e; + font->otm.otmfsType = 0; /* FT_FSTYPE_INSTALLABLE_EMBEDDING */ + ff_fsflags = pFT_Get_FSType_Flags(ft_face); + if ((ff_fsflags & FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING) || + (ff_fsflags & FT_FSTYPE_NO_SUBSETTING) || + (ff_fsflags & FT_FSTYPE_BITMAP_EMBEDDING_ONLY)) + font->otm.otmfsType |= 1 << 1; /* Bit 1: No-embedding flag. */ + if (ff_fsflags & FT_FSTYPE_PREVIEW_AND_PRINT_EMBEDDING) + font->otm.otmfsType |= 1 << 2; /* Bit 2: Read-Only flag. */ + if (ff_fsflags & FT_FSTYPE_EDITABLE_EMBEDDING) + font->otm.otmfsType |= 1 << 3; /* Bit 3: Editable flag? */ font->otm.otmsCharSlopeRise = pHori->caret_Slope_Rise; font->otm.otmsCharSlopeRun = pHori->caret_Slope_Run; font->otm.otmItalicAngle = 0; /* POST table */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9480
I don't think we need freetype for that. We already have the value, and can mask it as needed. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9480#note_143788
On Mon Jun 22 07:44:18 2026 +0000, Nikolay Sivov wrote:
I don't think we need freetype for that. We already have the value, and can mask it as needed. With wine-11.11 on my Debian system, the value is uninitialized and changes in-between calls to EnumFontFamiliesExA()'s callback function. The result is that the masked off value returned by GetOutlineTextMetricsA() cannot be used to get the font's licensing flag reliably, and apps that depend on it, (for legal reasons), wind up using fonts that they shouldn't or avoid fonts that they should use.
On the linked freetype documentation, they also say to use this function instead of relying on that value: ``` Use this function rather than directly reading the fs_type field in the PS_FontInfoRec structure, which is only guaranteed to return the correct results for Type 1 fonts. ``` -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9480#note_143793
On Mon Jun 22 07:44:18 2026 +0000, Patrick Hibbs wrote:
With wine-11.11 on my Debian system, the value is uninitialized and changes in-between calls to EnumFontFamiliesExA()'s callback function. The result is that the masked off value returned by GetOutlineTextMetricsA() cannot be used to get the font's licensing flag reliably, and apps that depend on it, (for legal reasons), wind up using fonts that they shouldn't or avoid fonts that they should use. On the linked freetype documentation, they also say to use this function instead of relying on that value: ``` Use this function rather than directly reading the fs_type field in the PS_FontInfoRec structure, which is only guaranteed to return the correct results for Type 1 fonts. ``` I'm not saying it shouldn't be fixed if it doesn't work right, but using library function for that seems unnecessary. And I don't think we ever supported Type 1 fonts. This code path is for when you have OS/2 table. Could you link to fonts that fail for you specifically?
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/9480#note_143798
On Mon Jun 22 07:53:22 2026 +0000, Nikolay Sivov wrote:
I'm not saying it shouldn't be fixed if it doesn't work right, but using library function for that seems unnecessary. And I don't think we ever supported Type 1 fonts. This code path is for when you have OS/2 table. Could you link to fonts that fail for you specifically? Some examples from different runs: (Note: The first value after the font name on the successful lines is the otmfsType value.)
``` 00fc:warn:debugstr:OutputDebugStringA "248 252 LoadWindowsFontFromMem_GetSize_Helper Result for font Liberation Sans 410820 0x0\n" 00fc:warn:debugstr:OutputDebugStringA "248 252 LoadWindowsFontFromMem Font considered valid. Attempting to import Liberation Sans into ImGui.\n" 00fc:warn:debugstr:OutputDebugStringA "248 252 LoadWindowsFontFromMem_GetSize_Helper Result for font Droid Sans Fallback 4033420 0x0\n" 00fc:warn:debugstr:OutputDebugStringA "248 252 LoadWindowsFontFromMem Font considered valid. Attempting to import Droid Sans Fallback into ImGui.\n" ``` ``` 00ec:warn:debugstr:OutputDebugStringA "232 236 LoadWindowsFontFromMem Licensing failure. Cannot use font Liberation Sans. otmfsType data: 0x6fff.\n" 00ec:warn:debugstr:OutputDebugStringA "232 236 LoadWindowsFontFromMem Licensing failure. Cannot use font Liberation Mono. otmfsType data: 0x6fff.\n" 00ec:warn:debugstr:OutputDebugStringA "232 236 LoadWindowsFontFromMem Licensing failure. Cannot use font Liberation Serif. otmfsType data: 0x6fff.\n" 00ec:warn:debugstr:OutputDebugStringA "232 236 LoadWindowsFontFromMem Licensing failure. Cannot use font Abyssinica SIL. otmfsType data: 0x80750007.\n" 00ec:warn:debugstr:OutputDebugStringA "232 236 LoadWindowsFontFromMem_GetSize_Helper Result for font Aerial 48260 0x0\n" 00ec:warn:debugstr:OutputDebugStringA "232 236 LoadWindowsFontFromMem Font considered valid. Attempting to import Aerial into ImGui.\n" ``` ``` 00ec:warn:debugstr:OutputDebugStringA "232 236 LoadWindowsFontFromMem Licensing failure. Cannot use font Dejima. otmfsType data: 0x6fff.\n" 00ec:warn:debugstr:OutputDebugStringA "232 236 LoadWindowsFontFromMem Licensing failure. Cannot use font Droid Sans Fallback. otmfsType data: 0x6fff.\n" 00ec:warn:debugstr:OutputDebugStringA "232 236 LoadWindowsFontFromMem Licensing failure. Cannot use font Droid Sans Fallback. otmfsType data: 0x6fff.\n" 00ec:warn:debugstr:OutputDebugStringA "232 236 LoadWindowsFontFromMem_GetSize_Helper Result for font KanjiStrokeOrders 18063056 0x0\n" 00ec:warn:debugstr:OutputDebugStringA "232 236 LoadWindowsFontFromMem Font considered valid. Attempting to import KanjiStrokeOrders into ImGui.\n" ``` Unfortunately, it's random. Sometimes a given font works, other times it doesn't. The worse case scenario is ImGui falling back to it's internal font when no font manages to pass the checks. (The version used has poor anti-aliasing support.) In some cases I've even gotten *cursive* fonts instead of the normal block script fonts, which is *very* disorienting to users. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9480#note_143806
On Mon Jun 22 08:17:08 2026 +0000, Patrick Hibbs wrote:
Some examples from different runs: (Note: The first value after the font name on the successful lines is the otmfsType value.) ``` 00fc:warn:debugstr:OutputDebugStringA "248 252 LoadWindowsFontFromMem_GetSize_Helper Result for font Liberation Sans 410820 0x0\n" 00fc:warn:debugstr:OutputDebugStringA "248 252 LoadWindowsFontFromMem Font considered valid. Attempting to import Liberation Sans into ImGui.\n" 00fc:warn:debugstr:OutputDebugStringA "248 252 LoadWindowsFontFromMem_GetSize_Helper Result for font Droid Sans Fallback 4033420 0x0\n" 00fc:warn:debugstr:OutputDebugStringA "248 252 LoadWindowsFontFromMem Font considered valid. Attempting to import Droid Sans Fallback into ImGui.\n" ``` ``` 00ec:warn:debugstr:OutputDebugStringA "232 236 LoadWindowsFontFromMem Licensing failure. Cannot use font Liberation Sans. otmfsType data: 0x6fff.\n" 00ec:warn:debugstr:OutputDebugStringA "232 236 LoadWindowsFontFromMem Licensing failure. Cannot use font Liberation Mono. otmfsType data: 0x6fff.\n" 00ec:warn:debugstr:OutputDebugStringA "232 236 LoadWindowsFontFromMem Licensing failure. Cannot use font Liberation Serif. otmfsType data: 0x6fff.\n" 00ec:warn:debugstr:OutputDebugStringA "232 236 LoadWindowsFontFromMem Licensing failure. Cannot use font Abyssinica SIL. otmfsType data: 0x80750007.\n" 00ec:warn:debugstr:OutputDebugStringA "232 236 LoadWindowsFontFromMem_GetSize_Helper Result for font Aerial 48260 0x0\n" 00ec:warn:debugstr:OutputDebugStringA "232 236 LoadWindowsFontFromMem Font considered valid. Attempting to import Aerial into ImGui.\n" ``` ``` 00ec:warn:debugstr:OutputDebugStringA "232 236 LoadWindowsFontFromMem Licensing failure. Cannot use font Dejima. otmfsType data: 0x6fff.\n" 00ec:warn:debugstr:OutputDebugStringA "232 236 LoadWindowsFontFromMem Licensing failure. Cannot use font Droid Sans Fallback. otmfsType data: 0x6fff.\n" 00ec:warn:debugstr:OutputDebugStringA "232 236 LoadWindowsFontFromMem Licensing failure. Cannot use font Droid Sans Fallback. otmfsType data: 0x6fff.\n" 00ec:warn:debugstr:OutputDebugStringA "232 236 LoadWindowsFontFromMem_GetSize_Helper Result for font KanjiStrokeOrders 18063056 0x0\n" 00ec:warn:debugstr:OutputDebugStringA "232 236 LoadWindowsFontFromMem Font considered valid. Attempting to import KanjiStrokeOrders into ImGui.\n" ``` Unfortunately, it's random. Sometimes a given font works, other times it doesn't. The worse case scenario is ImGui falling back to it's internal font when no font manages to pass the checks. (The version used has poor anti-aliasing support.) In some cases I've even gotten *cursive* fonts instead of the normal block script fonts, which is *very* disorienting to users. I should also point out that this happens with the Debian host's builtin fonts, Debian's fonts from their repos, as well as any fonts placed into C:\Windows\Fonts.
It's not limited to any specific font or source. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9480#note_143808
On Mon Jun 22 08:21:49 2026 +0000, Patrick Hibbs wrote:
I should also point out that this happens with the Debian host's builtin fonts, Debian's fonts from their repos, as well as any fonts placed into C:\Windows\Fonts. It's not limited to any specific font or source. To test anything about this we'll need specific font files. Also, if returned masks change over type for the same font, it indicates some other issue.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/9480#note_143809
On Mon Jun 22 08:24:32 2026 +0000, Nikolay Sivov wrote:
To test anything about this we'll need specific font files. Also, if returned masks change over type for the same font, it indicates some other issue. Fonts used:
[Liberation Sans, Liberation Mono, Liberation Serif](https://packages.debian.org/trixie/all/fonts-liberation/download) [Droid Sans Fallback](https://packages.debian.org/trixie/all/fonts-droid-fallback/download) [KanjiStrokeOrders](https://packages.debian.org/trixie/all/fonts-kanjistrokeorders/download) [Dejima](https://packages.debian.org/trixie/all/fonts-dejima-mincho/download) [Abyssinica SIL](https://packages.debian.org/trixie/all/fonts-sil-abyssinica/download) As for Aerial I believe it was just a symlink to another font for compatibility purposes, but I've since upgraded the system and that link is no longer there. So I can't say what it was. As for the PR itself, when I made the patch and put it into wine, the result of calling GetOutlineTextMetricsA() became consistent between callback calls on my system. If this is a problem from elsewhere, then at the very least, the freetype_set_outline_text_metrics() call is the last place in the call chain that will determine it's value. (Or nothing else alters it on my system.) -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9480#note_143815
participants (4)
-
Nikolay Sivov (@nsivov) -
Patrick Hibbs -
Patrick Hibbs (@hibbsncc1701) -
Patrick Hibbs (@hibbsncc1701)