--- old/src/java.desktop/share/classes/java/awt/Robot.java 2017-01-10 14:04:09.587653999 +0530 +++ new/src/java.desktop/share/classes/java/awt/Robot.java 2017-01-10 14:04:09.351536000 +0530 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, 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,8 @@ import java.awt.event.InputEvent; import java.awt.event.KeyEvent; +import java.awt.geom.AffineTransform; +import java.awt.image.BaseMultiResolutionImage; import java.awt.image.BufferedImage; import java.awt.image.DataBufferInt; import java.awt.image.DirectColorModel; @@ -405,11 +407,32 @@ * @see AWTPermission */ public synchronized BufferedImage createScreenCapture(Rectangle screenRect) { + return (BufferedImage) createScreenCapture(screenRect, false); + } + + /** + * Creates an image containing pixels read from the screen. + * This image does not include the mouse cursor. + * Returns BufferedImage for Non-HiDPI display and + * MultiResolutionImage for HiDPI display with two resolution variants, + * Base Image with user specified size and + * High Resolution Image with original size. + * @param screenRect Rect to capture in screen coordinates + * @param isHiDPI Indicates if HiDPI Display + * @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 Image createScreenCapture(Rectangle screenRect, boolean isHiDPI) { checkScreenCaptureAllowed(); checkValidRect(screenRect); - BufferedImage image; + BufferedImage lowResolutionImage; + BufferedImage highResolutionImage; DataBufferInt buffer; WritableRaster raster; @@ -421,31 +444,89 @@ */ screenCapCM = new DirectColorModel(24, - /* red mask */ 0x00FF0000, - /* green mask */ 0x0000FF00, - /* blue mask */ 0x000000FF); + /* red mask */ 0x00FF0000, + /* green mask */ 0x0000FF00, + /* blue mask */ 0x000000FF); } - // need to sync the toolkit prior to grabbing the pixels since in some - // cases rendering to the screen may be delayed - Toolkit.getDefaultToolkit().sync(); - - int pixels[]; int[] bandmasks = new int[3]; - - pixels = peer.getRGBPixels(screenRect); - buffer = new DataBufferInt(pixels, pixels.length); - 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[]; - raster = Raster.createPackedRaster(buffer, screenRect.width, screenRect.height, screenRect.width, bandmasks, null); - SunWritableRaster.makeTrackable(buffer); - - image = new BufferedImage(screenCapCM, raster, false, null); - - return image; + if (uiScaleX == 1 && uiScaleY == 1) { + pixels = peer.getRGBPixels(screenRect); + buffer = new DataBufferInt(pixels, pixels.length); + + 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); + + return new BufferedImage(screenCapCM, raster, false, null); + + } else { + + int x = screenRect.x; + int y = screenRect.y; + int width = screenRect.width; + int height = screenRect.height; + int pminx = (int) Math.floor(x * uiScaleX); + int pminy = (int) Math.floor(y * uiScaleY); + int pmaxx = (int) Math.ceil((x + width) * uiScaleX); + int pmaxy = (int) Math.ceil((y + height) * uiScaleY); + int pwidth = pmaxx - pminx; + int pheight = pmaxy - pminy; + int temppixels[]; + Rectangle scaledRect = new Rectangle(pminx, pminy, pwidth, pheight); + 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) { + return lowResolutionImage; + } else { + // MultiResoltuionImage + return new BaseMultiResolutionImage( + lowResolutionImage, highResolutionImage); + } + } } private static void checkValidRect(Rectangle rect) { --- old/src/java.desktop/windows/native/libawt/windows/awt_Robot.cpp 2017-01-10 14:04:10.227973999 +0530 +++ new/src/java.desktop/windows/native/libawt/windows/awt_Robot.cpp 2017-01-10 14:04:09.959840000 +0530 @@ -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-01-10 14:04:10.928324000 +0530 +++ new/src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java 2017-01-10 14:04:10.712216000 +0530 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, 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-01-10 14:04:11.528624000 +0530 +++ new/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c 2017-01-10 14:04:11.344531999 +0530 @@ -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-01-10 14:04:12.024872000 +0530 +++ new/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m 2017-01-10 14:04:11.856788000 +0530 @@ -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-01-10 14:04:12.633176000 +0530 +++ new/src/java.desktop/macosx/classes/sun/lwawt/macosx/CRobot.java 2017-01-10 14:04:12.445082000 +0530 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, 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,7 @@ @Override public int getRGBPixel(int x, int y) { int c[] = new int[1]; - getScreenPixels(new Rectangle(x, y, 1, 1), c); + getScreenPixels(new Rectangle(x, y, 1, 1), 1, c); return c[0]; } @@ -186,7 +186,8 @@ @Override public int [] getRGBPixels(final Rectangle bounds) { int c[] = new int[bounds.width * bounds.height]; - getScreenPixels(bounds, c); + double scale = fDevice.getScaleFactor(); + getScreenPixels(bounds, scale, c); return c; } @@ -197,8 +198,8 @@ boolean isButtonsDownState, 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); + private void getScreenPixels(Rectangle r, double scale, int[] pixels){ + 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); }