Milán Major

netscape-revival

1 branch
Code

sun-java/classsrc/sun/awt/image/Image.java

/*
 * @(#)Image.java	1.39 95/12/08 Jim Graham
 *
 * Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Permission to use, copy, modify, and distribute this software
 * and its documentation for NON-COMMERCIAL purposes and without
 * fee is hereby granted provided that this copyright notice
 * appears in all copies. Please refer to the file "copyright.html"
 * for further important copyright and licensing information.
 *
 * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 */

package sun.awt.image;

import java.util.Hashtable;
import java.util.Enumeration;

import java.awt.Graphics;
import java.awt.image.ColorModel;
import java.awt.image.ImageProducer;
import java.awt.image.ImageConsumer;
import java.awt.image.ImageObserver;
import sun.awt.image.OffScreenImageSource;
import sun.awt.image.ImageWatched;
import sun.awt.image.ImageRepresentation;
import sun.awt.image.FileImageSource;

public abstract class Image extends java.awt.Image {
    /**
     * The object which is used to reconstruct the original image data
     * as needed.
     */
    ImageProducer source;

    InputStreamImageSource src;

    /**
     * The object which intercepts the image dimension information
     * and redirects it into the image.
     */
    ImageInfoGrabber info;

    protected Image() {
    }

    /**
     * Construct an image for offscreen rendering to be used with a
     * given Component.
     */
    protected Image(int w, int h) {
	OffScreenImageSource osis = new OffScreenImageSource(w, h);
	source = osis;
	width = w;
	height = h;
	availinfo |= (ImageObserver.WIDTH | ImageObserver.HEIGHT);
	ImageRepresentation ir = getImageRep(-1, -1);
	representations.put(w + "x" + h, ir);
	representations.put("-1x-1", ir);
	ir.setDimensions(w, h);
	ir.offscreenInit();
	osis.setImageRep(ir);
    }

    /**
     * Construct an image from an ImageProducer object.
     */
    protected Image(ImageProducer is) {
	source = is;
	if (is instanceof InputStreamImageSource) {
	    src = (InputStreamImageSource) is;
	}
	info = new ImageInfoGrabber(this);
	info.setupConsumer();
    }

    public ImageProducer getSource() {
	if (src != null) {
	    src.checkSecurity(null, false);
	}
	return source;
    }

    private int width = -1;
    private int height = -1;
    private Hashtable properties;

    private int availinfo;

    /**
     * Return the width of the original image source.
     * If the width isn't known, then the image is reconstructed.
     */
    public int getWidth() {
	if (src != null) {
	    src.checkSecurity(null, false);
	}
	if ((availinfo & ImageObserver.WIDTH) == 0) {
	    reconstruct(ImageObserver.WIDTH);
	}
	return width;
    }

    /**
     * Return the width of the original image source.
     * If the width isn't known, then the ImageObserver object will be
     * notified when the data is available.
     */
    public synchronized int getWidth(ImageObserver iw) {
	if (src != null) {
	    src.checkSecurity(null, false);
	}
	if ((availinfo & ImageObserver.WIDTH) == 0) {
	    addWatcher(iw, true);
	    return -1;
	}
	return width;
    }

    /**
     * Return the height of the original image source.
     * If the height isn't known, then the image is reconstructed.
     */
    public int getHeight() {
	if (src != null) {
	    src.checkSecurity(null, false);
	}
	if ((availinfo & ImageObserver.HEIGHT) == 0) {
	    reconstruct(ImageObserver.HEIGHT);
	}
	return height;
    }

    /**
     * Return the height of the original image source.
     * If the height isn't known, then the ImageObserver object will be
     * notified when the data is available.
     */
    public synchronized int getHeight(ImageObserver iw) {
	if (src != null) {
	    src.checkSecurity(null, false);
	}
	if ((availinfo & ImageObserver.HEIGHT) == 0) {
	    addWatcher(iw, true);
	    return -1;
	}
	return height;
    }

    /**
     * Return a property of the image by name.  Individual property names
     * are defined by the various image formats.  If a property is not
     * defined for a particular image, then this method will return the
     * UndefinedProperty object.  If the properties for this image are
     * not yet known, then this method will return null and the ImageObserver
     * object will be notified later.  The property name "comment" should
     * be used to store an optional comment which can be presented to
     * the user as a description of the image, its source, or its author.
     */
    public Object getProperty(String name, ImageObserver observer) {
	if (src != null) {
	    src.checkSecurity(null, false);
	}
	if (properties == null) {
	    addWatcher(observer, true);
	    return null;
	}
	Object o = properties.get(name);
	if (o == null) {
	    o = Image.UndefinedProperty;
	}
	return o;
    }

    public boolean hasError() {
	if (src != null) {
	    src.checkSecurity(null, false);
	}
	return (availinfo & ImageObserver.ERROR) != 0;
    }

    public int check(ImageObserver iw) {
	if (src != null) {
	    src.checkSecurity(null, false);
	}
	if ((availinfo & ImageObserver.ERROR) == 0 &&
	    ((~availinfo) & (ImageObserver.WIDTH |
			     ImageObserver.HEIGHT |
			     ImageObserver.PROPERTIES)) != 0) {
	    addWatcher(iw, false);
	}
	return availinfo;
    }

