Skip to content

Commit 3b4df97

Browse files
committed
6176679: Application freezes when copying an animated gif image to the system clipboard
Backport-of: 6c71859ac240c788364169422e726f8f5443bf75
1 parent 2bc77e3 commit 3b4df97

File tree

2 files changed

+175
-13
lines changed

2 files changed

+175
-13
lines changed

src/java.desktop/share/classes/sun/awt/image/ImageRepresentation.java

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1995, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1995, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -27,24 +27,20 @@
2727

2828
import java.awt.Color;
2929
import java.awt.Graphics;
30-
import java.awt.Transparency;
31-
import java.awt.AWTException;
30+
import java.awt.Graphics2D;
3231
import java.awt.Rectangle;
32+
import java.awt.Transparency;
33+
import java.awt.geom.AffineTransform;
3334
import java.awt.image.BufferedImage;
3435
import java.awt.image.ColorModel;
36+
import java.awt.image.DataBuffer;
37+
import java.awt.image.DataBufferInt;
3538
import java.awt.image.DirectColorModel;
36-
import java.awt.image.IndexColorModel;
3739
import java.awt.image.ImageConsumer;
3840
import java.awt.image.ImageObserver;
39-
import sun.awt.image.ByteComponentRaster;
40-
import sun.awt.image.IntegerComponentRaster;
41+
import java.awt.image.IndexColorModel;
4142
import java.awt.image.Raster;
4243
import java.awt.image.WritableRaster;
43-
import java.awt.image.DataBuffer;
44-
import java.awt.image.DataBufferInt;
45-
import java.awt.Graphics2D;
46-
import java.awt.geom.AffineTransform;
47-
import sun.awt.image.ImageWatched;
4844
import java.util.Hashtable;
4945

