Builtin gdiplus behaves as documented but tests are indicating that Windows behaviour sometimes differs from the documentation.
I believe this issue is at least one of the contributing issues to bug https://bugs.winehq.org/show_bug.cgi?id=46947, if not the sole issue. I propose that this flag be disabled until it is well understood. I noticed as issue with DrawString seeming to ignore the flag sometimes(sometimes the text fits without any noticeable defects which I believe is the case with the program in the bug) and sometimes even drawing clipped text with the flag on. Other times it works as expected. I can't seem to find a pattern to identify that could be used to predict its behaviour.
Signed-off-by: David Kahurani k.kahurani@gmail.com
-- v5: gdiplus: fix StringFormatFlagsLineLimit handling
From: David Kahurani k.kahurani@gmail.com
If StringFormatFlagsLineLimit is set, analyze glyph outlines to determine the required height for drawing. This is to ensure that the whole line is drawn when we can establish that no clipping will occur and otherwise not draw the string.
Signed-off-by: David Kahurani k.kahurani@gmail.com --- dlls/gdiplus/gdiplus.c | 7 ++++ dlls/gdiplus/gdiplus_private.h | 2 + dlls/gdiplus/graphics.c | 76 +++++++++++++++++++++++++++++++++- dlls/gdiplus/graphicspath.c | 7 ---- 4 files changed, 83 insertions(+), 9 deletions(-)
diff --git a/dlls/gdiplus/gdiplus.c b/dlls/gdiplus/gdiplus.c index a3c85986ffc..fe15fd477ea 100644 --- a/dlls/gdiplus/gdiplus.c +++ b/dlls/gdiplus/gdiplus.c @@ -481,6 +481,13 @@ void delete_element(region_element* element) } }
+float fromfixedpoint(const FIXED v) +{ + float f = ((float)v.fract) / (1<<(sizeof(v.fract)*8)); + f += v.value; + return f; +} + const char *debugstr_rectf(const RectF* rc) { if (!rc) return "(null)"; diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index 1bc058b3413..ff1123c6936 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -200,6 +200,8 @@ static inline ARGB color_over_fgpremult(ARGB bg, ARGB fg) return (a<<24)|(r<<16)|(g<<8)|b; }
+extern float fromfixedpoint(const FIXED); + extern const char *debugstr_rectf(const RectF* rc);
extern const char *debugstr_pointf(const PointF* pt); diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 758889eca06..1992fa6a7a4 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -5152,6 +5152,71 @@ GpStatus WINGDIPAPI GdipIsVisibleRectI(GpGraphics *graphics, INT x, INT y, INT w return GdipIsVisibleRect(graphics, (REAL)x, (REAL)y, (REAL)width, (REAL)height, result); }
+static BOOL text_fits(HDC hdc, WCHAR* string, int index, int length, int available_height) +{ + GLYPHMETRICS gm; + static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} }; + TTPOLYGONHEADER *ph = NULL, *origph = NULL; + float topmost, bottommost; + int i; + + for (i = index; i < index + length; i++) + { + DWORD len, ofs = 0; + char *start; + + len = GetGlyphOutlineW(hdc, string[i], GGO_BEZIER, &gm, 0, NULL, &identity); + + origph = ph = heap_alloc_zero(len); + + len = GetGlyphOutlineW(hdc, string[i], GGO_BEZIER, &gm, len, (char *)ph, &identity); + topmost = fromfixedpoint(ph->pfxStart.y); + bottommost = fromfixedpoint(ph->pfxStart.y); + start = (char *)ph; + + while (ofs < len) + { + DWORD ofs_start = ofs; + ph = (TTPOLYGONHEADER*)&start[ofs]; + + if (topmost > fromfixedpoint(ph->pfxStart.y)) + topmost = fromfixedpoint(ph->pfxStart.y); + + if (bottommost < fromfixedpoint(ph->pfxStart.y)) + bottommost = fromfixedpoint(ph->pfxStart.y); + + ofs += sizeof(*ph); + + while (ofs - ofs_start < ph->cb) + { + int j; + TTPOLYCURVE *curve = (TTPOLYCURVE*)&start[ofs]; + ofs += sizeof(TTPOLYCURVE) + (curve->cpfx - 1) * sizeof(POINTFX); + + for (j = 0; j < curve->cpfx; ++j) + { + if (topmost > fromfixedpoint(curve->apfx[j].y)) + topmost = fromfixedpoint(curve->apfx[j].y); + + if (bottommost < fromfixedpoint(curve->apfx[j].y)) + bottommost = fromfixedpoint(curve->apfx[j].y); + + } + + } + } + + heap_free(origph); + + if ((bottommost - topmost) > available_height) + break; + } + + if (i != index + length) return FALSE; + + return TRUE; +} + GpStatus gdip_format_string(HDC hdc, GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font, GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format, int ignore_empty_clip, @@ -5290,9 +5355,16 @@ GpStatus gdip_format_string(HDC hdc,
if(height + size.cy > nheight) { - if (format->attr & StringFormatFlagsLineLimit) - break; bounds.Height = nheight - (height + size.cy); + + if (format->attr & StringFormatFlagsLineLimit) + { + if (!text_fits(hdc, stringdup, sum, lineend, nheight - height)) + break; + + bounds.Height = nheight - height; + } + } else bounds.Height = size.cy; diff --git a/dlls/gdiplus/graphicspath.c b/dlls/gdiplus/graphicspath.c index fd2622daf0e..7b4aa2119d6 100644 --- a/dlls/gdiplus/graphicspath.c +++ b/dlls/gdiplus/graphicspath.c @@ -935,13 +935,6 @@ GpStatus WINGDIPAPI GdipAddPathPolygonI(GpPath *path, GDIPCONST GpPoint *points, return status; }
-static float fromfixedpoint(const FIXED v) -{ - float f = ((float)v.fract) / (1<<(sizeof(v.fract)*8)); - f += v.value; - return f; -} - struct format_string_args { GpPath *path;
Okay, second attempt.
I have changed the code so it analyzes the glyph outlines when the flag is set to precisely determine if the text is going to get clipped when drawn.
On Fri Aug 11 19:45:18 2023 +0000, David Kahurani wrote:
Okay, second attempt. I have changed the code so it analyzes the glyph outlines when the flag is set to precisely determine if the text is going to get clipped when drawn.
I really don't think that's what native is doing.
This merge request was closed by David Kahurani.