JDK-8091832 : Provide a Screen.getScale method for Hi-DPI screens
  • Type: Enhancement
  • Component: javafx
  • Sub-Component: graphics
  • Affected Version: 8u20,9
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2015-02-13
  • Updated: 2016-10-14
  • Resolved: 2016-04-09
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 9
9Fixed
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
For some reason the Screen.getScale() method is private, even though getDpi() is public. There's no comment in the source explaining what's up with that. I want this so I can rescale an image to the right size without wasting excessive memory on non-retina systems.
Comments
http://hg.openjdk.java.net/openjfx/9-dev/rt/rev/cbdf23eafed3
09-04-2016

Looks good. +1
09-04-2016

New (hopefully final) webrevs: http://cr.openjdk.java.net/~flar/JDK-8091832/webrev.rt.07/ (This does include an rt.patch.diff file, but it doesn't really make sense because all that happened is that a few lines of new code moved down a few lines in the source file) Changes: - moved the lines that update the output scale when a window is shown down a few lines until after the scene is set into the peer.
09-04-2016

New webrevs: http://cr.openjdk.java.net/~flar/JDK-8091832/webrev.rt.06/ (includes a diff file for the patch vs. webrev.05 for quick reference) Changes: - default values for forceIntegerRenderScale and renderScaleX/Y - force render scale sync to peer when showing a Window (fixes blurry popups)
08-04-2016

I finished the review of the code. The javadoc for forceIntegerRenderScale, renderScaleX, and renderScaleY could use an "@defaultValue false". No other issues spotted. Of the functional issues found above with testing, I think all of them except the blurry popup issue can be handled with follow-up issues, since their effect is limited.
08-04-2016

I tested applets today on my Windows 10 machine with 125% scaling. The content in the applet Windows renders correctly. However, popups (such as Tooltip, ChoiceBox, or ComboBox) render too large and in the wrong position relative to the content in the applet stage. It looks like the positions of the stage in the applet window might be unscaled?
08-04-2016

Here are some final testing results. Mac and Linux are all fine -- no regressions. Windows ------------ All testing was done at 125% on Window 7 and Windows 10 (except for cross-checking the behavior of the failing unit tests, which I did with the glass.win.uiScale system property). * I get 6 Unit test failures (all other unit tests pass) RegionBackgroundFillUITest. basicFill_Radius1 RegionBackgroundFillUITest. basicFill_RadiusAndInsets RegionBackgroundFillUITest. testOnePixelBottomInset RegionBackgroundFillUITest. testOnePixelLeftInset RegionBackgroundFillUITest. testOnePixelRightInset RegionBackgroundFillUITest. testOnePixelTopInset I can visually see a problem with the testOnePixelXXXX test that I don't see at 100%. There is red on the edges other than the one which should be red. At 150% it also fails, but I don't see the same noticeable visual problem. The tests pass at 100% or 200%. * I'm seeing some very odd behavior with popups, such as ChoiceBox or ComboBox. The first time I click on the ComboBox it looks fine. If I dismiss the popup and then press on the combobox again it looks very blurry. I see this in Ensemble on some demos, but it it most easily reproduced with HelloComboBox. - Run HelloConboBox with windows screen scale set to 125% (my system is set this way by default) - Press the "Make a Choice" combo box - It will look fine - Press it again - Very blurry text * I am still seeing text spacing problems in some demos (PickTest3D is the most obvious), but only on Windows 7. It is fine on Windows 10
08-04-2016

Looks good to me. I only focusing my review on Region and GridPane. Testing was done on Windows 10 with 100% and 125% configurations running Ensemble8 and some toys programs.
07-04-2016

Jonathan managed to find out why the HelloAlert dialog boxes were laying out wrong and I was able to implement a fix to GridPane. This fixes the dialogs in HelloAlert as well as the bad highlight rectangle in HelloHTMLEditor. http://cr.openjdk.java.net/~flar/JDK-8091832/webrev.rt.05/ (Includes an rt.patch.diff file to show differences from webrev.rt.04) Changes: - Fixed GridPane comparing snapped values to pre-defined constants - Removed some verbose debugging code in the Region.snap*() methods - Fixed a potential race condition NPE in JFXPanel Potential TBD: - Modify snap*() methods to preserve non-positive values so that the predefined metric constants USE_PREF_SIZE and USE_COMPUTED_SIZE are not disturbed by snapping the values - this would be in case anyone else makes the same mistake as GridPane in snapping values before it checks if they are pre-defined constants.
07-04-2016

Latest version of the webrev: http://cr.openjdk.java.net/~flar/JDK-8091832/webrev.rt.04/ (You can see a diff of the webrev.03 patch linked at the top of the index.html file for convenience) Changes since last version: - added @since 9 tags (and updated @see tags) - fixed dirty region processing for non-integer scales - fixed scaling in JFXPanel - removed dead code (ScreenHelper)
07-04-2016