5046
public class ImageRepresentation extends ImageWatched implements ImageConsumer
@@ -114,8 +110,8 @@ public synchronized void reconstruct(int flags) {
114110
try {
115111
startProduction();
116112
missinginfo = flags & ~availinfo;
117-
while ((availinfo & ImageObserver.ERROR) == 0 &&
118-
missinginfo != 0)
113+
while ((availinfo & (ImageObserver.ERROR | ImageObserver.FRAMEBITS)) == 0
114+
&& missinginfo != 0)
119115
{
120116
try {
121117
wait();
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
import java.awt.Canvas;
25+
import java.awt.Color;
26+
import java.awt.EventQueue;
27+
import java.awt.Frame;
28+
import java.awt.Graphics;
29+
import java.awt.Image;
30+
import java.awt.Robot;
31+
import java.awt.Toolkit;
32+
import java.awt.datatransfer.Clipboard;
33+
import java.awt.datatransfer.DataFlavor;
34+
import java.awt.datatransfer.Transferable;
35+
import java.awt.datatransfer.UnsupportedFlavorException;
36+
import java.util.concurrent.CountDownLatch;
37+
38+
import static java.util.concurrent.TimeUnit.MILLISECONDS;
39+
40+
/*
41+
* @test
42+
* @key headful
43+
* @bug 6176679
44+
* @summary Tests that an application doesn't freeze when copying an animated
45+
* gif image to the system clipboard. We run the test two times. First with
46+
* image displayed on screen and second with it not displayed.
47+
* @run main CopyAnimatedGIFTest
48+
*/
49+
public class CopyAnimatedGIFTest {
50+
private static final long TIMEOUT = 10000;
51+
52+
private final CountDownLatch latch = new CountDownLatch(1);
53+
private final Image img = Toolkit.getDefaultToolkit().createImage(imageData);
54+
55+
private static final byte[] imageData = {
56+
(byte) 0x47, (byte) 0x49, (byte) 0x46, (byte) 0x38, (byte) 0x39,
57+
(byte) 0x61, (byte) 0x04, (byte) 0x00, (byte) 0x04, (byte) 0x00,
58+
(byte) 0xa1, (byte) 0x03, (byte) 0x00, (byte) 0xff, (byte) 0x00,
59+
(byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0x00, (byte) 0xff,
60+
(byte) 0xff, (byte) 0x00, (byte) 0xff, (byte) 0xff, (byte) 0xff,
61+
(byte) 0x21, (byte) 0xff, (byte) 0x0b, (byte) 0x4e, (byte) 0x45,
62+
(byte) 0x54, (byte) 0x53, (byte) 0x43, (byte) 0x41, (byte) 0x50,
63+
(byte) 0x45, (byte) 0x32, (byte) 0x2e, (byte) 0x30, (byte) 0x03,
64+
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x21,
65+
(byte) 0xf9, (byte) 0x04, (byte) 0x00, (byte) 0x0a, (byte) 0x00,
66+
(byte) 0xff, (byte) 0x00, (byte) 0x2c, (byte) 0x00, (byte) 0x00,
67+
(byte) 0x00, (byte) 0x00, (byte) 0x04, (byte) 0x00, (byte) 0x04,
68+
(byte) 0x00, (byte) 0x00, (byte) 0x02, (byte) 0x04, (byte) 0x84,
69+
(byte) 0x8f, (byte) 0x09, (byte) 0x05, (byte) 0x00, (byte) 0x21,
70+
(byte) 0xf9, (byte) 0x04, (byte) 0x01, (byte) 0x0a, (byte) 0x00,
71+
(byte) 0x03, (byte) 0x00, (byte) 0x2c, (byte) 0x00, (byte) 0x00,
72+
(byte) 0x00, (byte) 0x00, (byte) 0x04, (byte) 0x00, (byte) 0x04,
73+
(byte) 0x00, (byte) 0x00, (byte) 0x02, (byte) 0x04, (byte) 0x94,
74+
(byte) 0x8f, (byte) 0x29, (byte) 0x05, (byte) 0x00, (byte) 0x21,
75+
(byte) 0xf9, (byte) 0x04, (byte) 0x01, (byte) 0x0a, (byte) 0x00,
76+
(byte) 0x03, (byte) 0x00, (byte) 0x2c, (byte) 0x00, (byte) 0x00,
77+
(byte) 0x00, (byte) 0x00, (byte) 0x04, (byte) 0x00, (byte) 0x04,
78+
(byte) 0x00, (byte) 0x00, (byte) 0x02, (byte) 0x04, (byte) 0x8c,
79+
(byte) 0x8f, (byte) 0x19, (byte) 0x05, (byte) 0x00, (byte) 0x3b
80+
};
81+
82+
private void createGUI() {
83+
ImageCanvas canvas = new ImageCanvas(img);
84+
canvas.setBackground(Color.BLUE);
85+
86+
Frame frame = new Frame("CopyAnimatedGIFTest");
87+
frame.setSize(400, 200);
88+
frame.add(canvas);
89+
frame.setVisible(true);
90+
}
91+
92+
private void copyImage() {
93+
Clipboard sys = Toolkit.getDefaultToolkit().getSystemClipboard();
94+
sys.setContents(new MyTransferable(img), null);
95+
}
96+
97+
private void runTest(boolean isImageDisplayed) throws Exception {
98+
99+
if (isImageDisplayed) {
100+
Robot robot = new Robot();
101+
EventQueue.invokeAndWait(this::createGUI);
102+
robot.waitForIdle();
103+
robot.delay(1000);
104+
}
105+
106+
EventQueue.invokeLater(() -> {
107+
copyImage();
108+
latch.countDown();
109+
});
110+
111+
if (!latch.await(TIMEOUT, MILLISECONDS)) {
112+
String str = isImageDisplayed ? " displayed":" not displayed";
113+
throw new RuntimeException("Image copying taking too long for image"
114+
+ str + " case");
115+
}
116+
}
117+
118+
public static void main(String[] args) throws Exception {
119+
// run test with Image showing up on screen
120+
new CopyAnimatedGIFTest().runTest(true);
121+
122+
// run test without Image showing up
123+
new CopyAnimatedGIFTest().runTest(false);
124+
}
125+
126+
private static class ImageCanvas extends Canvas {
127+
private final Image img;
128+
public ImageCanvas(Image img) {
129+
this.img = img;
130+
}
131+
132+
@Override
133+
public void paint(Graphics g) {
134+
g.drawImage(img, 0, 0, getWidth(), getHeight(), this);
135+
}
136+
}
137+
138+
private static class MyTransferable implements Transferable {
139+
private final Image img;
140+
private final DataFlavor[] flavors = {DataFlavor.imageFlavor};
141+
142+
public MyTransferable(Image img) {
143+
this.img = img;
144+
}
145+
146+
@Override
147+
public DataFlavor[] getTransferDataFlavors() {
148+
return flavors;
149+
}
150+
151+
@Override
152+
public boolean isDataFlavorSupported(DataFlavor flavor) {
153+
return flavors[0].equals(flavor);
154+
}
155+
156+
@Override
157+
public Object getTransferData(DataFlavor flavor)
158+
throws UnsupportedFlavorException {
159+
if (!isDataFlavorSupported(flavor)) {
160+
throw new UnsupportedFlavorException(flavor);
161+
}
162+
return img;
163+
}
164+
}
165+
166+
}

0 commit comments

Comments
 (0)