<AWT Dev> "Invalid Image variant" exception from AWT when using MultiResolutionImage (bug in SunGraphics2D.drawHiDPIImage?)

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

<AWT Dev> "Invalid Image variant" exception from AWT when using MultiResolutionImage (bug in SunGraphics2D.drawHiDPIImage?)

Eirik Bakke-2

Hi, AWT-dev.

 

I tried to get HiDPI icons working on my Swing application on Windows 10 today on OpenJDK 10.0.2, and ran into what seems to be an AWT bug. See the exhibit at https://github.com/eirikbakke/InvalidImageVariantBugExhibit/blob/master/src/invalidimagevariant/InvalidImageVariantBugExhibit.java

 

Loading two differently sized images via Toolkit.getImage() and putting them into a BaseMultiResolutionImage yields an "IllegalArgumentException: Invalid Image variant" exception from SurfaceManager.getManager when the MultiResolutionImage is used as an icon in a JButton and the JFrame is dragged onto my 200%-scaling HiDPI screen. See the full stack trace pasted at the end of this email.

 

The bug seems to be due to a race condition, where SunGraphics2D.drawHiDPIImage may return null even when the image is in fact a MultiResolutionImage, if the underlying image alternatives have not yet been fully loaded by the time the first paint is attempted.

 

Waiting for the image to load using MediaTracker.waitForAll() "fixes" the problem for the simplest case. This is not always an option in client code, however; there are other MultiResolutionImage instances being created behind the scenes for instance when a JButton is disabled and its icon needs to be greyed-out.

 

Note that there is a timing aspect to this bug, so not all configurations might expose it. The bug did not appear when I disconnected my external monitor and _just_ used the HiDPI laptop one (not sure if this is a timing issue or something else).

 

Also note: On MacOS, Toolkit.getImage() and friends have had the ability to automatically detect and load HiDPI images with a "@2x" suffix in their file name (JDK-8011059) . Am I correct that there is no equivalent mechanism on Windows?

 

-- Eirik

 

Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Invalid Image variant

  at java.desktop/sun.awt.image.SurfaceManager.getManager(SurfaceManager.java:82)

  at java.desktop/sun.java2d.SurfaceData.getSourceSurfaceData(SurfaceData.java:218)

  at java.desktop/sun.java2d.pipe.DrawImage.renderImageScale(DrawImage.java:635)

  at java.desktop/sun.java2d.pipe.DrawImage.tryCopyOrScale(DrawImage.java:319)

  at java.desktop/sun.java2d.pipe.DrawImage.transformImage(DrawImage.java:258)

  at java.desktop/sun.java2d.pipe.DrawImage.copyImage(DrawImage.java:76)

  at java.desktop/sun.java2d.pipe.DrawImage.copyImage(DrawImage.java:1027)

  at java.desktop/sun.java2d.SunGraphics2D.drawImage(SunGraphics2D.java:3415)

  at java.desktop/sun.java2d.SunGraphics2D.drawImage(SunGraphics2D.java:3391)

  at java.desktop/javax.swing.ImageIcon.paintIcon(ImageIcon.java:425)

  at java.desktop/javax.swing.plaf.basic.BasicButtonUI.paintIcon(BasicButtonUI.java:358)

  at java.desktop/javax.swing.plaf.basic.BasicButtonUI.paint(BasicButtonUI.java:275)

  at java.desktop/com.sun.java.swing.plaf.windows.WindowsButtonUI.paint(WindowsButtonUI.java:167)

  at java.desktop/javax.swing.plaf.ComponentUI.update(ComponentUI.java:161)

  at java.desktop/javax.swing.JComponent.paintComponent(JComponent.java:797)

  at java.desktop/javax.swing.JComponent.paint(JComponent.java:1074)

  at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:907)

  at java.desktop/javax.swing.JComponent.paint(JComponent.java:1083)

  at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:907)

  at java.desktop/javax.swing.JComponent.paint(JComponent.java:1083)

  at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:907)

  at java.desktop/javax.swing.JComponent.paint(JComponent.java:1083)

  at java.desktop/javax.swing.JLayeredPane.paint(JLayeredPane.java:590)

  at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:907)

  at java.desktop/javax.swing.JComponent.paintToOffscreen(JComponent.java:5262)

  at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBufferedImpl(RepaintManager.java:1633)

  at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1608)

  at java.desktop/javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1546)

  at java.desktop/javax.swing.RepaintManager.paint(RepaintManager.java:1313)

  at java.desktop/javax.swing.JComponent.paint(JComponent.java:1060)

  at java.desktop/java.awt.GraphicsCallback$PaintCallback.run(GraphicsCallback.java:39)

  at java.desktop/sun.awt.SunGraphicsCallback.runOneComponent(SunGraphicsCallback.java:78)

  at java.desktop/sun.awt.SunGraphicsCallback.runComponents(SunGraphicsCallback.java:115)

  at java.desktop/java.awt.Container.paint(Container.java:2000)

  at java.desktop/java.awt.Window.paint(Window.java:3940)

  at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:868)

  at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:840)

  at java.base/java.security.AccessController.doPrivileged(Native Method)

  at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:87)

  at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:840)

  at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:815)

  at java.desktop/javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:764)

  at java.desktop/javax.swing.RepaintManager.access$1200(RepaintManager.java:69)

  at java.desktop/javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1880)

  at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)

  at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)

  at java.desktop/java.awt.EventQueue.access$600(EventQueue.java:97)

  at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)

  at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)

  at java.base/java.security.AccessController.doPrivileged(Native Method)

  at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:87)

  at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)

  at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)

  at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)

  at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)

  at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)

  at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)

  at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

