On Thu, 27 Apr 2023 19:25:55 GMT, Rajat Mahajan <[email protected]> wrote:
> Problem:
>
> Check boxes and radio buttons in Windows Look-and-Feel have rendering issues
> when window is moved from display with one scale to display with a different
> scale on a multi-monitor setup:
>
> - Scrawly ticks in checkboxes;
> - Wrong circle relations in selected radio buttons.
>
> Root-cause:
> We open theme on AWT Toolkit Window which always has Primary Monitor DPI.
> Due to this when the app window goes to Secondary Screen with different DPI
> UI buttons
> appear incorrectly rendered.
> Following is a list proposed changes to fix this issue.
>
>
> Proposed Fix with Summary of changes:
>
> 1. Open a new Theme Handle per the DPI of the Screen where the App window is.
> --> This makes sure we get the correct size for UI buttons based on the DPI
> of the screen where the app.
> window is.
>
> 2. GetPartSize() of icons returns size based on standard size = 96 DPI.
> --> This change makes sure that the default size of UI buttons is 96 since we
> use this on Java side to layout UI.
>
> 3. Rect size for icons in native paintBackground() function is fetched from
> Windows that specific DPI.
> -->This makes sure that the UI buttons aren't stretched because the size
> calculated on Java side is different from what Windows returns. Thus UI
> buttons are scaled correctly once we get their size back from Windows.
>
> 4. Adjust width and the height of the resolution variant image so that for
> scaling values of 1.25 , 2.25 , and such we always floor, while for 1.5,
> 1.75, 2.5, 2.75 , and such we always ceil.
> --> This helps make sure that for .25s scaling we get better rendering.
> This is because when we go from Double to Int for pixel rendering we
> sometimes need to floor or ceil to get crisp rendering.
>
> As of now with these changes the rendering is crisp and good for all scaling
> factors with the exception .25s wherein some small artifact is seen sometimes
> in rendering of buttons but is still much better compared to what we have now.
>
>
> Testing:
>
> Tested locally on my Windows machine with a 2 monitor setup 125%, 150%,
> 175%, 225% scaling values and on mach5.
>
> ___________________________________
> Monitor 1 | Monitor 2
> (Primary) |
> |
> 125% | 175%
> 150% | 175%
> 150% | 225%
> 175% | 175%
> 175% | 150%
> 175% | 225%
> _____________________ |_____________
>
> Also tested on setup with scaling values of up-to 350%.
src/java.desktop/share/classes/sun/swing/CachedPainter.java line 318:
> 316: public Image getResolutionVariant(double destWidth, double
> destHeight) {
> 317: int w = (int) Math.floor(destWidth + 0.5);
> 318: int h = (int) Math.floor(destHeight + 0.5);
Isn't it what `Region.clipRound` does?
src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/XPStyle.java
line 63:
> 61:
> 62: import java.lang.Math;
> 63:
The imports should be sorted, static imports follow regular class imports.
Please expand all wildcard imports with per-class imports, which is done when
classes are updated.
src/java.desktop/windows/classes/sun/awt/windows/ThemeReader.java line 108:
> 106: if(dpiAwareWidgetToTheme.containsKey(dpi))
> 107: {
> 108: if (!dpiAwareWidgetToTheme.get(dpi).isEmpty())
It is better to skip `containsKey` and use `get`; if `get` returns `null`, put
the key into the map.
src/java.desktop/windows/classes/sun/awt/windows/ThemeReader.java line 136:
> 134: if (!dpiAwareWidgetToTheme.isEmpty()) {
> 135: for (Long value :
> 136: dpiAwareWidgetToTheme.get(dpi).values()) {
I think it's still possible that `get(dpi)` returns `null`, you should handle
`null` gracefully.
src/java.desktop/windows/classes/sun/awt/windows/ThemeReader.java line 140:
> 138: }
> 139: dpiAwareWidgetToTheme.get(dpi).clear();
> 140: dpiAwareWidgetToTheme.clear();
You clear the entire map, yet it don't call `closeTheme` for dpi values other
than the passed one.
You should iterate over `dpiAwareWidgetToTheme.values().values()` (pseudo-code).
src/java.desktop/windows/classes/sun/awt/windows/ThemeReader.java line 155:
> 153: if(dpiAwareWidgetToTheme.containsKey(dpi))
> 154: {
> 155: theme = dpiAwareWidgetToTheme.get(dpi).get(widget);
Avoid using `contains` followed by `get`, use `get` instead and handle `null`
value.
src/java.desktop/windows/classes/sun/awt/windows/ThemeReader.java line 179:
> 177: try {
> 178:
> 179: /* We get the part size vased on the theme for current
> screen DPI and pass it to paintBackground */
Suggestion:
/* We get the part size based on the theme for current screen DPI
and pass it to paintBackground */
src/java.desktop/windows/classes/sun/awt/windows/ThemeReader.java line 185:
> 183: part, state,
> 184: (int)d.getWidth(),
> 185: (int)d.getHeight() , w, h, stride);
Suggestion:
d.width,
d.height, w, h, stride);
You can access the fields directly and avoid casting.
src/java.desktop/windows/native/libawt/windows/ThemeReader.cpp line 243:
> 241: (JNIEnv* env, jclass klass, jstring widget, jint dpi) {
> 242:
> 243: LPCTSTR str = (LPCTSTR)JNU_GetStringPlatformChars(env, widget, NULL);
I'd rather keep the original formatting for casts as well as for `JNIEnv *env`
in the declaration.
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/13701#discussion_r1182682786
PR Review Comment: https://git.openjdk.org/jdk/pull/13701#discussion_r1182685469
PR Review Comment: https://git.openjdk.org/jdk/pull/13701#discussion_r1182690251
PR Review Comment: https://git.openjdk.org/jdk/pull/13701#discussion_r1182694155
PR Review Comment: https://git.openjdk.org/jdk/pull/13701#discussion_r1182696873
PR Review Comment: https://git.openjdk.org/jdk/pull/13701#discussion_r1182699492
PR Review Comment: https://git.openjdk.org/jdk/pull/13701#discussion_r1182702793
PR Review Comment: https://git.openjdk.org/jdk/pull/13701#discussion_r1182704389
PR Review Comment: https://git.openjdk.org/jdk/pull/13701#discussion_r1182709855