On Thu, 27 Apr 2023 19:25:55 GMT, Rajat Mahajan <rmaha...@openjdk.org> 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