Reply | Threaded
Open this post in threaded view
|

Re: <AWT Dev> "Invalid Image variant" exception from AWT when using MultiResolutionImage (bug in SunGraphics2D.drawHiDPIImage?)

Eirik Bakke-2

I just reported the below bug on https://bugreport.java.com/bugreport ; the report got assigned review ID 9057526.

 

--Eirik

 

From: awt-dev <[hidden email]> On Behalf Of Eirik Bakke
Sent: Thursday, September 6, 2018 3:44 PM
To: awt-dev <[hidden email]>
Subject: <AWT Dev> "Invalid Image variant" exception from AWT when using MultiResolutionImage (bug in SunGraphics2D.drawHiDPIImage?)

 

Hi, AWT-dev.

 

I tried to get HiDPI icons working on my Swing application on Windows 10 today on OpenJDK 10.0.2, and ran into what seems to be an AWT bug. See the exhibit at https://github.com/eirikbakke/InvalidImageVariantBugExhibit/blob/master/src/invalidimagevariant/InvalidImageVariantBugExhibit.java

 

Loading two differently sized images via Toolkit.getImage() and putting them into a BaseMultiResolutionImage yields an "IllegalArgumentException: Invalid Image variant" exception from SurfaceManager.getManager when the MultiResolutionImage is used as an icon in a JButton and the JFrame is dragged onto my 200%-scaling HiDPI screen. See the full stack trace pasted at the end of this email.

 

The bug seems to be due to a race condition, where SunGraphics2D.drawHiDPIImage may return null even when the image is in fact a MultiResolutionImage, if the underlying image alternatives have not yet been fully loaded by the time the first paint is attempted.

 

Waiting for the image to load using MediaTracker.waitForAll() "fixes" the problem for the simplest case. This is not always an option in client code, however; there are other MultiResolutionImage instances being created behind the scenes for instance when a JButton is disabled and its icon needs to be greyed-out.

 

Note that there is a timing aspect to this bug, so not all configurations might expose it. The bug did not appear when I disconnected my external monitor and _just_ used the HiDPI laptop one (not sure if this is a timing issue or something else).

 

