--- old/src/java.desktop/share/classes/java/awt/Robot.java 2017-02-09 15:00:22.609640001 +0530 +++ new/src/java.desktop/share/classes/java/awt/Robot.java 2017-02-09 15:00:22.397640001 +0530 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, 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 @@ -27,6 +27,9 @@ import java.awt.event.InputEvent; import java.awt.event.KeyEvent; +import java.awt.geom.AffineTransform; +import java.awt.image.BaseMultiResolutionImage; +import java.awt.image.MultiResolutionImage; import java.awt.image.BufferedImage; import java.awt.image.DataBufferInt; import java.awt.image.DirectColorModel; @@ -390,6 +393,11 @@ * @return Color of the pixel */ public synchronized Color getPixelColor(int x, int y) { + AffineTransform tx = GraphicsEnvironment. + getLocalGraphicsEnvironment().getDefaultScreenDevice(). + getDefaultConfiguration().getDefaultTransform(); + x = (int) (x * tx.getScaleX()); + y = (int) (y * tx.getScaleY()); Color color = new Color(peer.getRGBPixel(x, y)); return color; } @@ -405,13 +413,68 @@ * @see AWTPermission */ public synchronized BufferedImage createScreenCapture(Rectangle screenRect) { + return createCompatibleImage(screenRect, false)[0]; + } + + /** + * Creates an image containing pixels read from the screen. + * This image does not include the mouse cursor. + * This method can be used in case there is a scaling transform + * from user space to screen (device) space. + * Typically this means that the display is a high resolution screen, + * although strictly it means any case in which there is such a transform. + * Returns a {@link java.awt.image.MultiResolutionImage}. + *

+ * For a non-scaled display, the {@code MultiResolutionImage} + * will have one image variant: + *

+ *

+ * For a high resolution display where there is a scaling transform, + * the {@code MultiResolutionImage} will have two image variants: + *

+ *

+ * Example: + *

+     *      Image nativeResImage;
+     *      Image baseResImage;
+     *      MultiResolutionImage mrImage = robot.createMultiResolutionScreenCapture(frame.getBounds());
+     *      List resolutionVariants = mrImage.getResolutionVariants();
+     *      if (resolutionVariants.size() > 1) {
+     *          nativeResImage = resolutionVariants.get(1);
+     *      } else {
+     *          baseResImage = resolutionVariants.get(0);
+     *      } 
+ * @param screenRect Rect to capture in screen coordinates + * @return The captured image + * @throws IllegalArgumentException if {@code screenRect} width and height are not greater than zero + * @throws SecurityException if {@code readDisplayPixels} permission is not granted + * @see SecurityManager#checkPermission + * @see AWTPermission + */ + public synchronized MultiResolutionImage + createMultiResolutionScreenCapture(Rectangle screenRect) { + + return new BaseMultiResolutionImage( + createCompatibleImage(screenRect, true)); + } + + private synchronized BufferedImage[] + createCompatibleImage(Rectangle screenRect, boolean isHiDPI) { + checkScreenCaptureAllowed(); checkValidRect(screenRect); - BufferedImage image; + BufferedImage lowResolutionImage; + BufferedImage highResolutionImage; DataBufferInt buffer; WritableRaster raster; + BufferedImage[] imageArray; if (screenCapCM == null) { /* @@ -421,31 +484,92 @@ */ screenCapCM = new DirectColorModel(24, - /* red mask */ 0x00FF0000, - /* green mask */ 0x0000FF00, - /* blue mask */ 0x000000FF); + /* red mask */ 0x00FF0000, + /* green mask */ 0x0000FF00, + /* blue mask */ 0x000000FF); } + int[] bandmasks = new int[3]; + bandmasks[0] = screenCapCM.getRedMask(); + bandmasks[1] = screenCapCM.getGreenMask(); + bandmasks[2] = screenCapCM.getBlueMask(); + // need to sync the toolkit prior to grabbing the pixels since in some // cases rendering to the screen may be delayed Toolkit.getDefaultToolkit().sync(); - + AffineTransform tx = GraphicsEnvironment. + getLocalGraphicsEnvironment().getDefaultScreenDevice(). + getDefaultConfiguration().getDefaultTransform(); + double uiScaleX = tx.getScaleX(); + double uiScaleY = tx.getScaleY(); int pixels[]; - int[] bandmasks = new int[3]; - pixels = peer.getRGBPixels(screenRect); - buffer = new DataBufferInt(pixels, pixels.length); + if (uiScaleX == 1 && uiScaleY == 1) { - bandmasks[0] = screenCapCM.getRedMask(); - bandmasks[1] = screenCapCM.getGreenMask(); - bandmasks[2] = screenCapCM.getBlueMask(); + pixels = peer.getRGBPixels(screenRect); + buffer = new DataBufferInt(pixels, pixels.length); - raster = Raster.createPackedRaster(buffer, screenRect.width, screenRect.height, screenRect.width, bandmasks, null); - SunWritableRaster.makeTrackable(buffer); + bandmasks[0] = screenCapCM.getRedMask(); + bandmasks[1] = screenCapCM.getGreenMask(); + bandmasks[2] = screenCapCM.getBlueMask(); + + raster = Raster.createPackedRaster(buffer, screenRect.width, + screenRect.height, screenRect.width, bandmasks, null); + SunWritableRaster.makeTrackable(buffer); + + highResolutionImage = new BufferedImage(screenCapCM, raster, + false, null); + imageArray = new BufferedImage[1]; + imageArray[0] = highResolutionImage; + + } else { + + int sX = (int) Math.floor(screenRect.x * uiScaleX); + int sY = (int) Math.floor(screenRect.y * uiScaleY); + int sWidth = (int) Math.ceil(screenRect.width * uiScaleX); + int sHeight = (int) Math.ceil(screenRect.height * uiScaleY); + int temppixels[]; + Rectangle scaledRect = new Rectangle(sX, sY, sWidth, sHeight); + temppixels = peer.getRGBPixels(scaledRect); + + // HighResolutionImage + pixels = temppixels; + buffer = new DataBufferInt(pixels, pixels.length); + raster = Raster.createPackedRaster(buffer, scaledRect.width, + scaledRect.height, scaledRect.width, bandmasks, null); + SunWritableRaster.makeTrackable(buffer); + + highResolutionImage = new BufferedImage(screenCapCM, raster, + false, null); + + + // LowResolutionImage + lowResolutionImage = new BufferedImage(screenRect.width, + screenRect.height, highResolutionImage.getType()); + Graphics2D g = lowResolutionImage.createGraphics(); + g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); + g.setRenderingHint(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_QUALITY); + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g.drawImage(highResolutionImage, 0, 0, + screenRect.width, screenRect.height, + 0, 0, scaledRect.width, scaledRect.height, null); + g.dispose(); + + if(!isHiDPI) { + imageArray = new BufferedImage[1]; + imageArray[0] = lowResolutionImage; + } else { + imageArray = new BufferedImage[2]; + imageArray[0] = lowResolutionImage; + imageArray[1] = highResolutionImage; + } - image = new BufferedImage(screenCapCM, raster, false, null); + } - return image; + return imageArray; } private static void checkValidRect(Rectangle rect) { --- old/src/java.desktop/windows/native/libawt/windows/awt_Robot.cpp 2017-02-09 15:00:23.105640001 +0530 +++ new/src/java.desktop/windows/native/libawt/windows/awt_Robot.cpp 2017-02-09 15:00:22.933640001 +0530 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, 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 @@ -224,24 +224,11 @@ 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 - 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); - } + VERIFY(::BitBlt(hdcMem, 0, 0, width, height, hdcScreen, x, y, + SRCCOPY | CAPTUREBLT) != 0); static const int BITS_PER_PIXEL = 32; static const int BYTES_PER_PIXEL = BITS_PER_PIXEL/8; --- old/src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java 2017-02-09 15:00:23.589640001 +0530 +++ new/src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java 2017-02-09 15:00:23.393640001 +0530 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, 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 @@ -115,8 +115,7 @@ @Override public int getRGBPixel(int x, int y) { int pixelArray[] = new int[1]; - getRGBPixelsImpl(xgc, x, y, 1, 1, xgc.getScale(), pixelArray, - useGtk); + getRGBPixelsImpl(xgc, x, y, 1, 1, pixelArray, useGtk); return pixelArray[0]; } @@ -124,7 +123,7 @@ public int [] getRGBPixels(Rectangle bounds) { int pixelArray[] = new int[bounds.width*bounds.height]; getRGBPixelsImpl(xgc, bounds.x, bounds.y, bounds.width, bounds.height, - xgc.getScale(), pixelArray, useGtk); + pixelArray, useGtk); return pixelArray; } @@ -140,6 +139,5 @@ private static synchronized native void keyReleaseImpl(int keycode); private static synchronized native void getRGBPixelsImpl(X11GraphicsConfig xgc, - int x, int y, int width, int height, int scale, - int pixelArray[], boolean isGtkSupported); + int x, int y, int width, int height, int pixelArray[], boolean isGtkSupported); } --- old/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c 2017-02-09 15:00:24.077640001 +0530 +++ new/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c 2017-02-09 15:00:23.901640001 +0530 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, 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 @@ -276,7 +276,6 @@ jint jy, jint jwidth, jint jheight, - jint scale, jintArray pixelArray, jboolean useGtk) { XImage *image; @@ -298,11 +297,6 @@ AWT_LOCK(); - jint sx = jx * scale; - jint sy = jy * scale; - jint swidth = jwidth * scale; - jint sheight = jheight * scale; - rootWindow = XRootWindow(awt_display, adata->awt_visInfo.screen); if (!useGtk) { @@ -314,10 +308,10 @@ } if (!XGetWindowAttributes(awt_display, rootWindow, &attr) - || sx + swidth <= attr.x - || attr.x + attr.width <= sx - || sy + sheight <= attr.y - || attr.y + attr.height <= sy) { + || jx + jwidth <= attr.x + || attr.x + attr.width <= jx + || jy + jheight <= attr.y + || attr.y + attr.height <= jy) { AWT_UNLOCK(); return; // Does not intersect with root window @@ -326,26 +320,25 @@ gboolean gtk_failed = TRUE; jint _x, _y; - jint x = MAX(sx, attr.x); - jint y = MAX(sy, attr.y); - jint width = MIN(sx + swidth, attr.x + attr.width) - x; - jint height = MIN(sy + sheight, attr.y + attr.height) - y; - + jint x = MAX(jx, attr.x); + jint y = MAX(jy, attr.y); + jint width = MIN(jx + jwidth, attr.x + attr.width) - x; + jint height = MIN(jy + jheight, attr.y + attr.height) - y; - int dx = attr.x > sx ? attr.x - sx : 0; - int dy = attr.y > sy ? attr.y - sy : 0; + int dx = attr.x > jx ? attr.x - jx : 0; + int dy = attr.y > jy ? attr.y - jy : 0; int index; if (useGtk) { gtk->gdk_threads_enter(); gtk_failed = gtk->get_drawable_data(env, pixelArray, x, y, width, - height, jwidth, dx, dy, scale); + height, jwidth, dx, dy, 1); gtk->gdk_threads_leave(); } if (gtk_failed) { - image = getWindowImage(awt_display, rootWindow, sx, sy, swidth, sheight); + image = getWindowImage(awt_display, rootWindow, x, y, width, height); ary = (*env)->GetPrimitiveArrayCritical(env, pixelArray, NULL); @@ -355,15 +348,10 @@ return; } - dx /= scale; - dy /= scale; - width /= scale; - height /= scale; - /* convert to Java ARGB pixels */ for (_y = 0; _y < height; _y++) { for (_x = 0; _x < width; _x++) { - jint pixel = (jint) XGetPixel(image, _x * scale, _y * scale); + jint pixel = (jint) XGetPixel(image, _x, _y); /* Note ignore upper * 32-bits on 64-bit * OSes. --- old/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m 2017-02-09 15:00:24.521640001 +0530 +++ new/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m 2017-02-09 15:00:24.365640001 +0530 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, 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 @@ -276,7 +276,7 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CRobot_nativeGetScreenPixels (JNIEnv *env, jobject peer, - jint x, jint y, jint width, jint height, jintArray pixels) + jint x, jint y, jint width, jint height, jdouble scale, jintArray pixels) { JNF_COCOA_ENTER(env); @@ -285,10 +285,11 @@ jint picWidth = width; jint picHeight = height; - CGRect screenRect = CGRectMake(picX, picY, picWidth, picHeight); + CGRect screenRect = CGRectMake(picX / scale, picY / scale, + picWidth / scale, picHeight / scale); CGImageRef screenPixelsImage = CGWindowListCreateImage(screenRect, kCGWindowListOptionOnScreenOnly, - kCGNullWindowID, kCGWindowImageDefault); + kCGNullWindowID, kCGWindowImageBestResolution); if (screenPixelsImage == NULL) { return; --- old/src/java.desktop/macosx/classes/sun/lwawt/macosx/CRobot.java 2017-02-09 15:00:25.073640001 +0530 +++ new/src/java.desktop/macosx/classes/sun/lwawt/macosx/CRobot.java 2017-02-09 15:00:24.861640001 +0530 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, 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 @@ -174,7 +174,8 @@ @Override public int getRGBPixel(int x, int y) { int c[] = new int[1]; - getScreenPixels(new Rectangle(x, y, 1, 1), c); + double scale = fDevice.getScaleFactor(); + getScreenPixels(new Rectangle(x, y, (int) scale, (int) scale), c); return c[0]; } @@ -185,7 +186,7 @@ */ @Override public int [] getRGBPixels(final Rectangle bounds) { - int c[] = new int[bounds.width * bounds.height]; + int c[] = new int[bounds.width * bounds.height]; getScreenPixels(bounds, c); return c; @@ -198,7 +199,8 @@ boolean isMouseMove); private native void keyEvent(int javaKeyCode, boolean keydown); private void getScreenPixels(Rectangle r, int[] pixels){ - nativeGetScreenPixels(r.x, r.y, r.width, r.height, pixels); + double scale = fDevice.getScaleFactor(); + nativeGetScreenPixels(r.x, r.y, r.width, r.height, scale, pixels); } - private native void nativeGetScreenPixels(int x, int y, int width, int height, int[] pixels); + private native void nativeGetScreenPixels(int x, int y, int width, int height, double scale, int[] pixels); } --- /dev/null 2017-02-09 11:50:18.248520000 +0530 +++ new/test/java/awt/Robot/HiDPIScreenCapture/ScreenCaptureTest.java 2017-02-09 15:00:25.465640001 +0530 @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2017, 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. + */ + + /* + * @test + * @bug 8162959 + * @summary Validate output of createMultiResolutionScreenCapture + * new API which returns MultiResolutionImage. + * @run main/othervm -Dsun.java2d.uiScale=1 ScreenCaptureTest + * @run main/othervm -Dsun.java2d.uiScale=2 ScreenCaptureTest + */ +import java.awt.Dimension; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.MultiResolutionImage; +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.Robot; +import java.util.List; + +public class ScreenCaptureTest { + + private static Robot robot; + private static Frame frame; + private static boolean isHiDPI = true; + private static final Color[] COLORS = { + Color.GREEN, Color.BLUE, Color.ORANGE, Color.RED}; + + public static void main(String[] args) throws Exception { + + frame = new Frame(); + frame.setBounds(0, 0, 400, 400); + frame.setUndecorated(true); + robot = new Robot(); + Panel panel = new Panel(new BorderLayout()); + Canvas canvas = new Canvas() { + 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.delay(500); + robot.waitForIdle(); + + int w = frame.getWidth(); + int h = frame.getHeight(); + + // getPixelColor Test + // Check pixel color in first quardant GREEN; x=100, y=100 + if (!robot.getPixelColor(w / 4, h / 4).equals(COLORS[0])) { + throw new RuntimeException("Wrong Pixel Color! Expected GREEN"); + } + // Check pixel color in second quardant; BLUE, x=300, y=100 + if (!robot.getPixelColor(3 * w / 4, h / 4).equals(COLORS[1])) { + throw new RuntimeException("Wrong Pixel Color! Expected BLUE"); + } + // Check pixel color in third quardant; ORANGE, x=100, y=300 + if (!robot.getPixelColor(w / 4, 3 * h / 4).equals(COLORS[2])) { + throw new RuntimeException("Wrong Pixel Color! Expected ORANGE"); + } + // Check pixel color in fourth quardant; RED, x=300, y=300 + if (!robot.getPixelColor(3 * w / 4, 3 * h / 4).equals(COLORS[3])) { + throw new RuntimeException("Wrong Pixel Color! Expected RED"); + } + + // createScreenCaptureTest + AffineTransform tx = GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration() + .getDefaultTransform(); + + if (tx.getScaleX() == 1 && tx.getScaleY() == 1) { + isHiDPI = false; + } + + MultiResolutionImage image + = robot.createMultiResolutionScreenCapture(frame.getBounds()); + List imageList = image.getResolutionVariants(); + int size = imageList.size(); + BufferedImage lowResImage; + BufferedImage highResImage; + + if (!isHiDPI) { + // Check if output is MultiResolutionImage with one variant + if (size != 1) { + throw new RuntimeException(" Invalid variant size"); + } + + lowResImage = (BufferedImage) imageList.get(0); + System.out.println(frame.getBounds()); + System.out.println(lowResImage.getWidth()+" "+lowResImage.getHeight()); + if (frame.getWidth() != lowResImage.getWidth() + || frame.getHeight() != lowResImage.getHeight()) { + throw new RuntimeException(" Invalid Image size"); + } + + } else { + // Check if output contains two variants. + if (size != 2) { + throw new RuntimeException(" Invalid variant size"); + } + + // Check if hight resolution image size is scale times low resolution image. + lowResImage = (BufferedImage) imageList.get(0); + highResImage = (BufferedImage) imageList.get(1); + + int lW = (int) lowResImage.getWidth(); + int lH = (int) lowResImage.getHeight(); + int hW = (int) highResImage.getWidth(); + int hH = (int) highResImage.getHeight(); + + if ( hW != (tx.getScaleX() * lW) || hH != (tx.getScaleY() * lH)) { + throw new RuntimeException(" Invalid Resolution Variants"); + } + + // Check if both image colors are same at some location. + if (lowResImage.getRGB(lW / 4, lH / 4) + != highResImage.getRGB(hW / 4, hH / 4)) { + throw new RuntimeException("Wrong image color!"); + } + + if (lowResImage.getRGB(3 * lW / 4, lH / 4) + != highResImage.getRGB(3 * hW / 4, hH / 4)) { + throw new RuntimeException("Wrong image color!"); + } + + if (lowResImage.getRGB(lW / 4, 3 * lH / 4) + != highResImage.getRGB(hW / 4, 3 * hH / 4)) { + throw new RuntimeException("Wrong image color!"); + } + + if (lowResImage.getRGB(3 * lW / 4, 3 * lH / 4) + != highResImage.getRGB(3 * hW / 4, 3 * hH / 4)) { + throw new RuntimeException("Wrong image color!"); + } + + } + + frame.dispose(); + } + +} --- /dev/null 2017-02-09 11:50:18.248520000 +0530 +++ new/test/java/awt/Robot/HiDPIScreenCapture/ScreenCaptureResolutionTest.java 2017-02-09 15:00:25.941640001 +0530 @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2017, 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. + */ + + /* + * @test + * @bug 8162959 + * @summary Visually validate multiresolution screencapture. + * @run main/othervm/manual -Dsun.java2d.uiScale=2 ScreenCaptureResolutionTest + */ +import java.awt.AWTException; +import java.awt.Color; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.util.concurrent.CountDownLatch; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.JButton; +import javax.swing.JFrame; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.concurrent.TimeUnit; +import javax.swing.ImageIcon; +import javax.swing.JLabel; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.util.List; +import java.awt.Image; +import java.awt.image.MultiResolutionImage; + +public class ScreenCaptureResolutionTest { + + public static void main(String args[]) throws Exception { + + final CountDownLatch latch = new CountDownLatch(1); + TestUI test = new TestUI(latch); + + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + try { + test.createUI(); + } catch (Exception ex) { + throw new RuntimeException("Exception while creating UI"); + } + } + }); + latch.await(3, TimeUnit.SECONDS); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + try { + test.validateScreenCapture(); + } catch (Exception ex) { + throw new RuntimeException("Exception while" + + " validating ScreenCapture"); + } + } + }); + boolean status = latch.await(5, TimeUnit.MINUTES); + if (!status) { + System.out.println("Test timed out."); + } + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + try { + test.disposeUI(); + } catch (Exception ex) { + throw new RuntimeException("Exception while disposing UI"); + } + } + }); + + if (test.testResult == false) { + throw new RuntimeException("Test Failed."); + } + } +} + +class TestUI { + + private static JFrame mainFrame; + private static JFrame outputImageFrame; + private static JFrame inputImageFrame; + private static JPanel outputControlPanel; + private static JPanel mainControlPanel; + + private static JTextArea instructionTextArea; + + private static JPanel inputImagePanel; + private static JPanel resultButtonPanel; + private static JButton passButton; + private static JButton failButton; + + private static GridBagLayout layout; + private final CountDownLatch latch; + public boolean testResult = false; + + public TestUI(CountDownLatch latch) throws Exception { + this.latch = latch; + } + + public void validateScreenCapture() throws AWTException { + Robot robot = new Robot(); + outputControlPanel = new JPanel(layout); + GridBagConstraints ogbc = new GridBagConstraints(); + + MultiResolutionImage image + = robot.createMultiResolutionScreenCapture(inputImageFrame.getBounds()); + List imageList = image.getResolutionVariants(); + int size = imageList.size(); + BufferedImage lowResImage = (BufferedImage) imageList.get(0); + BufferedImage highResImage = (BufferedImage) imageList.get(1); + + outputImageFrame = new JFrame("Output"); + outputImageFrame.getContentPane().setLayout(new GridBagLayout()); + ogbc.gridx = 0; + ogbc.gridy = 0; + ogbc.fill = GridBagConstraints.HORIZONTAL; + outputControlPanel.add(new JLabel(new ImageIcon(lowResImage)), ogbc); + int width = lowResImage.getWidth(); + int height = lowResImage.getHeight(); + JLabel labelImg1 = new JLabel("LEFT:Width: " + width + + " Height: " + height); + ogbc.gridx = 0; + ogbc.gridy = 1; + outputControlPanel.add(labelImg1, ogbc); + ogbc.gridx = 1; + ogbc.gridy = 0; + outputControlPanel.add(new JLabel(new ImageIcon(highResImage)), ogbc); + width = highResImage.getWidth(); + height = highResImage.getHeight(); + JLabel labelImg2 = new JLabel("RIGHT:Width: " + width + + " Height: " + height); + ogbc.gridx = 1; + ogbc.gridy = 1; + outputControlPanel.add(labelImg2, ogbc); + outputControlPanel.setBackground(Color.GRAY); + outputImageFrame.add(outputControlPanel); + + outputImageFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + outputImageFrame.setBounds(600, 0, 400, 300); + outputImageFrame.setLocationRelativeTo(null); + outputImageFrame.setVisible(true); + } + + public final void createUI() throws Exception { + + mainFrame = new JFrame("ScreenCaptureResolutionTest"); + + layout = new GridBagLayout(); + mainControlPanel = new JPanel(layout); + resultButtonPanel = new JPanel(layout); + + GridBagConstraints gbc = new GridBagConstraints(); + + // Create Test instructions + String instructions + = "INSTRUCTIONS:" + + "\n Test to Visually validate MultiResolutionn Image. " + + "\n 1. Check if output window contains two screenshot " + + "\n of input window. " + + "\n 2. Right image should be twice the size of Left. " + + "\n 3. Quality of Right image should be better than Left. " + + "\n If all the three conditons are satisfied, then " + + "\n click pass else fail."; + instructionTextArea = new JTextArea(); + instructionTextArea.setText(instructions); + instructionTextArea.setEnabled(false); + instructionTextArea.setDisabledTextColor(Color.black); + instructionTextArea.setBackground(Color.white); + + gbc.gridx = 0; + gbc.gridy = 0; + gbc.fill = GridBagConstraints.HORIZONTAL; + mainControlPanel.add(instructionTextArea, gbc); + + gbc.gridx = 0; + gbc.gridy = 1; + + inputImagePanel = new JPanel(layout); + JLabel label = new JLabel("Resolution"); + inputImagePanel.add(label); + inputImageFrame = new JFrame("Input"); + inputImageFrame.add(inputImagePanel); + + inputImageFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + inputImageFrame.setBounds(100, 200, 100, 100); + inputImageFrame.setVisible(true); + + passButton = new JButton("Pass"); + passButton.setActionCommand("Pass"); + passButton.addActionListener((ActionEvent e) -> { + outputImageFrame.dispose(); + inputImageFrame.dispose(); + testResult = true; + mainFrame.dispose(); + latch.countDown(); + + }); + failButton = new JButton("Fail"); + failButton.setActionCommand("Fail"); + failButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + outputImageFrame.dispose(); + inputImageFrame.dispose(); + testResult = false; + mainFrame.dispose(); + latch.countDown(); + } + }); + gbc.gridx = 0; + gbc.gridy = 0; + resultButtonPanel.add(passButton, gbc); + gbc.gridx = 1; + gbc.gridy = 0; + resultButtonPanel.add(failButton, gbc); + + gbc.gridx = 0; + gbc.gridy = 2; + mainControlPanel.add(resultButtonPanel, gbc); + + mainFrame.add(mainControlPanel); + mainFrame.pack(); + mainFrame.setVisible(true); + } + + public void disposeUI() { + outputImageFrame.dispose(); + inputImageFrame.dispose(); + mainFrame.setVisible(false); + mainFrame.dispose(); + } + +}