| /* AsyncImage.java -- Loads images asynchronously |
| Copyright (C) 2008 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath 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 for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| |
| package gnu.java.awt.image; |
| |
| |
| import java.awt.Graphics; |
| import java.awt.Image; |
| import java.awt.image.ImageConsumer; |
| import java.awt.image.ImageObserver; |
| import java.awt.image.ImageProducer; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| |
| /** |
| * Supports asynchronous loading of images. |
| */ |
| public class AsyncImage |
| extends Image |
| { |
| |
| /** |
| * The image source for AsyncImages. |
| */ |
| private class AsyncImageSource |
| implements ImageProducer |
| { |
| /** |
| * The real image source, if already present, or <code>null</code> |
| * otherwise. |
| */ |
| private ImageProducer realSource; |
| |
| public void addConsumer(ImageConsumer ic) |
| { |
| startProduction(ic); |
| } |
| |
| public boolean isConsumer(ImageConsumer ic) |
| { |
| return false; |
| } |
| |
| public void removeConsumer(ImageConsumer ic) |
| { |
| // Nothing to do here. |
| } |
| |
| public void requestTopDownLeftRightResend(ImageConsumer ic) |
| { |
| startProduction(ic); |
| } |
| |
| public void startProduction(ImageConsumer ic) |
| { |
| ImageProducer ip = getRealSource(); |
| if (ip == null) |
| { |
| ic.setDimensions(1, 1); |
| ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE); |
| } |
| else |
| { |
| ip.startProduction(ic); |
| } |
| } |
| |
| /** |
| * Returns the real image source, if already present. Otherwise, this |
| * returns <code>null</code>. |
| * |
| * @return the real image source, or <code>null</code> if not present |
| */ |
| private ImageProducer getRealSource() |
| { |
| synchronized (AsyncImage.this) |
| { |
| ImageProducer source = realSource; |
| if (source == null) |
| { |
| Image ri = realImage; |
| if (ri != null) |
| { |
| realSource = source = ri.getSource(); |
| } |
| } |
| return source; |
| } |
| } |
| } |
| |
| /** |
| * The real image. This is null as long as the image is not complete. |
| */ |
| private volatile Image realImage; |
| |
| /** |
| * The image observers. |
| * |
| * This is package private to avoid accessor methods. |
| */ |
| HashSet<ImageObserver> observers; |
| |
| private volatile boolean complete = false; |
| |
| /** |
| * Creates a new AsyncImage. |
| */ |
| AsyncImage() |
| { |
| observers = new HashSet<ImageObserver>(); |
| } |
| |
| public void flush() |
| { |
| // Nothing to do here. |
| } |
| |
| public Graphics getGraphics() |
| { |
| Image r = realImage; |
| Graphics g = null; |
| if (r != null) |
| g = r.getGraphics(); // Should we return some dummy graphics instead? |
| return g; |
| } |
| |
| public boolean isComplete() { |
| return complete; |
| } |
| |
| public int getHeight(ImageObserver observer) |
| { |
| addObserver(observer); |
| int height = -1; |
| waitForImage(observer); |
| Image r = realImage; |
| if (r != null) |
| height = r.getHeight(observer); |
| return height; |
| } |
| |
| public Object getProperty(String name, ImageObserver observer) |
| { |
| addObserver(observer); |
| Image r = realImage; |
| Object prop = null; |
| if (r != null) |
| prop = r.getProperty(name, observer); |
| return prop; |
| } |
| |
| public ImageProducer getSource() |
| { |
| return new AsyncImageSource(); |
| } |
| |
| public int getWidth(ImageObserver observer) |
| { |
| addObserver(observer); |
| int width = -1; |
| waitForImage(observer); |
| Image r = realImage; |
| if (r != null) |
| width = r.getWidth(observer); |
| return width; |
| } |
| |
| public void addObserver(ImageObserver obs) |
| { |
| if (obs != null) |
| { |
| synchronized (this) |
| { |
| // This field gets null when image loading is complete and we don't |
| // need to store any more observers. |
| HashSet<ImageObserver> observs = observers; |
| if (observs != null) |
| { |
| observs.add(obs); |
| } |
| } |
| } |
| } |
| |
| public boolean prepareImage(int w, int h, ImageObserver obs) |
| { |
| addObserver(obs); |
| return realImage != null; |
| } |
| |
| public int checkImage(int w, int h, ImageObserver obs) |
| { |
| addObserver(obs); |
| int flags = 0; |
| if (realImage != null) |
| flags = ImageObserver.ALLBITS | ImageObserver.WIDTH |
| | ImageObserver.HEIGHT | ImageObserver.PROPERTIES; |
| return flags; |
| } |
| |
| public Image getRealImage() |
| { |
| return realImage; |
| } |
| |
| public void setRealImage(Image im) |
| { |
| realImage = im; |
| int status = ImageObserver.HEIGHT | ImageObserver.WIDTH; |
| notifyObservers(status, 0, 0, im.getWidth(null), im.getHeight(null)); |
| } |
| |
| public void notifyObservers(int status, int x, int y, int w, int h) |
| { |
| synchronized (this) |
| { |
| HashSet observs = observers; |
| if (observs != null) |
| { |
| Iterator i = observs.iterator(); |
| while (i.hasNext()) |
| { |
| ImageObserver obs = (ImageObserver) i.next(); |
| boolean complete = obs.imageUpdate(this, status, x, y, realImage.getWidth(obs), realImage.getHeight(obs)); |
| if (complete) // Remove completed observers. |
| i.remove(); |
| } |
| } |
| if ((status & ImageObserver.ALLBITS) != 0) |
| { |
| complete = true; |
| notifyAll(); |
| } |
| } |
| } |
| |
| /** |
| * Waits for the image to be loaded completely, if the image observer |
| * is <code>null</code>. Otherwise this is not necessary, because the |
| * image observer can be notified about later completion. |
| * |
| * @param observer the image observer |
| */ |
| public void waitForImage(ImageObserver observer) |
| { |
| if (!complete && observer == null) |
| { |
| synchronized (this) |
| { |
| while (! complete) |
| { |
| try |
| { |
| wait(); |
| } |
| catch (InterruptedException ex) |
| { |
| Thread.currentThread().interrupt(); |
| } |
| } |
| } |
| } |
| } |
| } |