I fixed up the scaling in JFXPanel, but it will still suffer from popup/menu misplacement due to JDK-8153522. By default, both scales should agree so you won't see this unless you start playing with J2D_UISCALE and -Dglass.win.uiScale=N... The only remaining issues are odd layouts in HelloAlert and the odd highlights seen in some demos like HelloHTMLEditor.
07-04-2016

It looks like JFXPanel is forcing itself to perform an integer scale (using Math.round()!) when the values that come from the AWT methods are float, so I will fix that and remove the "wouldn't it be great if AWT..." comment (since it is great and they do...)
07-04-2016

Yes, that suffices. Go ahead and leave it as a read/write (meaning bindable) property.
07-04-2016

> 2. renderScaleXProperty / renderScaleYProperty -- since the render scale > can be updated by the system, it might be better to use a ReadOnlyProperty > (with a public setter) for these to prevent binding to it. This is similar to what > we do for the xProperty and yProperty on Window. Or do you think there are > use cases for binding them? If so, do you check for binding and avoid setting > the property if it is bound? If you look at the updateRenderSales() method you can see that it only sets them if they aren't bound. Does that suffice? BTW, I have a test case in our local test repo that allows you to set the render scale using a slider and it is bound bidirectionally to the slider so that as you drag it from screen to screen it will actually update to the new render scale and move the slider, but if you move the slider it will override. If it wasn't bidirectionally bound, though, then it would stop responding to per-monitor scale changes. I'm not sure if that is all desirable or not, but it works...
06-04-2016

JFXPanel test was the HelloJFXPanel2. It hasn't been moved to open yet, because I broke the linux-arm build the last time I did that (I need to redo it in a separate project from "Hello" so linux-arm doesn't barf). SwingNode test was EmbeddedSwing (ditto about not being in the open yet). Full screen test was hello.HelloFullscreen and hello.HelloFullscreenToggle (those are in rt/apps/toys/Hello) Oh, HTMLEditor can be a problem if you run in legacy mode and put jfxrt.jar on the boot classpath. I'll try the patch for dirtyopts.
06-04-2016

Keep in mind that we used to have oversized text on 125% screens. We used a 125% font, but on a 100% scaled window. This fix brings the rest of the graphics into line with the font size, so you should see the same sized text, just other parts of the window are now larger to match. SwingNode can't deal with non-integer scales yet, see JDK-8153522. I'll be working in concert with the AWT team to upgrade JLightweightFrame to deal with Window's non-integer scales soon. The small text in HelloFontSize looks bad to me at a variety of resolutions. Is there something specific you are seeing there? Does it look worse than 100% scaling? Same questions about the full-screen dialog. HelloHTMLEditor - still investigating, that's really odd, but I also get exceptions when I run it and it can't find some org.w3c classes. It still comes up, but I get 2 stack traces on launch. Which test case did you use with JFXPanel? And the full scr
06-04-2016

