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