I improved the image handling in the Escher peers to support
asynchronous image loading. It is possible to pass an ImageProducer into
Toolkit.createImage() that loads the image asynchronously, i.e. in
another thread. For such ImageProducers, the resulting image must not be
null, but a kind of asynchronous wrapper. I introduced the AsyncImage
class in gnu.java.awt.image, together with an ImageConverter (an
ImageConsumer that creates a new BufferedImage instance) class. IMO, the
GTK peers should also use this implementation. (Now they use their own
AsyncImage - from which this new version is derived - but which is very
much inferior to the new).

2008-02-18  Roman Kennke  <[EMAIL PROTECTED]>

        * gnu/java/awt/image/AsyncImage.java: New file. Implements
        asynchronous image loading.
        * gnu/java/awt/image/ImageConverter.java: New file.
        An image consumer that creates a concrete image with
        asynchronous behaviour.
        * gnu/java/awt/peer/x/ImageConverter.java: Removed.
        * gnu/java/awt/peer/x/XToolkit.java:
        (createImage(ImageProducer)): Use new ImageConverter.
        * gnu/java/awt/peer/x/XGraphics2D.java:
        (rawDrawImage): Unwrap AsyncImages before painting.
        (unwrap): New helper method.

/Roman

-- 
Dipl.-Inform. (FH) Roman Kennke, Software Engineer, http://kennke.org
aicas Allerton Interworks Computer Automated Systems GmbH
Haid-und-Neu-Straße 18 * D-76131 Karlsruhe * Germany
http://www.aicas.com   * Tel: +49-721-663 968-0
USt-Id: DE216375633, Handelsregister HRB 109481, AG Karlsruhe
Geschäftsführer: Dr. James J. Hunt
Index: gnu/java/awt/image/AsyncImage.java
===================================================================
RCS file: gnu/java/awt/image/AsyncImage.java
diff -N gnu/java/awt/image/AsyncImage.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gnu/java/awt/image/AsyncImage.java	18 Feb 2008 19:43:40 -0000
@@ -0,0 +1,300 @@
+/* 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();
+                  }
+              }
+          }
+      }
+  }
+}
Index: gnu/java/awt/image/ImageConverter.java
===================================================================
RCS file: gnu/java/awt/image/ImageConverter.java
diff -N gnu/java/awt/image/ImageConverter.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gnu/java/awt/image/ImageConverter.java	18 Feb 2008 19:43:40 -0000
@@ -0,0 +1,528 @@
+/* ImageConverter.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 gnu.java.awt.image.AsyncImage;
+
+import java.awt.GraphicsEnvironment;
+import java.awt.Image;
+import java.awt.Transparency;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.ImageConsumer;
+import java.awt.image.IndexColorModel;
+import java.awt.image.ImageObserver;
+import java.awt.image.SinglePixelPackedSampleModel;
+import java.awt.image.WritableRaster;
+import java.util.Hashtable;
+
+/**
+ * Convert an Image to a BufferedImage.
+ * 
+ * @author Roman Kennke ([EMAIL PROTECTED])
+ */
+public class ImageConverter implements ImageConsumer
+{
+
+  public static final String IMAGE_TRANSPARENCY_PROPERTY =
+    "gnu.awt.image.transparency";
+
+  public static final String IMAGE_PROPERTIES_PROPERTY =
+    "gnu.awt.image.properties";
+
+  private AsyncImage image;
+  private BufferedImage bImage;
+  private Hashtable imageProperties;
+  private int width, height;
+  private ColorModel colorModel;
+  private ColorModel targetColorModel;
+
+  public ImageConverter()
+  {
+    width = 0;
+    height = 0;
+    image = new AsyncImage();
+  }
+
+  public void setDimensions(int w, int h)
+  {
+    width = w;
+    height = h;
+  }
+
+  public void setProperties(Hashtable props)
+  {
+    // Ignore for now.
+  }
+
+  public void setColorModel(ColorModel model)
+  {
+    colorModel = model;
+  }
+
+  public void setHints(int flags)
+  {
+    // Ignore for now.
+  }
+
+  public void setPixels(int x, int y, int w, int h, ColorModel model,
+                        byte[] pixels, int offset, int scansize)
+  {
+    model = setupColorModel(model);
+
+    if (bImage == null)
+      {
+        createImage();
+      }
+
+    Integer t = (Integer) imageProperties.get("gnu.awt.image.transparency");
+    int transparency = t.intValue();
+
+    if(targetColorModel.equals(model))
+      {
+        transparency = transferPixels(x, y, w, h, model, pixels, offset,
+                                      scansize, transparency);
+      }
+    else if (model instanceof IndexColorModel
+             && targetColorModel.equals(ColorModel.getRGBdefault())) 
+      {
+        transparency = convertIndexColorModelToSRGB(x, y, w, h,
+                                                    (IndexColorModel) model,
+                                                    pixels, offset, scansize,
+                                                    transparency);
+      }
+    else
+      {
+        transparency = convertPixels(x, y, w, h, model, pixels, offset,
+                                     scansize, transparency);
+      }
+
+    imageProperties.put("gnu.awt.image.transparency",
+                        Integer.valueOf(transparency));
+  }
+
+  public void setPixels(int x, int y, int w, int h, ColorModel model,
+                        int[] pixels, int offset, int scansize)
+  {
+    model = setupColorModel(model);
+    if (bImage == null)
+      {
+        createImage();
+      }
+
+    Integer t = (Integer) imageProperties.get(IMAGE_TRANSPARENCY_PROPERTY);
+    int transparency= t.intValue();
+
+    if (targetColorModel.equals(model))
+      {
+        transparency = transferPixels(x, y, w, h, model, pixels, offset,
+                                      scansize, transparency);
+      }
+    else if (model instanceof IndexColorModel
+             && targetColorModel.equals(ColorModel.getRGBdefault()))
+      {
+        transparency = convertIndexColorModelToSRGB(x, y, w, h,
+                                                    (IndexColorModel) model,
+                                                    pixels, offset, scansize,
+                                                    transparency);
+      }
+    else
+      {
+        transparency = convertPixels(x, y, w, h, model, pixels, offset,
+                                     scansize, transparency);
+      }
+
+    imageProperties.put(IMAGE_TRANSPARENCY_PROPERTY,
+                        Integer.valueOf(transparency));
+
+  }
+
+  /**
+   * Initialize the color model for this setPixels run: <br/>
+   * 1. if no color model was given use the hinted color model <br/>
+   * 2. if no color model was given and non was hinted use the default sRGB color model. <br/>
+   * Also:<br/>
+   * If no target color model was set use the color model of the given pixels.
+   * @param model
+   * @return
+   */
+  private ColorModel setupColorModel(ColorModel model)
+  {
+    // If the given color model is null use the previously hinted color model.
+    if (model == null)
+      model = colorModel;
+
+    // If no color model was given or hinted use default sRGB.
+    if (model == null)
+      model = ColorModel.getRGBdefault();
+
+    // If no specific color model was requested for the target use the current
+    // pixels model.
+    if (targetColorModel == null)
+      targetColorModel = model;
+    targetColorModel = ColorModel.getRGBdefault();
+    return model;
+  }
+
+  /**
+   * Creates the image instance into which the pixel data is converted.
+   */
+  private void createImage()
+  {
+    if (imageProperties == null)
+      {
+        imageProperties = new Hashtable();
+      }
+
+    imageProperties.put(IMAGE_TRANSPARENCY_PROPERTY,
+                        Integer.valueOf(Transparency.OPAQUE));
+    imageProperties.put(IMAGE_PROPERTIES_PROPERTY, imageProperties);
+
+    // For the sRGB case let the GraphicsEnvironment create an image for us.
+    if (ColorModel.getRGBdefault().equals(targetColorModel))
+      {
+        bImage = GraphicsEnvironment.getLocalGraphicsEnvironment()
+                                    .getDefaultScreenDevice()
+                                    .getDefaultConfiguration()
+             .createCompatibleImage(width, height, Transparency.TRANSLUCENT);
+      }
+    else
+      {
+        WritableRaster raster =
+          targetColorModel.createCompatibleWritableRaster(width, height);
+        bImage = new BufferedImage(targetColorModel, raster, false,
+                                   imageProperties);
+      }
+    image.setRealImage(bImage);
+    return;
+  }
+
+  /**
+   * Transfers pixels into a raster of the same color model.
+   *
+   * @param x the X coordinate of the source pixel rectangle
+   * @param y the Y coordinate of the source pixel rectangle
+   * @param w the width of the source pixel rectangle
+   * @param h the height of the source pixel rectangle
+   * @param model the color model of the source pixels
+   * @param pixels the pixel data
+   * @param offset the offset in the pixel array
+   * @param scansize the scanline size
+   * @param transparency the assumed transparency
+   * 
+   * @return the determined transparency
+   */
+  private int transferPixels(int x, int y, int w, int h, ColorModel model,
+                             byte[] pixels, int offset, int scansize,
+                             int transparency)
+  {
+    // If we have the same color model, then we can simply drop
+    // the pixel value into the target raster.
+    bImage.getRaster().setDataElements(x, y, w, h, pixels);
+
+    for (int yy = 0; yy < h; yy++)
+      {
+        for (int xx = 0; xx < w; xx++)
+          {
+            int pixel = 0xFF & pixels[yy * scansize + xx + offset];
+            int alpha = model.getAlpha(pixel);
+            transparency = updateTransparency(alpha, transparency);
+          }
+      }
+    return transparency;
+  }
+
+  /**
+   * Transfers pixels into a raster of the same color model.
+   *
+   * @param x the X coordinate of the source pixel rectangle
+   * @param y the Y coordinate of the source pixel rectangle
+   * @param w the width of the source pixel rectangle
+   * @param h the height of the source pixel rectangle
+   * @param model the color model of the source pixels
+   * @param pixels the pixel data
+   * @param offset the offset in the pixel array
+   * @param scansize the scanline size
+   * @param transparency the assumed transparency
+   * 
+   * @return the determined transparency
+   */
+  private int transferPixels(int x, int y, int w, int h, ColorModel model,
+                             int[] pixels, int offset, int scansize,
+                             int transparency)
+  {
+    // If we have the same color model, then we can simply drop
+    // the pixel value into the target raster.
+    bImage.getRaster().setDataElements(x, y, w, h, pixels);
+
+    for (int yy = 0; yy < h; yy++)
+      {
+        for (int xx = 0; xx < w; xx++)
+          {
+            int pixel = pixels[yy * scansize + xx + offset];
+            int alpha = model.getAlpha(pixel);
+            transparency = updateTransparency(alpha, transparency);
+          }
+      }
+    return transparency;
+  }
+
+  /**
+   * Converts pixel from one color model to another, and stores them in the
+   * target image.
+   *
+   * @param x the X coordinate of the source pixel rectangle
+   * @param y the Y coordinate of the source pixel rectangle
+   * @param w the width of the source pixel rectangle
+   * @param h the height of the source pixel rectangle
+   * @param model the color model of the source pixels
+   * @param pixels the pixel data
+   * @param offset the offset in the pixel array
+   * @param scansize the scanline size
+   * @param transparency the assumed transparency
+   * 
+   * @return the determined transparency
+   */
+  private int convertPixels(int x, int y, int w, int h, ColorModel model,
+                            byte[] pixels, int offset, int scansize,
+                            int transparency)
+  {
+    // If the color models are not the same, we must convert the
+    // pixel values from one model to the other.
+    Object dataEl = null;
+    // Convert pixels to the destination color model.
+    for (int yy = 0; yy < h; yy++)
+      {
+        for (int xx = 0; xx < w; xx++)
+          {
+            int pixel = 0xFF & pixels[yy * scansize + xx + offset];
+            int rgb = model.getRGB(pixel);
+            int alpha = model.getAlpha(pixel);
+            transparency = updateTransparency(alpha, transparency);
+            dataEl = targetColorModel.getDataElements(rgb, dataEl);
+            bImage.getRaster().setDataElements(x + xx, y + yy, dataEl);
+          }
+      }
+    return transparency;
+  }
+
+  /**
+   * Converts pixel from one color model to another, and stores them in the
+   * target image.
+   *
+   * @param x the X coordinate of the source pixel rectangle
+   * @param y the Y coordinate of the source pixel rectangle
+   * @param w the width of the source pixel rectangle
+   * @param h the height of the source pixel rectangle
+   * @param model the color model of the source pixels
+   * @param pixels the pixel data
+   * @param offset the offset in the pixel array
+   * @param scansize the scanline size
+   * @param transparency the assumed transparency
+   * 
+   * @return the determined transparency
+   */
+  private int convertPixels(int x, int y, int w, int h, ColorModel model,
+                            int[] pixels, int offset, int scansize,
+                            int transparency)
+  {
+    // If the color models are not the same, we must convert the
+    // pixel values from one model to the other.
+    Object dataEl = null;
+    // Convert pixels to the destination color model.
+    for (int yy = 0; yy < h; yy++)
+      {
+        for (int xx = 0; xx < w; xx++)
+          {
+            int pixel = pixels[yy * scansize + xx + offset];
+            int rgb = model.getRGB(pixel);
+            int alpha = model.getAlpha(pixel);
+            transparency = updateTransparency(alpha, transparency);
+            dataEl = targetColorModel.getDataElements(rgb, dataEl);
+            bImage.getRaster().setDataElements(x + xx, y + yy, dataEl);
+          }
+      }
+    return transparency;
+  }
+
+  /**
+   * Converts pixels from an index color model to the target image.
+   *
+   * @param x the X coordinate of the source pixel rectangle
+   * @param y the Y coordinate of the source pixel rectangle
+   * @param w the width of the source pixel rectangle
+   * @param h the height of the source pixel rectangle
+   * @param model the color model of the source pixels
+   * @param pixels the pixel data
+   * @param offset the offset in the pixel array
+   * @param scansize the scanline size
+   * @param transparency the assumed transparency
+   * 
+   * @return the determined transparency
+   */
+  private int convertIndexColorModelToSRGB(int x, int y, int w, int h,
+                                           IndexColorModel model,
+                                           byte[] pixels, int offset,
+                                           int scansize, int transparency)
+  {
+
+    int mapSize = model.getMapSize();
+    int[] colorMap = new int[mapSize];
+    for(int i=0; i < mapSize; i++)
+      {
+        colorMap[i] = model.getRGB(i);
+      }
+
+    WritableRaster raster = bImage.getRaster();
+    SinglePixelPackedSampleModel sampleMode =
+      (SinglePixelPackedSampleModel) raster.getSampleModel();
+    DataBuffer dataBuffer = (DataBuffer) raster.getDataBuffer();
+
+    int rasterOffset = sampleMode.getOffset(x,y)+dataBuffer.getOffset();
+    int rasterScanline = sampleMode.getScanlineStride();
+
+    for (int yy = 0; yy < h; yy++)
+      {
+        int xoffset = offset;
+        for (int xx = 0; xx < w; xx++)
+          {
+            int argb  = colorMap[(pixels[xoffset++] & 0xFF)];
+            dataBuffer.setElem(rasterOffset+xx, argb);
+            int alpha = (argb >>> 24);
+            transparency = updateTransparency(alpha, transparency);
+          }
+        offset += scansize;
+        rasterOffset += rasterScanline;
+      }
+
+    return transparency;
+  }
+
+  /**
+   * Converts pixels from an index color model to the target image.
+   *
+   * @param x the X coordinate of the source pixel rectangle
+   * @param y the Y coordinate of the source pixel rectangle
+   * @param w the width of the source pixel rectangle
+   * @param h the height of the source pixel rectangle
+   * @param model the color model of the source pixels
+   * @param pixels the pixel data
+   * @param offset the offset in the pixel array
+   * @param scansize the scanline size
+   * @param transparency the assumed transparency
+   * 
+   * @return the determined transparency
+   */
+  private int convertIndexColorModelToSRGB(int x, int y, int w, int h,
+                                           IndexColorModel model, int[] pixels,
+                                           int offset, int scansize,
+                                           int transparency)
+  {
+    int mapSize = model.getMapSize();
+    int[] colorMap = new int[mapSize];
+    for(int i=0; i < mapSize; i++)
+      {
+        colorMap[i] = model.getRGB(i);
+      }
+
+    WritableRaster raster = bImage.getRaster();
+    SinglePixelPackedSampleModel sampleMode =
+      (SinglePixelPackedSampleModel) raster.getSampleModel();
+    DataBuffer dataBuffer = (DataBuffer)raster.getDataBuffer();
+
+    int rasterOffset = sampleMode.getOffset(x, y) + dataBuffer.getOffset();
+    int rasterScanline = sampleMode.getScanlineStride();
+
+    for (int yy = 0; yy < h; yy++)
+      {
+        int xoffset = offset;
+        for (int xx = 0; xx < w; xx++)
+          {
+            int argb  = colorMap[pixels[xoffset++]];
+            dataBuffer.setElem(rasterOffset + xx, argb);
+            int alpha = (argb >>> 24);
+            transparency = updateTransparency(alpha, transparency);
+          }
+        offset += scansize;
+        rasterOffset += rasterScanline;
+      }
+
+    return transparency;
+  }
+
+  /**
+   * Updates the transparency information according to the alpha pixel value.
+   *
+   * @param alpha the alpha pixel value
+   * @param transparency the old transparency
+   *
+   * @return the updated transparency
+   */
+  private int updateTransparency(int alpha, int transparency)
+  {
+    if (alpha != 0xFF)
+      {
+        if (alpha == 0x00 && transparency <= Transparency.BITMASK)
+          {
+            transparency = Transparency.BITMASK;
+          }
+        else if (transparency < Transparency.TRANSLUCENT)
+          {
+            transparency = Transparency.TRANSLUCENT;
+          }
+      }
+    return transparency;
+  }
+
+  public void imageComplete(int status)
+  {
+    image.notifyObservers(ImageObserver.ALLBITS, 0, 0, width, height);
+  }
+
+  public void setTargetColorModel(ColorModel model)
+  {
+    targetColorModel = model;
+  }
+
+  public Image getImage()
+  {
+    return image;
+  }
+}
Index: gnu/java/awt/peer/x/ImageConverter.java
===================================================================
RCS file: gnu/java/awt/peer/x/ImageConverter.java
diff -N gnu/java/awt/peer/x/ImageConverter.java
--- gnu/java/awt/peer/x/ImageConverter.java	29 Jun 2006 15:15:56 -0000	1.1
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,113 +0,0 @@
-/* ImageConverter.java -- Convert arbitrary Image impl to XImage
-   Copyright (C) 2006 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.peer.x;
-
-import java.awt.Color;
-import java.awt.Graphics;
-import java.awt.image.ColorModel;
-import java.awt.image.ImageConsumer;
-import java.util.Hashtable;
-
-/**
- * Convert a non-XImage to an XImage.
- * 
- * @author Roman Kennke ([EMAIL PROTECTED])
- */
-public class ImageConverter implements ImageConsumer
-{
-
-  private XImage image;
-  private Graphics imageGraphics;
-
-  public void setDimensions(int width, int height)
-  {
-    image = new XImage(width, height);
-  }
-
-  public void setProperties(Hashtable props)
-  {
-    // Ignore for now.
-  }
-
-  public void setColorModel(ColorModel model)
-  {
-    // Ignore for now.
-  }
-
-  public void setHints(int flags)
-  {
-    // Ignore for now.
-  }
-
-  public void setPixels(int x, int y, int w, int h, ColorModel model,
-                        byte[] pixels, int offset, int scansize)
-  {
-    // FIXME: Implement this.
-    throw new UnsupportedOperationException("Not yet implemented");
-  }
-
-  public void setPixels(int x, int y, int w, int h, ColorModel model,
-                        int[] pixels, int offset, int scansize)
-  {
-    System.err.println("transferType: " + model.getTransferType());
-    System.err.println("colorModel: " + model);
-    if (imageGraphics == null)
-      imageGraphics = image.getGraphics();
-    int xend = x + w;
-    int yend = y + h;
-    for (int yy = y; yy < yend; yy++)
-      {
-        for (int xx = x; xx < xend; xx++)
-          {
-            int pixel = pixels[yy * scansize + xx + offset];
-            imageGraphics.setColor(new Color(model.getRGB(pixel)));
-            imageGraphics.fillRect(xx, yy, 1, 1);
-          }
-      }
-  }
-
-  public void imageComplete(int status)
-  {
-    // Nothing to do here.
-  }
-
-  XImage getXImage()
-  {
-    return image;
-  }
-}
Index: gnu/java/awt/peer/x/XGraphics2D.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/awt/peer/x/XGraphics2D.java,v
retrieving revision 1.8
diff -u -1 -0 -r1.8 XGraphics2D.java
--- gnu/java/awt/peer/x/XGraphics2D.java	18 Feb 2008 11:00:53 -0000	1.8
+++ gnu/java/awt/peer/x/XGraphics2D.java	18 Feb 2008 19:43:40 -0000
@@ -50,20 +50,21 @@
 import java.awt.geom.AffineTransform;
 import java.awt.image.BufferedImage;
 import java.awt.image.ColorModel;
 import java.awt.image.DataBuffer;
 import java.awt.image.ImageObserver;
 import java.awt.image.Raster;
 import java.awt.peer.FontPeer;
 import java.util.HashMap;
 import java.util.WeakHashMap;
 