The dirty region errors were pointed out before and they also happen on regular jdk9 if you turn off "forceIntegerRenderScale". The distinction is that we now default that to true, but the code was untested. I think I had the action item to either do a quick fix or to change our default for that back to true. I actually found a very small fix to the issue with the following updated code in ViewPainter: int x0, y0; dirtyRect.x = x0 = (int) Math.floor(dirtyRegion.getMinX() * pixelScaleX); dirtyRect.y = y0 = (int) Math.floor(dirtyRegion.getMinY() * pixelScaleY); dirtyRect.width = (int) Math.ceil (dirtyRegion.getMaxX() * pixelScaleX) - x0; dirtyRect.height = (int) Math.ceil (dirtyRegion.getMaxY() * pixelScaleY) - y0; (Note that this replaces the old code that set dirtyRect and then tested pixelScales - the test wasn't going to save us much and just complicated the code and made these rounding out calculations less accurate so I just hard-code that we always scale the dirty Region and it fixes the dirty issues noted in the previous comment. This code will appear in the next webrev...)
06-04-2016

The following results are on Windows 7 system with 125% scaling. * I see dirty region issues (leftover bits of rectangle as it animates). This is reproducible with HelloAnimation as well as any of the animation samples in Ensemble8. * The text for dialogs is laid out vertically in AlertTest (in toys/Hello) rather than horizontally. * Text in the full-screen warning banner looks oddly antialiased. * HelloHTMLEditor -- Blue focus is not drawn correctly. * JFXPanel -- text and graphics in controls drawn in a JFXPanel look somewhat pixelated. I haven't done any extensive testing (e.,g, a WebNode in a JFXPanel would be a good test case). * Small text in HelloFontSize and PickTest3D has quality and spacing issues * Text is a little blurry in SwingNode sample
06-04-2016

Review of just the public API part of the webrev: 1. Need to add "@since 9" javadoc tags on all new public and protected methods and properties. For example, in Screen.java: /** * Gets the recommended output scale factor of this {@code Screen} in * the horizontal ({@code X}) direction. * This scale factor should be applied to a scene in order to compensate * for the resolution and viewing distance of the output device. * The visual bounds will be reported relative to this scale factor. * @return the recommended output scale factor for the screen. >>> * >>> * @since 9 */ public final double getOutputScaleX() { 2. renderScaleXProperty / renderScaleYProperty -- since the render scale can be updated by the system, it might be better to use a ReadOnlyProperty (with a public setter) for these to prevent binding to it. This is similar to what we do for the xProperty and yProperty on Window. Or do you think there are use cases for binding them? If so, do you check for binding and avoid setting the property if it is bound? The rest looks good. I'll review the implementation in a later pass.
06-04-2016

Latest webrev: http://cr.openjdk.java.net/~flar/JDK-8091832/webrev.rt.03/ Changes in this version: - Switch to using USER_DEFAULT_SCREEN_DPI pre-defined constant instead of hard-coded 96's - Added @Ignore to failing test RT32570Test.java
06-04-2016

I'll be creating a new webrev to add the @Ignore for the failing test case for RT-32570, so I'll make this change(s) while I'm at it.
05-04-2016

I thought it will be good to clean this up since you are already touching it, but I will leave it you to decide. May be having a comment might be good enough for now.
05-04-2016

It looks like our code protectively defines WM_DPICHANGED if it is not defined by the includes so it is not true that we can assume that USER_DEFAULT_SCREEN_DPI is defined as well, unless it pre-dates WM_DPICHANGED. I can find no reference to which releases it is defined in. I suppose I could just protectively define it similar to the way that we define WM_DPICHANGED. Note that we tend to use 96.0f which is a float constant, but using that compiler constant would require explicit casts to float to get the accurate floating point answers. Is this something that should be fixed in this patch?
04-04-2016

That's an interesting question. This isn't new to this particular patch, though, but in reading the DPI_CHANGED documentation they refer to a constant "USER_DEFAULT_SCREEN_DPI" which is set to 96. I suppose we should use that, but I can't find any reference for it other than a mention on that page, so I don't know which version of the Windows SDK is needed to see that constant. I suppose we assume that "DPI_CHANGED" is defined, so if that is defined then "USER_DEFAULT_SCREEN_DPI" must also be...
04-04-2016

I have tested this proposed change on Linux (dev-build-full), Mac and Windows (dev-build-lite). The code looks good to me except this minor point: Do you think it is better to define a constant and document the value 96.0f? ./native-font/fontpath.c: return (-ncmetrics.lfMessageFont.lfHeight) * 96.0f / dpiY; ./native-glass/win/GlassApplication.h: return IsUIScaleOverridden() ? overrideUIScale : dpi / 96.0f; ./native-glass/win/GlassWindow.cpp: jfloat xScale = xDPI / 96.0f; ./native-glass/win/GlassWindow.cpp: jfloat yScale = yDPI / 96.0f;
04-04-2016

Here is an update with the following additional fixes: http://cr.openjdk.java.net/~flar/JDK-8091832/webrev.rt.02/ - Redundant or obsolete command line overrides removed from Windows code as follows: Settings still supported: -Dglass.win.uiScale Settings no longer supported, implementation conflicts with Per-Monitor DPI support: -Dglass.win.minHiDPI Settings no longer supported, replaced by API in FX classes: -Dglass.win.renderScale -Dglass.win.forceIntegerRenderScale - Font size now scales with uiScale override on Windows - Fixes to scaling in JFXPanel - Fixes to scaling in SwingPanel - Monocle Screen initialization fixed Note that SwingNode does not seem to relay the FX scaling parameters to Swing correctly, but that was true before these fixes. This patch will keep the functionality roughly the same, but additional fixes are needed to do proper scaling of embedded Swing nodes. I looked at what was needed and have an idea of what the fix would involve, but decided that it was outside the scope of these fixes that are needed to get the HiDPI FX properties implemented.
31-03-2016

Here is the webrev for fixing snapToPixel and adding the following utility calls for querying and manipulating the scales for HiDPI screens: http://cr.openjdk.java.net/~flar/JDK-8091832/webrev.rt.00/ Methods added or deprecated: Screen.getOutputScaleX/Y() Window.getOutputScaleX/Y() // read-only properties Window.set/getForceIntegerRenderScale() // read-write property Window.set/getRenderScaleX/Y() // read-write properties Region.snapSpaceX/Y() // deprecated Region.snapSpace() Region.snapSizeX/Y() // deprecated Region.snapSize() Region.snapPositionX/Y() // deprecated Region.snapPosition()
29-03-2016

Similar APIs will be created to solve the "snap to pixel" issues with non-integer scale factors on Windows. The only difference is that we are going to provide separate X & Y values since Windows can express non-uniform scaling.
15-01-2016

This is an essential feature I am looking for too. How do you want to draw sharp and thin lines on a display if you do not know this scale factor? The necessary linewidth is 1.0 and the offset from the integer raster positions is 0.5 on an unscaled display. It would have to be 0.5 and 0.25 for a standard Mac retina display with a scale factor of 2 but how do you want to find that out if you don't have the scale facto?.
10-03-2015

This is something we will consider doing. We are currently looking to fix Hi-DPI issues on Windows for 8u60 without adding new API. We can consider this request along with any other new API for 9.
13-02-2015