Class HiDPIUtils
- java.lang.Object
-
- com.formdev.flatlaf.util.HiDPIUtils
-
public class HiDPIUtils extends java.lang.Object
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description static interface
HiDPIUtils.DirtyRegionCallback
static class
HiDPIUtils.HiDPIRepaintManager
A repaint manager that fixes a problem in Swing when repainting components at some scale factors (e.g.static interface
HiDPIUtils.Painter
-
Field Summary
Fields Modifier and Type Field Description private static float[]
CORRECTION_INTER
private static float[]
CORRECTION_OPEN_SANS
private static float[]
CORRECTION_SEGOE_UI
private static float[]
CORRECTION_TAHOMA
private static float[]
SCALE_FACTORS
private static java.lang.Boolean
useDebugScaleFactor
private static java.lang.Boolean
useTextYCorrection
-
Constructor Summary
Constructors Constructor Description HiDPIUtils()
-
Method Summary
All Methods Static Methods Concrete Methods Modifier and Type Method Description static void
addDirtyRegion(javax.swing.JComponent c, int x, int y, int width, int height, HiDPIUtils.DirtyRegionCallback callback)
Similar torepaint(Component, int, int, int, int)
, but invokes callback instead of invokingComponent.repaint(int, int, int, int)
.static float
computeTextYCorrection(java.awt.Graphics2D g)
When painting text on HiDPI screens and the JRE scales, then the text is painted too far down on some operating systems.private static float
correctionForScaleY(java.awt.Graphics2D g, float[] correction)
static java.awt.Graphics2D
createGraphicsTextYCorrection(java.awt.Graphics2D g)
Creates a graphics object and applies Y correction to string drawing methods.static void
drawStringUnderlineCharAtWithYCorrection(javax.swing.JComponent c, java.awt.Graphics2D g, java.lang.String text, int underlinedIndex, int x, int y)
Applies Y correction and draws the given string at the specified location underlining the specified character.static void
drawStringWithYCorrection(javax.swing.JComponent c, java.awt.Graphics2D g, java.lang.String text, int x, int y)
Applies Y correction and draws the given string at the specified location.private static float
getUserScaleFactor()
static void
installHiDPIRepaintManager()
Installs aHiDPIUtils.HiDPIRepaintManager
on Windows when running in Java 9+, but only if default repaint manager is currently installed.private static boolean
needsSpecialRepaint(java.awt.Component c, int x, int y, int width, int height)
There is a problem in Swing, when using scale factors that end on .25 or .75 (e.g.private static double
normalize(double value)
static void
paintAtScale1x(java.awt.Graphics2D g, int x, int y, int width, int height, HiDPIUtils.Painter painter)
Paint at system scale factor 1x to avoid rounding issues at 125%, 150% and 175% scaling.static void
paintAtScale1x(java.awt.Graphics2D g, javax.swing.JComponent c, HiDPIUtils.Painter painter)
static void
repaint(java.awt.Component c)
Repaints the given component.static void
repaint(java.awt.Component c, int x, int y, int width, int height)
Repaints the given component area.static void
repaint(java.awt.Component c, java.awt.Rectangle r)
Repaints the given component area.private static java.awt.geom.Rectangle2D.Double
scale(double scaleX, double scaleY, double px, double py, int width, int height)
Scales a rectangle in the same way as the JRE does in sun.java2d.pipe.PixelToParallelogramConverter.fillRectangle(), which is used by Graphics.fillRect().private static int
scaleFactor2index(float scaleFactor)
private static boolean
useDebugScaleFactor()
private static boolean
useTextYCorrection()
-
-
-
Field Detail
-
useTextYCorrection
private static java.lang.Boolean useTextYCorrection
-
SCALE_FACTORS
private static final float[] SCALE_FACTORS
-
CORRECTION_SEGOE_UI
private static final float[] CORRECTION_SEGOE_UI
-
CORRECTION_TAHOMA
private static final float[] CORRECTION_TAHOMA
-
CORRECTION_INTER
private static final float[] CORRECTION_INTER
-
CORRECTION_OPEN_SANS
private static final float[] CORRECTION_OPEN_SANS
-
useDebugScaleFactor
private static java.lang.Boolean useDebugScaleFactor
-
-
Method Detail
-
paintAtScale1x
public static void paintAtScale1x(java.awt.Graphics2D g, javax.swing.JComponent c, HiDPIUtils.Painter painter)
-
paintAtScale1x
public static void paintAtScale1x(java.awt.Graphics2D g, int x, int y, int width, int height, HiDPIUtils.Painter painter)
Paint at system scale factor 1x to avoid rounding issues at 125%, 150% and 175% scaling.Scales the given Graphics2D down to 100% and invokes the given painter passing scaled x, y, width and height.
Uses the same scaling calculation as the JRE uses.
-
scale
private static java.awt.geom.Rectangle2D.Double scale(double scaleX, double scaleY, double px, double py, int width, int height)
Scales a rectangle in the same way as the JRE does in sun.java2d.pipe.PixelToParallelogramConverter.fillRectangle(), which is used by Graphics.fillRect().
-
normalize
private static double normalize(double value)
-
useTextYCorrection
private static boolean useTextYCorrection()
-
computeTextYCorrection
public static float computeTextYCorrection(java.awt.Graphics2D g)
When painting text on HiDPI screens and the JRE scales, then the text is painted too far down on some operating systems. The higher the system scale factor is, the more.This method computes a correction value for the Y position.
-
correctionForScaleY
private static float correctionForScaleY(java.awt.Graphics2D g, float[] correction)
-
scaleFactor2index
private static int scaleFactor2index(float scaleFactor)
-
useDebugScaleFactor
private static boolean useDebugScaleFactor()
-
getUserScaleFactor
private static float getUserScaleFactor()
-
drawStringWithYCorrection
public static void drawStringWithYCorrection(javax.swing.JComponent c, java.awt.Graphics2D g, java.lang.String text, int x, int y)
Applies Y correction and draws the given string at the specified location. The provided component is used to query text properties and anti-aliasing hints.Use this method instead of
Graphics.drawString(String, int, int)
for correct anti-aliasing.Replacement for
SwingUtilities2.drawString()
.
-
drawStringUnderlineCharAtWithYCorrection
public static void drawStringUnderlineCharAtWithYCorrection(javax.swing.JComponent c, java.awt.Graphics2D g, java.lang.String text, int underlinedIndex, int x, int y)
Applies Y correction and draws the given string at the specified location underlining the specified character. The provided component is used to query text properties and anti-aliasing hints.Replacement for
SwingUtilities2.drawStringUnderlineCharAt()
.
-
createGraphicsTextYCorrection
public static java.awt.Graphics2D createGraphicsTextYCorrection(java.awt.Graphics2D g)
Creates a graphics object and applies Y correction to string drawing methods. If no Y correction is necessary, the passed in graphics object is returned.
-
repaint
public static void repaint(java.awt.Component c)
Repaints the given component.See
repaint(Component, int, int, int, int)
for more details.- Since:
- 3.5
-
repaint
public static void repaint(java.awt.Component c, java.awt.Rectangle r)
Repaints the given component area.See
repaint(Component, int, int, int, int)
for more details.- Since:
- 3.5
-
repaint
public static void repaint(java.awt.Component c, int x, int y, int width, int height)
Repaints the given component area.Invokes
Component.repaint(int, int, int, int)
on the given component,Use this method, instead of
Component.repaint(...)
, to fix a problem in Swing when using scale factors that end on .25 or .75 (e.g. 1.25, 1.75, 2.25, etc) and repainting single components, which may not repaint right and/or bottom 1px edge of component.The problem may occur under following conditions:
- using Java 9 or later
- system scale factor is 125%, 175%, 225%, ... (Windows only; Java on macOS and Linux does not support fractional scale factors)
- repaint whole component or right/bottom area of component
- component is opaque; or component is contained in a opaque container that has same right/bottom bounds as component
- component has bounds that Java/Swing scales different when repainting components
- Since:
- 3.5
-
needsSpecialRepaint
private static boolean needsSpecialRepaint(java.awt.Component c, int x, int y, int width, int height)
There is a problem in Swing, when using scale factors that end on .25 or .75 (e.g. 1.25, 1.75, 2.25, etc) and repainting single components, which may not repaint right and/or bottom 1px edge of component.The component is first painted to an in-memory image, and then that image is copied to the screen. See
javax.swing.RepaintManager.PaintManager#paintDoubleBufferedFPScales()
.There are two clipping rectangles involved when copying the image to the screen:
sun.java2d.SunGraphics2D#devClip
andsun.java2d.SunGraphics2D#usrClip
.devClip
is the device clipping in physical pixels. It gets the bounds of the painting component, which is either the passed component, or if it is non-opaque, then the first opaque ancestor of the passed component. It is calculated insun.java2d.SunGraphics2D#constrain()
while getting a graphics context viaJComponent.getGraphics()
.usrClip
is the user clipping, which is set viaGraphics
clipping methods. This is done injavax.swing.RepaintManager.PaintManager#paintDoubleBufferedFPScales()
.The intersection of
devClip
andusrClip
(computed insun.java2d.SunGraphics2D#validateCompClip()
) is used to copy the image to the screen.Unfortunately different scaling/rounding strategies are used to calculate the two clipping rectangles, which is the reason of the issue.
devClip
(seesun.java2d.SunGraphics2D#constrain()
):int devX = (int) (x * scale); int devWidth = Math.round( width * scale )
usrClip
(seejavax.swing.RepaintManager.PaintManager#paintDoubleBufferedFPScales()
):
X/Y coordinates are always rounded down forint usrX = (int) Math.ceil( (x * scale) - 0.5 ); int usrWidth = ((int) Math.ceil( ((x + width) * scale) - 0.5 )) - usrX;
devClip
, but rounded up forusrClip
. Width/height calculation is also different.
-
installHiDPIRepaintManager
public static void installHiDPIRepaintManager()
Installs aHiDPIUtils.HiDPIRepaintManager
on Windows when running in Java 9+, but only if default repaint manager is currently installed.Invoke once on application startup. Compatible with all/other LaFs.
- Since:
- 3.5
-
addDirtyRegion
public static void addDirtyRegion(javax.swing.JComponent c, int x, int y, int width, int height, HiDPIUtils.DirtyRegionCallback callback)
Similar torepaint(Component, int, int, int, int)
, but invokes callback instead of invokingComponent.repaint(int, int, int, int)
.For use in custom repaint managers.
- Since:
- 3.5
-
-