Passing exact bounding rectangle from GdipMeasureString() to GdipDrawString() may currently result in nothing being rendered because gdip_format_string decides the string does not fit in the rectangle. The effectively considered width is a result of truncation of float rect->Width. Even without any transform or scaling in play, the float math performed on margin and width in GdipDrawString() is enough to introduce rounding error so that the truncation rounds to smaller integer while float value is very close to the next one.
As tests shows, Windows seems to do some rounding on the value. I bisected the epsilon value more precisely locally and it looks like it is very close to 0.005. The result is a bit biased with the current font size in test (probably due to some extra math and rounding on the way) but doubling font size yields 0.005 almost exactly.
Fixes text rendering in a game which randomly skips characters (in fact, most of them).
From: Paul Gofman pgofman@codeweavers.com
--- dlls/gdiplus/graphics.c | 4 ++-- dlls/gdiplus/tests/graphics.c | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 371629a5bef..cc8411d54f7 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -5179,8 +5179,8 @@ GpStatus gdip_format_string(HDC hdc, if (!format) format = &default_drawstring_format;
- nwidth = rect->Width; - nheight = rect->Height; + nwidth = (int)(rect->Width + 0.005f); + nheight = (int)(rect->Height + 0.005f); if (ignore_empty_clip) { if (!nwidth) nwidth = INT_MAX; diff --git a/dlls/gdiplus/tests/graphics.c b/dlls/gdiplus/tests/graphics.c index de174257994..d71bc78c2ae 100644 --- a/dlls/gdiplus/tests/graphics.c +++ b/dlls/gdiplus/tests/graphics.c @@ -4770,7 +4770,7 @@ static void test_measure_string(void)
set_rect_empty(&rect); rect.Height = height; - rect.Width = width_2 - 0.05; + rect.Width = width_2 - 0.006; set_rect_empty(&bounds); status = GdipMeasureString(graphics, string, -1, font, &rect, format, &bounds, &glyphs, &lines); expect(Ok, status); @@ -4781,6 +4781,19 @@ static void test_measure_string(void) expectf_(width_1, bounds.Width, 0.01); expectf(height, bounds.Height);
+ set_rect_empty(&rect); + rect.Height = height; + rect.Width = width_2 - 0.004; + set_rect_empty(&bounds); + status = GdipMeasureString(graphics, string, -1, font, &rect, format, &bounds, &glyphs, &lines); + expect(Ok, status); + expect(2, glyphs); + expect(1, lines); + expectf(0.0, bounds.X); + expectf(0.0, bounds.Y); + expectf_(width_2, bounds.Width, 0.01); + expectf(height, bounds.Height); + /* Default (Near) alignment */ rect.X = 5.0; rect.Y = 5.0;
This merge request was approved by Esme Povirk.