RFR: 6176679: Application freezes when copying an animated gif image to the system clipboard

Alexey Ivanov aivanov at openjdk.org
Wed Apr 12 20:16:46 UTC 2023


On Mon, 10 Apr 2023 21:32:30 GMT, Rajat Mahajan <rmahajan at openjdk.org> wrote:

> **Problem:**
> 
> On pressing the Copy button we keep waiting in AWT-EventQueue thread in reconstruct() function as we detect that we have missing information for the animated image since we are copying single frame at a time.
> Due to this infinite wait the application freezes.
> 
> **Proposed Fix:**
> 
> There are conditions in the reconstruct() function that avoid entering the wait() code if we have some error reading the image , etc. So, I added the condition to avoid entering the wait() code if we are copying single frame at a time. This sounded logical to me since if we have incomplete information(single frame) about the animated image we shouldn’t keep waiting, as it leads to infinite wait. 
> After this change I see the GIF image being correctly copied and animated.
> 
> 
> **Testing:**
> 
> Added a test for this (bug6176679.java) and tested locally on my Windows machine and on mach5.

Changes requested by aivanov (Reviewer).

src/java.desktop/share/classes/sun/awt/image/ImageRepresentation.java line 1:

> 1: /*

Please update the copyright year to 2023.

src/java.desktop/share/classes/sun/awt/image/ImageRepresentation.java line 112:

> 110:         }
> 111:         int missinginfo = flags & ~availinfo;
> 112:         if ((availinfo & (ImageObserver.ERROR |  ImageObserver.FRAMEBITS) ) == 0 && missinginfo != 0) {

Suggestion:

        if ((availinfo & (ImageObserver.ERROR | ImageObserver.FRAMEBITS)) == 0
            && missinginfo != 0) {

The space between the closing parentheses is redundant as well as the extra space after `|` operator. The line could be wrapped to fit into 80-column limit.

test/jdk/javax/imageio/plugins/gif/6176679/bug6176679.java line 1:

> 1: /*

I think the test should not be in this directory: it does not test the GIF Image IO plugin. A better location is under `java/awt/Clipboard`.

test/jdk/javax/imageio/plugins/gif/6176679/bug6176679.java line 28:

> 26:  * @key headful
> 27:  * @bug 6176679
> 28:  * @summary Tests that an application doesn't freeze when copying an animated gif image to the system clipboard

Please wrap the line to fit into 80-column limit.

test/jdk/javax/imageio/plugins/gif/6176679/bug6176679.java line 33:

> 31: 
> 32: import java.awt.*;
> 33: import java.awt.datatransfer.*;

Please expand the wildcard imports.

test/jdk/javax/imageio/plugins/gif/6176679/bug6176679.java line 40:

> 38: 
> 39: 
> 40: public class bug6176679 implements ClipboardOwner, FlavorListener {

Are `ClipboardOwner` and `FlavorListener` really used? If not, they can be dropped.

The class name should have a descriptive name, like `CopyAnimatedGIFTest`.

test/jdk/javax/imageio/plugins/gif/6176679/bug6176679.java line 47:

> 45:     private static final CountDownLatch latch = new CountDownLatch(1);
> 46: 
> 47:     volatile static Image img = null;

Please use blessed modifier order: `static volatile`.

I think `img` should not be declared volatile, it's used only on EDT. It may even be non-static because it's accessed only from methods of the test class and you create an instance of it.

test/jdk/javax/imageio/plugins/gif/6176679/bug6176679.java line 62:

> 60:         panel.add(canvas);
> 61:         frame.add(panel);
> 62:         img = frame.getToolkit().getImage(System.getProperty("test.src", ".") + File.separator + FILENAME);

Could you wrap this long line, please?

The 80-column limit isn't strictly followed, yet it's better to fit into 100-column limit because the code becomes harder to read.

test/jdk/javax/imageio/plugins/gif/6176679/bug6176679.java line 101:

> 99:             } catch (Exception e) {
> 100:                 throw new RuntimeException(e);
> 101:             }

No checked exception is thrown within this try-block, thus it can be removed.

test/jdk/javax/imageio/plugins/gif/6176679/bug6176679.java line 111:

> 109:         {
> 110:             EventQueue.invokeAndWait(bug6176679::dispose);
> 111:         }

Suggestion:

        } else {
            EventQueue.invokeAndWait(bug6176679::dispose);
        }


Let's follow Java Coding Style conventions.

I think it also deserves a comment why the frame is disposed of only when the test doesn't fail. Perhaps, we can drop disposing altogether and let jtreg do the cleanup.

test/jdk/javax/imageio/plugins/gif/6176679/bug6176679.java line 131:

> 129:     }
> 130: 
> 131:     static class imgCanvas extends Canvas {

Suggestion:

    static class ImgCanvas extends Canvas {

Class names should start with a capital letter. Is `ImageCanvas` a better name?

I'd pass the image to the constructor of `ImgCanvas` and mark the `img` field `final` (and `private`). Then the `if` in paint can also be removed.

If the image isn't loaded, that is `img.getWidth()` and `img.getHeight()` return `-1`, the test should bail out before even creating the canvas.

test/jdk/javax/imageio/plugins/gif/6176679/bug6176679.java line 164:

> 162:                 df[0] = DataFlavor.imageFlavor;
> 163:             }
> 164:         }

You create the instance of `MyTransferable` with the image only, so you can declare the constructor to accept `Image` instead of `Object`.

Would `ImageTransferable` describe the purpose better?

As with the Canvas class above, I'd mark both `img` and `df` as `final` (and `private`).

test/jdk/javax/imageio/plugins/gif/6176679/bug6176679.java line 173:

> 171:         public boolean isDataFlavorSupported(DataFlavor flavor) {
> 172:             return true;
> 173:         }

The `@Override` annotation is missing. Add it to `getTransferData` too.

It's not important in this case, yet the method should rather return `df[0].equals(flavor)`.

test/jdk/javax/imageio/plugins/gif/6176679/bug6176679.java line 184:

> 182: 
> 183: 
> 184: }

Please add a final blank line.

-------------

PR Review: https://git.openjdk.org/jdk/pull/13414#pullrequestreview-1381935281
PR Review Comment: https://git.openjdk.org/jdk/pull/13414#discussion_r1164601058
PR Review Comment: https://git.openjdk.org/jdk/pull/13414#discussion_r1164600192
PR Review Comment: https://git.openjdk.org/jdk/pull/13414#discussion_r1164573562
PR Review Comment: https://git.openjdk.org/jdk/pull/13414#discussion_r1164548806
PR Review Comment: https://git.openjdk.org/jdk/pull/13414#discussion_r1164533378
PR Review Comment: https://git.openjdk.org/jdk/pull/13414#discussion_r1164548321
PR Review Comment: https://git.openjdk.org/jdk/pull/13414#discussion_r1164553188
PR Review Comment: https://git.openjdk.org/jdk/pull/13414#discussion_r1164589759
PR Review Comment: https://git.openjdk.org/jdk/pull/13414#discussion_r1164554274
PR Review Comment: https://git.openjdk.org/jdk/pull/13414#discussion_r1164559765
PR Review Comment: https://git.openjdk.org/jdk/pull/13414#discussion_r1164566145
PR Review Comment: https://git.openjdk.org/jdk/pull/13414#discussion_r1164567413
PR Review Comment: https://git.openjdk.org/jdk/pull/13414#discussion_r1164570631
PR Review Comment: https://git.openjdk.org/jdk/pull/13414#discussion_r1164571335



More information about the client-libs-dev mailing list