kirill-grouchnikov / radiance

Building modern, elegant and fast Swing applications
BSD 3-Clause "New" or "Revised" License
804 stars 89 forks source link

[Component] Text in labels truncated due to inconsistent FontMetrics #470

Closed ed-erwin-tf closed 4 months ago

ed-erwin-tf commented 5 months ago

Radiance 7.0.1

Theming

Java 11 (Corretto)

Windows 10

Text in labels sometimes truncated

The method RadianceLabelUI.paint(Graphics g, JComponent c) uses two separate instances of FontMetrics. When determining the value of "clippedText", it uses g.getFontMetrics(). When actually painting the label, it uses RadianceMetricsUtilities.getFontMetrics().

This can result in a bug where there is enough room to draw the complete text, but the incorrectly scaled metrics used to calculate "clippedText" thinks there is not enough room and thus truncates the text and adds "...".

It should use only the value from RadianceMetricsUtilities.

A similar bug exists in RadianceButtonUI and possibly RadianceRadioButtonUI.

The exact conditions necessary to reproduce this are hard to specify, but use of two separate metrics in the paint method seems to be an easy-to-fix mistake.

I have personally seen it only when I connect my computer to an external monitor and then using JComponent.printComponent(Graphics g) to paint to an image. The string width calculated by the two metrics differs by about 10% in this situation, which is enough to cause the text to be truncated.

kirill-grouchnikov commented 5 months ago

For the update path, all the UI delegates callRadianceCommonCortex.installDesktopHints before calling paint, so when it gets into the painting, calling Graphics.getFontMetrics() should return font metrics with text hinting configured.

The reason RadianceMetricsUtilities.getFontMetrics exists is for code paths that do not have a Graphics object at hand, which is specifically for sizing.

Do you see this issue only for printComponent calls? I haven't really given any attention to that codepath pretty much since the beginning of Substance, and it can very well be that there are some discrepancies there, minor or major.

kirill-grouchnikov commented 5 months ago

It can very well be that for printing, desktop hints that are set on the passed graphics context are ignored, but then when RadianceMetricsUtilities.getFontMetrics() is used to compute the text, it's using font metrics set on an offscreen image, and that's where the mismatch is from.

Would it be possible for you to replace line 143 in RadianceLabelUI to just get the metrics from g2d and see how it looks like? It might address this particular issue, however, there will still be a potential mismatch between getPreferredSize (using offscreen image) and update (using the passed in graphics context).

Again, I don't have any experience with printing in AWT, nor do I really want to get into it at this point in time.

ed-erwin-tf commented 5 months ago

Yes, I have only seen the problem when using printComponent. We use that to sometimes take a screenshot and save it as PNG. (I don't do any actual printing to paper.)

Thanks for your explanations.

I had already found a work-around by using RadianceMetricsUtilities.getFontMetrics() for the metrics in line 118 and 143. You suggest using g2d.getFontMetrics() in both cases. Probably either way would work. I'll try your suggestion when I get time. Or maybe I can override paintComponent in the top-level JPanel or JFrame so that it uses installDesktopHints.

In most cases, there is no problem. My testers were seeing an issue, and it took me months to find a way to reproduce it on my system.