    public void preload(ImageObserver iw) {
	if (src != null) {
	    src.checkSecurity(null, false);
	}
	if ((availinfo & ImageObserver.ALLBITS) == 0) {
	    addWatcher(iw, true);
	}
    }

    private synchronized void addWatcher(ImageObserver iw, boolean load) {
	if ((availinfo & ImageObserver.ERROR) != 0) {
	    if (iw != null) {
		iw.imageUpdate(this, ImageObserver.ERROR|ImageObserver.ABORT,
			       -1, -1, -1, -1);
	    }
	    return;
	}
	if (info == null) {
	    info = new ImageInfoGrabber(this);
	    info.setupConsumer();
	}
	info.addWatcher(iw);
	if (load) {
	    info.getInfo();
	}
    }

    private synchronized void reconstruct(int flags) {
	if ((flags & ~availinfo) != 0) {
	    if ((availinfo & ImageObserver.ERROR) != 0) {
		return;
	    }
	    if (info == null) {
		info = new ImageInfoGrabber(this);
	    }
	    info.getInfo();
	    while ((flags & ~availinfo) != 0) {
		try {
		    wait();
		} catch (InterruptedException e) {
		    Thread.currentThread().interrupt();
		    return;
		}
		if ((availinfo & ImageObserver.ERROR) != 0) {
		    return;
		}
	    }
	}
    }

    synchronized void addInfo(int newinfo) {
	availinfo |= newinfo;
	notifyAll();
	if (((~availinfo) & (ImageObserver.WIDTH |
			     ImageObserver.HEIGHT |
			     ImageObserver.PROPERTIES)) == 0) {
	    info.stopInfo();
	}
    }

    void setDimensions(int w, int h) {
	width = w;
	height = h;
	addInfo(ImageObserver.WIDTH | ImageObserver.HEIGHT);
    }

    void setProperties(Hashtable props) {
	if (props == null) {
	    props = new Hashtable();
	}
	properties = props;
	addInfo(ImageObserver.PROPERTIES);
    }

    synchronized void infoDone(int status) {
	if (status == ImageConsumer.IMAGEERROR ||
	    ((~availinfo) & (ImageObserver.WIDTH |
			     ImageObserver.HEIGHT)) != 0) {
	    addInfo(ImageObserver.ERROR);
	} else if ((availinfo & ImageObserver.PROPERTIES) == 0) {
	    setProperties(null);
	}
    }

    public void flush() {
	if (src != null) {
	    src.checkSecurity(null, false);
	}
	if (!(source instanceof OffScreenImageSource)) {
	    Enumeration enum;
	    synchronized (this) {
		availinfo &= ~ImageObserver.ERROR;
		enum = representations.elements();
		representations = new Hashtable();
		if (source instanceof InputStreamImageSource) {
		    ((InputStreamImageSource) source).flush();
		}
	    }
	    while (enum.hasMoreElements()) {
		ImageRepresentation ir =
		    (ImageRepresentation) enum.nextElement();
		ir.abort();
	    }
	}
    }

    Hashtable representations = new Hashtable();

    protected ImageRepresentation getImageRep(int w, int h) {
	if (src != null) {
	    src.checkSecurity(null, false);
	}
	String key = w + "x" + h;
	ImageRepresentation ir = (ImageRepresentation)representations.get(key);
	if (ir == null) {
	    // Now try it synchronized and add it if it isn't there
	    synchronized (this) {
		ir = (ImageRepresentation)representations.get(key);
		if (ir == null) {
		    ir = new ImageRepresentation(this, w, h, 0);
		    if (source instanceof OffScreenImageSource) {
			ir.offscreen = true;
		    } else {
			representations.put(key, ir);
		    }
		}
	    }
	}
	return ir;
    }
}

class ImageInfoGrabber extends ImageWatched implements ImageConsumer {
    Image image;

    public ImageInfoGrabber(Image img) {
	image = img;
    }

    public void setupConsumer() {
	image.getSource().addConsumer(this);
    }

    public void getInfo() {
	image.getSource().startProduction(this);
    }

    public void stopInfo() {
	image.getSource().removeConsumer(this);
	watchers = null;
    }

    public void setDimensions(int w, int h) {
	image.setDimensions(w, h);
	newInfo(image, (ImageObserver.WIDTH | ImageObserver.HEIGHT),
		0, 0, w, h);
    }

    public void setProperties(Hashtable props) {
	image.setProperties(props);
	newInfo(image, ImageObserver.PROPERTIES, 0, 0, 0, 0);
    }

    public void setColorModel(ColorModel model) {
	return;
    }

    public void setHints(int hints) {
	return;
    }

    public void setPixels(int srcX, int srcY, int srcW, int srcH,
			  ColorModel model,
			  byte pixels[], int srcOff, int srcScan) {
	return;
    }

    public void setPixels(int srcX, int srcY, int srcW, int srcH,
			  ColorModel model,
			  int pixels[], int srcOff, int srcScan) {
	return;
    }

    public void imageComplete(int status) {
	image.getSource().removeConsumer(this);
	if (status == ImageConsumer.IMAGEERROR) {
	    newInfo(image, ImageObserver.ERROR, -1, -1, -1, -1);
	} else if (status == ImageConsumer.IMAGEABORTED) {
	    newInfo(image, ImageObserver.ABORT, -1, -1, -1, -1);
	}
	image.infoDone(status);
    }
}