From 1d135a878079d304c87f0c4d0cdae686ffdbc190 Mon Sep 17 00:00:00 2001 From: Alexander Scherbatiy Date: Fri, 11 Mar 2016 21:57:43 +0400 Subject: [PATCH] 8069348: SunGraphics2D.copyArea() does not properly work for scaled graphics in D3D Reviewed-by: flar, serb --- .../sun/java2d/OSXOffScreenSurfaceData.java | 33 ++-- .../classes/sun/java2d/OSXSurfaceData.java | 10 +- .../sun/java2d/opengl/CGLSurfaceData.java | 25 --- .../classes/sun/java2d/SunGraphics2D.java | 54 +++--- .../share/classes/sun/java2d/SurfaceData.java | 5 + .../sun/java2d/opengl/OGLSurfaceData.java | 20 +-- .../sun/java2d/x11/X11SurfaceData.java | 5 +- .../classes/sun/java2d/xr/XRSurfaceData.java | 7 +- .../sun/java2d/d3d/D3DSurfaceData.java | 19 +- .../java2d/windows/GDIWindowSurfaceData.java | 5 +- .../CopyScaledArea/CopyScaledAreaTest.java | 164 ++++++++++++++++++ .../JInternalFrame/8069348/bug8069348.java | 144 +++++++++++++++ 12 files changed, 379 insertions(+), 112 deletions(-) create mode 100644 jdk/test/java/awt/Graphics/CopyScaledArea/CopyScaledAreaTest.java create mode 100644 jdk/test/javax/swing/JInternalFrame/8069348/bug8069348.java diff --git a/jdk/src/java.desktop/macosx/classes/sun/java2d/OSXOffScreenSurfaceData.java b/jdk/src/java.desktop/macosx/classes/sun/java2d/OSXOffScreenSurfaceData.java index 9f4f5b2f219..c4a09d86cef 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/java2d/OSXOffScreenSurfaceData.java +++ b/jdk/src/java.desktop/macosx/classes/sun/java2d/OSXOffScreenSurfaceData.java @@ -478,13 +478,9 @@ public class OSXOffScreenSurfaceData extends OSXSurfaceData // implements Raster // For the Sun2D renderer we should rely on the implementation of the super class. // BufImageSurfaceData.java doesn't have an implementation of copyArea() and relies on the super class. - int offsetX = 0; - int offsetY = 0; - if (sg2d.transformState == SunGraphics2D.TRANSFORM_ANY_TRANSLATE || - sg2d.transformState == SunGraphics2D.TRANSFORM_INT_TRANSLATE) { - offsetX = (int) sg2d.transform.getTranslateX(); - offsetY = (int) sg2d.transform.getTranslateY(); - } else if (sg2d.transformState != SunGraphics2D.TRANSFORM_ISIDENT) { return false; } + if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) { + return false; + } // reset the clip (this is how it works on windows) // we actually can handle a case with any clips but windows ignores the light clip @@ -498,18 +494,23 @@ public class OSXOffScreenSurfaceData extends OSXSurfaceData // implements Raster return true; } - // the rectangle returned from clipCopyArea() is in the coordinate space of the surface (image) - // we need to substract the offsetX and offsetY to move it to the coordinate space of the graphics2d. - // sg2d.drawImage expects the destination rect to be in the coord space of the graphics2d. - // (vm) - x = clippedCopyAreaRect.x - offsetX; - y = clippedCopyAreaRect.y - offsetY; + // the rectangle returned from clipCopyArea() is in the coordinate space + // of the surface (image) + x = clippedCopyAreaRect.x; + y = clippedCopyAreaRect.y; w = clippedCopyAreaRect.width; h = clippedCopyAreaRect.height; - // copy (dst coordinates are in the coord space of the graphics2d, and src coordinates are - // in the coordinate space of the image) - sg2d.drawImage(this.bim, x + dx, y + dy, x + dx + w, y + dy + h, x + offsetX, y + offsetY, x + w + offsetX, y + h + offsetY, null); + // copy (dst coordinates are in the coord space of the graphics2d, and + // src coordinates are in the coordinate space of the image) + // sg2d.drawImage expects the destination rect to be in the coord space + // of the graphics2d. (vm) + // we need to substract the transX and transY to move it + // to the coordinate space of the graphics2d. + int dstX = x + dx - sg2d.transX; + int dstY = y + dy - sg2d.transY; + sg2d.drawImage(this.bim, dstX, dstY, dstX + w, dstY + h, + x, y, x + w, y + h, null); // restore the clip sg2d.setClip(clip); diff --git a/jdk/src/java.desktop/macosx/classes/sun/java2d/OSXSurfaceData.java b/jdk/src/java.desktop/macosx/classes/sun/java2d/OSXSurfaceData.java index d1444b81a90..a0fd6486cb5 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/java2d/OSXSurfaceData.java +++ b/jdk/src/java.desktop/macosx/classes/sun/java2d/OSXSurfaceData.java @@ -1094,19 +1094,13 @@ public abstract class OSXSurfaceData extends BufImgSurfaceData { } /** - * Clips the copy area to the heavywieght bounds and returns the cliped rectangle. The tricky part here is the - * passed arguments x, y are in the coordinate space of the sg2d/lightweight comp. In order to do the clipping we - * translate them to the coordinate space of the surface, and the returned clipped rectangle is in the coordinate - * space of the surface. + * Clips the copy area to the heavyweight bounds and returns the clipped rectangle. + * The returned clipped rectangle is in the coordinate space of the surface. */ protected Rectangle clipCopyArea(SunGraphics2D sg2d, int x, int y, int w, int h, int dx, int dy) { // we need to clip against the heavyweight bounds copyAreaBounds.setBounds(sg2d.devClip.getLoX(), sg2d.devClip.getLoY(), sg2d.devClip.getWidth(), sg2d.devClip.getHeight()); - // put src rect into surface coordinate space - x += sg2d.transX; - y += sg2d.transY; - // clip src rect srcCopyAreaRect.setBounds(x, y, w, h); intersection(srcCopyAreaRect, copyAreaBounds, srcCopyAreaRect); diff --git a/jdk/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java b/jdk/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java index b59349f9cb8..2eb9048e71e 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java +++ b/jdk/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java @@ -175,31 +175,6 @@ public abstract class CGLSurfaceData extends OGLSurfaceData { return scale; } - @Override - public boolean copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, - int dx, int dy) { - final int state = sg2d.transformState; - if (state > SunGraphics2D.TRANSFORM_TRANSLATESCALE - || sg2d.compositeState >= SunGraphics2D.COMP_XOR) { - return false; - } - if (state <= SunGraphics2D.TRANSFORM_ANY_TRANSLATE) { - x += sg2d.transX; - y += sg2d.transY; - } else if (state == SunGraphics2D.TRANSFORM_TRANSLATESCALE) { - final double[] coords = {x, y, x + w, y + h, x + dx, y + dy}; - sg2d.transform.transform(coords, 0, coords, 0, 3); - x = (int) Math.ceil(coords[0] - 0.5); - y = (int) Math.ceil(coords[1] - 0.5); - w = ((int) Math.ceil(coords[2] - 0.5)) - x; - h = ((int) Math.ceil(coords[3] - 0.5)) - y; - dx = ((int) Math.ceil(coords[4] - 0.5)) - x; - dy = ((int) Math.ceil(coords[5] - 0.5)) - y; - } - oglRenderPipe.copyArea(sg2d, x, y, w, h, dx, dy); - return true; - } - protected native void clearWindow(); public static class CGLWindowSurfaceData extends CGLSurfaceData { diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java b/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java index 967077d6585..8207213e3e5 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java @@ -2101,13 +2101,39 @@ public final class SunGraphics2D if (w <= 0 || h <= 0) { return; } + + if (transformState == SunGraphics2D.TRANSFORM_ISIDENT) { + // do nothing + } else if (transformState <= SunGraphics2D.TRANSFORM_ANY_TRANSLATE) { + x += transX; + y += transY; + } else if (transformState == SunGraphics2D.TRANSFORM_TRANSLATESCALE) { + final double[] coords = {x, y, x + w, y + h, x + dx, y + dy}; + transform.transform(coords, 0, coords, 0, 3); + x = (int) Math.ceil(coords[0] - 0.5); + y = (int) Math.ceil(coords[1] - 0.5); + w = ((int) Math.ceil(coords[2] - 0.5)) - x; + h = ((int) Math.ceil(coords[3] - 0.5)) - y; + dx = ((int) Math.ceil(coords[4] - 0.5)) - x; + dy = ((int) Math.ceil(coords[5] - 0.5)) - y; + // In case of negative scale transform, reflect the rect coords. + if (w < 0) { + w = -w; + x -= w; + } + if (h < 0) { + h = -h; + y -= h; + } + } else { + throw new InternalError("transformed copyArea not implemented yet"); + } + SurfaceData theData = surfaceData; if (theData.copyArea(this, x, y, w, h, dx, dy)) { return; } - if (transformState > TRANSFORM_TRANSLATESCALE) { - throw new InternalError("transformed copyArea not implemented yet"); - } + // REMIND: This method does not deal with missing data from the // source object (i.e. it does not send exposure events...) @@ -2126,26 +2152,6 @@ public final class SunGraphics2D lastCAcomp = comp; } - double[] coords = {x, y, x + w, y + h, x + dx, y + dy}; - transform.transform(coords, 0, coords, 0, 3); - - x = (int)Math.ceil(coords[0] - 0.5); - y = (int)Math.ceil(coords[1] - 0.5); - w = ((int)Math.ceil(coords[2] - 0.5)) - x; - h = ((int)Math.ceil(coords[3] - 0.5)) - y; - dx = ((int)Math.ceil(coords[4] - 0.5)) - x; - dy = ((int)Math.ceil(coords[5] - 0.5)) - y; - - // In case of negative scale transform, reflect the rect coords. - if (w < 0) { - w *= -1; - x -= w; - } - if (h < 0) { - h *= -1; - y -= h; - } - Blit ob = lastCAblit; if (dy == 0 && dx > 0 && dx < w) { while (w > 0) { @@ -2167,7 +2173,7 @@ public final class SunGraphics2D } return; } - ob.Blit(theData, theData, comp, clip, x, y, x+dx, y+dy, w, h); + ob.Blit(theData, theData, comp, clip, x, y, x+dx, y+dy, w, h); } /* diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/SurfaceData.java b/jdk/src/java.desktop/share/classes/sun/java2d/SurfaceData.java index 4de1a1fc576..806bf05bced 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/SurfaceData.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/SurfaceData.java @@ -1039,6 +1039,11 @@ public abstract class SurfaceData * Performs a copyarea within this surface. Returns * false if there is no algorithm to perform the copyarea * given the current settings of the SunGraphics2D. + * + * @param x the x coordinate of the area in device space + * @param y the y coordinate of the area in device space + * @param w the width of the area in device space + * @param h the height of the area in device space */ public boolean copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, int dx, int dy) diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceData.java b/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceData.java index 914b97aba05..5e6f802da14 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceData.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceData.java @@ -542,20 +542,14 @@ public abstract class OGLSurfaceData extends SurfaceData return super.getMaskFill(sg2d); } - public boolean copyArea(SunGraphics2D sg2d, - int x, int y, int w, int h, int dx, int dy) - { - if (sg2d.transformState < SunGraphics2D.TRANSFORM_TRANSLATESCALE && - sg2d.compositeState < SunGraphics2D.COMP_XOR) - { - x += sg2d.transX; - y += sg2d.transY; - - oglRenderPipe.copyArea(sg2d, x, y, w, h, dx, dy); - - return true; + @Override + public boolean copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, + int dx, int dy) { + if (sg2d.compositeState >= SunGraphics2D.COMP_XOR) { + return false; } - return false; + oglRenderPipe.copyArea(sg2d, x, y, w, h, dx, dy); + return true; } public void flush() { diff --git a/jdk/src/java.desktop/unix/classes/sun/java2d/x11/X11SurfaceData.java b/jdk/src/java.desktop/unix/classes/sun/java2d/x11/X11SurfaceData.java index 1d83b65a876..3ce34effd39 100644 --- a/jdk/src/java.desktop/unix/classes/sun/java2d/x11/X11SurfaceData.java +++ b/jdk/src/java.desktop/unix/classes/sun/java2d/x11/X11SurfaceData.java @@ -487,12 +487,9 @@ public abstract class X11SurfaceData extends XSurfaceData { makePipes(); } CompositeType comptype = sg2d.imageComp; - if (sg2d.transformState < SunGraphics2D.TRANSFORM_TRANSLATESCALE && - (CompositeType.SrcOverNoEa.equals(comptype) || + if ((CompositeType.SrcOverNoEa.equals(comptype) || CompositeType.SrcNoEa.equals(comptype))) { - x += sg2d.transX; - y += sg2d.transY; SunToolkit.awtLock(); try { boolean needExposures = canSourceSendExposures(x, y, w, h); diff --git a/jdk/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceData.java b/jdk/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceData.java index aabdda0db1e..b88c5507984 100644 --- a/jdk/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceData.java +++ b/jdk/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceData.java @@ -365,12 +365,9 @@ public abstract class XRSurfaceData extends XSurfaceData { makePipes(); } CompositeType comptype = sg2d.imageComp; - if (sg2d.transformState < SunGraphics2D.TRANSFORM_TRANSLATESCALE && - (CompositeType.SrcOverNoEa.equals(comptype) || - CompositeType.SrcNoEa.equals(comptype))) + if (CompositeType.SrcOverNoEa.equals(comptype) || + CompositeType.SrcNoEa.equals(comptype)) { - x += sg2d.transX; - y += sg2d.transY; try { SunToolkit.awtLock(); boolean needExposures = canSourceSendExposures(x, y, w, h); diff --git a/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java b/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java index c6b25970951..e2b08016e56 100644 --- a/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java +++ b/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java @@ -703,20 +703,13 @@ public class D3DSurfaceData extends SurfaceData implements AccelSurface { } @Override - public boolean copyArea(SunGraphics2D sg2d, - int x, int y, int w, int h, int dx, int dy) - { - if (sg2d.transformState < SunGraphics2D.TRANSFORM_TRANSLATESCALE && - sg2d.compositeState < SunGraphics2D.COMP_XOR) - { - x += sg2d.transX; - y += sg2d.transY; - - d3dRenderPipe.copyArea(sg2d, x, y, w, h, dx, dy); - - return true; + public boolean copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, + int dx, int dy) { + if (sg2d.compositeState >= SunGraphics2D.COMP_XOR) { + return false; } - return false; + d3dRenderPipe.copyArea(sg2d, x, y, w, h, dx, dy); + return true; } @Override diff --git a/jdk/src/java.desktop/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java b/jdk/src/java.desktop/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java index 2ba2b11aa59..ad211ab473c 100644 --- a/jdk/src/java.desktop/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java +++ b/jdk/src/java.desktop/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java @@ -311,13 +311,10 @@ public class GDIWindowSurfaceData extends SurfaceData { int x, int y, int w, int h, int dx, int dy) { CompositeType comptype = sg2d.imageComp; - if (sg2d.transformState < SunGraphics2D.TRANSFORM_TRANSLATESCALE && - sg2d.clipState != SunGraphics2D.CLIP_SHAPE && + if (sg2d.clipState != SunGraphics2D.CLIP_SHAPE && (CompositeType.SrcOverNoEa.equals(comptype) || CompositeType.SrcNoEa.equals(comptype))) { - x += sg2d.transX; - y += sg2d.transY; int dstx1 = x + dx; int dsty1 = y + dy; int dstx2 = dstx1 + w; diff --git a/jdk/test/java/awt/Graphics/CopyScaledArea/CopyScaledAreaTest.java b/jdk/test/java/awt/Graphics/CopyScaledArea/CopyScaledAreaTest.java new file mode 100644 index 00000000000..92d8540787c --- /dev/null +++ b/jdk/test/java/awt/Graphics/CopyScaledArea/CopyScaledAreaTest.java @@ -0,0 +1,164 @@ +/* + * 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.*; +import java.awt.image.BufferedImage; +import java.awt.image.VolatileImage; +import static sun.awt.OSInfo.*; + +/** + * @test + * @bug 8069348 + * @summary SunGraphics2D.copyArea() does not properly work for scaled graphics + * @modules java.desktop/sun.awt + * @run main/othervm -Dsun.java2d.uiScale=2 CopyScaledAreaTest + * @run main/othervm -Dsun.java2d.opengl=true -Dsun.java2d.uiScale=2 CopyScaledAreaTest + * @run main/othervm -Dsun.java2d.d3d=true -Dsun.java2d.uiScale=2 CopyScaledAreaTest + * @run main/othervm -Dsun.java2d.d3d=false -Dsun.java2d.opengl=false + * -Dsun.java2d.uiScale=2 CopyScaledAreaTest + */ +public class CopyScaledAreaTest { + + private static final int IMAGE_WIDTH = 800; + private static final int IMAGE_HEIGHT = 800; + private static final int X = 50; + private static final int Y = 50; + private static final int W = 100; + private static final int H = 75; + private static final int DX = 15; + private static final int DY = 10; + private static final int N = 3; + private static final Color BACKGROUND_COLOR = Color.YELLOW; + private static final Color FILL_COLOR = Color.ORANGE; + private static final double[][] SCALES = {{1.3, 1.4}, {0.3, 2.3}, {2.7, 0.1}}; + + private static boolean isSupported() { + String d3d = System.getProperty("sun.java2d.d3d"); + return !Boolean.getBoolean(d3d) || getOSType() == OSType.WINDOWS; + } + + private static int scale(int x, double scale) { + return (int) Math.floor(x * scale); + } + + private static VolatileImage createVolatileImage(GraphicsConfiguration conf) { + return conf.createCompatibleVolatileImage(IMAGE_WIDTH, IMAGE_HEIGHT); + } + + // rendering to the image + private static void renderOffscreen(VolatileImage vImg, + GraphicsConfiguration conf, + double scaleX, + double scaleY) + { + int attempts = 0; + do { + + if (attempts > 10) { + throw new RuntimeException("Too many attempts!"); + } + + if (vImg.validate(conf) == VolatileImage.IMAGE_INCOMPATIBLE) { + // old vImg doesn't work with new GraphicsConfig; re-create it + vImg = createVolatileImage(conf); + } + Graphics2D g = vImg.createGraphics(); + // + // miscellaneous rendering commands... + // + g.setColor(BACKGROUND_COLOR); + g.fillRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT); + g.scale(scaleX, scaleY); + + g.setColor(FILL_COLOR); + g.fillRect(X, Y, W, H); + + for (int i = 0; i < N; i++) { + g.copyArea(X + i * DX, Y + i * DY, W, H, DX, DY); + } + g.dispose(); + attempts++; + } while (vImg.contentsLost()); + } + + public static void main(String[] args) throws Exception { + + if (!isSupported()) { + return; + } + + GraphicsConfiguration graphicsConfiguration = + GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + + for(double[] scales: SCALES){ + testScale(scales[0], scales[1], graphicsConfiguration); + } + } + + private static void testScale(double scaleX, double scaleY, + GraphicsConfiguration gc) throws Exception + { + + BufferedImage buffImage = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, + BufferedImage.TYPE_INT_RGB); + Graphics g = buffImage.createGraphics(); + + VolatileImage vImg = createVolatileImage(gc); + + int attempts = 0; + do { + + if (attempts > 10) { + throw new RuntimeException("Too many attempts!"); + } + + int returnCode = vImg.validate(gc); + if (returnCode == VolatileImage.IMAGE_RESTORED) { + // Contents need to be restored + renderOffscreen(vImg, gc, scaleX, scaleY); // restore contents + } else if (returnCode == VolatileImage.IMAGE_INCOMPATIBLE) { + // old vImg doesn't work with new GraphicsConfig; re-create it + vImg = createVolatileImage(gc); + renderOffscreen(vImg, gc, scaleX, scaleY); + } + g.drawImage(vImg, 0, 0, null); + attempts++; + } while (vImg.contentsLost()); + + g.dispose(); + + int x = scale(X + N * DX, scaleX) + 1; + int y = scale(Y + N * DY, scaleY) + 1; + int w = scale(W, scaleX) - 2; + int h = scale(H, scaleY) - 2; + + for (int i = x; i < x + w; i++) { + for (int j = y; j < y + h; j++) { + if (buffImage.getRGB(i, j) != FILL_COLOR.getRGB()) { + throw new RuntimeException("Wrong rectangle color!"); + } + } + } + } +} diff --git a/jdk/test/javax/swing/JInternalFrame/8069348/bug8069348.java b/jdk/test/javax/swing/JInternalFrame/8069348/bug8069348.java new file mode 100644 index 00000000000..d9deeefb99b --- /dev/null +++ b/jdk/test/javax/swing/JInternalFrame/8069348/bug8069348.java @@ -0,0 +1,144 @@ +/* + * 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.Color; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.event.InputEvent; +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import static sun.awt.OSInfo.*; + +/** + * @test + * @bug 8069348 + * @summary SunGraphics2D.copyArea() does not properly work for scaled graphics + * @author Alexandr Scherbatiy + * @modules java.desktop/sun.awt + * @run main/othervm -Dsun.java2d.uiScale=2 bug8069348 + * @run main/othervm -Dsun.java2d.opengl=true -Dsun.java2d.uiScale=2 bug8069348 + * @run main/othervm -Dsun.java2d.d3d=true -Dsun.java2d.uiScale=2 bug8069348 + */ +public class bug8069348 { + + private static final int WIN_WIDTH = 500; + private static final int WIN_HEIGHT = 500; + + private static final Color DESKTOPPANE_COLOR = Color.YELLOW; + private static final Color FRAME_COLOR = Color.ORANGE; + + private static JFrame frame; + private static JInternalFrame internalFrame; + + public static void main(String[] args) throws Exception { + + if (!isSupported()) { + return; + } + + try { + + SwingUtilities.invokeAndWait(bug8069348::createAndShowGUI); + + Robot robot = new Robot(); + robot.setAutoDelay(50); + robot.waitForIdle(); + + Rectangle screenBounds = getInternalFrameScreenBounds(); + + int x = screenBounds.x + screenBounds.width / 2; + int y = screenBounds.y + 10; + int dx = screenBounds.width / 2; + int dy = screenBounds.height / 2; + + robot.mouseMove(x, y); + robot.waitForIdle(); + + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mouseMove(x + dx, y + dy); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.waitForIdle(); + + int cx = screenBounds.x + screenBounds.width + dx / 2; + int cy = screenBounds.y + screenBounds.height + dy / 2; + + robot.mouseMove(cx, cy); + if (!FRAME_COLOR.equals(robot.getPixelColor(cx, cy))) { + throw new RuntimeException("Internal frame is not correctly dragged!"); + } + } finally { + if (frame != null) { + frame.dispose(); + } + } + } + + private static boolean isSupported() { + String d3d = System.getProperty("sun.java2d.d3d"); + return !Boolean.getBoolean(d3d) || getOSType() == OSType.WINDOWS; + } + + private static Rectangle getInternalFrameScreenBounds() throws Exception { + Rectangle[] points = new Rectangle[1]; + SwingUtilities.invokeAndWait(() -> { + points[0] = new Rectangle(internalFrame.getLocationOnScreen(), + internalFrame.getSize()); + }); + return points[0]; + } + + private static void createAndShowGUI() { + + frame = new JFrame(); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + JDesktopPane desktopPane = new JDesktopPane(); + desktopPane.setBackground(DESKTOPPANE_COLOR); + + internalFrame = new JInternalFrame("Test") { + + @Override + public void paint(Graphics g) { + super.paint(g); + g.setColor(FRAME_COLOR); + g.fillRect(0, 0, getWidth(), getHeight()); + } + }; + internalFrame.setSize(WIN_WIDTH / 3, WIN_HEIGHT / 3); + internalFrame.setVisible(true); + desktopPane.add(internalFrame); + + JPanel panel = new JPanel(); + panel.setLayout(new BorderLayout()); + panel.add(desktopPane, BorderLayout.CENTER); + frame.add(panel); + frame.setSize(WIN_WIDTH, WIN_HEIGHT); + frame.setVisible(true); + frame.requestFocus(); + } +}