+import gnu.java.awt.image.AsyncImage;
 import gnu.java.awt.java2d.AbstractGraphics2D;
 import gnu.java.awt.java2d.ScanlineCoverage;
 import gnu.x11.Colormap;
 import gnu.x11.Drawable;
 import gnu.x11.GC;
 import gnu.x11.image.ZPixmap;
 
 public class XGraphics2D
   extends AbstractGraphics2D
 {
@@ -324,20 +325,21 @@
   {
     synchronized (xdrawable.display) {
       super.fillShape(s, isFont);
     }
   }
 
   private static WeakHashMap<Image,ZPixmap> imageCache = new WeakHashMap<Image,ZPixmap>();
 
   protected boolean rawDrawImage(Image image, int x, int y, ImageObserver obs)
   {
+    image = unwrap(image);
     boolean ret;
     if (image instanceof XImage)
       {
         XImage xImage = (XImage) image;
         xdrawable.copy_area(xImage.pixmap, xgc, 0, 0, xImage.getWidth(obs),
                             xImage.getHeight(obs), x, y);
         ret = true;
       }
     else if (image instanceof PixmapVolatileImage)
       {
@@ -452,12 +454,32 @@
       {
         int tx = (int) transform.getTranslateX();
         int ty = (int) transform.getTranslateY();
         xdrawable.text(xgc, x + tx, y + ty, s);
       }
     else
       {
         super.drawString(s, x, y);
       }
   }
+
+  /**
+   * Extracts an image instance out of an AsyncImage. If the image isn't
+   * an AsyncImage, then the original instance is returned.
+   *
+   * @param im the image
+   *
+   * @return the image to render
+   */
+  private Image unwrap(Image im)
+  {
+    Image image = im;
+    if (image instanceof AsyncImage)
+      {
+        AsyncImage aIm = (AsyncImage) image;
+        image = aIm.getRealImage();
+      }
+    return image;
+  }
+
 }
 
Index: gnu/java/awt/peer/x/XToolkit.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/awt/peer/x/XToolkit.java,v
retrieving revision 1.9
diff -u -1 -0 -r1.9 XToolkit.java
--- gnu/java/awt/peer/x/XToolkit.java	20 Sep 2007 14:01:09 -0000	1.9
+++ gnu/java/awt/peer/x/XToolkit.java	18 Feb 2008 19:43:40 -0000
@@ -112,20 +112,21 @@
 import java.util.Map;
 import java.util.Properties;
 import java.util.WeakHashMap;
 
 import javax.imageio.ImageIO;
 
 import gnu.classpath.SystemProperties;
 import gnu.java.awt.ClasspathToolkit;
 import gnu.java.awt.EmbeddedWindow;
 import gnu.java.awt.font.OpenTypeFontPeer;
+import gnu.java.awt.image.ImageConverter;
 import gnu.java.awt.peer.ClasspathFontPeer;
 import gnu.java.awt.peer.EmbeddedWindowPeer;
 import gnu.java.awt.peer.swing.SwingCanvasPeer;
 import gnu.java.awt.peer.swing.SwingLabelPeer;
 import gnu.java.awt.peer.swing.SwingPanelPeer;
 
 public class XToolkit
   extends ClasspathToolkit
 {
 
@@ -520,21 +521,21 @@
   public int checkImage(Image image, int width, int height, ImageObserver observer)
   {
     // TODO: Implement this.
     throw new UnsupportedOperationException("Not yet implemented.");
   }
 
   public Image createImage(ImageProducer producer)
   {
     ImageConverter conv = new ImageConverter();
     producer.startProduction(conv);
-    Image image = conv.getXImage();
+    Image image = conv.getImage();
     return image;
   }
 
   public Image createImage(byte[] data, int offset, int len)
   {
     Image image;
     try
       {
         ByteArrayInputStream i = new ByteArrayInputStream(data, offset, len);
         image = createImage(i);

Reply via email to