blob: 958d691ce2357a89e54a9e3be921c8ce43a1a4f5 [file] [log] [blame]
/*
* 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 Oleg V. Khaschansky
* @version $Revision$
*/
/*
* Created on 18.01.2005
*/
package org.apache.harmony.awt.gl.image;
import java.awt.image.ImageConsumer;
import java.awt.image.ImageProducer;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* This is an abstract class that encapsulates a main part of ImageProducer functionality
* for the images being decoded by the native decoders, like PNG, JPEG and GIF.
* It helps to integrate image decoders into producer/consumer model. It provides
* functionality for working with several decoder instances and several image consumers
* simultaneously.
*/
public abstract class DecodingImageSource implements ImageProducer {
List<ImageConsumer> consumers = new ArrayList<ImageConsumer>(5);
List<ImageDecoder> decoders = new ArrayList<ImageDecoder>(5);
boolean loading;
ImageDecoder decoder;
protected abstract boolean checkConnection();
protected abstract InputStream getInputStream();
public synchronized void addConsumer(ImageConsumer ic) {
if (!checkConnection()) { // No permission for this consumer
ic.imageComplete(ImageConsumer.IMAGEERROR);
return;
}
ImageConsumer cons = findConsumer(consumers, ic);
if (cons == null) { // Try to look in the decoders
ImageDecoder d = null;
// Check for all existing decoders
for (Iterator<ImageDecoder> i = decoders.iterator(); i.hasNext();) {
d = i.next();
cons = findConsumer(d.consumers, ic);
if (cons != null) {
break;
}
}
}
if (cons == null) { // Not found, add this consumer
consumers.add(ic);
}
}
/**
* This method stops sending data to the given consumer
* @param ic - consumer
*/
private void abortConsumer(ImageConsumer ic) {
ic.imageComplete(ImageConsumer.IMAGEERROR);
consumers.remove(ic);
}
/**
* This method stops sending data to the list of consumers.
* @param consumersList - list of consumers
*/
private void abortAllConsumers(List<ImageConsumer> consumersList) {
for (ImageConsumer imageConsumer : consumersList) {
abortConsumer(imageConsumer);
}
}
public synchronized void removeConsumer(ImageConsumer ic) {
ImageDecoder d = null;
// Remove in all existing decoders
for (Iterator<ImageDecoder> i = decoders.iterator(); i.hasNext();) {
d = i.next();
removeConsumer(d.consumers, ic);
if (d.consumers.size() <= 0) {
d.terminate();
}
}
// Remove in the current queue of consumers
removeConsumer(consumers, ic);
}
/**
* Static implementation of removeConsumer method
* @param consumersList - list of consumers
* @param ic - consumer to be removed
*/
private static void removeConsumer(List<ImageConsumer> consumersList, ImageConsumer ic) {
ImageConsumer cons = null;
for (Iterator<ImageConsumer> i = consumersList.iterator(); i.hasNext();) {
cons = i.next();
if (cons.equals(ic)) {
i.remove();
}
}
}
public void requestTopDownLeftRightResend(ImageConsumer consumer) {
// Do nothing
}
public synchronized void startProduction(ImageConsumer ic) {
if (ic != null) {
addConsumer(ic);
}
if (!loading && consumers.size() > 0) {
ImageLoader.addImageSource(this);
loading = true;
}
}
public synchronized boolean isConsumer(ImageConsumer ic) {
ImageDecoder d = null;
// Check for all existing decoders
for (Iterator<ImageDecoder> i = decoders.iterator(); i.hasNext();) {
d = i.next();
if (findConsumer(d.consumers, ic) != null) {
return true;
}
}
// Check current queue of consumers
return findConsumer(consumers, ic) != null;
}
/**
* Checks if the consumer is in the list and returns it it is there
* @param consumersList - list of consumers
* @param ic - consumer
* @return consumer if found, null otherwise
*/
private static ImageConsumer findConsumer(List<ImageConsumer> consumersList, ImageConsumer ic) {
ImageConsumer res = null;
for (Iterator<ImageConsumer> i = consumersList.iterator(); i.hasNext();) {
res = i.next();
if (res.equals(ic)) {
return res;
}
}
return null;
}
/**
* Use this method to finish decoding or lock the list of consumers
* for a particular decoder
* @param d - decoder
*/
synchronized void lockDecoder(ImageDecoder d) {
if (d == decoder) {
decoder = null;
startProduction(null);
}
}
/**
* Tries to find an appropriate decoder for the input stream and adds it
* to the list of decoders
* @return created decoder
*/
private ImageDecoder createDecoder() {
InputStream is = getInputStream();
ImageDecoder decoder;
if (is == null) {
decoder = null;
} else {
decoder = ImageDecoder.createDecoder(this, is);
}
if (decoder != null) {
synchronized (this) {
decoders.add(decoder);
this.decoder = decoder;
loading = false;
consumers = new ArrayList<ImageConsumer>(5); // Reset queue
}
return decoder;
}
// We were not able to find appropriate decoder
List<ImageConsumer> cs;
synchronized (this) {
cs = consumers;
consumers = new ArrayList<ImageConsumer>(5);
loading = false;
}
abortAllConsumers(cs);
return null;
}
/**
* Stop the given decoder and remove it from the list
* @param dr - decoder
*/
private synchronized void removeDecoder(ImageDecoder dr) {
lockDecoder(dr);
decoders.remove(dr);
}
/**
* This method serves as an entry point.
* It starts the decoder and loads the image data.
*/
public void load() {
synchronized (this) {
if (consumers.size() == 0) {
loading = false;
return;
}
}
ImageDecoder d = createDecoder();
if (d != null) {
try {
decoder.decodeImage();
} catch (IOException e) {
e.printStackTrace();
} finally {
removeDecoder(d);
abortAllConsumers(d.consumers);
}
}
}
}