I have investigated `GdipGetGenericFontFamily*` functions from native gdiplus.dll.
The result of investigation * GdipGetGenericFontFamilySansSerif: is taking first `"Microsoft Sans Serif"` font, then `Arial` [(here is the comparison)](http://www.identifont.com/differences?first=Microsoft+Sans+Serif&second=...). The replacement for Arial is `"Liberation Sans"`. [(here is the comparison)](http://www.identifont.com/differences?first=Liberation+Sans&second=Arial...). If these fonts are not found then [`Tahoma` is taken.](http://www.identifont.com/differences?first=Liberation+Sans&second=Tahom...)
* GdipGetGenericFontFamilySerif: If `"Times New Roman"` is not found, then the fonts from `FamilySansSerif` is taken. * GdipGetGenericFontFamilyMonospace: If `"Courier New"` is not found, then the fonts from `FamilySansSerif` is taken.
It seems that most risky was previous implementation of `GdipGetGenericFontFamilySansSerif`, as it used only priopritary fonts. With proposed solution all `GdipGetGenericFontFamily*` functions have free replacement from Liberation fonts.
More information about Liberation Fonts: https://en.wikipedia.org/wiki/Liberation_fonts
-- v6: gdiplus: Fix GdipGetGenericFontFamily functions according to native gdiplus.dll
From: Bartosz Kosiorek gang65@poczta.onet.pl
--- dlls/gdiplus/font.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-)
diff --git a/dlls/gdiplus/font.c b/dlls/gdiplus/font.c index bcf36a60090..8b85f567aab 100644 --- a/dlls/gdiplus/font.c +++ b/dlls/gdiplus/font.c @@ -969,19 +969,22 @@ GpStatus WINGDIPAPI GdipIsStyleAvailable(GDIPCONST GpFontFamily* family, /***************************************************************************** * GdipGetGenericFontFamilyMonospace [GDIPLUS.@] * - * Obtains a serif family (Courier New on Windows) + * Obtains a monospace family (Courier New on Windows) * * PARAMS - * **nativeFamily [I] Where the font will be stored + * **nativeFamily [O] Where the font will be stored * * RETURNS * InvalidParameter if nativeFamily is NULL. + * FontFamilyNotFound if unable to get font. * Ok otherwise. */ GpStatus WINGDIPAPI GdipGetGenericFontFamilyMonospace(GpFontFamily **nativeFamily) { GpStatus stat;
+ TRACE("(%p)\n", nativeFamily); + if (nativeFamily == NULL) return InvalidParameter;
stat = GdipCreateFontFamilyFromName(L"Courier New", NULL, nativeFamily); @@ -990,7 +993,7 @@ GpStatus WINGDIPAPI GdipGetGenericFontFamilyMonospace(GpFontFamily **nativeFamil stat = GdipCreateFontFamilyFromName(L"Liberation Mono", NULL, nativeFamily);
if (stat == FontFamilyNotFound) - ERR("Missing 'Courier New' font\n"); + stat = GdipCreateFontFamilyFromName(L"Courier", NULL, nativeFamily);
return stat; } @@ -1001,10 +1004,11 @@ GpStatus WINGDIPAPI GdipGetGenericFontFamilyMonospace(GpFontFamily **nativeFamil * Obtains a serif family (Times New Roman on Windows) * * PARAMS - * **nativeFamily [I] Where the font will be stored + * **nativeFamily [O] Where the font will be stored * * RETURNS * InvalidParameter if nativeFamily is NULL. + * FontFamilyNotFound if unable to get font. * Ok otherwise. */ GpStatus WINGDIPAPI GdipGetGenericFontFamilySerif(GpFontFamily **nativeFamily) @@ -1021,7 +1025,7 @@ GpStatus WINGDIPAPI GdipGetGenericFontFamilySerif(GpFontFamily **nativeFamily) stat = GdipCreateFontFamilyFromName(L"Liberation Serif", NULL, nativeFamily);
if (stat == FontFamilyNotFound) - ERR("Missing 'Times New Roman' font\n"); + stat = GdipGetGenericFontFamilySansSerif(nativeFamily);
return stat; } @@ -1029,13 +1033,14 @@ GpStatus WINGDIPAPI GdipGetGenericFontFamilySerif(GpFontFamily **nativeFamily) /***************************************************************************** * GdipGetGenericFontFamilySansSerif [GDIPLUS.@] * - * Obtains a serif family (Microsoft Sans Serif on Windows) + * Obtains a sans serif family (Microsoft Sans Serif or Arial on Windows) * * PARAMS - * **nativeFamily [I] Where the font will be stored + * **nativeFamily [O] Where the font will be stored * * RETURNS * InvalidParameter if nativeFamily is NULL. + * FontFamilyNotFound if unable to get font. * Ok otherwise. */ GpStatus WINGDIPAPI GdipGetGenericFontFamilySansSerif(GpFontFamily **nativeFamily) @@ -1049,7 +1054,12 @@ GpStatus WINGDIPAPI GdipGetGenericFontFamilySansSerif(GpFontFamily **nativeFamil stat = GdipCreateFontFamilyFromName(L"Microsoft Sans Serif", NULL, nativeFamily);
if (stat == FontFamilyNotFound) - /* FIXME: Microsoft Sans Serif is not installed on Wine. */ + stat = GdipCreateFontFamilyFromName(L"Arial", NULL, nativeFamily); + + if (stat == FontFamilyNotFound) + stat = GdipCreateFontFamilyFromName(L"Liberation Sans", NULL, nativeFamily); + + if (stat == FontFamilyNotFound) stat = GdipCreateFontFamilyFromName(L"Tahoma", NULL, nativeFamily);
return stat;
How about using font fallback mechanism inside GDI? That is creating a logical font (`LOGFONT`) with a certain `lfPitchAndFamily` value (e.g. `FF_ROMAN`). Then, you can make `GdipFamily` from `LOGFONT` via `GdipCreateFromLogfont` and `GdipGetFamily`.
Win32u.dll has some fallback lists including Liberation fonts. See around https://gitlab.winehq.org/wine/wine/-/blob/wine-8.8/dlls/win32u/font.c#L997 for the implementation.
GDI fallback sounds complicated, and I don't really trust it.
I see Wine doesn't ship with a serif font, so I guess we either have to use GDI to find one or not give the app a serif font. But, if we don't have any on the list, the one we get is essentially random. Between those choices, I think I prefer the sans fallback.
This merge request was approved by Esme Povirk.