[Bug 59569] New: `AutoSize` not correctly calculated for framed labels
http://bugs.winehq.org/show_bug.cgi?id=59569 Bug ID: 59569 Summary: `AutoSize` not correctly calculated for framed labels Product: Framework Mono Version: 6.12.0 Hardware: x86-64 OS: Linux Status: UNCONFIRMED Severity: normal Priority: P2 Component: System.Windows.Forms Assignee: wine-bugs@list.winehq.org Reporter: matthias.klaey@gmx.ch CC: madewokherd@gmail.com Distribution: --- Created attachment 80625 --> http://bugs.winehq.org/attachment.cgi?id=80625 Screenshots [Windows 11 Textscale 100%], [Windows 11 Textscale 125%], [Mono Debian WSL], [Mono Ubuntu] With certain combinations of font sizes, `Label` as well as `ToolStripStatusLabel` do not correctly calculate `AutoSize` if label is framed with `BorderStyle.Fixed*`, `Border3DStyle.Raised*` or `Border3DStyle.Sunken*`. Issue can be worked around by manually increasing the dimensions by 2 pixels, i.e. either `AutoSize` does not correctly take framing into account. Or even more likely, `AutoSize` has an issue with measuring and rounding font size, e.g. `Math.Round()` rather than `Math.Ceil()`. The attached .zip contains screenshots demonstrating the issue: - Windows 11 .NET Framework 4.8 => all fine. - Debian 12 with Mono 6.12.0 => issues with Deja Vu Sans Mono 9. - Ubuntu 24 with Mono 6.12.0 => issues with Noto Sans 11.25. -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=59569 --- Comment #1 from matthias.klaey@gmx.ch <matthias.klaey@gmx.ch> --- Workaround: ``` /// <remarks> /// Works around https://bugs.winehq.org/show_bug.cgi?id=59569. /// </remarks> [Conditional("MONO")] public static void ApplyMonoFramedLabelWorkaround(Label label) { var s = new Size((label.Width + 2), label.Height); label.AutoSize = false; label.Size = s; } /// <remarks> /// Works around https://bugs.winehq.org/show_bug.cgi?id=59569. /// </remarks> [Conditional("MONO")] public static void ApplyMonoFramedLabelWorkaround(ToolStripStatusLabel label) { var s = new Size((label.Width + 2), label.Height); label.AutoSize = false; label.Size = s; } ``` Workaround has to be applied to the initializer of all forms and controls that contain framed labels: ``` #if (MONO) SuspendLayout(); var framedLabels = new Label[] { label1, label2 }; foreach (var l in framedLabels) { ControlEx.ApplyMonoFramedLabelWorkaround(l); } ResumeLayout(); #endif ``` -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=59569 --- Comment #2 from matthias.klaey@gmx.ch <matthias.klaey@gmx.ch> --- Correction, of course the height must be adapted as well: ``` var s = new Size((label.Width + 2), (label.Height + 2)); ``` -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=59569 --- Comment #3 from Esme Povirk <madewokherd@gmail.com> --- There is some attempt to account for border style, but I don't really understand it: https://gitlab.winehq.org/mono/mono/-/blob/main/mcs/class/System.Windows.For... -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=59569 --- Comment #4 from Esme Povirk <madewokherd@gmail.com> --- Whew, OK! So. I've compared the actual drawing to the size calculation, and the current size calculation makes very little sense. Drawing: * Handled by LabelPainter.Draw. This method draws to PaddingClientRectangle, which excludes padding and borders. * Label.Image is drawn using DrawImage. This isn't accounted for in GetPreferredSizeCore at all. * Text is drawn using Graphics.DrawString. In GetPreferredSizeCore, we use TextRenderer.MeasureString (different font engines, could give different results). We do correctly use Size.Ceiling. Padding and borders: * Padding appears to be correctly handled in GetPreferredSizeCore. * BorderStyle.FixedSingle removes BorderStaticSize == Size(1,1) from the client area. BorderStyle.Fixed3D removes Border3DSize == Size(2,2) from the client area. Oddly, that's all handled in the Hwnd class based on window style flags. Also, I would've expected the sizes to be even, since the border size needs to be removed from both sides along each axis. Anyway, GetPreferredSizeCore adds Size(0, 6) to its rectangle, and only if UseCompatibleTextRendering is set. If UseCompatibleTextRendering is set, but BorderStyle is None, it adds Size(0,3). So, where are they getting Size(0, 6)? Well, there is one sizing test that accounts for BorderStyle: https://gitlab.winehq.org/mono/mono/-/blob/main/mcs/class/System.Windows.For... This test consistently fails in .NET Framework, in my testing for Wine Mono. I guess it probably passed for some developer on some version of .NET Framework, at some point, but who knows? The extra padding in case of UseCompatibleTextRendering is probably just the padding that Windows GDI+ likes to apply to all text measurements, because GDI+ made the questionable decision to try to make text scale linearly, while still drawing individual glyphs as bitmaps with hinting that doesn't scale linearly, and they added a bunch of padding so they could mostly fudge things when that doesn't work. I have no idea why BorderSize affects the preferred height only when UseCompatibleTextRendering is set. Also, Mono seems to default UseCompatibleTextRendering to true, while MSDN says the default is false. Also, given issues we've been having with calendar sizing, there's a good chance the size calculation in libgdiplus is just broken sometimes. -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=59569 --- Comment #5 from Esme Povirk <madewokherd@gmail.com> --- Possibly related: https://github.com/DanielVanNoord/System.Windows.Forms/pull/63 -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=59569 --- Comment #6 from Esme Povirk <madewokherd@gmail.com> --- I guess the way to get this right would be: * Make all the label sizing tests actually pass on .NET Framework. We don't really need them to pass on Mono, but it's good information. * Account properly for BorderSize in Label.GetPreferredSizeCore. * Test the default for UseCompatibleTextRendering on .NET Framework, and make sure Mono matches it. * Use the same API for text rendering and measurement, based on UseCompatibleTextRendering. -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=59569 --- Comment #7 from Esme Povirk <madewokherd@gmail.com> --- In my testing, BorderStyle doesn't affect PreferredHeight (or PreferredSize) at all in .NET Framework. Maybe the layout is supposed to account for borders in some other way? -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=59569 --- Comment #8 from Esme Povirk <madewokherd@gmail.com> --- Nope, .NET core winforms source agrees with the Mono tests, and acknowledges that the behavior makes no sense https://github.com/dotnet/dotnet/blob/b0f34d51fccc69fd334253924abd8d6853fad7... Maybe the Mono tests are getting tripped up by some caching. -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=59569 --- Comment #9 from Esme Povirk <madewokherd@gmail.com> --- OK, I have some questions, because I am no longer certain this is a layout problem (it might be a libgdiplus measurement/rendering thing), and I want to make sure I can reproduce exactly what you're seeing, as simply as possible, before I start drilling down to figure out what layer is broken. 1. Do you set UseCompatibleTextRendering or call SetCompatibleTextRenderingDefault, and if so, to what value? 2. Does your libgdiplus.so, according to ldd -d /usr/lib/libgdiplus.so, link to libpango? 3. What is the value of Label.PreferredSize, and the corresponding font and text, on one of the broken labels? -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=59569 --- Comment #10 from matthias.klaey@gmx.ch <matthias.klaey@gmx.ch> --- Hi Esme, Thanks for analyzing and gettig back. Here's the details: 1. Application.SetCompatibleTextRenderingDefault(false); (https://sourceforge.net/p/y-a-terminal/code/6819/tree/trunk/YAT/YATLib/YAT.S...) The setting follows "In most cases, it's recommended that you leave UseCompatibleTextRendering set to the default value of false." (https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.applicatio...). Or does Mono recommend GDI+ instead? 2. `ldd -d /usr/lib/libgdiplus.so` @ Debian 12 WSL linux-vdso.so.1 (0x00007fff225d6000) libpangocairo-1.0.so.0 => /lib/x86_64-linux-gnu/libpangocairo-1.0.so.0 (0x00007e6d454ab000) libpango-1.0.so.0 => /lib/x86_64-linux-gnu/libpango-1.0.so.0 (0x00007e6d45442000) libgobject-2.0.so.0 => /lib/x86_64-linux-gnu/libgobject-2.0.so.0 (0x00007e6d453e3000) libglib-2.0.so.0 => /lib/x86_64-linux-gnu/libglib-2.0.so.0 (0x00007e6d452ab000) libharfbuzz.so.0 => /lib/x86_64-linux-gnu/libharfbuzz.so.0 (0x00007e6d451a7000) libcairo.so.2 => /lib/x86_64-linux-gnu/libcairo.so.2 (0x00007e6d45081000) libjpeg.so.62 => /lib/x86_64-linux-gnu/libjpeg.so.62 (0x00007e6d44fee000) libtiff.so.6 => /lib/x86_64-linux-gnu/libtiff.so.6 (0x00007e6d44f62000) libgif.so.7 => /lib/x86_64-linux-gnu/libgif.so.7 (0x00007e6d44f57000) libpng16.so.16 => /lib/x86_64-linux-gnu/libpng16.so.16 (0x00007e6d44f21000) libX11.so.6 => /lib/x86_64-linux-gnu/libX11.so.6 (0x00007e6d44ddf000) libexif.so.12 => /lib/x86_64-linux-gnu/libexif.so.12 (0x00007e6d44d8e000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007e6d44cae000) libfontconfig.so.1 => /lib/x86_64-linux-gnu/libfontconfig.so.1 (0x00007e6d44c63000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007e6d44a82000) libpangoft2-1.0.so.0 => /lib/x86_64-linux-gnu/libpangoft2-1.0.so.0 (0x00007e6d44a69000) libgio-2.0.so.0 => /lib/x86_64-linux-gnu/libgio-2.0.so.0 (0x00007e6d44889000) libfribidi.so.0 => /lib/x86_64-linux-gnu/libfribidi.so.0 (0x00007e6d4486b000) libthai.so.0 => /lib/x86_64-linux-gnu/libthai.so.0 (0x00007e6d44860000) libffi.so.8 => /lib/x86_64-linux-gnu/libffi.so.8 (0x00007e6d44854000) libpcre2-8.so.0 => /lib/x86_64-linux-gnu/libpcre2-8.so.0 (0x00007e6d447ba000) libfreetype.so.6 => /lib/x86_64-linux-gnu/libfreetype.so.6 (0x00007e6d446f0000) libgraphite2.so.3 => /lib/x86_64-linux-gnu/libgraphite2.so.3 (0x00007e6d446c2000) libpixman-1.so.0 => /lib/x86_64-linux-gnu/libpixman-1.so.0 (0x00007e6d44617000) libxcb-shm.so.0 => /lib/x86_64-linux-gnu/libxcb-shm.so.0 (0x00007e6d44612000) libxcb.so.1 => /lib/x86_64-linux-gnu/libxcb.so.1 (0x00007e6d445e8000) libxcb-render.so.0 => /lib/x86_64-linux-gnu/libxcb-render.so.0 (0x00007e6d445da000) libXrender.so.1 => /lib/x86_64-linux-gnu/libXrender.so.1 (0x00007e6d445cd000) libXext.so.6 => /lib/x86_64-linux-gnu/libXext.so.6 (0x00007e6d445b6000) libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007e6d44597000) /lib64/ld-linux-x86-64.so.2 (0x00007e6d45547000) libwebp.so.7 => /lib/x86_64-linux-gnu/libwebp.so.7 (0x00007e6d44525000) libzstd.so.1 => /lib/x86_64-linux-gnu/libzstd.so.1 (0x00007e6d44469000) liblzma.so.5 => /lib/x86_64-linux-gnu/liblzma.so.5 (0x00007e6d4443a000) libLerc.so.4 => /lib/x86_64-linux-gnu/libLerc.so.4 (0x00007e6d443a0000) libjbig.so.0 => /lib/x86_64-linux-gnu/libjbig.so.0 (0x00007e6d4438f000) libdeflate.so.0 => /lib/x86_64-linux-gnu/libdeflate.so.0 (0x00007e6d44369000) libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007e6d4433e000) libgmodule-2.0.so.0 => /lib/x86_64-linux-gnu/libgmodule-2.0.so.0 (0x00007e6d44338000) libmount.so.1 => /lib/x86_64-linux-gnu/libmount.so.1 (0x00007e6d442d3000) libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007e6d442a5000) libdatrie.so.1 => /lib/x86_64-linux-gnu/libdatrie.so.1 (0x00007e6d4429b000) libbrotlidec.so.1 => /lib/x86_64-linux-gnu/libbrotlidec.so.1 (0x00007e6d4428e000) libXau.so.6 => /lib/x86_64-linux-gnu/libXau.so.6 (0x00007e6d44289000) libXdmcp.so.6 => /lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007e6d44000000) libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007e6d43c00000) libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007e6d44267000) libblkid.so.1 => /lib/x86_64-linux-gnu/libblkid.so.1 (0x00007e6d44210000) libbrotlicommon.so.1 => /lib/x86_64-linux-gnu/libbrotlicommon.so.1 (0x00007e6d43fdd000) libbsd.so.0 => /lib/x86_64-linux-gnu/libbsd.so.0 (0x00007e6d43fc7000) libmd.so.0 => /lib/x86_64-linux-gnu/libmd.so.0 (0x00007e6d43fba000) 3. I have just updated the values commented at https://sourceforge.net/p/y-a-terminal/code/6819/tree/trunk/YAT/YATLib/YAT.S... and the following lines. See https://sourceforge.net/p/y-a-terminal/code/6819/tree/trunk/YAT/YATLib/YAT.S... for related screenshots. -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=59569 --- Comment #11 from matthias.klaey@gmx.ch <matthias.klaey@gmx.ch> --- Hi Esme, Your question on libgdiplus triggered my curiousity on GDI vs GDI+ and indeed, when using GDI+ `Application.SetCompatibleTextRenderingDefault(true);` all labels correctly show their text! Is there any documentation on a Mono requirement to use GDI+, rather than GDI as recommended by Microsoft on Windows? Best regards, Matthias -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=59569 --- Comment #12 from Esme Povirk <madewokherd@gmail.com> --- I'm not aware of any official recommendation or documentation about this. It does make sense that it'd change the behavior, though, as the Label size calculation is different depending that setting. Perhaps the TextRenderer version is wrong. From what I could tell, Mono's default is GDI+, which contradicts MSDN, but it also suggests the TextRenderer path isn't as well-tested. -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=59569 --- Comment #13 from Esme Povirk <madewokherd@gmail.com> --- Updated the Mono tests to account for size caching by realizing the label, and confirmed the TextRenderer size calculation doesn't match .NET Framework. MR sent, should hopefully fix this: https://gitlab.winehq.org/mono/mono/-/merge_requests/206 -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=59569 --- Comment #14 from Esme Povirk <madewokherd@gmail.com> --- Fix (hopefully) merged. -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=59569 --- Comment #15 from matthias.klaey@gmx.ch <matthias.klaey@gmx.ch> --- Hi Esme, I assume the fix is "good enough", however it may not look fully "nice" without also incrementing `Width`. The other thing, `ToolStripStatusLabel` is also impacted. In the PR I have only seen changes to `Label`. Best regards, Matthias -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
participants (1)
-
WineHQ Bugzilla