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