Also, currently we render animated GIFs by continually decoding them, which is a CPU waste, but it does save a little on memory. That design also complicates this MediaTracker issue since the tracking and the loading and the frames are all equated under the covers in a way that makes it hard for MT to say "I'm OK now, but don't stop loading on my account" while at the same time allowing our ImageLoader threads to have some metric that lets them know when to stop decoding the GIF. The MT also can't distinguish between frames that happen while still loading the file and those that happen after the file is loaded and are just repeating.

Given the relatively modest savings in memory, I think it might be better to find a way to decode every frame once and keep it around in the ToolkitImage, and then use just a simple "time to render the next frame" mechanism to periodically call the imageUpdate methods and switch to the next decoded frame. If we moved to such a system, then this particular bug may have an alternate (and possibly easier) way to fix it since it wouldn't be side effecting the loading of images to trigger frame repainting and MT notices. But...

Another complication is that animated GIFs send FRAMEBITS on every frame even if it is a repeat until the properties say that the animation is over and only then do they send ALLBITS. As a result, MT has a choice between ending its interest at the first frame (as it currently does which causes us to dispose() internally), keeping interest forever which might turn into a long term CPU leak and means it will never answer "fully loaded now", or perhaps guessing at the number of frames? There is no good answer there for MT. If we had a way to communicate that the multi-frame image had loaded all of its frames and was now "fully loaded" even though it was still animating, then MT could use that instead - but that would involve new ImageObserver API - perhaps a new bit meaning "ALLFRAMESLOADED" that can get tacked on to FRAMEBITS, but doesn't mean "ALLBITS" (since ALLBITS currently means the animation has reached its end). Even then, how does a MT know the difference between an image loader that supports this convention and one that doesn't? Perhaps "FRAMEBITS | NOTALLFRAMESLOADED" could mean the opposite (and would only be used for cases of a limited number of frames like an animated GIF, not cases where a custom Producer might produce an infinite number of frames). MT would then unregister on the first FRAMEBITS that did not have NOTALLFRAMESLOADED or on the first ALLBITS?

(Note to self "NOTALLFRAMESLOADED" is a bad name for a new flag...)

                        ...jim

On 12/18/13 2:21 PM, Jim Graham wrote:
Hi Petr,

Have you verified that if someone draws an animated GIF and then later
returns false from the observer that the associated ImageLoader thread
goes away?  I think the dispose() method had a side effect of allowing
the thread to go away and if you don't call it then the ImageLoader
threads that serve the displayers of an animated GIF may run forever
once triggered...

             ...jim

On 12/18/13 6:01 AM, Petr Pchelko wrote:
Hello, AWT and 2D teams.

Please review the fix for the issue:
https://bugs.openjdk.java.net/browse/JDK-8029250
It also resolves the issue:
https://bugs.openjdk.java.net/browse/JDK-6740321
The fix is available at:
http://cr.openjdk.java.net/~pchelko/9/8029250/webrev/

The problem:
In AWT we use a MediaTracker to wait for the tray icon loading.
However, if the TrayIcon is an animated gif the following happen:
The MediaTracker installs an ImageObserver to an image and starts
loading. After the first frame is loaded (and it's really all we need)
the media tracker correctly exits and removes it's ImageObserver. And
as it's the only observer the checkConsumption is called in an
ImageRepresentation. As the availinfo is just FRAMEBITS the
successfully loaded frame was immediately disposed and AWT failed
to draw a tray icon.

With best regards. Petr.

Reply via email to