| /* |
| * 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); |
| } |
| } |
| } |
| } |