Also note: On MacOS, Toolkit.getImage() and friends have had the ability to automatically detect and load HiDPI images with a "@2x" suffix in their file name (JDK-8011059) . Am I correct that there is no equivalent mechanism on Windows?

 

-- Eirik

 

Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Invalid Image variant

  at java.desktop/sun.awt.image.SurfaceManager.getManager(SurfaceManager.java:82)

  at java.desktop/sun.java2d.SurfaceData.getSourceSurfaceData(SurfaceData.java:218)

  at java.desktop/sun.java2d.pipe.DrawImage.renderImageScale(DrawImage.java:635)

  at java.desktop/sun.java2d.pipe.DrawImage.tryCopyOrScale(DrawImage.java:319)

  at java.desktop/sun.java2d.pipe.DrawImage.transformImage(DrawImage.java:258)

  at java.desktop/sun.java2d.pipe.DrawImage.copyImage(DrawImage.java:76)

  at java.desktop/sun.java2d.pipe.DrawImage.copyImage(DrawImage.java:1027)

  at java.desktop/sun.java2d.SunGraphics2D.drawImage(SunGraphics2D.java:3415)

  at java.desktop/sun.java2d.SunGraphics2D.drawImage(SunGraphics2D.java:3391)

  at java.desktop/javax.swing.ImageIcon.paintIcon(ImageIcon.java:425)

  at java.desktop/javax.swing.plaf.basic.BasicButtonUI.paintIcon(BasicButtonUI.java:358)

  at java.desktop/javax.swing.plaf.basic.BasicButtonUI.paint(BasicButtonUI.java:275)

  at java.desktop/com.sun.java.swing.plaf.windows.WindowsButtonUI.paint(WindowsButtonUI.java:167)

  at java.desktop/javax.swing.plaf.ComponentUI.update(ComponentUI.java:161)

  at java.desktop/javax.swing.JComponent.paintComponent(JComponent.java:797)

  at java.desktop/javax.swing.JComponent.paint(JComponent.java:1074)

  at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:907)

  at java.desktop/javax.swing.JComponent.paint(JComponent.java:1083)

  at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:907)

  at java.desktop/javax.swing.JComponent.paint(JComponent.java:1083)

  at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:907)

  at java.desktop/javax.swing.JComponent.paint(JComponent.java:1083)

  at java.desktop/javax.swing.JLayeredPane.paint(JLayeredPane.java:590)

  at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:907)

  at java.desktop/javax.swing.JComponent.paintToOffscreen(JComponent.java:5262)

  at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBufferedImpl(RepaintManager.java:1633)

  at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1608)

  at java.desktop/javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1546)

  at java.desktop/javax.swing.RepaintManager.paint(RepaintManager.java:1313)

  at java.desktop/javax.swing.JComponent.paint(JComponent.java:1060)

  at java.desktop/java.awt.GraphicsCallback$PaintCallback.run(GraphicsCallback.java:39)

  at java.desktop/sun.awt.SunGraphicsCallback.runOneComponent(SunGraphicsCallback.java:78)

  at java.desktop/sun.awt.SunGraphicsCallback.runComponents(SunGraphicsCallback.java:115)

  at java.desktop/java.awt.Container.paint(Container.java:2000)

  at java.desktop/java.awt.Window.paint(Window.java:3940)

  at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:868)

  at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:840)

  at java.base/java.security.AccessController.doPrivileged(Native Method)

  at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:87)

  at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:840)

  at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:815)

  at java.desktop/javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:764)

  at java.desktop/javax.swing.RepaintManager.access$1200(RepaintManager.java:69)

  at java.desktop/javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1880)

  at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)

  at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)

  at java.desktop/java.awt.EventQueue.access$600(EventQueue.java:97)

  at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)

  at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)

  at java.base/java.security.AccessController.doPrivileged(Native Method)

  at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:87)

  at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)

  at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)

  at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)

  at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)

  at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)

  at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)

  at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)