8279227: Access Bridge: Wrong frame position and hit test result on HiDPI display

Reviewed-by: ant, kizune, aivanov
This commit is contained in:
Aleksandr Veselov 2022-01-18 18:51:58 +00:00 committed by Anton Tarasov
parent bd35f9740d
commit 20ef954158

View File

@ -27,6 +27,7 @@ package com.sun.java.accessibility.internal;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.AffineTransform;
import java.util.*;
import java.lang.*;
import java.lang.reflect.*;
@ -478,6 +479,9 @@ public final class AccessBridge {
if (parent == null) {
return null;
}
Point userSpaceXY = AccessibilityGraphicsEnvironment.toUserSpace(x, y);
x = userSpaceXY.x;
y = userSpaceXY.y;
if (windowHandleToContextMap != null &&
windowHandleToContextMap.containsValue(getRootAccessibleContext(parent))) {
// Path for applications that register their top-level
@ -1593,6 +1597,8 @@ public final class AccessBridge {
if (p != null) {
r.x = p.x;
r.y = p.y;
r = AccessibilityGraphicsEnvironment.toDeviceSpaceAbs(r);
return r;
}
} catch (Exception e) {
@ -2257,6 +2263,7 @@ public final class AccessBridge {
if (s != null && s.equals("\n")) {
rect.width = 0;
}
rect = AccessibilityGraphicsEnvironment.toDeviceSpaceAbs(rect);
return rect;
}
}
@ -7338,4 +7345,182 @@ public final class AccessBridge {
}
}
}
/**
* A helper class to handle coordinate conversion between screen and user spaces.
* See {@link sun.java2d.SunGraphicsEnvironment}
*/
private static abstract class AccessibilityGraphicsEnvironment extends GraphicsEnvironment {
/**
* Returns the graphics configuration which bounds contain the given point in the user's space.
*
* See {@link sun.java2d.SunGraphicsEnvironment#getGraphicsConfigurationAtPoint(GraphicsConfiguration, double, double)}
*
* @param x the x coordinate of the given point in the user's space
* @param y the y coordinate of the given point in the user's space
* @return the graphics configuration
*/
public static GraphicsConfiguration getGraphicsConfigurationAtPoint(double x, double y) {
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment()
.getDefaultScreenDevice().getDefaultConfiguration();
return getGraphicsConfigurationAtPoint(gc, x, y);
}
/**
* Returns the graphics configuration which bounds contain the given point in the user's space.
*
* See {@link sun.java2d.SunGraphicsEnvironment#getGraphicsConfigurationAtPoint(GraphicsConfiguration, double, double)}
*
* @param current the default configuration which is checked in the first
* place
* @param x the x coordinate of the given point in the user's space
* @param y the y coordinate of the given point in the user's space
* @return the graphics configuration
*/
public static GraphicsConfiguration getGraphicsConfigurationAtPoint(
GraphicsConfiguration current, double x, double y) {
if (containsUserSpacePoint(current, x, y)) {
return current;
}
GraphicsEnvironment env = getLocalGraphicsEnvironment();
for (GraphicsDevice device : env.getScreenDevices()) {
GraphicsConfiguration config = device.getDefaultConfiguration();
if (containsUserSpacePoint(config, x, y)) {
return config;
}
}
return current;
}
/**
* Returns the graphics configuration which bounds contain the given point in the device space.
*
* @param x the x coordinate of the given point in the device space
* @param y the y coordinate of the given point in the device space
* @return the graphics configuration
*/
public static GraphicsConfiguration getGraphicsConfigurationAtDevicePoint(double x, double y) {
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment()
.getDefaultScreenDevice().getDefaultConfiguration();
return getGraphicsConfigurationAtDevicePoint(gc, x, y);
}
/**
* Returns the graphics configuration which bounds contain the given point in the device space.
*
* @param current the default configuration which is checked in the first
* place
* @param x the x coordinate of the given point in the device space
* @param y the y coordinate of the given point in the device space
* @return the graphics configuration
*/
public static GraphicsConfiguration getGraphicsConfigurationAtDevicePoint(
GraphicsConfiguration current, double x, double y) {
if (containsDeviceSpacePoint(current, x, y)) {
return current;
}
GraphicsEnvironment env = getLocalGraphicsEnvironment();
for (GraphicsDevice device : env.getScreenDevices()) {
GraphicsConfiguration config = device.getDefaultConfiguration();
if (containsDeviceSpacePoint(config, x, y)) {
return config;
}
}
return current;
}
private static boolean containsDeviceSpacePoint(GraphicsConfiguration config, double x, double y) {
Rectangle bounds = config.getBounds();
bounds = toDeviceSpaceAbs(config, bounds.x, bounds.y, bounds.width, bounds.height);
return bounds.contains(x, y);
}
private static boolean containsUserSpacePoint(GraphicsConfiguration config, double x, double y) {
Rectangle bounds = config.getBounds();
return bounds.contains(x, y);
}
/**
* Converts absolute coordinates from the device
* space to the user's space space using appropriate device transformation.
*
* @param x absolute x coordinate in the device's space
* @param y absolute y coordinate in the device's space
* @return the corresponding coordinates in user's space
*/
public static Point toUserSpace(int x, int y) {
GraphicsConfiguration gc = getGraphicsConfigurationAtDevicePoint(x, y);
return toUserSpace(gc, x, y);
}
/**
* Converts absolute coordinates from the device
* space to the user's space using passed graphics configuration.
*
* @param gc the graphics configuration to be used for transformation
* @param x absolute x coordinate in the device's space
* @param y absolute y coordinate in the device's space
* @return the corresponding coordinates in user's space
*/
public static Point toUserSpace(GraphicsConfiguration gc, int x, int y) {
AffineTransform tx = gc.getDefaultTransform();
Rectangle screen = gc.getBounds();
int userX = screen.x + clipRound((x - screen.x) / tx.getScaleX());
int userY = screen.y + clipRound((y - screen.y) / tx.getScaleY());
return new Point(userX, userY);
}
/**
* Converts the rectangle from the user's space to the device space using
* appropriate device transformation.
*
* See {@link sun.java2d.SunGraphicsEnvironment#toDeviceSpaceAbs(Rectangle)}
*
* @param rect the rectangle in the user's space
* @return the rectangle which uses device space (pixels)
*/
public static Rectangle toDeviceSpaceAbs(Rectangle rect) {
GraphicsConfiguration gc = getGraphicsConfigurationAtPoint(rect.x, rect.y);
return toDeviceSpaceAbs(gc, rect.x, rect.y, rect.width, rect.height);
}
/**
* Converts absolute coordinates (x, y) and the size (w, h) from the user's
* space to the device space using passed graphics configuration.
*
* See {@link sun.java2d.SunGraphicsEnvironment#toDeviceSpaceAbs(GraphicsConfiguration, int, int, int, int)}
*
* @param gc the graphics configuration to be used for transformation
* @param x absolute coordinate in the user's space
* @param y absolute coordinate in the user's space
* @param w the width in the user's space
* @param h the height in the user's space
* @return the rectangle which uses device space (pixels)
*/
public static Rectangle toDeviceSpaceAbs(GraphicsConfiguration gc,
int x, int y, int w, int h) {
AffineTransform tx = gc.getDefaultTransform();
Rectangle screen = gc.getBounds();
return new Rectangle(
screen.x + clipRound((x - screen.x) * tx.getScaleX()),
screen.y + clipRound((y - screen.y) * tx.getScaleY()),
clipRound(w * tx.getScaleX()),
clipRound(h * tx.getScaleY())
);
}
/**
* See {@link sun.java2d.pipe.Region#clipRound}
*/
private static int clipRound(final double coordinate) {
final double newv = coordinate - 0.5;
if (newv < Integer.MIN_VALUE) {
return Integer.MIN_VALUE;
}
if (newv > Integer.MAX_VALUE) {
return Integer.MAX_VALUE;
}
return (int) Math.ceil(newv);
}
}
}