Freetype's FT_Load_Glyph may return different glyph metrics (in particular, horiAdvance) depending on load target flags (FT_LOAD_TARGET_MONO, FT_LOAD_TARGET_NORMAL ...). Among the consequences of that are: - the size of, e. g, GetTextExtentPoint() doesn't match the size of actually rendered text; - DrawTextW() with DT_CALCRECT flag returns wrong bounding rectangle.
In the core of that is GetGlyphOutline() returning different values for GGO_METRICS format (used in various glyph metrics query functions) and the actual format used during rendering.
It probably make sense to use effective fonts rendering option for GGO_METRICS so that matches. I did some ad-hoc testing on Windows with currently problematic Tahoma font and quite expectedly GetGlyphOutline(GGO_METRICS) always returns the same metrics as other output format options. While all the options also have the same metrics between each other (which is still not the case with Wine). I guess it is not easily possible to make all the face load options match each other with freetype (nor I am sure that is always the case on Windows for all the possible fonts), but making GGO_METRICS return the metrics matching actual gdi device context setup looks more important.
Fixes Idle Spiral being unable to render typed text in save / load dialogs (which is using Winforms from Unity's Mono).
From: Paul Gofman pgofman@codeweavers.com
--- dlls/win32u/font.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/win32u/font.c b/dlls/win32u/font.c index edeba90b981..ccd36517038 100644 --- a/dlls/win32u/font.c +++ b/dlls/win32u/font.c @@ -4671,6 +4671,7 @@ static HFONT font_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags ) *aa_flags = font_smoothing; } *aa_flags = font_funcs->get_aa_flags( font, *aa_flags, antialias_fakes ); + font->aa_flags = *aa_flags; } TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), (int)lf.lfHeight, *aa_flags ); pthread_mutex_unlock( &font_lock );
From: Paul Gofman pgofman@codeweavers.com
--- dlls/win32u/freetype.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/dlls/win32u/freetype.c b/dlls/win32u/freetype.c index 6043c66bc53..90edeae670d 100644 --- a/dlls/win32u/freetype.c +++ b/dlls/win32u/freetype.c @@ -3401,10 +3401,13 @@ static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int b return needed; }
-static FT_Int get_load_flags( UINT format ) +static FT_Int get_load_flags( UINT format, BOOL vertical_metrics, BOOL force_no_bitmap ) { FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
+ if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT; + if (force_no_bitmap || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP; + if (format & GGO_UNHINTED) return load_flags | FT_LOAD_NO_HINTING;
@@ -3444,7 +3447,7 @@ static UINT freetype_get_glyph_outline( struct gdi_font *font, UINT glyph, UINT FT_Glyph_Metrics metrics; FT_Error err; FT_BBox bbox; - FT_Int load_flags = get_load_flags(format); + FT_Int load_flags; FT_Matrix transform_matrices[3], *matrices = NULL; BOOL vertical_metrics;
@@ -3454,8 +3457,6 @@ static UINT freetype_get_glyph_outline( struct gdi_font *font, UINT glyph, UINT font->matrix.eM11, font->matrix.eM12, font->matrix.eM21, font->matrix.eM22);
- format &= ~GGO_UNHINTED; - matrices = get_transform_matrices( font, tategaki, lpmat, transform_matrices );
vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face)); @@ -3463,9 +3464,7 @@ static UINT freetype_get_glyph_outline( struct gdi_font *font, UINT glyph, UINT properly scaled and correct in 2.4.0 or greater */ if (vertical_metrics && FT_SimpleVersion < FT_VERSION_VALUE(2, 4, 0)) vertical_metrics = FALSE; - - if (matrices || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP; - if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT; + load_flags = get_load_flags(format, vertical_metrics, !!matrices);
err = pFT_Load_Glyph(ft_face, glyph, load_flags); if (err && !(load_flags & FT_LOAD_NO_HINTING)) @@ -3480,6 +3479,8 @@ static UINT freetype_get_glyph_outline( struct gdi_font *font, UINT glyph, UINT return GDI_ERROR; }
+ format &= ~GGO_UNHINTED; + metrics = ft_face->glyph->metrics; if(font->fake_bold) { if (!get_bold_glyph_outline(ft_face->glyph, font->ppem, &metrics) && metrics.width)
From: Paul Gofman pgofman@codeweavers.com
--- dlls/win32u/freetype.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/dlls/win32u/freetype.c b/dlls/win32u/freetype.c index 90edeae670d..dcc90e728be 100644 --- a/dlls/win32u/freetype.c +++ b/dlls/win32u/freetype.c @@ -3450,6 +3450,7 @@ static UINT freetype_get_glyph_outline( struct gdi_font *font, UINT glyph, UINT FT_Int load_flags; FT_Matrix transform_matrices[3], *matrices = NULL; BOOL vertical_metrics; + UINT effective_format = format;
TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm, buflen, buf, lpmat);
@@ -3459,14 +3460,22 @@ static UINT freetype_get_glyph_outline( struct gdi_font *font, UINT glyph, UINT
matrices = get_transform_matrices( font, tategaki, lpmat, transform_matrices );
+ if ((format & ~GGO_GLYPH_INDEX) == GGO_METRICS) + effective_format = font->aa_flags | (format & GGO_GLYPH_INDEX); vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face)); /* there is a freetype bug where vertical metrics are only properly scaled and correct in 2.4.0 or greater */ if (vertical_metrics && FT_SimpleVersion < FT_VERSION_VALUE(2, 4, 0)) vertical_metrics = FALSE; - load_flags = get_load_flags(format, vertical_metrics, !!matrices); + load_flags = get_load_flags(effective_format, vertical_metrics, !!matrices);
err = pFT_Load_Glyph(ft_face, glyph, load_flags); + if (err && format != effective_format) + { + WARN("Failed to load glyph %#x, retrying with GGO_METRICS. Error %#x.\n", glyph, err); + load_flags = get_load_flags(effective_format, vertical_metrics, !!matrices); + err = pFT_Load_Glyph(ft_face, glyph, load_flags); + } if (err && !(load_flags & FT_LOAD_NO_HINTING)) { WARN("Failed to load glyph %#x, retrying without hinting. Error %#x.\n", glyph, err);
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=139918
Your paranoid android.
=== debian11b (64 bit WoW report) ===
d3dx9_36: core.c:615: Test failed: Character b: Got 0, expected -1. core.c:611: Test succeeded inside todo block: Character c: Got 6, expected 6. core.c:613: Test succeeded inside todo block: Character c: Got 7, expected 7. core.c:615: Test failed: Character c: Got -2, expected -1. core.c:617: Test failed: Character c: Got 2, expected 4. core.c:611: Test succeeded inside todo block: Character e: Got 6, expected 6. core.c:617: Test failed: Character e: Got 3, expected 4. core.c:613: Test succeeded inside todo block: Character g: Got 9, expected 9. core.c:617: Test failed: Character g: Got 2, expected 4. core.c:615: Test failed: Character h: Got 0, expected -1. core.c:615: Test failed: Character i: Got 0, expected -1. core.c:617: Test failed: Character i: Got 1, expected 2. core.c:615: Test failed: Character j: Got -2, expected -1. core.c:617: Test failed: Character j: Got 1, expected 2. core.c:615: Test failed: Character k: Got 0, expected -1. core.c:615: Test failed: Character l: Got 0, expected -1. core.c:615: Test failed: Character m: Got 0, expected -1. core.c:617: Test failed: Character m: Got 3, expected 4. core.c:615: Test failed: Character n: Got 0, expected -1. core.c:617: Test failed: Character n: Got 3, expected 4. core.c:617: Test failed: Character o: Got 3, expected 4. core.c:615: Test failed: Character p: Got 0, expected -1. core.c:617: Test failed: Character p: Got 3, expected 4. core.c:617: Test failed: Character q: Got 3, expected 4. core.c:615: Test failed: Character r: Got 0, expected -1. core.c:617: Test failed: Character r: Got 3, expected 4. core.c:611: Test succeeded inside todo block: Character s: Got 5, expected 5. core.c:615: Test failed: Character s: Got -2, expected -1. core.c:617: Test failed: Character s: Got 3, expected 4. core.c:611: Test succeeded inside todo block: Character t: Got 4, expected 4. core.c:617: Test failed: Character t: Got 1, expected 2. core.c:615: Test failed: Character u: Got 0, expected -1. core.c:617: Test failed: Character u: Got 3, expected 4. core.c:617: Test failed: Character v: Got 3, expected 4. core.c:617: Test failed: Character w: Got 3, expected 4. core.c:617: Test failed: Character x: Got 3, expected 4. core.c:617: Test failed: Character y: Got 3, expected 4. core.c:615: Test failed: Character z: Got 0, expected -1. core.c:617: Test failed: Character z: Got 3, expected 4.