Home | History | Annotate | Download | only in image
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 /**
     18  * @author Oleg V. Khaschansky
     19  * @version $Revision$
     20  */
     21 /*
     22  * Created on 18.01.2005
     23  */
     24 package org.apache.harmony.awt.gl.image;
     25 
     26 import java.awt.image.ImageConsumer;
     27 import java.awt.image.ImageProducer;
     28 import java.io.IOException;
     29 import java.io.InputStream;
     30 import java.util.ArrayList;
     31 import java.util.Iterator;
     32 import java.util.List;
     33 
     34 /**
     35  * This is an abstract class that encapsulates a main part of ImageProducer functionality
     36  * for the images being decoded by the native decoders, like PNG, JPEG and GIF.
     37  * It helps to integrate image decoders into producer/consumer model. It provides
     38  * functionality for working with several decoder instances and several image consumers
     39  * simultaneously.
     40  */
     41 public abstract class DecodingImageSource implements ImageProducer {
     42     List<ImageConsumer> consumers = new ArrayList<ImageConsumer>(5);
     43     List<ImageDecoder> decoders = new ArrayList<ImageDecoder>(5);
     44     boolean loading;
     45 
     46     ImageDecoder decoder;
     47 
     48     protected abstract boolean checkConnection();
     49 
     50     protected abstract InputStream getInputStream();
     51 
     52     public synchronized void addConsumer(ImageConsumer ic) {
     53         if (!checkConnection()) { // No permission for this consumer
     54             ic.imageComplete(ImageConsumer.IMAGEERROR);
     55             return;
     56         }
     57 
     58         ImageConsumer cons = findConsumer(consumers, ic);
     59 
     60         if (cons == null) { // Try to look in the decoders
     61             ImageDecoder d = null;
     62 
     63             // Check for all existing decoders
     64             for (Iterator<ImageDecoder> i = decoders.iterator(); i.hasNext();) {
     65                 d = i.next();
     66                 cons = findConsumer(d.consumers, ic);
     67                 if (cons != null) {
     68                     break;
     69                 }
     70             }
     71         }
     72 
     73         if (cons == null) { // Not found, add this consumer
     74             consumers.add(ic);
     75         }
     76     }
     77 
     78     /**
     79      * This method stops sending data to the given consumer
     80      * @param ic - consumer
     81      */
     82     private void abortConsumer(ImageConsumer ic) {
     83         ic.imageComplete(ImageConsumer.IMAGEERROR);
     84         consumers.remove(ic);
     85     }
     86 
     87     /**
     88      * This method stops sending data to the list of consumers.
     89      * @param consumersList - list of consumers
     90      */
     91     private void abortAllConsumers(List<ImageConsumer> consumersList) {
     92         for (ImageConsumer imageConsumer : consumersList) {
     93             abortConsumer(imageConsumer);
     94         }
     95     }
     96 
     97     public synchronized void removeConsumer(ImageConsumer ic) {
     98         ImageDecoder d = null;
     99 
    100         // Remove in all existing decoders
    101         for (Iterator<ImageDecoder> i = decoders.iterator(); i.hasNext();) {
    102             d = i.next();
    103             removeConsumer(d.consumers, ic);
    104             if (d.consumers.size() <= 0) {
    105                 d.terminate();
    106             }
    107         }
    108 
    109         // Remove in the current queue of consumers
    110         removeConsumer(consumers, ic);
    111     }
    112 
    113     /**
    114      * Static implementation of removeConsumer method
    115      * @param consumersList - list of consumers
    116      * @param ic - consumer to be removed
    117      */
    118     private static void removeConsumer(List<ImageConsumer> consumersList, ImageConsumer ic) {
    119         ImageConsumer cons = null;
    120 
    121         for (Iterator<ImageConsumer> i = consumersList.iterator(); i.hasNext();) {
    122             cons = i.next();
    123             if (cons.equals(ic)) {
    124                 i.remove();
    125             }
    126         }
    127     }
    128 
    129     public void requestTopDownLeftRightResend(ImageConsumer consumer) {
    130         // Do nothing
    131     }
    132 
    133     public synchronized void startProduction(ImageConsumer ic) {
    134         if (ic != null) {
    135             addConsumer(ic);
    136         }
    137 
    138         if (!loading && consumers.size() > 0) {
    139             ImageLoader.addImageSource(this);
    140             loading = true;
    141         }
    142     }
    143 
    144     public synchronized boolean isConsumer(ImageConsumer ic) {
    145         ImageDecoder d = null;
    146 
    147         // Check for all existing decoders
    148         for (Iterator<ImageDecoder> i = decoders.iterator(); i.hasNext();) {
    149             d = i.next();
    150             if (findConsumer(d.consumers, ic) != null) {
    151                 return true;
    152             }
    153         }
    154 
    155         // Check current queue of consumers
    156         return findConsumer(consumers, ic) != null;
    157     }
    158 
    159     /**
    160      * Checks if the consumer is in the list and returns it it is there
    161      * @param consumersList - list of consumers
    162      * @param ic - consumer
    163      * @return consumer if found, null otherwise
    164      */
    165     private static ImageConsumer findConsumer(List<ImageConsumer> consumersList, ImageConsumer ic) {
    166         ImageConsumer res = null;
    167 
    168         for (Iterator<ImageConsumer> i = consumersList.iterator(); i.hasNext();) {
    169             res = i.next();
    170             if (res.equals(ic)) {
    171                 return res;
    172             }
    173         }
    174 
    175         return null;
    176     }
    177 
    178     /**
    179      * Use this method to finish decoding or lock the list of consumers
    180      * for a particular decoder
    181      * @param d - decoder
    182      */
    183     synchronized void lockDecoder(ImageDecoder d) {
    184         if (d == decoder) {
    185             decoder = null;
    186             startProduction(null);
    187         }
    188     }
    189 
    190     /**
    191      * Tries to find an appropriate decoder for the input stream and adds it
    192      * to the list of decoders
    193      * @return created decoder
    194      */
    195     private ImageDecoder createDecoder() {
    196         InputStream is = getInputStream();
    197 
    198         ImageDecoder decoder;
    199 
    200         if (is == null) {
    201             decoder = null;
    202         } else {
    203             decoder = ImageDecoder.createDecoder(this, is);
    204         }
    205 
    206         if (decoder != null) {
    207             synchronized (this) {
    208                 decoders.add(decoder);
    209                 this.decoder = decoder;
    210                 loading = false;
    211                 consumers = new ArrayList<ImageConsumer>(5); // Reset queue
    212             }
    213 
    214             return decoder;
    215         }
    216         // We were not able to find appropriate decoder
    217         List<ImageConsumer> cs;
    218         synchronized (this) {
    219             cs = consumers;
    220             consumers = new ArrayList<ImageConsumer>(5);
    221             loading = false;
    222         }
    223         abortAllConsumers(cs);
    224 
    225         return null;
    226     }
    227 
    228     /**
    229      * Stop the given decoder and remove it from the list
    230      * @param dr - decoder
    231      */
    232     private synchronized void removeDecoder(ImageDecoder dr) {
    233         lockDecoder(dr);
    234         decoders.remove(dr);
    235     }
    236 
    237     /**
    238      * This method serves as an entry point.
    239      * It starts the decoder and loads the image data.
    240      */
    241     public void load() {
    242         synchronized (this) {
    243             if (consumers.size() == 0) {
    244                 loading = false;
    245                 return;
    246             }
    247         }
    248 
    249         ImageDecoder d = createDecoder();
    250         if (d != null) {
    251             try {
    252                 decoder.decodeImage();
    253             } catch (IOException e) {
    254                 e.printStackTrace();
    255             } finally {
    256                 removeDecoder(d);
    257                 abortAllConsumers(d.consumers);
    258             }
    259         }
    260     }
    261 }
    262