001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Oleg V. Khaschansky
019: * @version $Revision$
020: */package org.apache.harmony.awt.gl.image;
021:
022: import java.awt.image.ImageConsumer;
023: import java.awt.image.ImageProducer;
024: import java.io.IOException;
025: import java.io.InputStream;
026: import java.util.ArrayList;
027: import java.util.Iterator;
028: import java.util.List;
029:
030: /**
031: * This is an abstract class that encapsulates a main part of ImageProducer functionality
032: * for the images being decoded by the native decoders, like PNG, JPEG and GIF.
033: * It helps to integrate image decoders into producer/consumer model. It provides
034: * functionality for working with several decoder instances and several image consumers
035: * simultaneously.
036: */
037: public abstract class DecodingImageSource implements ImageProducer {
038: List<ImageConsumer> consumers = new ArrayList<ImageConsumer>(5);
039: List<ImageDecoder> decoders = new ArrayList<ImageDecoder>(5);
040: boolean loading;
041:
042: ImageDecoder decoder;
043:
044: protected abstract boolean checkConnection();
045:
046: protected abstract InputStream getInputStream();
047:
048: public synchronized void addConsumer(ImageConsumer ic) {
049: if (!checkConnection()) { // No permission for this consumer
050: ic.imageComplete(ImageConsumer.IMAGEERROR);
051: return;
052: }
053:
054: ImageConsumer cons = findConsumer(consumers, ic);
055:
056: if (cons == null) { // Try to look in the decoders
057: ImageDecoder d = null;
058:
059: // Check for all existing decoders
060: for (Iterator<ImageDecoder> i = decoders.iterator(); i
061: .hasNext();) {
062: d = i.next();
063: cons = findConsumer(d.consumers, ic);
064: if (cons != null) {
065: break;
066: }
067: }
068: }
069:
070: if (cons == null) { // Not found, add this consumer
071: consumers.add(ic);
072: }
073: }
074:
075: /**
076: * This method stops sending data to the given consumer
077: * @param ic - consumer
078: */
079: private void abortConsumer(ImageConsumer ic) {
080: ic.imageComplete(ImageConsumer.IMAGEERROR);
081: consumers.remove(ic);
082: }
083:
084: /**
085: * This method stops sending data to the list of consumers.
086: * @param consumersList - list of consumers
087: */
088: private void abortAllConsumers(List<ImageConsumer> consumersList) {
089: for (ImageConsumer imageConsumer : consumersList) {
090: abortConsumer(imageConsumer);
091: }
092: }
093:
094: public synchronized void removeConsumer(ImageConsumer ic) {
095: ImageDecoder d = null;
096:
097: // Remove in all existing decoders
098: for (Iterator<ImageDecoder> i = decoders.iterator(); i
099: .hasNext();) {
100: d = i.next();
101: removeConsumer(d.consumers, ic);
102: if (d.consumers.size() <= 0) {
103: d.terminate();
104: }
105: }
106:
107: // Remove in the current queue of consumers
108: removeConsumer(consumers, ic);
109: }
110:
111: /**
112: * Static implementation of removeConsumer method
113: * @param consumersList - list of consumers
114: * @param ic - consumer to be removed
115: */
116: private static void removeConsumer(
117: List<ImageConsumer> consumersList, ImageConsumer ic) {
118: ImageConsumer cons = null;
119:
120: for (Iterator<ImageConsumer> i = consumersList.iterator(); i
121: .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
149: .hasNext();) {
150: d = i.next();
151: if (findConsumer(d.consumers, ic) != null) {
152: return true;
153: }
154: }
155:
156: // Check current queue of consumers
157: return findConsumer(consumers, ic) != null;
158: }
159:
160: /**
161: * Checks if the consumer is in the list and returns it it is there
162: * @param consumersList - list of consumers
163: * @param ic - consumer
164: * @return consumer if found, null otherwise
165: */
166: private static ImageConsumer findConsumer(
167: List<ImageConsumer> consumersList, ImageConsumer ic) {
168: ImageConsumer res = null;
169:
170: for (Iterator<ImageConsumer> i = consumersList.iterator(); i
171: .hasNext();) {
172: res = i.next();
173: if (res.equals(ic)) {
174: return res;
175: }
176: }
177:
178: return null;
179: }
180:
181: /**
182: * Use this method to finish decoding or lock the list of consumers
183: * for a particular decoder
184: * @param d - decoder
185: */
186: synchronized void lockDecoder(ImageDecoder d) {
187: if (d == decoder) {
188: decoder = null;
189: startProduction(null);
190: }
191: }
192:
193: /**
194: * Tries to find an appropriate decoder for the input stream and adds it
195: * to the list of decoders
196: * @return created decoder
197: */
198: private ImageDecoder createDecoder() {
199: InputStream is = getInputStream();
200:
201: ImageDecoder decoder;
202:
203: if (is == null) {
204: decoder = null;
205: } else {
206: decoder = ImageDecoder.createDecoder(this , is);
207: }
208:
209: if (decoder != null) {
210: synchronized (this ) {
211: decoders.add(decoder);
212: this .decoder = decoder;
213: loading = false;
214: consumers = new ArrayList<ImageConsumer>(5); // Reset queue
215: }
216:
217: return decoder;
218: }
219: // We were not able to find appropriate decoder
220: List<ImageConsumer> cs;
221: synchronized (this ) {
222: cs = consumers;
223: consumers = new ArrayList<ImageConsumer>(5);
224: loading = false;
225: }
226: abortAllConsumers(cs);
227:
228: return null;
229: }
230:
231: /**
232: * Stop the given decoder and remove it from the list
233: * @param dr - decoder
234: */
235: private synchronized void removeDecoder(ImageDecoder dr) {
236: lockDecoder(dr);
237: decoders.remove(dr);
238: }
239:
240: /**
241: * This method serves as an entry point.
242: * It starts the decoder and loads the image data.
243: */
244: public void load() {
245: synchronized (this ) {
246: if (consumers.size() == 0) {
247: loading = false;
248: return;
249: }
250: }
251:
252: ImageDecoder d = createDecoder();
253: if (d != null) {
254: try {
255: decoder.decodeImage();
256: } catch (IOException e) {
257: e.printStackTrace();
258: } finally {
259: removeDecoder(d);
260: abortAllConsumers(d.consumers);
261: }
262: }
263: }
264: }
|