Skip to content

Commit

Permalink
6176679: Application freezes when copying an animated gif image to th…
Browse files Browse the repository at this point in the history
…e system clipboard

Reviewed-by: aivanov, dmarkov
  • Loading branch information
rajamah authored and aivanov-jdk committed May 5, 2023
1 parent 65a5488 commit 6c71859
Show file tree
Hide file tree
Showing 2 changed files with 175 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1995, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1995, 2023, 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
Expand Down Expand Up @@ -27,24 +27,20 @@

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Transparency;
import java.awt.AWTException;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferInt;
import java.awt.image.DirectColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.ImageConsumer;
import java.awt.image.ImageObserver;
import sun.awt.image.ByteComponentRaster;
import sun.awt.image.IntegerComponentRaster;
import java.awt.image.IndexColorModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferInt;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import sun.awt.image.ImageWatched;
import java.util.Hashtable;

public class ImageRepresentation extends ImageWatched implements ImageConsumer
Expand Down Expand Up @@ -114,8 +110,8 @@ public synchronized void reconstruct(int flags) {
try {
startProduction();
missinginfo = flags & ~availinfo;
while ((availinfo & ImageObserver.ERROR) == 0 &&
missinginfo != 0)
while ((availinfo & (ImageObserver.ERROR | ImageObserver.FRAMEBITS)) == 0
&& missinginfo != 0)
{
try {
wait();
Expand Down
166 changes: 166 additions & 0 deletions test/jdk/java/awt/Clipboard/CopyAnimatedGIFTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/*
* Copyright (c) 2023, 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.Canvas;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.util.concurrent.CountDownLatch;

import static java.util.concurrent.TimeUnit.MILLISECONDS;

/*
* @test
* @key headful
* @bug 6176679
* @summary Tests that an application doesn't freeze when copying an animated
* gif image to the system clipboard. We run the test two times. First with
* image displayed on screen and second with it not displayed.
* @run main CopyAnimatedGIFTest
*/
public class CopyAnimatedGIFTest {
private static final long TIMEOUT = 10000;

private final CountDownLatch latch = new CountDownLatch(1);
private final Image img = Toolkit.getDefaultToolkit().createImage(imageData);

private static final byte[] imageData = {
(byte) 0x47, (byte) 0x49, (byte) 0x46, (byte) 0x38, (byte) 0x39,
(byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x04, (byte) 0x00,
(byte) 0xa1, (byte) 0x03, (byte) 0x00, (byte) 0xff, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0x00, (byte) 0xff,
(byte) 0xff, (byte) 0x00, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0x21, (byte) 0xff, (byte) 0x0b, (byte) 0x4e, (byte) 0x45,
(byte) 0x54, (byte) 0x53, (byte) 0x43, (byte) 0x41, (byte) 0x50,
(byte) 0x45, (byte) 0x32, (byte) 0x2e, (byte) 0x30, (byte) 0x03,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x21,
(byte) 0xf9, (byte) 0x04, (byte) 0x00, (byte) 0x0a, (byte) 0x00,
(byte) 0xff, (byte) 0x00, (byte) 0x2c, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x04, (byte) 0x00, (byte) 0x04,
(byte) 0x00, (byte) 0x00, (byte) 0x02, (byte) 0x04, (byte) 0x84,
(byte) 0x8f, (byte) 0x09, (byte) 0x05, (byte) 0x00, (byte) 0x21,
(byte) 0xf9, (byte) 0x04, (byte) 0x01, (byte) 0x0a, (byte) 0x00,
(byte) 0x03, (byte) 0x00, (byte) 0x2c, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x04, (byte) 0x00, (byte) 0x04,
(byte) 0x00, (byte) 0x00, (byte) 0x02, (byte) 0x04, (byte) 0x94,
(byte) 0x8f, (byte) 0x29, (byte) 0x05, (byte) 0x00, (byte) 0x21,
(byte) 0xf9, (byte) 0x04, (byte) 0x01, (byte) 0x0a, (byte) 0x00,
(byte) 0x03, (byte) 0x00, (byte) 0x2c, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x04, (byte) 0x00, (byte) 0x04,
(byte) 0x00, (byte) 0x00, (byte) 0x02, (byte) 0x04, (byte) 0x8c,
(byte) 0x8f, (byte) 0x19, (byte) 0x05, (byte) 0x00, (byte) 0x3b
};

private void createGUI() {
ImageCanvas canvas = new ImageCanvas(img);
canvas.setBackground(Color.BLUE);

Frame frame = new Frame("CopyAnimatedGIFTest");
frame.setSize(400, 200);
frame.add(canvas);
frame.setVisible(true);
}

private void copyImage() {
Clipboard sys = Toolkit.getDefaultToolkit().getSystemClipboard();
sys.setContents(new MyTransferable(img), null);
}

private void runTest(boolean isImageDisplayed) throws Exception {

if (isImageDisplayed) {
Robot robot = new Robot();
EventQueue.invokeAndWait(this::createGUI);
robot.waitForIdle();
robot.delay(1000);
}

EventQueue.invokeLater(() -> {
copyImage();
latch.countDown();
});

if (!latch.await(TIMEOUT, MILLISECONDS)) {
String str = isImageDisplayed ? " displayed":" not displayed";
throw new RuntimeException("Image copying taking too long for image"
+ str + " case");
}
}

public static void main(String[] args) throws Exception {
// run test with Image showing up on screen
new CopyAnimatedGIFTest().runTest(true);

// run test without Image showing up
new CopyAnimatedGIFTest().runTest(false);
}

private static class ImageCanvas extends Canvas {
private final Image img;
public ImageCanvas(Image img) {
this.img = img;
}

@Override
public void paint(Graphics g) {
g.drawImage(img, 0, 0, getWidth(), getHeight(), this);
}
}

private static class MyTransferable implements Transferable {
private final Image img;
private final DataFlavor[] flavors = {DataFlavor.imageFlavor};

public MyTransferable(Image img) {
this.img = img;
}

@Override
public DataFlavor[] getTransferDataFlavors() {
return flavors;
}

@Override
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavors[0].equals(flavor);
}

@Override
public Object getTransferData(DataFlavor flavor)
throws UnsupportedFlavorException {
if (!isDataFlavorSupported(flavor)) {
throw new UnsupportedFlavorException(flavor);
}
return img;
}
}

}

3 comments on commit 6c71859

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@GoeLin
Copy link
Member

@GoeLin GoeLin commented on 6c71859 Jul 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/backport jdk17u-dev

@openjdk
Copy link

@openjdk openjdk bot commented on 6c71859 Jul 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@GoeLin the backport was successfully created on the branch GoeLin-backport-6c71859a in my personal fork of openjdk/jdk17u-dev. To create a pull request with this backport targeting openjdk/jdk17u-dev:master, just click the following link:

➡️ Create pull request

The title of the pull request is automatically filled in correctly and below you find a suggestion for the pull request body:

Hi all,

This pull request contains a backport of commit 6c71859a from the openjdk/jdk repository.

The commit being backported was authored by Rajat Mahajan on 5 May 2023 and was reviewed by Alexey Ivanov and Dmitry Markov.

Thanks!

If you need to update the source branch of the pull then run the following commands in a local clone of your personal fork of openjdk/jdk17u-dev:

$ git fetch https://github.com/openjdk-bots/jdk17u-dev.git GoeLin-backport-6c71859a:GoeLin-backport-6c71859a
$ git checkout GoeLin-backport-6c71859a
# make changes
$ git add paths/to/changed/files
$ git commit --message 'Describe additional changes made'
$ git push https://github.com/openjdk-bots/jdk17u-dev.git GoeLin-backport-6c71859a

Please sign in to comment.