--- a/jdk/src/java.base/windows/native/launcher/java.manifest Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.base/windows/native/launcher/java.manifest Fri Nov 13 05:02:26 2015 -0800
@@ -37,7 +37,7 @@
<!-- Indicate JDK is high-dpi aware. -->
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
- <dpiAware>true</dpiAware>
+ <dpiAware>true/PM</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
--- a/jdk/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java Fri Nov 13 05:02:26 2015 -0800
@@ -166,7 +166,12 @@
}
@Override
- public int getDefaultScale() {
+ public double getDefaultScaleX() {
+ return scale;
+ }
+
+ @Override
+ public double getDefaultScaleY() {
return scale;
}
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java Fri Nov 13 05:02:26 2015 -0800
@@ -1156,7 +1156,9 @@
&& !(dst instanceof NullSurfaceData)
&& !(src instanceof NullSurfaceData)
&& src.getSurfaceType().equals(dst.getSurfaceType())
- && src.getDefaultScale() == dst.getDefaultScale()) {
+ && src.getDefaultScaleX() == dst.getDefaultScaleX()
+ && src.getDefaultScaleY() == dst.getDefaultScaleY())
+ {
final Rectangle size = src.getBounds();
final Blit blit = Blit.locate(src.getSurfaceType(),
CompositeType.Src,
--- a/jdk/src/java.desktop/share/classes/sun/awt/image/BufImgSurfaceData.java Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/BufImgSurfaceData.java Fri Nov 13 05:02:26 2015 -0800
@@ -50,6 +50,8 @@
BufferedImage bufImg;
private BufferedImageGraphicsConfig graphicsConfig;
RenderLoops solidloops;
+ private final double scaleX;
+ private final double scaleY;
private static native void initIDs(Class<?> ICM, Class<?> ICMColorData);
@@ -73,6 +75,12 @@
}
public static SurfaceData createData(BufferedImage bufImg) {
+ return createData(bufImg, 1, 1);
+ }
+
+ public static SurfaceData createData(BufferedImage bufImg,
+ double scaleX, double scaleY)
+ {
if (bufImg == null) {
throw new NullPointerException("BufferedImage cannot be null");
}
@@ -82,31 +90,36 @@
// REMIND: Check the image type and pick an appropriate subclass
switch (type) {
case BufferedImage.TYPE_INT_BGR:
- sData = createDataIC(bufImg, SurfaceType.IntBgr);
+ sData = createDataIC(bufImg, SurfaceType.IntBgr, scaleX, scaleY);
break;
case BufferedImage.TYPE_INT_RGB:
- sData = createDataIC(bufImg, SurfaceType.IntRgb);
+ sData = createDataIC(bufImg, SurfaceType.IntRgb, scaleX, scaleY);
break;
case BufferedImage.TYPE_INT_ARGB:
- sData = createDataIC(bufImg, SurfaceType.IntArgb);
+ sData = createDataIC(bufImg, SurfaceType.IntArgb, scaleX, scaleY);
break;
case BufferedImage.TYPE_INT_ARGB_PRE:
- sData = createDataIC(bufImg, SurfaceType.IntArgbPre);
+ sData = createDataIC(bufImg, SurfaceType.IntArgbPre, scaleX, scaleY);
break;
case BufferedImage.TYPE_3BYTE_BGR:
- sData = createDataBC(bufImg, SurfaceType.ThreeByteBgr, 2);
+ sData = createDataBC(bufImg, SurfaceType.ThreeByteBgr, 2,
+ scaleX, scaleY);
break;
case BufferedImage.TYPE_4BYTE_ABGR:
- sData = createDataBC(bufImg, SurfaceType.FourByteAbgr, 3);
+ sData = createDataBC(bufImg, SurfaceType.FourByteAbgr, 3,
+ scaleX, scaleY);
break;
case BufferedImage.TYPE_4BYTE_ABGR_PRE:
- sData = createDataBC(bufImg, SurfaceType.FourByteAbgrPre, 3);
+ sData = createDataBC(bufImg, SurfaceType.FourByteAbgrPre, 3,
+ scaleX, scaleY);
break;
case BufferedImage.TYPE_USHORT_565_RGB:
- sData = createDataSC(bufImg, SurfaceType.Ushort565Rgb, null);
+ sData = createDataSC(bufImg, SurfaceType.Ushort565Rgb, null,
+ scaleX, scaleY);
break;
case BufferedImage.TYPE_USHORT_555_RGB:
- sData = createDataSC(bufImg, SurfaceType.Ushort555Rgb, null);
+ sData = createDataSC(bufImg, SurfaceType.Ushort555Rgb, null,
+ scaleX, scaleY);
break;
case BufferedImage.TYPE_BYTE_INDEXED:
{
@@ -128,14 +141,16 @@
default:
throw new InternalError("Unrecognized transparency");
}
- sData = createDataBC(bufImg, sType, 0);
+ sData = createDataBC(bufImg, sType, 0, scaleX, scaleY);
}
break;
case BufferedImage.TYPE_BYTE_GRAY:
- sData = createDataBC(bufImg, SurfaceType.ByteGray, 0);
+ sData = createDataBC(bufImg, SurfaceType.ByteGray, 0,
+ scaleX, scaleY);
break;
case BufferedImage.TYPE_USHORT_GRAY:
- sData = createDataSC(bufImg, SurfaceType.UshortGray, null);
+ sData = createDataSC(bufImg, SurfaceType.UshortGray, null,
+ scaleX, scaleY);
break;
case BufferedImage.TYPE_BYTE_BINARY:
{
@@ -154,7 +169,7 @@
default:
throw new InternalError("Unrecognized pixel size");
}
- sData = createDataBP(bufImg, sType);
+ sData = createDataBP(bufImg, sType, scaleX, scaleY);
}
break;
case BufferedImage.TYPE_CUSTOM:
@@ -191,7 +206,7 @@
sType = SurfaceType.AnyDcm;
}
}
- sData = createDataIC(bufImg, sType);
+ sData = createDataIC(bufImg, sType, scaleX, scaleY);
break;
} else if (raster instanceof ShortComponentRaster &&
raster.getNumDataElements() == 1 &&
@@ -233,11 +248,12 @@
icm = null;
}
}
- sData = createDataSC(bufImg, sType, icm);
+ sData = createDataSC(bufImg, sType, icm, scaleX, scaleY);
break;
}
- sData = new BufImgSurfaceData(raster.getDataBuffer(),
- bufImg, SurfaceType.Custom);
+ sData = new BufImgSurfaceData(raster.getDataBuffer(), bufImg,
+ SurfaceType.Custom,
+ scaleX, scaleY);
}
break;
}
@@ -250,11 +266,15 @@
}
public static SurfaceData createDataIC(BufferedImage bImg,
- SurfaceType sType) {
+ SurfaceType sType,
+ double scaleX,
+ double scaleY)
+ {
IntegerComponentRaster icRaster =
(IntegerComponentRaster)bImg.getRaster();
BufImgSurfaceData bisd =
- new BufImgSurfaceData(icRaster.getDataBuffer(), bImg, sType);
+ new BufImgSurfaceData(icRaster.getDataBuffer(), bImg, sType,
+ scaleX, scaleY);
bisd.initRaster(icRaster.getDataStorage(),
icRaster.getDataOffset(0) * 4, 0,
icRaster.getWidth(),
@@ -267,11 +287,14 @@
public static SurfaceData createDataSC(BufferedImage bImg,
SurfaceType sType,
- IndexColorModel icm) {
+ IndexColorModel icm,
+ double scaleX, double scaleY)
+ {
ShortComponentRaster scRaster =
(ShortComponentRaster)bImg.getRaster();
BufImgSurfaceData bisd =
- new BufImgSurfaceData(scRaster.getDataBuffer(), bImg, sType);
+ new BufImgSurfaceData(scRaster.getDataBuffer(), bImg, sType,
+ scaleX, scaleY);
bisd.initRaster(scRaster.getDataStorage(),
scRaster.getDataOffset(0) * 2, 0,
scRaster.getWidth(),
@@ -284,11 +307,14 @@
public static SurfaceData createDataBC(BufferedImage bImg,
SurfaceType sType,
- int primaryBank) {
+ int primaryBank,
+ double scaleX, double scaleY)
+ {
ByteComponentRaster bcRaster =
(ByteComponentRaster)bImg.getRaster();
BufImgSurfaceData bisd =
- new BufImgSurfaceData(bcRaster.getDataBuffer(), bImg, sType);
+ new BufImgSurfaceData(bcRaster.getDataBuffer(), bImg, sType,
+ scaleX, scaleY);
ColorModel cm = bImg.getColorModel();
IndexColorModel icm = ((cm instanceof IndexColorModel)
? (IndexColorModel) cm
@@ -304,11 +330,14 @@
}
public static SurfaceData createDataBP(BufferedImage bImg,
- SurfaceType sType) {
+ SurfaceType sType,
+ double scaleX, double scaleY)
+ {
BytePackedRaster bpRaster =
(BytePackedRaster)bImg.getRaster();
BufImgSurfaceData bisd =
- new BufImgSurfaceData(bpRaster.getDataBuffer(), bImg, sType);
+ new BufImgSurfaceData(bpRaster.getDataBuffer(), bImg, sType,
+ scaleX, scaleY);
ColorModel cm = bImg.getColorModel();
IndexColorModel icm = ((cm instanceof IndexColorModel)
? (IndexColorModel) cm
@@ -350,15 +379,22 @@
IndexColorModel icm);
public BufImgSurfaceData(DataBuffer db,
- BufferedImage bufImg, SurfaceType sType)
+ BufferedImage bufImg,
+ SurfaceType sType,
+ double scaleX,
+ double scaleY)
{
super(SunWritableRaster.stealTrackable(db),
sType, bufImg.getColorModel());
this.bufImg = bufImg;
+ this.scaleX = scaleX;
+ this.scaleY = scaleY;
}
protected BufImgSurfaceData(SurfaceType surfaceType, ColorModel cm) {
super(surfaceType, cm);
+ this.scaleX = 1;
+ this.scaleY = 1;
}
public void initSolidLoops() {
@@ -395,7 +431,8 @@
public synchronized GraphicsConfiguration getDeviceConfiguration() {
if (graphicsConfig == null) {
- graphicsConfig = BufferedImageGraphicsConfig.getConfig(bufImg);
+ graphicsConfig = BufferedImageGraphicsConfig
+ .getConfig(bufImg, scaleX, scaleY);
}
return graphicsConfig;
}
@@ -418,6 +455,16 @@
return bufImg;
}
+ @Override
+ public double getDefaultScaleX() {
+ return scaleX;
+ }
+
+ @Override
+ public double getDefaultScaleY() {
+ return scaleY;
+ }
+
public static final class ICMColorData {
private long pData = 0L;
--- a/jdk/src/java.desktop/share/classes/sun/awt/image/BufferedImageGraphicsConfig.java Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/BufferedImageGraphicsConfig.java Fri Nov 13 05:02:26 2015 -0800
@@ -45,19 +45,32 @@
extends GraphicsConfiguration
{
private static final int numconfigs = BufferedImage.TYPE_BYTE_BINARY;
- private static BufferedImageGraphicsConfig configs[] =
+ private static BufferedImageGraphicsConfig standardConfigs[] =
+ new BufferedImageGraphicsConfig[numconfigs];
+ private static BufferedImageGraphicsConfig scaledConfigs[] =
new BufferedImageGraphicsConfig[numconfigs];
public static BufferedImageGraphicsConfig getConfig(BufferedImage bImg) {
+ return getConfig(bImg, 1, 1);
+ }
+
+ public static BufferedImageGraphicsConfig getConfig(BufferedImage bImg,
+ double scaleX,
+ double scaleY)
+ {
BufferedImageGraphicsConfig ret;
int type = bImg.getType();
+
+ BufferedImageGraphicsConfig[] configs = (scaleX == 1 && scaleY == 1)
+ ? standardConfigs : scaledConfigs;
+
if (type > 0 && type < numconfigs) {
ret = configs[type];
- if (ret != null) {
+ if (ret != null && ret.scaleX == scaleX && ret.scaleY == scaleY) {
return ret;
}
}
- ret = new BufferedImageGraphicsConfig(bImg, null);
+ ret = new BufferedImageGraphicsConfig(bImg, null, scaleX, scaleY);
if (type > 0 && type < numconfigs) {
configs[type] = ret;
}
@@ -67,8 +80,16 @@
GraphicsDevice gd;
ColorModel model;
Raster raster;
+ private final double scaleX;
+ private final double scaleY;
public BufferedImageGraphicsConfig(BufferedImage bufImg, Component comp) {
+ this(bufImg, comp, 1, 1);
+ }
+
+ public BufferedImageGraphicsConfig(BufferedImage bufImg, Component comp,
+ double scaleX, double scaleY)
+ {
if (comp == null) {
this.gd = new BufferedImageDevice(this);
} else {
@@ -77,6 +98,8 @@
}
this.model = bufImg.getColorModel();
this.raster = bufImg.getRaster().createCompatibleWritableRaster(1, 1);
+ this.scaleX = scaleX;
+ this.scaleY = scaleY;
}
/**
@@ -138,7 +161,7 @@
* For image buffers, this Transform will be the Identity transform.
*/
public AffineTransform getDefaultTransform() {
- return new AffineTransform();
+ return AffineTransform.getScaleInstance(scaleX, scaleY);
}
/**
--- a/jdk/src/java.desktop/share/classes/sun/awt/image/SunVolatileImage.java Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/SunVolatileImage.java Fri Nov 13 05:02:26 2015 -0800
@@ -233,8 +233,17 @@
* or a backup surface.
*/
public BufferedImage getBackupImage() {
- return graphicsConfig.createCompatibleImage(getWidth(), getHeight(),
- getTransparency());
+ return getBackupImage(1, 1);
+ }
+
+ /**
+ * This method creates a BufferedImage intended for use as a "snapshot"
+ * or a backup surface with the given horizontal and vertical scale factors.
+ */
+ public BufferedImage getBackupImage(double scaleX, double scaleY) {
+ int w = (int) Math.ceil(getWidth() * scaleX);
+ int h = (int) Math.ceil(getHeight() * scaleY);
+ return graphicsConfig.createCompatibleImage(w, h, getTransparency());
}
public BufferedImage getSnapshot() {
--- a/jdk/src/java.desktop/share/classes/sun/awt/image/SurfaceManager.java Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/SurfaceManager.java Fri Nov 13 05:02:26 2015 -0800
@@ -290,16 +290,30 @@
}
/**
- * Returns a scale factor of the image. This is utility method, which
- * fetches information from the SurfaceData of the image.
+ * Returns a horizontal scale factor of the image. This is utility method,
+ * which fetches information from the SurfaceData of the image.
*
- * @see SurfaceData#getDefaultScale
+ * @see SurfaceData#getDefaultScaleX
*/
- public static int getImageScale(final Image img) {
+ public static double getImageScaleX(final Image img) {
if (!(img instanceof VolatileImage)) {
return 1;
}
final SurfaceManager sm = getManager(img);
- return sm.getPrimarySurfaceData().getDefaultScale();
+ return sm.getPrimarySurfaceData().getDefaultScaleX();
+ }
+
+ /**
+ * Returns a vertical scale factor of the image. This is utility method,
+ * which fetches information from the SurfaceData of the image.
+ *
+ * @see SurfaceData#getDefaultScaleY
+ */
+ public static double getImageScaleY(final Image img) {
+ if (!(img instanceof VolatileImage)) {
+ return 1;
+ }
+ final SurfaceManager sm = getManager(img);
+ return sm.getPrimarySurfaceData().getDefaultScaleY();
}
}
--- a/jdk/src/java.desktop/share/classes/sun/awt/image/VolatileSurfaceManager.java Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/VolatileSurfaceManager.java Fri Nov 13 05:02:26 2015 -0800
@@ -25,18 +25,16 @@
package sun.awt.image;
-import java.awt.Color;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.ImageCapabilities;
+import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.VolatileImage;
import sun.awt.DisplayChangedListener;
-import sun.awt.image.SunVolatileImage;
import sun.java2d.SunGraphicsEnvironment;
import sun.java2d.SurfaceData;
-import sun.java2d.loops.CompositeType;
import static sun.java2d.pipe.hw.AccelSurface.*;
/**
@@ -260,12 +258,16 @@
*/
protected SurfaceData getBackupSurface() {
if (sdBackup == null) {
- BufferedImage bImg = vImg.getBackupImage();
+ GraphicsConfiguration gc = vImg.getGraphicsConfig();
+ AffineTransform tx = gc.getDefaultTransform();
+ double scaleX = tx.getScaleX();
+ double scaleY = tx.getScaleY();
+ BufferedImage bImg = vImg.getBackupImage(scaleX, scaleY);
// Sabotage the acceleration capabilities of the BufImg surface
SunWritableRaster.stealTrackable(bImg
.getRaster()
.getDataBuffer()).setUntrackable();
- sdBackup = BufImgSurfaceData.createData(bImg);
+ sdBackup = BufImgSurfaceData.createData(bImg, scaleX, scaleY);
}
return sdBackup;
}
--- a/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java Fri Nov 13 05:02:26 2015 -0800
@@ -61,7 +61,6 @@
import java.awt.Rectangle;
import java.text.AttributedCharacterIterator;
import java.awt.Font;
-import java.awt.Point;
import java.awt.image.ImageObserver;
import java.awt.Transparency;
import java.awt.font.GlyphVector;
@@ -99,6 +98,7 @@
import static java.awt.geom.AffineTransform.TYPE_FLIP;
import static java.awt.geom.AffineTransform.TYPE_MASK_SCALE;
import static java.awt.geom.AffineTransform.TYPE_TRANSLATION;
+import java.awt.image.VolatileImage;
import sun.awt.image.MultiResolutionToolkitImage;
import sun.awt.image.ToolkitImage;
@@ -3086,30 +3086,50 @@
}
// end of text rendering methods
- private boolean isHiDPIImage(final Image img) {
- return (SurfaceManager.getImageScale(img) != 1)
- || img instanceof MultiResolutionImage;
- }
-
- private boolean drawHiDPIImage(Image img, int dx1, int dy1, int dx2,
- int dy2, int sx1, int sy1, int sx2, int sy2,
- Color bgcolor, ImageObserver observer) {
-
- if (SurfaceManager.getImageScale(img) != 1) { // Volatile Image
- final int scale = SurfaceManager.getImageScale(img);
- sx1 = Region.clipScale(sx1, scale);
- sx2 = Region.clipScale(sx2, scale);
- sy1 = Region.clipScale(sy1, scale);
- sy2 = Region.clipScale(sy2, scale);
- } else if (img instanceof MultiResolutionImage) {
+ private Boolean drawHiDPIImage(Image img,
+ int dx1, int dy1, int dx2, int dy2,
+ int sx1, int sy1, int sx2, int sy2,
+ Color bgcolor, ImageObserver observer,
+ AffineTransform xform) {
+
+ if (img instanceof VolatileImage) {
+ final SurfaceData sd = SurfaceManager.getManager(img)
+ .getPrimarySurfaceData();
+ final double scaleX = sd.getDefaultScaleX();
+ final double scaleY = sd.getDefaultScaleY();
+ if (scaleX == 1 && scaleY == 1) {
+ return null;
+ }
+ sx1 = Region.clipScale(sx1, scaleX);
+ sx2 = Region.clipScale(sx2, scaleX);
+ sy1 = Region.clipScale(sy1, scaleY);
+ sy2 = Region.clipScale(sy2, scaleY);
+
+ AffineTransform tx = null;
+ if (xform != null) {
+ tx = new AffineTransform(transform);
+ transform(xform);
+ }
+ boolean result = scaleImage(img, dx1, dy1, dx2, dy2,
+ sx1, sy1, sx2, sy2,
+ bgcolor, observer);
+ if (tx != null) {
+ transform.setTransform(tx);
+ invalidateTransform();
+ }
+ return result;
+ } else if (resolutionVariantHint != SunHints.INTVAL_RESOLUTION_VARIANT_BASE
+ && (img instanceof MultiResolutionImage)) {
// get scaled destination image size
int width = img.getWidth(observer);
int height = img.getHeight(observer);
- Image resolutionVariant = getResolutionVariant(
- (MultiResolutionImage) img, width, height,
- dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2);
+ MultiResolutionImage mrImage = (MultiResolutionImage) img;
+ Image resolutionVariant = getResolutionVariant(mrImage, width, height,
+ dx1, dy1, dx2, dy2,
+ sx1, sy1, sx2, sy2,
+ xform);
if (resolutionVariant != img && resolutionVariant != null) {
// recalculate source region for the resolution variant
@@ -3123,8 +3143,8 @@
if (0 < width && 0 < height && 0 < rvWidth && 0 < rvHeight) {
- float widthScale = ((float) rvWidth) / width;
- float heightScale = ((float) rvHeight) / height;
+ double widthScale = ((double) rvWidth) / width;
+ double heightScale = ((double) rvHeight) / height;
sx1 = Region.clipScale(sx1, widthScale);
sy1 = Region.clipScale(sy1, heightScale);
@@ -3133,10 +3153,29 @@
observer = rvObserver;
img = resolutionVariant;
+
+ if (xform != null) {
+ assert dx1 == 0 && dy1 == 0;
+ assert dx2 == img.getWidth(observer);
+ assert dy2 == img.getHeight(observer);
+ AffineTransform renderTX = new AffineTransform(xform);
+ renderTX.scale(1 / widthScale, 1 / heightScale);
+ return transformImage(img, renderTX, observer);
+ }
+
+ return scaleImage(img, dx1, dy1, dx2, dy2,
+ sx1, sy1, sx2, sy2,
+ bgcolor, observer);
}
}
}
-
+ return null;
+ }
+
+ private boolean scaleImage(Image img, int dx1, int dy1, int dx2, int dy2,
+ int sx1, int sy1, int sx2, int sy2,
+ Color bgcolor, ImageObserver observer)
+ {
try {
return imagepipe.scaleImage(this, img, dx1, dy1, dx2, dy2, sx1, sy1,
sx2, sy2, bgcolor, observer);
@@ -3156,9 +3195,30 @@
}
}
+ private boolean transformImage(Image img,
+ AffineTransform xform,
+ ImageObserver observer)
+ {
+ try {
+ return imagepipe.transformImage(this, img, xform, observer);
+ } catch (InvalidPipeException e) {
+ try {
+ revalidateAll();
+ return imagepipe.transformImage(this, img, xform, observer);
+ } catch (InvalidPipeException e2) {
+ // Still catching the exception; we are not yet ready to
+ // validate the surfaceData correctly. Fail for now and
+ // try again next time around.
+ return false;
+ }
+ } finally {
+ surfaceData.markDirty();
+ }
+ }
+
private Image getResolutionVariant(MultiResolutionImage img,
int srcWidth, int srcHeight, int dx1, int dy1, int dx2, int dy2,
- int sx1, int sy1, int sx2, int sy2) {
+ int sx1, int sy1, int sx2, int sy2, AffineTransform xform) {
if (srcWidth <= 0 || srcHeight <= 0) {
return null;
@@ -3171,7 +3231,16 @@
return null;
}
- int type = transform.getType();
+ AffineTransform tx;
+
+ if (xform == null) {
+ tx = transform;
+ } else {
+ tx = new AffineTransform(transform);
+ tx.concatenate(xform);
+ }
+
+ int type = tx.getType();
int dw = dx2 - dx1;
int dh = dy2 - dy1;
@@ -3198,13 +3267,13 @@
destRegionWidth = dw;
destRegionHeight = dh;
} else if ((type & ~(TYPE_TRANSLATION | TYPE_FLIP | TYPE_MASK_SCALE)) == 0) {
- destRegionWidth = dw * transform.getScaleX();
- destRegionHeight = dh * transform.getScaleY();
+ destRegionWidth = dw * tx.getScaleX();
+ destRegionHeight = dh * tx.getScaleY();
} else {
destRegionWidth = dw * Math.hypot(
- transform.getScaleX(), transform.getShearY());
+ tx.getScaleX(), tx.getShearY());
destRegionHeight = dh * Math.hypot(
- transform.getShearX(), transform.getScaleY());
+ tx.getShearX(), tx.getScaleY());
}
destImageWidth = Math.abs(srcWidth * destRegionWidth / sw);
destImageHeight = Math.abs(srcHeight * destRegionHeight / sh);
@@ -3277,9 +3346,11 @@
final int imgW = img.getWidth(null);
final int imgH = img.getHeight(null);
- if (isHiDPIImage(img)) {
- return drawHiDPIImage(img, x, y, x + width, y + height, 0, 0, imgW,
- imgH, bg, observer);
+ Boolean hidpiImageDrawn = drawHiDPIImage(img, x, y, x + width, y + height,
+ 0, 0, imgW, imgH, bg, observer,
+ null);
+ if (hidpiImageDrawn != null) {
+ return hidpiImageDrawn;
}
if (width == imgW && height == imgH) {
@@ -3323,11 +3394,13 @@
return true;
}
- if (isHiDPIImage(img)) {
- final int imgW = img.getWidth(null);
- final int imgH = img.getHeight(null);
- return drawHiDPIImage(img, x, y, x + imgW, y + imgH, 0, 0, imgW,
- imgH, bg, observer);
+ final int imgW = img.getWidth(null);
+ final int imgH = img.getHeight(null);
+ Boolean hidpiImageDrawn = drawHiDPIImage(img, x, y, x + imgW, y + imgH,
+ 0, 0, imgW, imgH, bg, observer,
+ null);
+ if (hidpiImageDrawn != null) {
+ return hidpiImageDrawn;
}
try {
@@ -3378,9 +3451,12 @@
return true;
}
- if (isHiDPIImage(img)) {
- return drawHiDPIImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2,
- bgcolor, observer);
+ Boolean hidpiImageDrawn = drawHiDPIImage(img, dx1, dy1, dx2, dy2,
+ sx1, sy1, sx2, sy2,
+ bgcolor, observer, null);
+
+ if (hidpiImageDrawn != null) {
+ return hidpiImageDrawn;
}
if (((sx2 - sx1) == (dx2 - dx1)) &&
@@ -3461,33 +3537,16 @@
return drawImage(img, 0, 0, null, observer);
}
- if (isHiDPIImage(img)) {
- final int w = img.getWidth(null);
- final int h = img.getHeight(null);
- final AffineTransform tx = new AffineTransform(transform);
- transform(xform);
- boolean result = drawHiDPIImage(img, 0, 0, w, h, 0, 0, w, h, null,
- observer);
- transform.setTransform(tx);
- invalidateTransform();
- return result;
+ final int w = img.getWidth(null);
+ final int h = img.getHeight(null);
+ Boolean hidpiImageDrawn = drawHiDPIImage(img, 0, 0, w, h, 0, 0, w, h,
+ null, observer, xform);
+
+ if (hidpiImageDrawn != null) {
+ return hidpiImageDrawn;
}
- try {
- return imagepipe.transformImage(this, img, xform, observer);
- } catch (InvalidPipeException e) {
- try {
- revalidateAll();
- return imagepipe.transformImage(this, img, xform, observer);
- } catch (InvalidPipeException e2) {
- // Still catching the exception; we are not yet ready to
- // validate the surfaceData correctly. Fail for now and
- // try again next time around.
- return false;
- }
- } finally {
- surfaceData.markDirty();
- }
+ return transformImage(img, xform, observer);
}
public void drawImage(BufferedImage bImg,
--- a/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphicsEnvironment.java Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphicsEnvironment.java Fri Nov 13 05:02:26 2015 -0800
@@ -66,6 +66,8 @@
import sun.font.FontManagerFactory;
import sun.font.FontManagerForSGE;
import sun.font.NativeFont;
+import java.security.AccessController;
+import sun.security.action.GetPropertyAction;
/**
* This is an implementation of a GraphicsEnvironment object for the
@@ -80,6 +82,15 @@
public static boolean isOpenSolaris;
private static Font defaultFont;
+ private static final boolean uiScaleEnabled;
+ private static final double debugScale;
+
+ static {
+ uiScaleEnabled = "true".equals(AccessController.doPrivileged(
+ new GetPropertyAction("sun.java2d.uiScale.enabled", "true")));
+ debugScale = uiScaleEnabled ? getScaleFactor("sun.java2d.uiScale") : -1;
+ }
+
public SunGraphicsEnvironment() {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Object>() {
@@ -341,4 +352,41 @@
public boolean isFlipStrategyPreferred(ComponentPeer peer) {
return false;
}
+
+ public static boolean isUIScaleEnabled() {
+ return uiScaleEnabled;
+ }
+
+ public static double getDebugScale() {
+ return debugScale;
+ }
+
+ public static double getScaleFactor(String propertyName) {
+
+ String scaleFactor = AccessController.doPrivileged(
+ new GetPropertyAction(propertyName, "-1"));
+
+ if (scaleFactor == null || scaleFactor.equals("-1")) {
+ return -1;
+ }
+
+ try {
+ double units = 1.0;
+
+ if (scaleFactor.endsWith("x")) {
+ scaleFactor = scaleFactor.substring(0, scaleFactor.length() - 1);
+ } else if (scaleFactor.endsWith("dpi")) {
+ units = 96;
+ scaleFactor = scaleFactor.substring(0, scaleFactor.length() - 3);
+ } else if (scaleFactor.endsWith("%")) {
+ units = 100;
+ scaleFactor = scaleFactor.substring(0, scaleFactor.length() - 1);
+ }
+
+ double scale = Double.parseDouble(scaleFactor);
+ return scale <= 0 ? -1 : scale / units;
+ } catch (NumberFormatException ignored) {
+ return -1;
+ }
+ }
}
--- a/jdk/src/java.desktop/share/classes/sun/java2d/SurfaceData.java Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/SurfaceData.java Fri Nov 13 05:02:26 2015 -0800
@@ -1059,12 +1059,22 @@
public abstract Object getDestination();
/**
- * Returns default scale factor of the destination surface. Scale factor
- * describes the mapping between virtual and physical coordinates of the
+ * Returns default horizontal scale factor of the destination surface. Scale
+ * factor describes the mapping between virtual and physical coordinates of the
* SurfaceData. If the scale is 2 then virtual pixel coordinates need to be
* doubled for physical pixels.
*/
- public int getDefaultScale() {
+ public double getDefaultScaleX() {
+ return 1;
+ }
+
+ /**
+ * Returns default vertical scale factor of the destination surface. Scale
+ * factor describes the mapping between virtual and physical coordinates of the
+ * SurfaceData. If the scale is 2 then virtual pixel coordinates need to be
+ * doubled for physical pixels.
+ */
+ public double getDefaultScaleY() {
return 1;
}
}
--- a/jdk/src/java.desktop/share/classes/sun/java2d/pipe/DrawImage.java Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/pipe/DrawImage.java Fri Nov 13 05:02:26 2015 -0800
@@ -736,9 +736,10 @@
atfm.scale(m00, m11);
atfm.translate(srcX-sx1, srcY-sy1);
- final int scale = SurfaceManager.getImageScale(img);
- final int imgW = img.getWidth(null) * scale;
- final int imgH = img.getHeight(null) * scale;
+ final double scaleX = SurfaceManager.getImageScaleX(img);
+ final double scaleY = SurfaceManager.getImageScaleY(img);
+ final int imgW = (int) Math.ceil(img.getWidth(null) * scaleX);
+ final int imgH = (int) Math.ceil(img.getHeight(null) * scaleY);
srcW += srcX;
srcH += srcY;
// Make sure we are not out of bounds
--- a/jdk/src/java.desktop/windows/classes/sun/awt/Win32GraphicsConfig.java Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/Win32GraphicsConfig.java Fri Nov 13 05:02:26 2015 -0800
@@ -106,7 +106,7 @@
/**
* Return the graphics device associated with this configuration.
*/
- public GraphicsDevice getDevice() {
+ public Win32GraphicsDevice getDevice() {
return screen;
}
@@ -182,7 +182,9 @@
* For image buffers, this Transform will be the Identity transform.
*/
public AffineTransform getDefaultTransform() {
- return new AffineTransform();
+ double scaleX = screen.getDefaultScaleX();
+ double scaleY = screen.getDefaultScaleY();
+ return AffineTransform.getScaleInstance(scaleX, scaleY);
}
/**
--- a/jdk/src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java Fri Nov 13 05:02:26 2015 -0800
@@ -37,13 +37,19 @@
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
+import java.awt.geom.Point2D;
import java.awt.image.ColorModel;
import java.util.ArrayList;
import java.util.Vector;
import java.awt.peer.WindowPeer;
+import java.security.AccessController;
import sun.awt.windows.WWindowPeer;
+import sun.java2d.SunGraphicsEnvironment;
import sun.java2d.opengl.WGLGraphicsConfig;
import sun.java2d.windows.WindowsFlags;
+import sun.security.action.GetPropertyAction;
+import static sun.awt.Win32GraphicsEnvironment.debugScaleX;
+import static sun.awt.Win32GraphicsEnvironment.debugScaleY;
/**
* This is an implementation of a GraphicsDevice object for a single
@@ -81,6 +87,9 @@
// activation/deactivation listener for the full-screen window
private WindowListener fsWindowListener;
+ private float scaleX;
+ private float scaleY;
+
static {
// 4455041 - Even when ddraw is disabled, ddraw.dll is loaded when
@@ -97,6 +106,10 @@
private static native void initIDs();
native void initDevice(int screen);
+ native void initNativeScale(int screen);
+ native void setNativeScale(int screen, float scaleX, float scaleY);
+ native float getNativeScaleX(int screen);
+ native float getNativeScaleY(int screen);
public Win32GraphicsDevice(int screennum) {
this.screen = screennum;
@@ -109,6 +122,7 @@
valid = true;
initDevice(screennum);
+ initScaleFactors();
}
/**
@@ -128,6 +142,31 @@
return screen;
}
+ public float getDefaultScaleX() {
+ return scaleX;
+ }
+
+ public float getDefaultScaleY() {
+ return scaleY;
+ }
+
+ private void initScaleFactors() {
+ if (SunGraphicsEnvironment.isUIScaleEnabled()) {
+ if (debugScaleX > 0 && debugScaleY > 0) {
+ scaleX = debugScaleX;
+ scaleY = debugScaleY;
+ setNativeScale(screen, scaleX, scaleY);
+ } else {
+ initNativeScale(screen);
+ scaleX = getNativeScaleX(screen);
+ scaleY = getNativeScaleY(screen);
+ }
+ } else {
+ scaleX = 1;
+ scaleY = 1;
+ }
+ }
+
/**
* Returns whether this is a valid devicie. Device can become
* invalid as a result of device removal event.
@@ -486,6 +525,7 @@
configs = null;
// pass on to all top-level windows on this display
topLevels.notifyListeners();
+ initScaleFactors();
}
/**
--- a/jdk/src/java.desktop/windows/classes/sun/awt/Win32GraphicsEnvironment.java Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/Win32GraphicsEnvironment.java Fri Nov 13 05:02:26 2015 -0800
@@ -51,6 +51,9 @@
public final class Win32GraphicsEnvironment extends SunGraphicsEnvironment {
+ static final float debugScaleX;
+ static final float debugScaleY;
+
static {
// Ensure awt is loaded already. Also, this forces static init
// of WToolkit and Toolkit, which we depend upon
@@ -61,6 +64,21 @@
// Install correct surface manager factory.
SurfaceManagerFactory.setInstance(new WindowsSurfaceManagerFactory());
+
+ double sx = -1;
+ double sy = -1;
+ if (isUIScaleEnabled()) {
+ sx = getScaleFactor("sun.java2d.win.uiScaleX");
+ sy = getScaleFactor("sun.java2d.win.uiScaleY");
+ if (sx <= 0 || sy <= 0) {
+ double s = getDebugScale();
+ sx = s;
+ sy = s;
+ }
+ }
+
+ debugScaleX = (float) sx;
+ debugScaleY = (float) sy;
}
/**
--- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java Fri Nov 13 05:02:26 2015 -0800
@@ -294,6 +294,12 @@
synchronized native void reshapeFrame(int x, int y, int width, int height);
+ native Dimension getNativeWindowSize();
+
+ public Dimension getScaledWindowSize() {
+ return getNativeWindowSize();
+ }
+
public boolean requestWindowFocus(CausedFocusEvent.Cause cause) {
if (!focusAllowedFor()) {
return false;
@@ -490,8 +496,7 @@
}
// get current GD
- Win32GraphicsDevice oldDev = (Win32GraphicsDevice)winGraphicsConfig
- .getDevice();
+ Win32GraphicsDevice oldDev = winGraphicsConfig.getDevice();
Win32GraphicsDevice newDev;
GraphicsDevice devs[] = GraphicsEnvironment
--- a/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java Fri Nov 13 05:02:26 2015 -0800
@@ -63,9 +63,12 @@
import static sun.java2d.pipe.hw.ExtendedBufferCapabilities.VSyncType.*;
import sun.java2d.pipe.hw.ExtendedBufferCapabilities.VSyncType;
import java.awt.BufferCapabilities.FlipContents;
+import java.awt.Dimension;
import java.awt.Window;
+import java.awt.geom.AffineTransform;
import sun.awt.SunToolkit;
import sun.awt.image.SunVolatileImage;
+import sun.awt.windows.WWindowPeer;
import sun.java2d.ScreenUpdateManager;
import sun.java2d.StateTracker;
import sun.java2d.SurfaceDataProxy;
@@ -162,6 +165,8 @@
private int type;
private int width, height;
+ private final double scaleX;
+ private final double scaleY;
// these fields are set from the native code when the surface is
// initialized
private int nativeWidth, nativeHeight;
@@ -218,16 +223,29 @@
{
super(getCustomSurfaceType(type), cm);
this.graphicsDevice = gc.getD3DDevice();
+ this.scaleX = type == TEXTURE ? 1 : graphicsDevice.getDefaultScaleX();
+ this.scaleY = type == TEXTURE ? 1 : graphicsDevice.getDefaultScaleY();
this.peer = peer;
this.type = type;
- this.width = width;
- this.height = height;
+
+ if (scaleX == 1 && scaleY == 1) {
+ this.width = width;
+ this.height = height;
+ } else if (peer instanceof WWindowPeer) {
+ Dimension scaledSize = ((WWindowPeer) peer).getScaledWindowSize();
+ this.width = scaledSize.width;
+ this.height = scaledSize.height;
+ } else {
+ this.width = (int) Math.ceil(width * scaleX);
+ this.height = (int) Math.ceil(height * scaleY);
+ }
+
this.offscreenImage = image;
this.backBuffersNum = numBackBuffers;
this.swapEffect = swapEffect;
this.syncType = vSyncType;
- initOps(graphicsDevice.getScreen(), width, height);
+ initOps(graphicsDevice.getScreen(), this.width, this.height);
if (type == WINDOW) {
// we put the surface into the "lost"
// state; it will be restored by the D3DScreenUpdateManager
@@ -241,6 +259,16 @@
}
@Override
+ public double getDefaultScaleX() {
+ return scaleX;
+ }
+
+ @Override
+ public double getDefaultScaleY() {
+ return scaleY;
+ }
+
+ @Override
public SurfaceDataProxy makeProxyFor(SurfaceData srcData) {
return D3DSurfaceDataProxy.
createProxy(srcData,
@@ -777,8 +805,12 @@
public Rectangle getBounds() {
if (type == FLIP_BACKBUFFER || type == WINDOW) {
+ double scaleX = getDefaultScaleX();
+ double scaleY = getDefaultScaleY();
Rectangle r = peer.getBounds();
r.x = r.y = 0;
+ r.width = (int) Math.ceil(r.width * scaleX);
+ r.height = (int) Math.ceil(r.height * scaleY);
return r;
} else {
return new Rectangle(width, height);
--- a/jdk/src/java.desktop/windows/classes/sun/java2d/opengl/WGLSurfaceData.java Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/windows/classes/sun/java2d/opengl/WGLSurfaceData.java Fri Nov 13 05:02:26 2015 -0800
@@ -31,8 +31,10 @@
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Rectangle;
+import java.awt.geom.AffineTransform;
import java.awt.image.ColorModel;
import sun.awt.SunToolkit;
+import sun.awt.Win32GraphicsDevice;
import sun.awt.windows.WComponentPeer;
import sun.java2d.SurfaceData;
@@ -40,6 +42,8 @@
protected WComponentPeer peer;
private WGLGraphicsConfig graphicsConfig;
+ protected double scaleX = 1;
+ protected double scaleY = 1;
private native void initOps(long pConfigInfo, WComponentPeer peer,
long hwnd);
@@ -50,6 +54,9 @@
super(gc, cm, type);
this.peer = peer;
this.graphicsConfig = gc;
+ Win32GraphicsDevice device = gc.getDevice();
+ this.scaleX = type == TEXTURE ? 1 : device.getDefaultScaleX();
+ this.scaleY = type == TEXTURE ? 1 : device.getDefaultScaleY();
long pConfigInfo = gc.getNativeConfigInfo();
long hwnd = peer != null ? peer.getHWnd() : 0L;
@@ -57,6 +64,16 @@
initOps(pConfigInfo, peer, hwnd);
}
+ @Override
+ public double getDefaultScaleX() {
+ return scaleX;
+ }
+
+ @Override
+ public double getDefaultScaleY() {
+ return scaleY;
+ }
+
public GraphicsConfiguration getDeviceConfiguration() {
return graphicsConfig;
}
@@ -148,6 +165,8 @@
public Rectangle getBounds() {
Rectangle r = peer.getBounds();
r.x = r.y = 0;
+ r.width = (int) Math.ceil(r.width * scaleX);
+ r.height = (int) Math.ceil(r.height * scaleY);
return r;
}
@@ -208,11 +227,11 @@
{
super(peer, gc, cm, type);
- this.width = width;
- this.height = height;
+ this.width = (int) Math.ceil(width * scaleX);
+ this.height = (int) Math.ceil(height * scaleY);
offscreenImage = image;
- initSurface(width, height);
+ initSurface(this.width, this.height);
}
public SurfaceData getReplacement() {
@@ -222,6 +241,8 @@
public Rectangle getBounds() {
if (type == FLIP_BACKBUFFER) {
Rectangle r = peer.getBounds();
+ r.width = (int) Math.ceil(r.width * scaleX);
+ r.height = (int) Math.ceil(r.height * scaleY);
r.x = r.y = 0;
return r;
} else {
--- a/jdk/src/java.desktop/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java Fri Nov 13 05:02:26 2015 -0800
@@ -28,6 +28,7 @@
import java.awt.Rectangle;
import java.awt.GraphicsConfiguration;
import java.awt.color.ColorSpace;
+import java.awt.geom.AffineTransform;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DirectColorModel;
@@ -77,6 +78,9 @@
private static native void initIDs(Class<?> xorComp);
+ private final double scaleX;
+ private final double scaleY;
+
static {
initIDs(XORComposite.class);
if (WindowsFlags.isGdiBlitEnabled()) {
@@ -265,13 +269,23 @@
this.graphicsConfig =
(Win32GraphicsConfig) peer.getGraphicsConfiguration();
this.solidloops = graphicsConfig.getSolidLoops(sType);
-
- Win32GraphicsDevice gd =
- (Win32GraphicsDevice)graphicsConfig.getDevice();
+ Win32GraphicsDevice gd = graphicsConfig.getDevice();
+ scaleX = gd.getDefaultScaleX();
+ scaleY = gd.getDefaultScaleY();
initOps(peer, depth, rMask, gMask, bMask, gd.getScreen());
setBlitProxyKey(graphicsConfig.getProxyKey());
}
+ @Override
+ public double getDefaultScaleX() {
+ return scaleX;
+ }
+
+ @Override
+ public double getDefaultScaleY() {
+ return scaleY;
+ }
+
/**
* {@inheritDoc}
*
@@ -288,6 +302,8 @@
public Rectangle getBounds() {
Rectangle r = peer.getBounds();
r.x = r.y = 0;
+ r.width = (int) Math.ceil(r.width * scaleX);
+ r.height = (int) Math.ceil(r.height * scaleY);
return r;
}
--- a/jdk/src/java.desktop/windows/native/libawt/windows/MouseInfo.cpp Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/MouseInfo.cpp Fri Nov 13 05:02:26 2015 -0800
@@ -94,12 +94,21 @@
pointClass = (jclass)env->NewGlobalRef(pointClassLocal);
env->DeleteLocalRef(pointClassLocal);
}
+
+ int screen = AwtWin32GraphicsDevice::GetDefaultDeviceIndex();
+ Devices::InstanceAccess devices;
+ AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
+
xID = env->GetFieldID(pointClass, "x", "I");
CHECK_NULL_RETURN(xID, (jint)0);
yID = env->GetFieldID(pointClass, "y", "I");
CHECK_NULL_RETURN(yID, (jint)0);
- env->SetIntField(point, xID, pt.x);
- env->SetIntField(point, yID, pt.y);
+
+ int x = (device == NULL) ? pt.x : device->ScaleDownX(pt.x);
+ int y = (device == NULL) ? pt.y : device->ScaleDownY(pt.y);
+
+ env->SetIntField(point, xID, x);
+ env->SetIntField(point, yID, y);
// Always return 0 on Windows: we assume there's always a
// virtual screen device used.
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Choice.cpp Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Choice.cpp Fri Nov 13 05:02:26 2015 -0800
@@ -206,9 +206,10 @@
int itemHeight =(int)::SendMessage(GetHWnd(), CB_GETITEMHEIGHT, (UINT)0,0);
int numItemsToShow = (int)::SendMessage(GetHWnd(), CB_GETCOUNT, 0,0);
numItemsToShow = min(MINIMUM_NUMBER_OF_VISIBLE_ITEMS, numItemsToShow);
+
// drop-down height snaps to nearest line, so add a
// fudge factor of 1/2 line to ensure last line shows
- return itemHeight*numItemsToShow + itemHeight/2;
+ return ScaleDownY(itemHeight * numItemsToShow + itemHeight / 2);
}
// get the height of the field portion of the combobox
@@ -221,7 +222,7 @@
// Win 4.x (3d edge) vs 3.x (1 pixel line)
borderHeight = ::GetSystemMetrics(SM_CYEDGE);
fieldHeight += borderHeight*2;
- return fieldHeight;
+ return ScaleDownY(fieldHeight);
}
// gets the total height of the combobox, including drop down
@@ -325,8 +326,8 @@
* Fix: Set the Choice to its actual size in the component.
*/
::GetClientRect(GetHWnd(), &rc);
- env->SetIntField(target, AwtComponent::widthID, (jint)rc.right);
- env->SetIntField(target, AwtComponent::heightID, (jint)rc.bottom);
+ env->SetIntField(target, AwtComponent::widthID, ScaleDownX(rc.right));
+ env->SetIntField(target, AwtComponent::heightID, ScaleDownY(rc.bottom));
env->DeleteLocalRef(target);
env->DeleteLocalRef(parent);
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp Fri Nov 13 05:02:26 2015 -0800
@@ -963,6 +963,12 @@
::MapWindowPoints(HWND_DESKTOP, ::GetParent(GetHWnd()), (LPPOINT)&rc, 2);
DTRACE_PRINTLN4("AwtComponent::Reshape from %d, %d, %d, %d", rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top);
#endif
+
+ x = ScaleUpX(x);
+ y = ScaleUpY(y);
+ w = ScaleUpX(w);
+ h = ScaleUpY(h);
+
AwtWindow* container = GetContainer();
AwtComponent* parent = GetParent();
if (container != NULL && container == parent) {
@@ -2212,8 +2218,11 @@
}
for(i = 0; i < 2; i++) {
if (un[i] != 0) {
- DoCallback("handleExpose", "(IIII)V", un[i]->left, un[i]->top,
- un[i]->right-un[i]->left, un[i]->bottom-un[i]->top);
+ DoCallback("handleExpose", "(IIII)V",
+ ScaleDownX(un[i]->left),
+ ScaleDownY(un[i]->top),
+ ScaleDownX(un[i]->right - un[i]->left),
+ ScaleDownY(un[i]->bottom - un[i]->top));
}
}
delete [] buffer;
@@ -4608,6 +4617,34 @@
}
}
+int AwtComponent::ScaleUpX(int x) {
+ int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd());
+ Devices::InstanceAccess devices;
+ AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
+ return device == NULL ? x : device->ScaleUpX(x);
+}
+
+int AwtComponent::ScaleUpY(int y) {
+ int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd());
+ Devices::InstanceAccess devices;
+ AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
+ return device == NULL ? y : device->ScaleUpY(y);
+}
+
+int AwtComponent::ScaleDownX(int x) {
+ int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd());
+ Devices::InstanceAccess devices;
+ AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
+ return device == NULL ? x : device->ScaleDownX(x);
+}
+
+int AwtComponent::ScaleDownY(int y) {
+ int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd());
+ Devices::InstanceAccess devices;
+ AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
+ return device == NULL ? y : device->ScaleDownY(y);
+}
+
jintArray AwtComponent::CreatePrintedPixels(SIZE &loc, SIZE &size, int alpha) {
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
@@ -4901,8 +4938,9 @@
jobject mouseEvent = env->NewObject(mouseEventCls, mouseEventConst,
target,
id, when, modifiers,
- x+insets.left, y+insets.top,
- xAbs, yAbs,
+ ScaleDownX(x + insets.left),
+ ScaleDownY(y + insets.top),
+ ScaleDownX(xAbs), ScaleDownY(yAbs),
clickCount, popupTrigger, button);
if (safe_ExceptionOccurred(env)) {
@@ -4969,8 +5007,10 @@
mouseWheelEventConst,
target,
id, when, modifiers,
- x+insets.left, y+insets.top,
- xAbs, yAbs,
+ ScaleDownX(x + insets.left),
+ ScaleDownY(y + insets.top),
+ ScaleDownX(xAbs),
+ ScaleDownY(yAbs),
clickCount, popupTrigger,
scrollType, scrollAmount,
roundedWheelRotation, preciseWheelRotation);
@@ -5476,7 +5516,8 @@
RECT rect;
VERIFY(::GetWindowRect(p->GetHWnd(),&rect));
result = JNU_NewObjectByName(env, "java/awt/Point", "(II)V",
- rect.left, rect.top);
+ p->ScaleDownX(rect.left),
+ p->ScaleDownY(rect.top));
}
ret:
env->DeleteGlobalRef(self);
@@ -7064,6 +7105,11 @@
target = parent;
}
+ x = ScaleUpX(x);
+ y = ScaleUpY(y);
+ width = ScaleUpX(width);
+ height = ScaleUpY(height);
+
// Test whether component's bounds match the native window's
RECT rect;
VERIFY(::GetWindowRect(GetHWnd(), &rect));
@@ -7256,5 +7302,4 @@
removedDCs = removedDCs->next;
delete tmpDCList;
}
-}
-
+}
\ No newline at end of file
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h Fri Nov 13 05:02:26 2015 -0800
@@ -746,6 +746,11 @@
virtual void FillBackground(HDC hMemoryDC, SIZE &size);
virtual void FillAlpha(void *bitmapBits, SIZE &size, BYTE alpha);
+ int ScaleUpX(int x);
+ int ScaleUpY(int y);
+ int ScaleDownX(int x);
+ int ScaleDownY(int y);
+
private:
/* A bitmask keeps the button's numbers as MK_LBUTTON, MK_MBUTTON, MK_RBUTTON
* which are allowed to
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Font.cpp Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Font.cpp Fri Nov 13 05:02:26 2015 -0800
@@ -398,6 +398,38 @@
}
+static int ScaleUpX(float x) {
+ int deviceIndex = AwtWin32GraphicsDevice::DeviceIndexForWindow(
+ ::GetDesktopWindow());
+ Devices::InstanceAccess devices;
+ AwtWin32GraphicsDevice *device = devices->GetDevice(deviceIndex);
+ return device == NULL ? x : device->ScaleUpX(x);
+}
+
+static int ScaleUpY(int y) {
+ int deviceIndex = AwtWin32GraphicsDevice::DeviceIndexForWindow(
+ ::GetDesktopWindow());
+ Devices::InstanceAccess devices;
+ AwtWin32GraphicsDevice *device = devices->GetDevice(deviceIndex);
+ return device == NULL ? y : device->ScaleUpY(y);
+}
+
+static int ScaleDownX(int x) {
+ int deviceIndex = AwtWin32GraphicsDevice::DeviceIndexForWindow(
+ ::GetDesktopWindow());
+ Devices::InstanceAccess devices;
+ AwtWin32GraphicsDevice *device = devices->GetDevice(deviceIndex);
+ return device == NULL ? x : device->ScaleDownX(x);
+}
+
+static int ScaleDownY(int y) {
+ int deviceIndex = AwtWin32GraphicsDevice::DeviceIndexForWindow(
+ ::GetDesktopWindow());
+ Devices::InstanceAccess devices;
+ AwtWin32GraphicsDevice *device = devices->GetDevice(deviceIndex);
+ return device == NULL ? y : device->ScaleDownY(y);
+}
+
static HFONT CreateHFont_sub(LPCWSTR name, int style, int height,
int angle=0, float awScale=1.0f)
{
@@ -424,7 +456,7 @@
logFont.lfUnderline = 0;//(style & java_awt_Font_UNDERLINE) != 0;
// Get point size
- logFont.lfHeight = -height;
+ logFont.lfHeight = ScaleUpY(-height);
// Set font name
WCHAR tmpname[80];
@@ -451,7 +483,7 @@
VERIFY(::DeleteObject(oldFont));
}
avgWidth = tm.tmAveCharWidth;
- logFont.lfWidth = (LONG)((fabs)(avgWidth*awScale));
+ logFont.lfWidth = (LONG) ScaleUpX((fabs) (avgWidth * awScale));
hFont = ::CreateFontIndirect(&logFont);
DASSERT(hFont != NULL);
VERIFY(::ReleaseDC(0, hDC));
@@ -535,19 +567,20 @@
int ascent = metrics.tmAscent;
int descent = metrics.tmDescent;
int leading = metrics.tmExternalLeading;
- env->SetIntField(fontMetrics, AwtFont::ascentID, ascent);
- env->SetIntField(fontMetrics, AwtFont::descentID, descent);
- env->SetIntField(fontMetrics, AwtFont::leadingID, leading);
- env->SetIntField(fontMetrics, AwtFont::heightID, metrics.tmAscent +
- metrics.tmDescent + leading);
- env->SetIntField(fontMetrics, AwtFont::maxAscentID, ascent);
- env->SetIntField(fontMetrics, AwtFont::maxDescentID, descent);
+
+ env->SetIntField(fontMetrics, AwtFont::ascentID, ScaleDownY(ascent));
+ env->SetIntField(fontMetrics, AwtFont::descentID, ScaleDownY(descent));
+ env->SetIntField(fontMetrics, AwtFont::leadingID, ScaleDownX(leading));
+ env->SetIntField(fontMetrics, AwtFont::heightID,
+ ScaleDownY(metrics.tmAscent + metrics.tmDescent + leading));
+ env->SetIntField(fontMetrics, AwtFont::maxAscentID, ScaleDownY(ascent));
+ env->SetIntField(fontMetrics, AwtFont::maxDescentID, ScaleDownY(descent));
int maxHeight = ascent + descent + leading;
- env->SetIntField(fontMetrics, AwtFont::maxHeightID, maxHeight);
+ env->SetIntField(fontMetrics, AwtFont::maxHeightID, ScaleDownY(maxHeight));
int maxAdvance = metrics.tmMaxCharWidth;
- env->SetIntField(fontMetrics, AwtFont::maxAdvanceID, maxAdvance);
+ env->SetIntField(fontMetrics, AwtFont::maxAdvanceID, ScaleDownX(maxAdvance));
awtFont->m_overhang = metrics.tmOverhang;
@@ -818,6 +851,7 @@
jobject font = env->GetObjectField(self, AwtFont::fontID);
long ret = AwtFont::getMFStringWidth(hDC, font, str);
+ ret = ScaleDownX(ret);
VERIFY(::ReleaseDC(0, hDC));
return ret;
@@ -924,7 +958,7 @@
}
env->ReleasePrimitiveArrayCritical(str, pStrBody, 0);
- return result;
+ return ScaleDownX(result);
CATCH_BAD_ALLOC_RET(0);
}
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Robot.cpp Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Robot.cpp Fri Nov 13 05:02:26 2015 -0800
@@ -80,6 +80,13 @@
(PVOID)newSpeed,
SPIF_SENDCHANGE);
+ int primaryIndex = AwtWin32GraphicsDevice::GetDefaultDeviceIndex();
+ Devices::InstanceAccess devices;
+ AwtWin32GraphicsDevice *device = devices->GetDevice(primaryIndex);
+
+ x = (device == NULL) ? x : device->ScaleUpX(x);
+ y = (device == NULL) ? y : device->ScaleUpY(y);
+
POINT curPos;
::GetCursorPos(&curPos);
x -= curPos.x;
@@ -217,11 +224,24 @@
AwtWin32GraphicsDevice::SelectPalette(hdcMem, primaryIndex);
AwtWin32GraphicsDevice::RealizePalette(hdcMem, primaryIndex);
+ Devices::InstanceAccess devices;
+ AwtWin32GraphicsDevice *device = devices->GetDevice(primaryIndex);
+ int sWidth = (device == NULL) ? width : device->ScaleUpX(width);
+ int sHeight = (device == NULL) ? height : device->ScaleUpY(height);
+
// copy screen image to offscreen bitmap
// CAPTUREBLT flag is required to capture WS_EX_LAYERED windows' contents
// correctly on Win2K/XP
- VERIFY(::BitBlt(hdcMem, 0, 0, width, height, hdcScreen, x, y,
- SRCCOPY|CAPTUREBLT) != 0);
+ if (width == sWidth && height == sHeight) {
+ VERIFY(::BitBlt(hdcMem, 0, 0, width, height, hdcScreen, x, y,
+ SRCCOPY | CAPTUREBLT) != 0);
+ } else {
+ int sX = (device == NULL) ? x : device->ScaleUpX(x);
+ int sY = (device == NULL) ? y : device->ScaleUpY(y);
+ VERIFY(::StretchBlt(hdcMem, 0, 0, width, height,
+ hdcScreen, sX, sY, sWidth, sHeight,
+ SRCCOPY | CAPTUREBLT) != 0);
+ }
static const int BITS_PER_PIXEL = 32;
static const int BYTES_PER_PIXEL = BITS_PER_PIXEL/8;
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp Fri Nov 13 05:02:26 2015 -0800
@@ -2355,8 +2355,13 @@
{
TRY;
- return ::GetSystemMetrics(SM_CXSCREEN);
-
+ int width = ::GetSystemMetrics(SM_CXSCREEN);
+
+ Devices::InstanceAccess devices;
+ AwtWin32GraphicsDevice *device = devices->GetDevice(
+ AwtWin32GraphicsDevice::GetDefaultDeviceIndex());
+
+ return (device == NULL) ? width : device->ScaleDownX(width);
CATCH_BAD_ALLOC_RET(0);
}
@@ -2370,7 +2375,12 @@
{
TRY;
- return ::GetSystemMetrics(SM_CYSCREEN);
+ int height = ::GetSystemMetrics(SM_CYSCREEN);
+ Devices::InstanceAccess devices;
+ AwtWin32GraphicsDevice *device = devices->GetDevice(
+ AwtWin32GraphicsDevice::GetDefaultDeviceIndex());
+
+ return (device == NULL) ? height : device->ScaleDownY(height);
CATCH_BAD_ALLOC_RET(0);
}
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsConfig.cpp Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsConfig.cpp Fri Nov 13 05:02:26 2015 -0800
@@ -95,19 +95,31 @@
mid = env->GetMethodID(clazz, "<init>", "(IIII)V");
if (mid != 0) {
RECT rRW = {0, 0, 0, 0};
+ Devices::InstanceAccess devices;
+ AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
+
if (TRUE == MonitorBounds(AwtWin32GraphicsDevice::GetMonitor(screen), &rRW)) {
- bounds = env->NewObject(clazz, mid,
- rRW.left, rRW.top,
- rRW.right - rRW.left,
- rRW.bottom - rRW.top);
+
+ int x = (device == NULL) ? rRW.left : device->ScaleDownX(rRW.left);
+ int y = (device == NULL) ? rRW.top : device->ScaleDownY(rRW.top);
+ int w = (device == NULL) ? rRW.right - rRW.left
+ : device->ScaleDownX(rRW.right - rRW.left);
+ int h = (device == NULL) ? rRW.bottom - rRW.top
+ : device->ScaleDownY(rRW.bottom - rRW.top);
+
+ bounds = env->NewObject(clazz, mid, x, y, w, h);
+
}
else {
// 4910760 - don't return a null bounds, return the bounds of the
// primary screen
+ int w = ::GetSystemMetrics(SM_CXSCREEN);
+ int h = ::GetSystemMetrics(SM_CYSCREEN);
+
bounds = env->NewObject(clazz, mid,
0, 0,
- ::GetSystemMetrics(SM_CXSCREEN),
- ::GetSystemMetrics(SM_CYSCREEN));
+ device == NULL ? w : device->ScaleDownX(w),
+ device == NULL ? h : device->ScaleDownY(h));
}
if (safe_ExceptionOccurred(env)) {
return 0;
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp Fri Nov 13 05:02:26 2015 -0800
@@ -49,6 +49,12 @@
#include "dither.h"
#include "img_util_md.h"
#include "Devices.h"
+#include <d2d1.h>
+#pragma comment(lib, "d2d1")
+
+#ifndef MDT_Effective_DPI
+#define MDT_Effective_DPI 0
+#endif
uns_ordered_dither_array img_oda_alpha;
@@ -74,6 +80,8 @@
{
this->screen = screen;
this->devicesArray = arr;
+ this->scaleX = 1;
+ this->scaleY = 1;
javaDevice = NULL;
colorData = new ImgColorData;
colorData->grayscale = GS_NOTGRAY;
@@ -617,6 +625,104 @@
}
/**
+ * Sets horizontal and vertical scale factors
+ */
+void AwtWin32GraphicsDevice::SetScale(float sx, float sy)
+{
+ scaleX = sx;
+ scaleY = sy;
+}
+
+int AwtWin32GraphicsDevice::ScaleUpX(int x)
+{
+ return (int)ceil(x * scaleX);
+}
+
+int AwtWin32GraphicsDevice::ScaleUpY(int y)
+{
+ return (int)ceil(y * scaleY);
+}
+
+int AwtWin32GraphicsDevice::ScaleDownX(int x)
+{
+ return (int)ceil(x / scaleX);
+}
+
+int AwtWin32GraphicsDevice::ScaleDownY(int y)
+{
+ return (int)ceil(y / scaleY);
+}
+
+void AwtWin32GraphicsDevice::InitDesktopScales()
+{
+ unsigned x = 0;
+ unsigned y = 0;
+ float dpiX = -1.0f;
+ float dpiY = -1.0f;
+
+ // for debug purposes
+ static float scale = -2.0f;
+ if (scale == -2) {
+ scale = -1;
+ char *uiScale = getenv("J2D_UISCALE");
+ if (uiScale != NULL) {
+ scale = (float)strtod(uiScale, NULL);
+ if (errno == ERANGE || scale <= 0) {
+ scale = -1;
+ }
+ }
+ }
+
+ if (scale > 0) {
+ SetScale(scale, scale);
+ return;
+ }
+
+ typedef HRESULT(WINAPI GetDpiForMonitorFunc)(HMONITOR, int, UINT*, UINT*);
+ static HMODULE hLibSHCoreDll = NULL;
+ static GetDpiForMonitorFunc *lpGetDpiForMonitor = NULL;
+
+ if (hLibSHCoreDll == NULL) {
+ hLibSHCoreDll = JDK_LoadSystemLibrary("shcore.dll");
+ if (hLibSHCoreDll != NULL) {
+ lpGetDpiForMonitor = (GetDpiForMonitorFunc*)GetProcAddress(
+ hLibSHCoreDll, "GetDpiForMonitor");
+ }
+ }
+
+ if (lpGetDpiForMonitor != NULL) {
+ HRESULT hResult = lpGetDpiForMonitor(GetMonitor(),
+ MDT_Effective_DPI, &x, &y);
+ if (hResult == S_OK) {
+ dpiX = static_cast<float>(x);
+ dpiY = static_cast<float>(y);
+ }
+ } else {
+ ID2D1Factory* m_pDirect2dFactory;
+ HRESULT res = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
+ &m_pDirect2dFactory);
+ if (res == S_OK) {
+ m_pDirect2dFactory->GetDesktopDpi(&dpiX, &dpiY);
+ m_pDirect2dFactory->Release();
+ }
+ }
+
+ if (dpiX > 0 && dpiY > 0) {
+ SetScale(dpiX / 96, dpiY / 96);
+ }
+}
+
+float AwtWin32GraphicsDevice::GetScaleX()
+{
+ return scaleX;
+}
+
+float AwtWin32GraphicsDevice::GetScaleY()
+{
+ return scaleY;
+}
+
+/**
* Disables offscreen acceleration for this device. This
* sets a flag in the java object that is used to determine
* whether offscreen surfaces can be created on the device.
@@ -1304,3 +1410,65 @@
Devices::InstanceAccess devices;
devices->GetDevice(screen)->SetJavaDevice(env, thisPtr);
}
+
+/*
+ * Class: sun_awt_Win32GraphicsDevice
+ * Method: setNativeScale
+ * Signature: (I,F,F)V
+ */
+JNIEXPORT void JNICALL
+ Java_sun_awt_Win32GraphicsDevice_setNativeScale
+ (JNIEnv *env, jobject thisPtr, jint screen, jfloat scaleX, jfloat scaleY)
+{
+ Devices::InstanceAccess devices;
+ AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
+
+ if (device != NULL ) {
+ device->SetScale(scaleX, scaleY);
+ }
+}
+
+/*
+ * Class: sun_awt_Win32GraphicsDevice
+ * Method: getNativeScaleX
+ * Signature: (I)F
+ */
+JNIEXPORT jfloat JNICALL
+ Java_sun_awt_Win32GraphicsDevice_getNativeScaleX
+ (JNIEnv *env, jobject thisPtr, jint screen)
+{
+ Devices::InstanceAccess devices;
+ AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
+ return (device == NULL) ? 1 : device->GetScaleX();
+}
+
+/*
+ * Class: sun_awt_Win32GraphicsDevice
+ * Method: getNativeScaleY
+ * Signature: (I)F
+ */
+JNIEXPORT jfloat JNICALL
+ Java_sun_awt_Win32GraphicsDevice_getNativeScaleY
+ (JNIEnv *env, jobject thisPtr, jint screen)
+{
+ Devices::InstanceAccess devices;
+ AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
+ return (device == NULL) ? 1 : device->GetScaleY();
+}
+
+/*
+* Class: sun_awt_Win32GraphicsDevice
+* Method: initNativeScale
+* Signature: (I)V;
+*/
+JNIEXPORT void JNICALL
+Java_sun_awt_Win32GraphicsDevice_initNativeScale
+(JNIEnv *env, jobject thisPtr, jint screen)
+{
+ Devices::InstanceAccess devices;
+ AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
+
+ if (device != NULL) {
+ device->InitDesktopScales();
+ }
+}
\ No newline at end of file
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.h Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.h Fri Nov 13 05:02:26 2015 -0800
@@ -66,6 +66,14 @@
void Release();
void DisableOffscreenAcceleration();
void Invalidate(JNIEnv *env);
+ void InitDesktopScales();
+ void SetScale(float scaleX, float scaleY);
+ float GetScaleX();
+ float GetScaleY();
+ int ScaleUpX(int x);
+ int ScaleUpY(int y);
+ int ScaleDownX(int x);
+ int ScaleDownY(int y);
static int DeviceIndexForWindow(HWND hWnd);
static jobject GetColorModel(JNIEnv *env, jboolean dynamic,
@@ -107,6 +115,8 @@
LPMONITORINFO pMonitorInfo;
jobject javaDevice;
Devices *devicesArray;
+ float scaleX;
+ float scaleY;
static HDC MakeDCFromMonitor(HMONITOR);
};
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Window.cpp Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Window.cpp Fri Nov 13 05:02:26 2015 -0800
@@ -1407,19 +1407,19 @@
/* Get insets into our peer directly */
jobject peerInsets = (env)->GetObjectField(peer, AwtPanel::insets_ID);
DASSERT(!safe_ExceptionOccurred(env));
+
if (peerInsets != NULL) { // may have been called during creation
- (env)->SetIntField(peerInsets, AwtInsets::topID, m_insets.top);
- (env)->SetIntField(peerInsets, AwtInsets::bottomID,
- m_insets.bottom);
- (env)->SetIntField(peerInsets, AwtInsets::leftID, m_insets.left);
- (env)->SetIntField(peerInsets, AwtInsets::rightID, m_insets.right);
+ (env)->SetIntField(peerInsets, AwtInsets::topID, ScaleDownY(m_insets.top));
+ (env)->SetIntField(peerInsets, AwtInsets::bottomID, ScaleDownY(m_insets.bottom));
+ (env)->SetIntField(peerInsets, AwtInsets::leftID, ScaleDownX(m_insets.left));
+ (env)->SetIntField(peerInsets, AwtInsets::rightID, ScaleDownX(m_insets.right));
}
/* Get insets into the Inset object (if any) that was passed */
if (insets != NULL) {
- (env)->SetIntField(insets, AwtInsets::topID, m_insets.top);
- (env)->SetIntField(insets, AwtInsets::bottomID, m_insets.bottom);
- (env)->SetIntField(insets, AwtInsets::leftID, m_insets.left);
- (env)->SetIntField(insets, AwtInsets::rightID, m_insets.right);
+ (env)->SetIntField(insets, AwtInsets::topID, ScaleDownY(m_insets.top));
+ (env)->SetIntField(insets, AwtInsets::bottomID, ScaleDownY(m_insets.bottom));
+ (env)->SetIntField(insets, AwtInsets::leftID, ScaleDownX(m_insets.left));
+ (env)->SetIntField(insets, AwtInsets::rightID, ScaleDownX(m_insets.right));
}
env->DeleteLocalRef(peerInsets);
@@ -1735,10 +1735,10 @@
RECT rect;
::GetWindowRect(GetHWnd(), &rect);
- (env)->SetIntField(target, AwtComponent::xID, rect.left);
- (env)->SetIntField(target, AwtComponent::yID, rect.top);
- (env)->SetIntField(peer, AwtWindow::sysXID, rect.left);
- (env)->SetIntField(peer, AwtWindow::sysYID, rect.top);
+ (env)->SetIntField(target, AwtComponent::xID, ScaleDownX(rect.left));
+ (env)->SetIntField(target, AwtComponent::yID, ScaleDownY(rect.top));
+ (env)->SetIntField(peer, AwtWindow::sysXID, ScaleDownX(rect.left));
+ (env)->SetIntField(peer, AwtWindow::sysYID, ScaleDownY(rect.top));
SendComponentEvent(java_awt_event_ComponentEvent_COMPONENT_MOVED);
env->DeleteLocalRef(target);
@@ -1803,12 +1803,12 @@
int newWidth = w + m_insets.left + m_insets.right;
int newHeight = h + m_insets.top + m_insets.bottom;
- (env)->SetIntField(target, AwtComponent::widthID, newWidth);
- (env)->SetIntField(target, AwtComponent::heightID, newHeight);
+ (env)->SetIntField(target, AwtComponent::widthID, ScaleDownX(newWidth));
+ (env)->SetIntField(target, AwtComponent::heightID, ScaleDownY(newHeight));
jobject peer = GetPeer(env);
- (env)->SetIntField(peer, AwtWindow::sysWID, newWidth);
- (env)->SetIntField(peer, AwtWindow::sysHID, newHeight);
+ (env)->SetIntField(peer, AwtWindow::sysWID, ScaleDownX(newWidth));
+ (env)->SetIntField(peer, AwtWindow::sysHID, ScaleDownY(newHeight));
if (!AwtWindow::IsResizing()) {
WindowResized();
@@ -3072,6 +3072,25 @@
delete data;
}
+void AwtWindow::_GetNativeWindowSize(void* param) {
+
+ JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
+
+ SizeStruct *ss = (SizeStruct *)param;
+ jobject self = ss->window;
+ AwtWindow *window = NULL;
+ PDATA pData;
+ JNI_CHECK_PEER_RETURN(self);
+ window = (AwtWindow *)pData;
+
+ RECT rc;
+ ::GetWindowRect(window->GetHWnd(), &rc);
+ ss->w = rc.right - rc.left;
+ ss->h = rc.bottom - rc.top;
+
+ env->DeleteGlobalRef(self);
+}
+
extern "C" {
/*
@@ -3303,6 +3322,46 @@
/*
* Class: sun_awt_windows_WWindowPeer
+* Method: getNativeWindowSize
+* Signature: ()Ljava/awt/Dimension;
+*/
+JNIEXPORT jobject JNICALL Java_sun_awt_windows_WWindowPeer_getNativeWindowSize
+(JNIEnv *env, jobject self) {
+
+ jobject res = NULL;
+ TRY;
+ SizeStruct *ss = new SizeStruct;
+ ss->window = env->NewGlobalRef(self);
+
+ AwtToolkit::GetInstance().SyncCall(AwtWindow::_GetNativeWindowSize, ss);
+
+ int w = ss->w;
+ int h = ss->h;
+
+ delete ss;
+ // global ref is deleted in _GetNativeWindowSize()
+
+ static jmethodID dimMID = NULL;
+ static jclass dimClassID = NULL;
+ if (dimClassID == NULL) {
+ jclass dimClassIDLocal = env->FindClass("java/awt/Dimension");
+ CHECK_NULL_RETURN(dimClassIDLocal, NULL);
+ dimClassID = (jclass)env->NewGlobalRef(dimClassIDLocal);
+ env->DeleteLocalRef(dimClassIDLocal);
+ }
+
+ if (dimMID == NULL) {
+ dimMID = env->GetMethodID(dimClassID, "<init>", "(II)V");
+ CHECK_NULL_RETURN(dimMID, NULL);
+ }
+
+ return env->NewObject(dimClassID, dimMID, w, h);
+
+ CATCH_BAD_ALLOC_RET(NULL);
+}
+
+/*
+ * Class: sun_awt_windows_WWindowPeer
* Method: getSysMinWidth
* Signature: ()I
*/
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Window.h Thu Nov 12 12:27:36 2015 -0600
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Window.h Fri Nov 13 05:02:26 2015 -0800
@@ -241,6 +241,7 @@
static void _UpdateWindow(void* param);
static void _RepositionSecurityWarning(void* param);
static void _SetFullScreenExclusiveModeState(void* param);
+ static void _GetNativeWindowSize(void* param);
inline static BOOL IsResizing() {
return sm_resizing;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Robot/HiDPIMouseClick/HiDPIRobotMouseClick.java Fri Nov 13 05:02:26 2015 -0800
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.awt.Frame;
+import java.awt.Rectangle;
+import java.awt.Robot;
+import java.awt.event.InputEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import javax.swing.UIManager;
+
+/* @test
+ * @bug 8073320
+ * @summary Windows HiDPI support
+ * @author Alexander Scherbatiy
+ * @requires (os.family == "windows")
+ * @run main/othervm -Dsun.java2d.win.uiScale=2 HiDPIRobotMouseClick
+ */
+public class HiDPIRobotMouseClick {
+
+ private static volatile int mouseX;
+ private static volatile int mouseY;
+
+ public static void main(String[] args) throws Exception {
+
+ try {
+ UIManager.setLookAndFeel(
+ "com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
+ } catch (Exception e) {
+ return;
+ }
+
+ Frame frame = new Frame();
+ frame.setBounds(30, 20, 400, 300);
+ frame.setUndecorated(true);
+
+ frame.addMouseListener(new MouseAdapter() {
+
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ mouseX = e.getXOnScreen();
+ mouseY = e.getYOnScreen();
+ }
+ });
+
+ frame.setVisible(true);
+
+ Robot robot = new Robot();
+ robot.waitForIdle();
+ Thread.sleep(200);
+
+ Rectangle rect = frame.getBounds();
+ rect.setLocation(frame.getLocationOnScreen());
+
+ int x = (int) rect.getCenterX();
+ int y = (int) rect.getCenterY();
+
+ robot.mouseMove(x, y);
+ robot.mousePress(InputEvent.BUTTON1_MASK);
+ robot.mouseRelease(InputEvent.BUTTON1_MASK);
+ robot.waitForIdle();
+
+ if (x != mouseX || y != mouseY) {
+ throw new RuntimeException("Wrong mouse click point!");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Robot/HiDPIScreenCapture/HiDPIRobotScreenCaptureTest.java Fri Nov 13 05:02:26 2015 -0800
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.awt.BorderLayout;
+import java.awt.Canvas;
+import java.awt.Color;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Panel;
+import java.awt.Rectangle;
+import java.awt.Robot;
+import java.awt.image.BufferedImage;
+import javax.swing.UIManager;
+
+/* @test
+ * @bug 8073320
+ * @summary Windows HiDPI support
+ * @author Alexander Scherbatiy
+ * @requires (os.family == "windows")
+ * @run main/othervm -Dsun.java2d.win.uiScaleX=3 -Dsun.java2d.win.uiScaleY=2
+ * HiDPIRobotScreenCaptureTest
+ */
+public class HiDPIRobotScreenCaptureTest {
+
+ private static final Color[] COLORS = {
+ Color.GREEN, Color.BLUE, Color.ORANGE, Color.RED};
+
+ public static void main(String[] args) throws Exception {
+
+ try {
+ UIManager.setLookAndFeel(
+ "com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
+ } catch (Exception e) {
+ return;
+ }
+
+ Frame frame = new Frame();
+ frame.setBounds(40, 30, 400, 300);
+ frame.setUndecorated(true);
+
+ Panel panel = new Panel(new BorderLayout());
+ Canvas canvas = new Canvas() {
+ @Override
+ public void paint(Graphics g) {
+ super.paint(g);
+ int w = getWidth();
+ int h = getHeight();
+ g.setColor(COLORS[0]);
+ g.fillRect(0, 0, w / 2, h / 2);
+ g.setColor(COLORS[1]);
+ g.fillRect(w / 2, 0, w / 2, h / 2);
+ g.setColor(COLORS[2]);
+ g.fillRect(0, h / 2, w / 2, h / 2);
+ g.setColor(COLORS[3]);
+ g.fillRect(w / 2, h / 2, w / 2, h / 2);
+ }
+ };
+
+ panel.add(canvas);
+ frame.add(panel);
+ frame.setVisible(true);
+ Robot robot = new Robot();
+ robot.waitForIdle();
+ Thread.sleep(200);
+
+ Rectangle rect = canvas.getBounds();
+ rect.setLocation(canvas.getLocationOnScreen());
+
+ BufferedImage image = robot.createScreenCapture(rect);
+ frame.dispose();
+
+ int w = image.getWidth();
+ int h = image.getHeight();
+
+ if (w != frame.getWidth() || h != frame.getHeight()) {
+ throw new RuntimeException("Wrong image size!");
+ }
+
+ if (image.getRGB(w / 4, h / 4) != COLORS[0].getRGB()) {
+ throw new RuntimeException("Wrong image color!");
+ }
+
+ if (image.getRGB(3 * w / 4, h / 4) != COLORS[1].getRGB()) {
+ throw new RuntimeException("Wrong image color!");
+ }
+
+ if (image.getRGB(w / 4, 3 * h / 4) != COLORS[2].getRGB()) {
+ throw new RuntimeException("Wrong image color!");
+ }
+
+ if (image.getRGB(3 * w / 4, 3 * h / 4) != COLORS[3].getRGB()) {
+ throw new RuntimeException("Wrong image color!");
+ }
+ }
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/hidpi/properties/HiDPIPropertiesWindowsTest.java Fri Nov 13 05:02:26 2015 -0800
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.awt.Dialog;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.geom.AffineTransform;
+import javax.swing.UIManager;
+
+/* @test
+ * @bug 8073320
+ * @summary Windows HiDPI support
+ * @author Alexander Scherbatiy
+ * @requires (os.family == "windows")
+ * @run main/othervm -Dsun.java2d.uiScale.enabled=false
+ * -Dsun.java2d.win.uiScaleX=3 -Dsun.java2d.win.uiScaleY=2
+ * HiDPIPropertiesWindowsTest UISCALE_DISABLED
+ * @run main/othervm -Dsun.java2d.uiScale.enabled=false
+ * -Dsun.java2d.uiScale=3
+ * HiDPIPropertiesWindowsTest UISCALE_DISABLED
+ * @run main/othervm -Dsun.java2d.uiScale.enabled=false
+ * -Dsun.java2d.uiScale=3
+ * -Dsun.java2d.win.uiScaleX=5 -Dsun.java2d.win.uiScaleY=6
+ * HiDPIPropertiesWindowsTest UISCALE_DISABLED
+ * @run main/othervm -Dsun.java2d.uiScale.enabled=true
+ * -Dsun.java2d.uiScale=3
+ * HiDPIPropertiesWindowsTest UISCALE_3
+ * @run main/othervm -Dsun.java2d.uiScale.enabled=true
+ * -Dsun.java2d.uiScale=4
+ * -Dsun.java2d.win.uiScaleX=2 -Dsun.java2d.win.uiScaleY=3
+ * HiDPIPropertiesWindowsTest UISCALE_2X3
+ * @run main/othervm -Dsun.java2d.uiScale.enabled=true
+ * -Dsun.java2d.win.uiScaleX=3 -Dsun.java2d.win.uiScaleY=2
+ * HiDPIPropertiesWindowsTest UISCALE_3X2
+ * @run main/othervm -Dsun.java2d.uiScale=4
+ * HiDPIPropertiesWindowsTest UISCALE_4
+ * @run main/othervm -Dsun.java2d.uiScale=4
+ * -Dsun.java2d.win.uiScaleX=2 -Dsun.java2d.win.uiScaleY=3
+ * HiDPIPropertiesWindowsTest UISCALE_2X3
+ * @run main/othervm -Dsun.java2d.win.uiScaleX=4 -Dsun.java2d.win.uiScaleY=5
+ * HiDPIPropertiesWindowsTest UISCALE_4X5
+ * @run main/othervm -Dsun.java2d.uiScale=3
+ * -Dsun.java2d.win.uiScaleX=0 -Dsun.java2d.win.uiScaleY=0
+ * HiDPIPropertiesWindowsTest UISCALE_3
+ * @run main/othervm -Dsun.java2d.uiScale=4
+ * -Dsun.java2d.win.uiScaleX=-7 -Dsun.java2d.win.uiScaleY=-8
+ * HiDPIPropertiesWindowsTest UISCALE_4
+ * @run main/othervm -Dsun.java2d.uiScale=4x
+ * HiDPIPropertiesWindowsTest UISCALE_4
+ * @run main/othervm -Dsun.java2d.win.uiScaleX=4x -Dsun.java2d.win.uiScaleY=5x
+ * HiDPIPropertiesWindowsTest UISCALE_4X5
+ * @run main/othervm -Dsun.java2d.uiScale=384dpi
+ * HiDPIPropertiesWindowsTest UISCALE_4
+ * @run main/othervm -Dsun.java2d.uiScale=300%
+ * HiDPIPropertiesWindowsTest UISCALE_3
+ * @run main/othervm -Dsun.java2d.win.uiScaleX=400% -Dsun.java2d.win.uiScaleY=500%
+ * HiDPIPropertiesWindowsTest UISCALE_4X5
+ * @run main/othervm -Dsun.java2d.win.uiScaleX=288dpi -Dsun.java2d.win.uiScaleY=192dpi
+ * HiDPIPropertiesWindowsTest UISCALE_3X2
+ * @run main/othervm -Dsun.java2d.win.uiScaleX=200% -Dsun.java2d.win.uiScaleY=288dpi
+ * HiDPIPropertiesWindowsTest UISCALE_2X3
+ */
+public class HiDPIPropertiesWindowsTest {
+
+ public static void main(String[] args) throws Exception {
+
+ try {
+ UIManager.setLookAndFeel(
+ "com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
+ } catch (Exception e) {
+ return;
+ }
+
+ String testCase = args[0];
+ switch (testCase) {
+ case "UISCALE_DISABLED":
+ testScale(1.0, 1.0);
+ break;
+ case "UISCALE_3":
+ testScale(3.0, 3.0);
+ break;
+ case "UISCALE_4":
+ testScale(4.0, 4.0);
+ break;
+ case "UISCALE_2X3":
+ testScale(2.0, 3.0);
+ break;
+ case "UISCALE_3X2":
+ testScale(3.0, 2.0);
+ break;
+ case "UISCALE_4X5":
+ testScale(4.0, 5.0);
+ break;
+ default:
+ throw new RuntimeException("Unknown test case: " + testCase);
+ }
+ }
+
+ private static void testScale(double scaleX, double scaleY) {
+
+ Dialog dialog = new Dialog((Frame) null, true) {
+
+ @Override
+ public void paint(Graphics g) {
+ super.paint(g);
+ AffineTransform tx = ((Graphics2D) g).getTransform();
+ dispose();
+ if (scaleX != tx.getScaleX() || scaleY != tx.getScaleY()) {
+ throw new RuntimeException(String.format("Wrong scale:"
+ + "[%f, %f] instead of [%f, %f].",
+ tx.getScaleX(), tx.getScaleY(), scaleX, scaleY));
+ }
+ }
+ };
+ dialog.setSize(200, 300);
+ dialog.setVisible(true);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/image/MultiResolutionImage/MultiResolutionDrawImageWithTransformTest.java Fri Nov 13 05:02:26 2015 -0800
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.awt.Color;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
+import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+import java.awt.image.BaseMultiResolutionImage;
+import static java.awt.RenderingHints.KEY_RESOLUTION_VARIANT;
+import static java.awt.RenderingHints.VALUE_RESOLUTION_VARIANT_SIZE_FIT;
+import java.awt.geom.AffineTransform;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+import sun.java2d.StateTrackable;
+import sun.java2d.SunGraphics2D;
+import sun.java2d.SurfaceData;
+import sun.java2d.loops.SurfaceType;
+
+/**
+ * @test
+ * @bug 8073320
+ * @author Alexander Scherbatiy
+ * @summary Windows HiDPI support
+ * @modules java.desktop/sun.java2d java.desktop/sun.java2d.loops
+ * @run main MultiResolutionDrawImageWithTransformTest
+ */
+public class MultiResolutionDrawImageWithTransformTest {
+
+ private static final int SCREEN_SIZE = 400;
+ private static final int IMAGE_SIZE = SCREEN_SIZE / 4;
+ private static final Color BACKGROUND_COLOR = Color.PINK;
+ private static final Color[] COLORS = {
+ Color.CYAN, Color.GREEN, Color.BLUE, Color.ORANGE
+ };
+
+ public static void main(String[] args) throws Exception {
+
+ int length = COLORS.length;
+ BufferedImage[] resolutionVariants = new BufferedImage[length];
+ for (int i = 0; i < length; i++) {
+ resolutionVariants[i] = createRVImage(getSize(i), COLORS[i]);
+ }
+
+ BaseMultiResolutionImage mrImage = new BaseMultiResolutionImage(
+ resolutionVariants);
+
+ // scale 1, transform 1, resolution variant 1
+ Color color = getImageColor(mrImage, 1, 1);
+ if (!getColorForScale(1).equals(color)) {
+ throw new RuntimeException("Wrong resolution variant!");
+ }
+
+ // scale 1, transform 2, resolution variant 2
+ color = getImageColor(mrImage, 1, 2);
+ if (!getColorForScale(2).equals(color)) {
+ throw new RuntimeException("Wrong resolution variant!");
+ }
+
+ // scale 2, transform 1, resolution variant 2
+ color = getImageColor(mrImage, 2, 1);
+ if (!getColorForScale(2).equals(color)) {
+ throw new RuntimeException("Wrong resolution variant!");
+ }
+
+ // scale 2, transform 2, resolution variant 4
+ color = getImageColor(mrImage, 2, 2);
+ if (!getColorForScale(4).equals(color)) {
+ throw new RuntimeException("Wrong resolution variant!");
+ }
+ }
+
+ private static Color getColorForScale(int scale) {
+ return COLORS[scale - 1];
+ }
+
+ private static Color getImageColor(Image image, double configScale,
+ double transformScale) {
+
+ TestSurfaceData surface = new TestSurfaceData(SCREEN_SIZE, SCREEN_SIZE,
+ configScale);
+ SunGraphics2D g2d = new SunGraphics2D(surface,
+ Color.BLACK, Color.BLACK, null);
+ g2d.setRenderingHint(KEY_RESOLUTION_VARIANT,
+ VALUE_RESOLUTION_VARIANT_SIZE_FIT);
+ AffineTransform tx = AffineTransform.getScaleInstance(transformScale,
+ transformScale);
+ g2d.drawImage(image, tx, null);
+ g2d.dispose();
+
+ int backgroundX = (int) (1.5 * image.getWidth(null) * transformScale);
+ int backgroundY = (int) (1.5 * image.getHeight(null) * transformScale);
+ Color backgroundColor = surface.getColor(backgroundX, backgroundY);
+ //surface.show(String.format("Config: %f, transform: %f", configScale, transformScale));
+ if (!BACKGROUND_COLOR.equals(backgroundColor)) {
+ throw new RuntimeException("Wrong background color!");
+ }
+ return surface.getColor(IMAGE_SIZE / 4, IMAGE_SIZE / 4);
+ }
+
+ private static int getSize(int i) {
+ return (i + 1) * IMAGE_SIZE;
+ }
+
+ private static BufferedImage createRVImage(int size, Color color) {
+ BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
+ Graphics g = image.createGraphics();
+ g.setColor(color);
+ g.fillRect(0, 0, size, size);
+ g.dispose();
+ return image;
+ }
+
+ static class TestGraphicsConfig extends GraphicsConfiguration {
+
+ private final double scale;
+
+ TestGraphicsConfig(double scale) {
+ this.scale = scale;
+ }
+
+ @Override
+ public GraphicsDevice getDevice() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public ColorModel getColorModel() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public ColorModel getColorModel(int transparency) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public AffineTransform getDefaultTransform() {
+ return AffineTransform.getScaleInstance(scale, scale);
+ }
+
+ @Override
+ public AffineTransform getNormalizingTransform() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public Rectangle getBounds() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+ }
+
+ static class TestSurfaceData extends SurfaceData {
+
+ private final int width;
+ private final int height;
+ private final GraphicsConfiguration gc;
+ private final BufferedImage buffImage;
+ private final double scale;
+
+ public TestSurfaceData(int width, int height, double scale) {
+ super(StateTrackable.State.DYNAMIC, SurfaceType.Custom, ColorModel.getRGBdefault());
+ this.scale = scale;
+ gc = new TestGraphicsConfig(scale);
+ this.width = (int) Math.ceil(scale * width);
+ this.height = (int) Math.ceil(scale * height);
+ buffImage = new BufferedImage(this.width, this.height,
+ BufferedImage.TYPE_INT_RGB);
+
+ Graphics imageGraphics = buffImage.createGraphics();
+ imageGraphics.setColor(BACKGROUND_COLOR);
+ imageGraphics.fillRect(0, 0, this.width, this.height);
+ imageGraphics.dispose();
+ }
+
+ Color getColor(int x, int y) {
+ int sx = (int) Math.ceil(x * scale);
+ int sy = (int) Math.ceil(y * scale);
+ return new Color(buffImage.getRGB(sx, sy));
+ }
+
+ @Override
+ public SurfaceData getReplacement() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public GraphicsConfiguration getDeviceConfiguration() {
+ return gc;
+ }
+
+ @Override
+ public Raster getRaster(int x, int y, int w, int h) {
+ return buffImage.getRaster();
+ }
+
+ @Override
+ public Rectangle getBounds() {
+ return new Rectangle(0, 0, width, height);
+ }
+
+ @Override
+ public Object getDestination() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ private void show(String title) {
+ Frame frame = new Frame() {
+
+ @Override
+ public void paint(Graphics g) {
+ super.paint(g);
+ g.drawImage(buffImage, 0, 0, this);
+ g.setColor(Color.GRAY);
+ g.drawRect(0, 0, width, height);
+ g.drawRect(0, height / 2, width, height / 2);
+ g.drawRect(width / 2, 0, width / 2, height);
+ }
+ };
+ frame.setTitle(title);
+ frame.setSize(width, height);
+ frame.setVisible(true);
+ }
+ }
+}