跳到主要内容

JEP 263: HiDPI Graphics on Windows and Linux

Summary

Implement HiDPI graphics on Windows and Linux.

Motivation

Developers and users have some basic expectations for applications running on HiDPI displays:

  • Windows and GUI components should have an appropriate size based on the platform recommendations,

  • Text should remain crisp despite any default scaling indicated by the HiDPI settings, and

  • Icons and images should be smooth and preferably have details appropriate for the pixel density of the display.

Unfortunately, Java applications are still sized and rendered based on pixels on Windows and Linux even on HiDPI displays that can have pixel densities 2 to 3 times as high as traditional displays. This leads to GUI components and windows that are 2 to 3 times too small and thus too small to read or effectively interact with.

The JDK already supports HiDPI "retina displays" on Mac OS X and displays crisp text and images at the appropriate sizes for the density of the display. A fair amount of groundwork for supporting HiDPI displays on all platforms has already been provided by the Mac "retina" support, but differences in the way that applications are supposed to handle HiDPI in the various platforms means that additional work remains to generalize what was done for the Mac.

The same automatic scaling and sizing should now be provided for the Windows and Linux platforms.

Description

HiDPI on Windows

The Windows control panel has provided a number of ways for users to request scaling of components and windows on the desktop for several releases (in various forms since as far back as Windows XP). Some OS versions have also provided facilities for automatic scaling of applications that are not declared to be "DPI-aware". The default scaling for "DPI-unaware" applications can cause a number of visual artifacts including blurry windows and inaccurate layouts and clipped text, so the Java runtime has declared itself to be "DPI-aware" for some time in order to avoid the blurriness and layout problems. Support for scaling the content according to the DPI was not a trivial task, though, and since most display densities only called for a small 25% scaling it was decided to just ignore the recommended scaling guidelines and policies and continue to render AWT and Swing components at 1:1 pixel scaling and let JDK applications be slightly smaller than the norm, but with crisp text and graphics.

Recently, though, displays have made large jumps in pixel densities and it is easy to find laptops with screens that are 2 to 3 times the density of displays that were common when those decisions were made. As a result, Java applications on these newer Windows machines can sometimes be so small as to be unusable -- this is no longer a case of "slightly smaller vs. blurry windows", and so we need to properly scale our application windows.

The Windows APIs provide metrics, mechanisms, and guidelines to write DPI–aware applications to make a UI look consistent across a wide variety of DPI display settings and respond to user preferences for making the UI large enough for users to be comfortable interacting with UI components.

The Windows Direct2D graphics API automatically honors the system DPI, expresses coordinates in DIPs (a device independent pixel), enables bitmaps to have a DPI, and correctly scales them by taking the DPI into account. However, the AWT and Swing libraries are not based on the Direct2D graphics API.

Windows 7 and later releases provide a number of methods to to get the horizontal and vertical DPI of the desktop, including the GetDesktopDpi method and, more recently in Windows 8.1, the GetDpiForMonitor method and the WM_DPICHANGED messages. These values can be used to scale window sizes, mouse coordinates, and fonts for the HiDPI support in AWT/Swing libraries. The necessary support for scaling is already present in the Java2D rendering layer, but we need to advertise these values to Swing and AWT and update their components to recognize and honor the scale factor. This support includes making sure that the desired rendering scale factor is supplied to the Java2D Graphics object, that intermediate rendering images are rendered with the appropriate scale factor for the destination, and any assumptions about how the coordinates in rendering calls map to pixels need to be reexamined.

HiDPI on Linux

HiDPI support has been implemented in the GTK+ 3 libraries. The GTK library automatically scales applications on the client side when a HiDPI display is used.

Java2D and AWT use the XLib library, which does not support HiDPI. As a result, current Java applications can look 2 to 3 times too small on HiDPI displays on Linux.

Additionally, any Java applications that use the GTK look&feel style may automatically benefit from the support of HiDPI in the GTK library while the size of the window and other components may match the GTK components which have been enlarged by 2-3x to satisfy the HiDPI requirements. This can lead to problems such as those described in JDK-8058742.

Alternatives

A developer could manually scale all GUI elements in an application when running on a HiDPI display, but this requires a lot of refactoring work for the application and the Swing and AWT components are not written to cooperate well with attempts to scale them from the outside.

Testing

The following testing should be done on HiDPI displays. A variety of screen scales would be preferable -- 192 DPI and 144 DPI would be a good minimal support matrix. Note that a very high DPI display can be set to a lower artificial DPI using the Windows control panel so additional systems are not necessarily required, but they would have to be reconfigured between test runs. Additionally, changing the DPI on Windows typically requires a restart for the new DPI to be advertised to applications.

In Windows, DPI settings can be set in the Control Panel. Different variations of the control panel and the allowed settings are present on Windows 7, Windows 8.1, and older versions of Windows, but all tend to result in the same type of information being delivered to the application (an indicated DPI for X & Y), so no additional testing is required under the variations of the control panel at this time, this simply becomes a detail that affects how the test environments are configured.

On Linux, DPI settings can be emulated using the GDK_SCALE environment variable for GTK+ 3, or the scaling-factor setting for GNOME 3.

The following items should be checked:

  • Text should not be blurry
  • Text in components (labels and buttons) should not be clipped
  • UI component Layouts should remain sensible on AWT/Swing (i.e. no overlapping or odd gaps)
  • High-resolution icons should be used on AWT/Swing dialogs and components when provided by the application or test case
  • Application should correctly handle mouse events
  • Applications should have a similar size to well-behaved DPI-aware native applications