weblaf icon indicating copy to clipboard operation
weblaf copied to clipboard

Text rendering issues on non-opaque destination

Open FisherYu-CN opened this issue 10 years ago • 19 comments

Hi mgarin,

I do enjoy weblaf, it's really amazing. But I found some problems when I try to use it together with JDK8 in Windows 7. It seems the menu items render differently when they are in different menus. Please look at the screen shot below.

untitled

This problem becomes more obvious when I change the default font.

untitled

I haven't done anything particular to initialize those menu items.

menuBar = new JMenuBar();
this.setJMenuBar(menuBar);

settingsMenu = new JMenu("Menu1");
menuBar.add(settingsMenu);

sourceSettingMenuItem = new JMenuItem("MenuItem1");
settingsMenu.add(sourceSettingMenuItem);

basicSettingMenuItem = new JMenuItem("MenuItem2");
settingsMenu.add(basicSettingMenuItem);

helpMenu = new JMenu("Menu2");
menuBar.add(helpMenu);

aboutHuntersMenuItem = new JMenuItem("MenuItem1");
helpMenu.add(aboutHuntersMenuItem);

Is it a bug or there's something else I need to do? Thanks.

FisherYu-CN avatar May 29 '14 09:05 FisherYu-CN

Not sure whether this is painting a bug or just some font-related rendering issue. In any case that looks pretty weird, I will investigate it.

Thanks for reporting :)

mgarin avatar May 29 '14 12:05 mgarin

I got an idea of what causes this bug - most probably when 1st menu is displayed - it gets outside of the frame bounds and, obviously, rendered on a separate window. Menu styling forces its window to become background-transparent and render all the text in the frame using Java base AA which causes the effect you see in the first menu.

The second menu still in the window bounds and rendered without AA which makes font better in most cases and more system-like.

Unfortunately i cannot fix this issue anyhow since this is a JDK-related bug (or behavior) which is not going to be fixed anytime soon as it seems (it is there for a loooong time).

mgarin avatar May 30 '14 07:05 mgarin

Yes, I guess it makes sense. Thanks for your effort. Good job, best laf I have ever seen :)

FisherYu-CN avatar May 30 '14 07:05 FisherYu-CN

Here is a similar older bug with more explanations and examples, by the way: https://github.com/mgarin/weblaf/issues/84

I'll close this issue as well. If some day there will be a way to fix this rendering issue i will surely do it.

mgarin avatar May 30 '14 07:05 mgarin

By the way, as a workaround - menu shadows can be reduced so that popup menu fits into window bounds and rendered normally. But that will help only while menu stays in frame bounds, otherwise you will see font rendering issue coming back.

mgarin avatar Jun 02 '14 16:06 mgarin

@mgarin, Is there a way to disable drop shadows in the LAF globally? I know it's not nearly as cool without them, but with window decorations enabled (#84 like you referenced), all text rendering in the entire UI is done with Java AA, since the main window has a drop shadow. Since I think your window decorations are cool, a fair trade-off for me would be to have no drop shadow for windows or menus, and square window edges (if necessary), in exchange for sharper text rendering and cooler-looking window chrome.

On Windows at least, where the current UI is typically flat, a lack of shadows isn't as noticeable. :)

Wasn't sure if this should be a new ticket or just a question for this one; please move it if necessary. I can also look into creating a pull request for this feature if you like the idea but don't have time to look into it.

bobbylight avatar Jul 16 '14 21:07 bobbylight

You can disable shades and use squared shapes, but windows will still be transparent.

Disabling transparent windows might be a good option overall considering some bugs (including font rendering) it causes. Though it will require some additional modifications. It is better to move it into a separate issue.

mgarin avatar Jul 17 '14 08:07 mgarin

I'll keep this issue opened as the oldest one for reference. If something changes regarding subpixel rendering on non-opaque windows I will make sure to post an update here.

mgarin avatar Sep 16 '16 10:09 mgarin

I have experience the same issue in Darklaf. To mitigate it one can paint the text to an opaque off-screen image and then paint the image to the component graphics. This way subpixel AA is enabled for the text rendering.

See PaintUtil#drawStringImpl.

weisJ avatar Jun 17 '20 12:06 weisJ

