/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Igor V. Stolyarov
*/
/*
* Created on 22.12.2004
*
*/
package org.apache.harmony.awt.gl.image;
import java.util.ConcurrentModificationException;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;
import org.apache.harmony.awt.gl.ImageSurface;
import org.apache.harmony.awt.internal.nls.Messages;
import com.jgraph.gaeawt.java.awt.Graphics;
import com.jgraph.gaeawt.java.awt.Image;
import com.jgraph.gaeawt.java.awt.image.BufferedImage;
import com.jgraph.gaeawt.java.awt.image.ColorModel;
import com.jgraph.gaeawt.java.awt.image.ImageConsumer;
import com.jgraph.gaeawt.java.awt.image.ImageObserver;
import com.jgraph.gaeawt.java.awt.image.ImageProducer;
import com.jgraph.gaeawt.java.awt.image.WritableRaster;
/**
* This class represent implementation of abstact Image class
*/
public class OffscreenImage extends Image implements ImageConsumer
{
static final ColorModel rgbCM = ColorModel.getRGBdefault();
ImageProducer src;
BufferedImage image;
ColorModel cm;
WritableRaster raster;
boolean isIntRGB;
Hashtable<?, ?> properties;
Vector<ImageObserver> observers;
int width;
int height;
int imageState;
int hints;
private boolean producing;
private boolean done;
private ImageSurface imageSurf;
public OffscreenImage(ImageProducer ip)
{
imageState = 0;
src = ip;
width = -1;
height = -1;
observers = new Vector<ImageObserver>();
producing = false;
done = false;
}
@Override
public Object getProperty(String name, ImageObserver observer)
{
if (name == null)
{
// awt.38=Property name is not defined
throw new NullPointerException(Messages.getString("awt.38")); //$NON-NLS-1$
}
if (!done && properties == null)
{
startProduction(observer);
}
if (properties == null)
{
return null;
}
Object prop = properties.get(name);
if (prop == null)
{
prop = UndefinedProperty;
}
return prop;
}
@Override
public ImageProducer getSource()
{
return src;
}
@Override
public int getWidth(ImageObserver observer)
{
if (!done && (imageState & ImageObserver.WIDTH) == 0)
{
startProduction(observer);
}
return width;
}
@Override
public int getHeight(ImageObserver observer)
{
if (!done && (imageState & ImageObserver.HEIGHT) == 0)
{
startProduction(observer);
}
return height;
}
@Override
public Graphics getGraphics()
{
// awt.39=This method is not implemented for image obtained from ImageProducer
throw new UnsupportedOperationException(Messages.getString("awt.39")); //$NON-NLS-1$
}
@Override
public void flush()
{
imageUpdate(ImageObserver.ABORT, -1, -1, -1, -1);
synchronized (this)
{
imageState = 0;
image = null;
imageSurf = null;
cm = null;
raster = null;
hints = 0;
width = -1;
height = -1;
}
}
public void setProperties(Hashtable<?, ?> properties)
{
synchronized (this)
{
this.properties = properties;
}
imageUpdate(ImageObserver.PROPERTIES);
}
public synchronized void setColorModel(ColorModel cm)
{
this.cm = cm;
}
/*
* We suppose what in case loading JPEG image then image has DirectColorModel
* and for infill image Raster will use setPixels method with int array.
*
* In case loading GIF image, for raster infill, is used setPixels method with
* byte array and Color Model is IndexColorModel. But Color Model may
* be changed during this process. Then is called setPixels method with
* int array and image force to default color model - int ARGB. The rest
* pixels are sending in DirectColorModel.
*/
public void setPixels(int x, int y, int w, int h, ColorModel model,
int[] pixels, int off, int scansize)
{
if (raster == null)
{
if (cm == null)
{
if (model == null)
{
// awt.3A=Color Model is null
throw new NullPointerException(Messages.getString("awt.3A")); //$NON-NLS-1$
}
cm = model;
}
createRaster();
}
if (model == null)
{
model = cm;
}
if (cm != model)
{
forceToIntARGB();
}
int[] db = raster.getDataBuffer();
int[] surfData = db;
synchronized (surfData)
{
if (cm == model && raster.getNumDataElements() == 1)
{
int data[] = surfData;
int scanline = raster.getWidth();
int rof = y * scanline + x;
for (int lineOff = off, line = y; line < y + h; line++, lineOff += scansize, rof += scanline)
{
System.arraycopy(pixels, lineOff, data, rof, w);
}
}
else if (isIntRGB)
{
int buff[] = new int[w];
int data[] = surfData;
int scanline = raster.getWidth();
int rof = y * scanline + x;
for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize, rof += scanline)
{
for (int sx = x, idx = 0; sx < x + w; sx++, idx++)
{
buff[idx] = pixels[sOff + idx];
}
System.arraycopy(buff, 0, data, rof, w);
}
}
else
{
int buf;
for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize)
{
for (int sx = x, idx = 0; sx < x + w; sx++, idx++)
{
int rgb = pixels[sOff + idx];
buf = rgb;
raster.setDataElements(sx, sy, buf);
}
}
}
}
imageUpdate(ImageObserver.SOMEBITS);
}
public void setPixels(int x, int y, int w, int h, ColorModel model,
byte[] pixels, int off, int scansize)
{
if (raster == null)
{
if (cm == null)
{
if (model == null)
{
// awt.3A=Color Model is null
throw new NullPointerException(Messages.getString("awt.3A")); //$NON-NLS-1$
}
cm = model;
}
createRaster();
}
if (model == null)
{
model = cm;
}
if (model != cm && cm != rgbCM)
{
forceToIntARGB();
}
int[] db = raster.getDataBuffer();
int[] surfData = db;
synchronized (surfData)
{
if (isIntRGB)
{
int buff[] = new int[w];
int data[] = surfData;
int scanline = raster.getWidth();
int rof = + y * scanline + x;
for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize, rof += scanline)
{
for (int sx = x, idx = 0; sx < x + w; sx++, idx++)
{
buff[idx] = pixels[sOff + idx] & 0xff;
}
System.arraycopy(buff, 0, data, rof, w);
}
}
for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize)
{
for (int sx = x, idx = 0; sx < x + w; sx++, idx++)
{
int rgb = pixels[sOff + idx] & 0xff;
raster.setDataElements(sx, sy, rgb);
}
}
}
imageUpdate(ImageObserver.SOMEBITS);
}
public void setDimensions(int width, int height)
{
if (width <= 0 || height <= 0)
{
imageComplete(IMAGEERROR);
return;
}
synchronized (this)
{
this.width = width;
this.height = height;
}
imageUpdate(ImageObserver.WIDTH | ImageObserver.HEIGHT);
}
public void setHints(int hints)
{
synchronized (this)
{
this.hints = hints;
}
}
public void imageComplete(int state)
{
int flag;
switch (state)
{
case IMAGEABORTED:
flag = ImageObserver.ABORT;
break;
case IMAGEERROR:
flag = ImageObserver.ERROR | ImageObserver.ABORT;
break;
case SINGLEFRAMEDONE:
flag = ImageObserver.FRAMEBITS;
break;
case STATICIMAGEDONE:
flag = ImageObserver.ALLBITS;
break;
default:
// awt.3B=Incorrect ImageConsumer completion status
throw new IllegalArgumentException(Messages.getString("awt.3B")); //$NON-NLS-1$
}
imageUpdate(flag);
if ((imageState & (ImageObserver.ERROR | ImageObserver.ABORT | ImageObserver.ALLBITS)) != 0)
{
stopProduction();
}
}
public BufferedImage getBufferedImage()
{
if (image == null)
{
ColorModel model = getColorModel();
WritableRaster wr = getRaster();
if (model != null && wr != null)
{
image = new BufferedImage(model, wr, null);
}
}
return image;
}
public int checkImage(ImageObserver observer)
{
synchronized (this)
{
addObserver(observer);
}
return imageState;
}
public boolean prepareImage(ImageObserver observer)
{
if (!done)
{
if ((imageState & ImageObserver.ERROR) != 0)
{
if (observer != null)
{
observer.imageUpdate(this, ImageObserver.ERROR
| ImageObserver.ABORT, -1, -1, -1, -1);
}
return false;
}
startProduction(observer);
}
return ((imageState & ImageObserver.ALLBITS) != 0);
}
public ColorModel getColorModel()
{
if (cm == null)
{
startProduction(null);
}
return cm;
}
public WritableRaster getRaster()
{
if (raster == null)
{
startProduction(null);
}
return raster;
}
public int getState()
{
return imageState;
}
private void addObserver(ImageObserver observer)
{
if (observer != null)
{
if (observers.contains(observer))
return;
if ((imageState & ImageObserver.ERROR) != 0)
{
observer.imageUpdate(this, ImageObserver.ERROR
| ImageObserver.ABORT, -1, -1, -1, -1);
return;
}
if ((imageState & ImageObserver.ALLBITS) != 0)
{
observer.imageUpdate(this, imageState, 0, 0, width, height);
return;
}
synchronized (observers)
{
observers.add(observer);
}
}
}
private void startProduction(ImageObserver observer)
{
addObserver(observer);
if (!producing && !done)
{
synchronized (this)
{
imageState &= ~ImageObserver.ABORT;
producing = true;
src.startProduction(this);
}
}
}
private synchronized void stopProduction()
{
producing = false;
src.removeConsumer(this);
synchronized (observers)
{
observers.clear();
}
}
private void createRaster()
{
try
{
raster = cm.createCompatibleWritableRaster(width, height);
isIntRGB = true;
}
catch (Exception e)
{
cm = ColorModel.getRGBdefault();
raster = cm.createCompatibleWritableRaster(width, height);
isIntRGB = true;
}
}
private void imageUpdate(int state)
{
imageUpdate(state, 0, 0, width, height);
}
private void imageUpdate(int state, int x, int y, int width, int height)
{
synchronized (this)
{
imageState |= state;
if ((imageState & (ImageObserver.ALLBITS)) != 0)
{
done = true;
}
}
ImageObserver observer = null;
for (Iterator<ImageObserver> i = observers.iterator(); i.hasNext();)
{
try
{
observer = i.next();
}
catch (ConcurrentModificationException e)
{
i = observers.iterator();
continue;
}
observer.imageUpdate(this, imageState, x, y, width, height);
}
}
private void forceToIntARGB()
{
int w = raster.getWidth();
int h = raster.getHeight();
WritableRaster destRaster = rgbCM.createCompatibleWritableRaster(w, h);
int pixels[] = new int[w];
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
pixels[x] = raster.getDataElements(x, y);
}
destRaster.setDataElements(0, y, w, 1, pixels);
}
synchronized (this)
{
if (imageSurf != null)
{
imageSurf.dispose();
imageSurf = null;
}
if (image != null)
{
image.flush();
image = null;
}
cm = rgbCM;
raster = destRaster;
isIntRGB = true;
}
}
public ImageSurface getImageSurface()
{
if (imageSurf == null)
{
ColorModel model = getColorModel();
WritableRaster wr = getRaster();
if (model != null && wr != null)
{
imageSurf = new ImageSurface(model, wr);
}
}
return imageSurf;
}
}