1 /* AsyncImage.java -- Loads images asynchronously
2    Copyright (C) 2006 Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 package gnu.java.awt.peer.gtk;
40 
41 import java.awt.Graphics;
42 import java.awt.Image;
43 import java.awt.image.ImageConsumer;
44 import java.awt.image.ImageObserver;
45 import java.awt.image.ImageProducer;
46 import java.net.URL;
47 import java.util.ArrayList;
48 import java.util.HashSet;
49 import java.util.Iterator;
50 
51 /**
52  * Supports asynchronous loading of images.
53  */
54 public class AsyncImage
55   extends Image
56 {
57 
58   /**
59    * Returned as source as long as the image is not complete.
60    */
61   private class NullImageSource
62     implements ImageProducer
63   {
64     private ArrayList<ImageConsumer> consumers;
65 
NullImageSource()66     NullImageSource()
67     {
68       consumers = new ArrayList<ImageConsumer>();
69     }
70 
addConsumer(ImageConsumer ic)71     public void addConsumer(ImageConsumer ic)
72     {
73       consumers.add(ic);
74     }
75 
isConsumer(ImageConsumer ic)76     public boolean isConsumer(ImageConsumer ic)
77     {
78       return consumers.contains(ic);
79     }
80 
removeConsumer(ImageConsumer ic)81     public void removeConsumer(ImageConsumer ic)
82     {
83       consumers.remove(ic);
84     }
85 
requestTopDownLeftRightResend(ImageConsumer ic)86     public void requestTopDownLeftRightResend(ImageConsumer ic)
87     {
88       startProduction(ic);
89     }
90 
startProduction(ImageConsumer ic)91     public void startProduction(ImageConsumer ic)
92     {
93       consumers.add(ic);
94       for (int i = consumers.size() - 1; i >= 0; i--)
95         {
96           ImageConsumer c = (ImageConsumer) consumers.get(i);
97           c.setDimensions(1, 1);
98           ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE);
99         }
100     }
101 
102   }
103 
104   /**
105    * Loads the image asynchronously.
106    */
107   private class Loader
108     implements Runnable
109   {
110     private URL url;
Loader(URL u)111     Loader(URL u)
112     {
113       url = u;
114     }
115 
run()116     public void run()
117     {
118       Image image;
119       try
120         {
121           GtkImage gtkImage = new GtkImage(url);
122           image = CairoSurface.getBufferedImage(gtkImage);
123         }
124       catch (IllegalArgumentException iae)
125         {
126           image = null;
127         }
128       realImage = GtkToolkit.imageOrError(image);
129       synchronized (AsyncImage.this)
130         {
131           notifyObservers(ImageObserver.ALLBITS | ImageObserver.HEIGHT
132                           | ImageObserver.WIDTH | ImageObserver.PROPERTIES);
133           observers = null; // Not needed anymore.
134         }
135     }
136   }
137 
138   /**
139    * The real image. This is null as long as the image is not complete.
140    */
141   Image realImage;
142 
143   /**
144    * The image observers.
145    *
146    * This is package private to avoid accessor methods.
147    */
148   HashSet<ImageObserver> observers;
149 
150   /**
151    * Creates a new AsyncImage that loads from the specified URL.
152    */
AsyncImage(URL url)153   AsyncImage(URL url)
154   {
155     observers = new HashSet<ImageObserver>();
156     Loader l = new Loader(url);
157     Thread t = new Thread(l);
158     t.start();
159   }
160 
flush()161   public void flush()
162   {
163     // Nothing to do here.
164   }
165 
getGraphics()166   public Graphics getGraphics()
167   {
168     Image r = realImage;
169     Graphics g = null;
170     if (r != null)
171       g = r.getGraphics(); // Should we return some dummy graphics instead?
172     return g;
173   }
174 
getHeight(ImageObserver observer)175   public int getHeight(ImageObserver observer)
176   {
177     addObserver(observer);
178     int height = 0;
179     Image r = realImage;
180     if (r != null)
181       height = r.getHeight(observer);
182     return height;
183   }
184 
getProperty(String name, ImageObserver observer)185   public Object getProperty(String name, ImageObserver observer)
186   {
187     addObserver(observer);
188     Image r = realImage;
189     Object prop = null;
190     if (r != null)
191       prop = r.getProperty(name, observer);
192     return prop;
193   }
194 
getSource()195   public ImageProducer getSource()
196   {
197     Image r = realImage;
198     ImageProducer source;
199     if (r == null)
200       source = new NullImageSource();
201     else
202       source = r.getSource();
203     return source;
204   }
205 
getWidth(ImageObserver observer)206   public int getWidth(ImageObserver observer)
207   {
208     addObserver(observer);
209     int width = 0;
210     Image r = realImage;
211     if (r != null)
212       width = r.getWidth(observer);
213     return width;
214   }
215 
addObserver(ImageObserver obs)216   void addObserver(ImageObserver obs)
217   {
218     if (obs != null)
219       {
220         synchronized (this)
221           {
222             // This field gets null when image loading is complete and we don't
223             // need to store any more observers.
224             HashSet<ImageObserver> observs = observers;
225             if (observs != null)
226               {
227                 observs.add(obs);
228               }
229             else
230               {
231                 // When the image is complete, notify the observer. Dunno if
232                 // that's really needed, but to be sure.
233                 obs.imageUpdate(this, ImageObserver.WIDTH
234                                 | ImageObserver.HEIGHT
235                                 |ImageObserver.ALLBITS
236                                 | ImageObserver.PROPERTIES, 0, 0,
237                                 realImage.getWidth(null),
238                                 realImage.getHeight(null));
239               }
240           }
241       }
242   }
243 
realImage(Image img, ImageObserver obs)244   static Image realImage(Image img, ImageObserver obs)
245   {
246     if (img instanceof AsyncImage)
247       {
248         ((AsyncImage) img).addObserver(obs);
249         Image r = ((AsyncImage) img).realImage;
250         if (r != null)
251           img = r;
252       }
253     return img;
254   }
255 
notifyObservers(int status)256   void notifyObservers(int status)
257   {
258     assert Thread.holdsLock(this);
259     // This field gets null when image loading is complete.
260     HashSet observs = observers;
261     if (observs != null)
262       {
263         Image r = realImage;
264         Iterator i = observs.iterator();
265         while (i.hasNext())
266           {
267             ImageObserver obs = (ImageObserver) i.next();
268             obs.imageUpdate(this, status, 0, 0, r.getWidth(null),
269                             r.getHeight(null));
270           }
271       }
272   }
273 
checkImage(ImageObserver obs)274   int checkImage(ImageObserver obs)
275   {
276     addObserver(obs);
277     int flags = 0;
278     if (realImage != null)
279       flags = ImageObserver.ALLBITS | ImageObserver.WIDTH
280               | ImageObserver.HEIGHT | ImageObserver.PROPERTIES;
281     return flags;
282   }
283 }
284