[PATCH v2 0/2] MR10672: win32u: Initialize Uniscribe fallback registry keys on startup.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=27641 @aricstewart I thought about the trade-offs between the two approaches (this and https://gitlab.winehq.org/wine/wine/-/merge_requests/10630) and finally decided to go through with this, because this would allow for a more better UX. How does this look? If it looks better, we can close the previous MR. Also I will open a separate MR for the script tag, which will hopefully have a better solution than just using one script tag for a script. -- v2: win32u: Initialize Uniscribe fallback registry keys on startup. win32u: Implement fontconfig_get_default_font_for_char(). https://gitlab.winehq.org/wine/wine/-/merge_requests/10672
From: समीर सिंह Sameer Singh <lumarzeli30@gmail.com> This would allow Uniscribe to dynamically populate script based fallback mappings in the registry based on the system's available fonts. --- dlls/win32u/freetype.c | 45 +++++++++++++++++++++++++++++++++++++ dlls/win32u/ntgdi_private.h | 1 + 2 files changed, 46 insertions(+) diff --git a/dlls/win32u/freetype.c b/dlls/win32u/freetype.c index a660b166a0f..b5238ab337c 100644 --- a/dlls/win32u/freetype.c +++ b/dlls/win32u/freetype.c @@ -131,6 +131,10 @@ MAKE_FUNCPTR(FcDefaultSubstitute); MAKE_FUNCPTR(FcFontList); MAKE_FUNCPTR(FcFontMatch); MAKE_FUNCPTR(FcFontSetDestroy); +MAKE_FUNCPTR(FcCharSetAddChar); +MAKE_FUNCPTR(FcCharSetCreate); +MAKE_FUNCPTR(FcCharSetDestroy); +MAKE_FUNCPTR(FcPatternAddCharSet); MAKE_FUNCPTR(FcInit); MAKE_FUNCPTR(FcPatternAddString); MAKE_FUNCPTR(FcPatternCreate); @@ -1249,6 +1253,10 @@ static void init_fontconfig(void) LOAD_FUNCPTR(FcFontList); LOAD_FUNCPTR(FcFontMatch); LOAD_FUNCPTR(FcFontSetDestroy); + LOAD_FUNCPTR(FcCharSetAddChar); + LOAD_FUNCPTR(FcCharSetCreate); + LOAD_FUNCPTR(FcCharSetDestroy); + LOAD_FUNCPTR(FcPatternAddCharSet); LOAD_FUNCPTR(FcInit); LOAD_FUNCPTR(FcPatternAddString); LOAD_FUNCPTR(FcPatternCreate); @@ -2027,6 +2035,42 @@ static BOOL fontconfig_enum_family_fallbacks( UINT pitch_and_family, int index, return FALSE; } +/************************************************************* + * fontconfig_get_default_font_for_char + */ +static void fontconfig_get_default_font_for_char( DWORD ch, WCHAR *font_name ) +{ +#ifdef SONAME_LIBFONTCONFIG + FcPattern *pattern, *match; + FcResult result; + const char *name = NULL; + FcCharSet *charset; + DWORD len; + + *font_name = 0; + + pattern = pFcPatternCreate(); + charset = pFcCharSetCreate(); + pFcCharSetAddChar( charset, ch ); + pFcPatternAddCharSet( pattern, FC_CHARSET, charset ); + pFcCharSetDestroy( charset ); + + pFcConfigSubstitute( NULL, pattern, FcMatchPattern ); + pFcDefaultSubstitute( pattern ); + match = pFcFontMatch( NULL, pattern, &result ); + if (match) + { + if (pFcPatternGetString( match, FC_FAMILY, 0, (FcChar8 **)&name ) == FcResultMatch && name) + { + RtlUTF8ToUnicodeN( font_name, (LF_FACESIZE - 1) * sizeof(WCHAR), &len, name, strlen(name) ); + font_name[len / sizeof(WCHAR)] = 0; + } + pFcPatternDestroy( match ); + } + pFcPatternDestroy( pattern ); +#endif +} + static DWORD get_ttc_offset( FT_Face ft_face, UINT face_index ) { FT_ULong len; @@ -3873,6 +3917,7 @@ static UINT freetype_get_kerning_pairs( struct gdi_font *font, KERNINGPAIR **pai static const struct font_backend_funcs font_funcs = { freetype_load_fonts, + fontconfig_get_default_font_for_char, fontconfig_enum_family_fallbacks, freetype_add_font, freetype_add_mem_font, diff --git a/dlls/win32u/ntgdi_private.h b/dlls/win32u/ntgdi_private.h index fcfbce58fea..ac77d2aa6ed 100644 --- a/dlls/win32u/ntgdi_private.h +++ b/dlls/win32u/ntgdi_private.h @@ -320,6 +320,7 @@ struct gdi_font struct font_backend_funcs { void (*load_fonts)(void); + void (*get_default_font_for_char)( DWORD ch, WCHAR *font_name ); BOOL (*enum_family_fallbacks)( UINT pitch_and_family, int index, WCHAR buffer[LF_FACESIZE] ); INT (*add_font)( const WCHAR *file, UINT flags ); INT (*add_mem_font)( void *ptr, SIZE_T size, UINT flags ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10672
From: समीर सिंह Sameer Singh <lumarzeli30@gmail.com> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=27641 --- dlls/win32u/font.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/dlls/win32u/font.c b/dlls/win32u/font.c index e34cb13d0e5..e921f2f4ffd 100644 --- a/dlls/win32u/font.c +++ b/dlls/win32u/font.c @@ -6700,6 +6700,83 @@ static void load_registry_fonts(void) NtClose( hkey ); } +static void init_uniscribe_fallbacks(void) +{ + HKEY hkey; + DWORD disp; + WCHAR font_name[LF_FACESIZE]; + int i; + + /* Table kept in sync with scriptInformation[] in dlls/gdi32/uniscribe/usp10.c */ + static const struct + { + DWORD ch; + DWORD tag; + } + fallbacks[] = + { + {0x0531, MS_MAKE_TAG('a', 'r', 'm', 'n')}, + {0x05d0, MS_MAKE_TAG('h', 'e', 'b', 'r')}, + {0x0627, MS_MAKE_TAG('a', 'r', 'a', 'b')}, + {0x0710, MS_MAKE_TAG('s', 'y', 'r', 'c')}, + {0x0780, MS_MAKE_TAG('t', 'h', 'a', 'a')}, + {0x07c0, MS_MAKE_TAG('n', 'k', 'o', ' ')}, + {0x0905, MS_MAKE_TAG('d', 'e', 'v', 'a')}, + {0x0985, MS_MAKE_TAG('b', 'e', 'n', 'g')}, + {0x0a05, MS_MAKE_TAG('g', 'u', 'r', 'u')}, + {0x0a85, MS_MAKE_TAG('g', 'u', 'j', 'r')}, + {0x0b05, MS_MAKE_TAG('o', 'r', 'y', 'a')}, + {0x0b85, MS_MAKE_TAG('t', 'a', 'm', 'l')}, + {0x0c05, MS_MAKE_TAG('t', 'e', 'l', 'u')}, + {0x0c85, MS_MAKE_TAG('k', 'n', 'd', 'a')}, + {0x0d05, MS_MAKE_TAG('m', 'l', 'y', 'm')}, + {0x0d85, MS_MAKE_TAG('s', 'i', 'n', 'h')}, + {0x0e01, MS_MAKE_TAG('t', 'h', 'a', 'i')}, + {0x0e81, MS_MAKE_TAG('l', 'a', 'o', ' ')}, + {0x0f40, MS_MAKE_TAG('t', 'i', 'b', 't')}, + {0x10a0, MS_MAKE_TAG('g', 'e', 'o', 'r')}, + {0x1000, MS_MAKE_TAG('m', 'y', 'm', 'r')}, + {0x1200, MS_MAKE_TAG('e', 't', 'h', 'i')}, + {0x13a0, MS_MAKE_TAG('c', 'h', 'e', 'r')}, + {0x1401, MS_MAKE_TAG('c', 'a', 'n', 's')}, + {0x1681, MS_MAKE_TAG('o', 'g', 'a', 'm')}, + {0x16a0, MS_MAKE_TAG('r', 'u', 'n', 'r')}, + {0x1780, MS_MAKE_TAG('k', 'h', 'm', 'r')}, + {0x1820, MS_MAKE_TAG('m', 'o', 'n', 'g')}, + {0x1950, MS_MAKE_TAG('t', 'a', 'l', 'o')}, + {0x1980, MS_MAKE_TAG('t', 'a', 'l', 'u')}, + {0x2801, MS_MAKE_TAG('b', 'r', 'a', 'i')}, + {0x2d30, MS_MAKE_TAG('t', 'f', 'n', 'g')}, + {0x3041, MS_MAKE_TAG('k', 'a', 'n', 'a')}, + {0x3105, MS_MAKE_TAG('b', 'o', 'p', 'o')}, + {0x4e00, MS_MAKE_TAG('h', 'a', 'n', 'i')}, + {0xa840, MS_MAKE_TAG('p', 'h', 'a', 'g')}, + {0xac00, MS_MAKE_TAG('h', 'a', 'n', 'g')}, + {0xa000, MS_MAKE_TAG('y', 'i', ' ', ' ')}, + {0xa500, MS_MAKE_TAG('v', 'a', 'i', ' ')}, + {0x10400, MS_MAKE_TAG('d', 's', 'r', 't')}, + {0x10480, MS_MAKE_TAG('o', 's', 'm', 'a')}, + {0x1d400, MS_MAKE_TAG('m', 'a', 't', 'h')}, + }; + + hkey = reg_create_ascii_key(hkcu_key, "Software\\Wine\\Uniscribe\\Fallback", 0, &disp); + if (!hkey) return; + + for (i = 0; i < ARRAY_SIZE(fallbacks); i++) + { + font_funcs->get_default_font_for_char(fallbacks[i].ch, font_name); + if (font_name[0]) + { + WCHAR nameW[9]; + char tag_str[9]; + sprintf(tag_str, "%x", fallbacks[i].tag); + ascii_to_unicode(nameW, tag_str, strlen(tag_str) + 1); + set_reg_value(hkey, nameW, REG_SZ, font_name, (lstrlenW(font_name) + 1) * sizeof(WCHAR)); + } + } + NtClose(hkey); +} + static HKEY open_hkcu(void) { char buffer[256]; @@ -6781,6 +6858,7 @@ UINT font_init(void) reorder_font_list(); load_gdi_font_subst(); load_gdi_font_replacements(); + init_uniscribe_fallbacks(); load_system_links(); dump_gdi_font_list(); dump_gdi_font_subst(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10672
Ok a few questions. I see it is using freetype to query the default font for a given script for the system. and the populating the fallback section of the registry. This would mean even if the user as installed the normal fallback for a script, such as Mangal for Devanagari, if that font is not the default font for the script on their system they will not end up using that font. It feels like it could be a bit counter-intuitive. Additionally if the user/application sets the fallback for a given script then this code will blow that away and replace it unconditionally. Also feels like it could be an issue. What I think I would be more comfortable with, would be having a default fallback, which is the same as Windows, and then have a system fallback that we could then populate. So you also update the font search in usp10 `ScriptStringAnalyse` and `find_fallback_font` so that it tries the default fallback and if that fails tries the system fallback. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10672#note_137761
participants (3)
-
Aric Stewart (@aricstewart) -
समीर सिंह Sameer Singh -
समीरसिंह Sameer Singh (@ss141309)