I can't really do that when the destination of the text is semi-transparent (which is the case with menus for instance), so it's not a solution I can use unfortunately. It might be fine for cases when text is clearly drawn on top of an opaque element, but unfortunately due to the way all parts of each component are drawn in WebLaF - I have no reasonable way to find out whether text is drawn on an opaque or non-opaque destination.

mgarin avatar Jun 17 '20 13:06 mgarin

I see. If you are willing to use reflection then the following approach will work even with transparent surfaces. It’s not a 100% perfect as the area under the text is still a bit more opaque than the rest, but it’s barely noticeable.

https://gist.github.com/weisJ/4cf624c149819f42a6c5ad75407901b5

e.g. here is a tooltip with a gradient paint and transparency: tooltip_aa

weisJ avatar Jun 17 '20 19:06 weisJ

Thats... an interesting solution. Thanks for the code example, I'll look into that!

My main and only concern with it is performance, especially when a lot of text is drawn on a window (let's say you're using a custom window decoration for the main app window) - that will require some testing and benchmarking.

And reflection is not an issue, WebLaF uses lots of reflection for accessing various Swing stuff and not only that, so that wouldn't really change anything.

mgarin avatar Jun 17 '20 23:06 mgarin

Upon further testing I found that with a dark background the area under the text is still quite visible. The background color might need to be manually adjusted to mitigate the impact.

weisJ avatar Jun 18 '20 12:06 weisJ

I have updated the gist with an approach that doesn't preserve the background. When drawing the off-screen image to the graphics object we ignore all pixels that have the background color. For all other pixels we calculate the channel alpha values to reconstruct the anti-aliased color values now with the current graphics image as the destination surface.

Performance wise this could probably be a bit improved by converting the FilterImageSource to a BuffereImageOp.

It might still be feasible to calculate a background based on the foreground color to ensure it has maximal contrast. tooltip_aatooltip_aa_dark

Note If the the graphics object has SurfaceData of type CGLSurfaceData then the resulting text will be gray scaled anti-aliased. (This could be circumvented by first painting the graphics offscreen image to a BufferedImage so it matches the expected type).

weisJ avatar Jun 18 '20 13:06 weisJ

Thanks for the update!

It might still be feasible to calculate a background based on the foreground color to ensure it has maximal contrast.

It will only work in case background color retrieval can be automated and performed within the text painting code, otherwise it will be very hard to determine exact background code in many cases, so this is something I'll have to investigate once I get to it.

Also one more thing I just realized - a separate solution will be required for the JTextComponents as this only covers plain/html text rendering. Theoretically the actual painting part can be provided separately into the utility, but I haven't really fully looked into it yet, so not sure about that.

mgarin avatar Jun 19 '20 12:06 mgarin

Thanks for the update!

It might still be feasible to calculate a background based on the foreground color to ensure it has maximal contrast.

It will only work in case background color retrieval can be automated and performed within the text painting code, otherwise it will be very hard to determine exact background code in many cases, so this is something I'll have to investigate once I get to it.

I have already incorporated background color generation in the gist.

Also one more thing I just realized - a separate solution will be required for the JTextComponents as this only covers plain/html text rendering. Theoretically the actual painting part can be provided separately into the utility, but I haven't really fully looked into it yet, so not sure about that.

I haven't checked yet whether it would work for JTextComponent. I'll try it out later.

weisJ avatar Jun 19 '20 12:06 weisJ

I have already incorporated background color generation in the gist.

Yep, noticed it now, was mostly just glancing over the code :)

I haven't checked yet whether it would work for JTextComponent. I'll try it out later.

It should work, unless there are some issues with custom non-text elements - although I doubt it since it works with HTML view that has a lot of custom stuff.

mgarin avatar Jun 19 '20 13:06 mgarin

I'll probably try it out next week on the simple text implementation (in AbstractTextContent.java) to see how it performs on demo app and maybe one of our large proprietary apps and will post results here.

mgarin avatar Jun 19 '20 13:06 mgarin

I have made some corrections to accommodate components that are part of a more complex hierarchy (previously the text rectangle was assumed to be relative to the parent window).

weisJ avatar Jun 19 '20 17:06 weisJ