001: /*
002: * @(#)ImageRepresentation.java 1.64 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package sun.awt.image;
029:
030: import java.awt.Color;
031: import java.awt.Graphics;
032: import java.awt.AWTException;
033: import java.awt.Rectangle;
034: import java.awt.image.ColorModel;
035: import java.awt.image.ImageConsumer;
036: import java.awt.image.ImageObserver;
037: import sun.awt.image.ImageWatched;
038: import sun.awt.AWTFinalizeable;
039: import sun.awt.AWTFinalizer;
040: import java.util.Hashtable;
041:
042: public abstract class ImageRepresentation extends ImageWatched
043: implements ImageConsumer, AWTFinalizeable {
044: private int pData;
045: private InputStreamImageSource src;
046: Image image;
047: private int tag;
048: private int width;
049: private int height;
050: private int hints;
051: private int availinfo;
052: boolean offscreen;
053: private Rectangle newbits;
054:
055: /**
056: * Create an ImageRepresentation for the given Image scaled
057: * to the given width and height and dithered or converted to
058: * a ColorModel appropriate for the given image tag.
059: */
060: public ImageRepresentation(Image im, int t) {
061: image = im;
062: tag = t;
063: if (image.getSource() instanceof InputStreamImageSource) {
064: src = (InputStreamImageSource) image.getSource();
065: }
066: }
067:
068: /**
069: * Initialize this ImageRepresentation object to act as the
070: * destination drawable for this OffScreen Image.
071: */
072: protected abstract void offscreenInit(Color bg);
073:
074: /* TODO: Only used for Frame.setIcon - should use ImageWatcher instead */
075: public synchronized void reconstruct(int flags) {
076: if (src != null) {
077: src.checkSecurity(null, false);
078: }
079: int missinginfo = flags & ~availinfo;
080: if ((availinfo & ImageObserver.ERROR) == 0 && missinginfo != 0) {
081: numWaiters++;
082: try {
083: startProduction();
084: missinginfo = flags & ~availinfo;
085: while ((availinfo & ImageObserver.ERROR) == 0
086: && missinginfo != 0) {
087: try {
088: wait();
089: } catch (InterruptedException e) {
090: Thread.currentThread().interrupt();
091: return;
092: }
093: missinginfo = flags & ~availinfo;
094: }
095: } finally {
096: decrementWaiters();
097: }
098: }
099: }
100:
101: public int getWidth() {
102: return width;
103: }
104:
105: public int getHeight() {
106: return height;
107: }
108:
109: public void setDimensions(int w, int h) {
110: if (src != null) {
111: src.checkSecurity(null, false);
112: }
113: image.setDimensions(w, h);
114: newInfo(image, (ImageObserver.WIDTH | ImageObserver.HEIGHT), 0,
115: 0, w, h);
116: width = w;
117: height = h;
118: if (width <= 0 || height <= 0) {
119: imageComplete(ImageConsumer.IMAGEERROR);
120: return;
121: }
122: availinfo |= ImageObserver.WIDTH | ImageObserver.HEIGHT;
123: }
124:
125: public void setProperties(Hashtable props) {
126: if (src != null) {
127: src.checkSecurity(null, false);
128: }
129: image.setProperties(props);
130: newInfo(image, ImageObserver.PROPERTIES, 0, 0, 0, 0);
131: }
132:
133: public void setColorModel(ColorModel model) {
134: if (src != null) {
135: src.checkSecurity(null, false);
136: }
137: }
138:
139: public void setHints(int h) {
140: if (src != null) {
141: src.checkSecurity(null, false);
142: }
143: hints = h;
144: }
145:
146: protected abstract boolean setBytePixels(int x, int y, int w,
147: int h, ColorModel model, byte pix[], int off, int scansize);
148:
149: public void setPixels(int x, int y, int w, int h, ColorModel model,
150: byte pix[], int off, int scansize) {
151: if (src != null) {
152: src.checkSecurity(null, false);
153: }
154: boolean ok = false;
155: int cx, cy, cw, ch;
156: synchronized (this ) {
157: if (newbits == null) {
158: newbits = new Rectangle(0, 0, width, height);
159: }
160: if (setBytePixels(x, y, w, h, model, pix, off, scansize)) {
161: availinfo |= ImageObserver.SOMEBITS;
162: ok = true;
163: }
164: cx = newbits.x;
165: cy = newbits.y;
166: cw = newbits.width;
167: ch = newbits.height;
168: }
169: if (ok && !offscreen
170: && ((availinfo & ImageObserver.FRAMEBITS) == 0)) {
171: newInfo(image, ImageObserver.SOMEBITS, cx, cy, cw, ch);
172: }
173: }
174:
175: protected abstract boolean setIntPixels(int x, int y, int w, int h,
176: ColorModel model, int pix[], int off, int scansize);
177:
178: public void setPixels(int x, int y, int w, int h, ColorModel model,
179: int pix[], int off, int scansize) {
180: if (src != null) {
181: src.checkSecurity(null, false);
182: }
183: boolean ok = false;
184: int cx, cy, cw, ch;
185: synchronized (this ) {
186: if (newbits == null) {
187: newbits = new Rectangle(0, 0, width, height);
188: }
189: if (setIntPixels(x, y, w, h, model, pix, off, scansize)) {
190: availinfo |= ImageObserver.SOMEBITS;
191: ok = true;
192: }
193: cx = newbits.x;
194: cy = newbits.y;
195: cw = newbits.width;
196: ch = newbits.height;
197: }
198: if (ok && !offscreen
199: && ((availinfo & ImageObserver.FRAMEBITS) == 0)) {
200: newInfo(image, ImageObserver.SOMEBITS, cx, cy, cw, ch);
201: }
202: }
203:
204: private boolean consuming = false;
205:
206: protected abstract boolean finish(boolean force);
207:
208: public void imageComplete(int status) {
209: if (src != null) {
210: src.checkSecurity(null, false);
211: }
212: boolean done;
213: int info;
214: switch (status) {
215: default:
216: case ImageConsumer.IMAGEABORTED:
217: done = true;
218: info = ImageObserver.ABORT;
219: break;
220:
221: case ImageConsumer.IMAGEERROR:
222: image.addInfo(ImageObserver.ERROR);
223: done = true;
224: info = ImageObserver.ERROR;
225: dispose();
226: break;
227:
228: case ImageConsumer.STATICIMAGEDONE:
229: done = true;
230: info = ImageObserver.ALLBITS;
231: if (finish(false)) {
232: image.getSource().requestTopDownLeftRightResend(this );
233: finish(true);
234: }
235: break;
236:
237: case ImageConsumer.SINGLEFRAMEDONE:
238: done = false;
239: info = ImageObserver.FRAMEBITS;
240: break;
241: }
242: synchronized (this ) {
243: if (done) {
244: image.getSource().removeConsumer(this );
245: consuming = false;
246: newbits = null;
247: }
248: availinfo |= info;
249: notifyAll();
250: }
251: if (!offscreen) {
252: newInfo(image, info, 0, 0, width, height);
253: }
254: image.infoDone(status);
255: }
256:
257: /*synchronized*/void startProduction() {
258: if (!ImageProductionMonitor.allowsProduction()) {
259: // we are low on memory so terminate
260: // image loading and flag an image error.
261: //
262: imageComplete(ImageConsumer.IMAGEERROR);
263: return;
264: }
265: if (!consuming) {
266: consuming = true;
267: image.getSource().startProduction(this );
268: }
269: }
270:
271: private int numWaiters;
272:
273: private synchronized void checkConsumption() {
274: if (watchers == null && numWaiters == 0
275: && ((availinfo & ImageObserver.ALLBITS) == 0)) {
276: dispose();
277: }
278: }
279:
280: public synchronized void removeWatcher(ImageObserver iw) {
281: super .removeWatcher(iw);
282: checkConsumption();
283: }
284:
285: private synchronized void decrementWaiters() {
286: --numWaiters;
287: checkConsumption();
288: }
289:
290: public boolean prepare(ImageObserver iw) {
291: if (src != null) {
292: src.checkSecurity(null, false);
293: }
294: if ((availinfo & ImageObserver.ERROR) != 0) {
295: if (iw != null) {
296: iw.imageUpdate(image, ImageObserver.ERROR
297: | ImageObserver.ABORT, -1, -1, -1, -1);
298: }
299: return false;
300: }
301: boolean done = ((availinfo & ImageObserver.ALLBITS) != 0);
302: if (!done) {
303: addWatcher(iw);
304: startProduction();
305: // Some producers deliver image data synchronously
306: done = ((availinfo & ImageObserver.ALLBITS) != 0);
307: }
308: return done;
309: }
310:
311: public int check(ImageObserver iw) {
312: if (src != null) {
313: src.checkSecurity(null, false);
314: }
315: if ((availinfo & (ImageObserver.ERROR | ImageObserver.ALLBITS)) == 0) {
316: addWatcher(iw);
317: }
318: return availinfo;
319: }
320:
321: protected abstract void imageDraw(Graphics g, int x, int y, Color c);
322:
323: protected abstract void imageStretch(Graphics g, int dx1, int dy1,
324: int dx2, int dy2, int sx1, int sy1, int sx2, int sy2,
325: Color c);
326:
327: /*
328: * Delegates to the abstract imageStretch() routine to be implemented by the
329: * subclasses. Opportunities also exist for the subclasses to cache the
330: * scaled image representations to avoid recomputations.
331: */
332: protected void imageScale(Graphics g, int x, int y, int w, int h,
333: Color c, boolean done) {
334: imageStretch(g, x, y, x + w, y + h, 0, 0, width, height, c);
335: }
336:
337: public boolean drawImage(Graphics g, int x, int y, Color c,
338: ImageObserver iw) {
339: if (src != null) {
340: src.checkSecurity(null, false);
341: }
342: if ((availinfo & ImageObserver.ERROR) != 0) {
343: if (iw != null) {
344: iw.imageUpdate(image, ImageObserver.ERROR
345: | ImageObserver.ABORT, -1, -1, -1, -1);
346: }
347: return false;
348: }
349: boolean done = ((availinfo & ImageObserver.ALLBITS) != 0);
350: if (!done) {
351: addWatcher(iw);
352: startProduction();
353: // Some producers deliver image data synchronously
354: done = ((availinfo & ImageObserver.ALLBITS) != 0);
355: }
356: imageDraw(g, x, y, c);
357: return done;
358: }
359:
360: public boolean drawStretchImage(Graphics g, int dx1, int dy1,
361: int dx2, int dy2, int sx1, int sy1, int sx2, int sy2,
362: Color c, ImageObserver iw) {
363: if (src != null) {
364: src.checkSecurity(null, false);
365: }
366: if ((availinfo & ImageObserver.ERROR) != 0) {
367: if (iw != null) {
368: iw.imageUpdate(image, ImageObserver.ERROR
369: | ImageObserver.ABORT, -1, -1, -1, -1);
370: }
371: return false;
372: }
373: boolean done = ((availinfo & ImageObserver.ALLBITS) != 0);
374: if (!done) {
375: addWatcher(iw);
376: startProduction();
377: // Some producers deliver image data synchronously
378: done = ((availinfo & ImageObserver.ALLBITS) != 0);
379: }
380: imageStretch(g, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, c);
381: return done;
382: }
383:
384: public boolean drawScaledImage(Graphics g, int x, int y, int w,
385: int h, Color c, ImageObserver iw) {
386: if (src != null) {
387: src.checkSecurity(null, false);
388: }
389: if ((availinfo & ImageObserver.ERROR) != 0) {
390: if (iw != null) {
391: iw.imageUpdate(image, ImageObserver.ERROR
392: | ImageObserver.ABORT, -1, -1, -1, -1);
393: }
394: return false;
395: }
396: boolean done = ((availinfo & ImageObserver.ALLBITS) != 0);
397: if (!done) {
398: addWatcher(iw);
399: startProduction();
400: // Some producers deliver image data synchronously
401: done = ((availinfo & ImageObserver.ALLBITS) != 0);
402: }
403: if ((~availinfo & (ImageObserver.WIDTH | ImageObserver.HEIGHT)) != 0) {
404: return false;
405: }
406: if (w < 0) {
407: if (h < 0) {
408: w = width;
409: h = height;
410: } else {
411: w = h * width / height;
412: }
413: } else if (h < 0) {
414: h = w * height / width;
415: }
416: if (w == width && h == height) {
417: imageDraw(g, x, y, c);
418: } else {
419: imageScale(g, x, y, w, h, c, done);
420: }
421: return done;
422: }
423:
424: //
425: // Check with all our ImageObservers to see if anybody is still interested.
426: // If not, remove ourselves as a consumer. cf.
427: // InputStreamImageSource.proactivelyUpdateObservers()
428: //
429: void checkForInterest() {
430: newInfo(image, 0, -1, -1, -1, -1);
431: }
432:
433: protected abstract void disposeImage();
434:
435: synchronized void abort() {
436: image.getSource().removeConsumer(this );
437: consuming = false;
438: newbits = null;
439: disposeImage();
440: newInfo(image, ImageObserver.ABORT, -1, -1, -1, -1);
441: availinfo &= ~(ImageObserver.SOMEBITS | ImageObserver.FRAMEBITS
442: | ImageObserver.ALLBITS | ImageObserver.ERROR);
443: }
444:
445: synchronized void dispose() {
446: image.getSource().removeConsumer(this );
447: consuming = false;
448: newbits = null;
449: disposeImage();
450: availinfo &= ~(ImageObserver.SOMEBITS | ImageObserver.FRAMEBITS | ImageObserver.ALLBITS);
451: }
452:
453: AWTFinalizeable finalnext;
454:
455: public void finalize() {
456: AWTFinalizer.addFinalizeable(this );
457: }
458:
459: public void doFinalization() {
460: disposeImage();
461: }
462:
463: public void setNextFinalizeable(AWTFinalizeable o) {
464: finalnext = o;
465: }
466:
467: public AWTFinalizeable getNextFinalizeable() {
468: return finalnext;
469: }
470: }
|