001: /*
002: * @(#)PixelStore.java 1.31 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.Image;
031: import java.awt.image.*;
032: import java.util.Hashtable;
033: import sun.misc.Ref;
034:
035: /**
036: * A memory cache object for pixel data. The actual pixels are stored
037: * in a Ref so that they can be freed when necessary.
038: *
039: * @version 1.27 08/19/02
040: * @author Jim Graham
041: */
042: public abstract class PixelStore extends Ref {
043: int width;
044: int height;
045: ColorModel colormodel;
046: Hashtable properties;
047: boolean seen[];
048: int numlines;
049: int availinfo;
050: int hints;
051:
052: public PixelStore() {
053: }
054:
055: public PixelStore(int w, int h) {
056: setDimensions(w, h);
057: }
058:
059: public PixelStore(int w, int h, ColorModel cm) {
060: setDimensions(w, h);
061: setColorModel(cm);
062: }
063:
064: public synchronized void setDimensions(int w, int h) {
065: width = w;
066: height = h;
067: availinfo |= ImageObserver.WIDTH | ImageObserver.HEIGHT;
068: }
069:
070: public synchronized void setProperties(Hashtable props) {
071: properties = props;
072: availinfo |= ImageObserver.PROPERTIES;
073: }
074:
075: public synchronized void setColorModel(ColorModel cm) {
076: colormodel = cm;
077: }
078:
079: public synchronized void setHints(int h) {
080: hints = h;
081: }
082:
083: protected void recordPixels(int x, int y, int w, int h) {
084: numlines = Math.max(numlines, y + h);
085: if ((hints & ImageConsumer.TOPDOWNLEFTRIGHT) == 0) {
086: if (seen == null) {
087: seen = new boolean[height];
088: }
089: for (int i = 0; i < h; i++) {
090: seen[y + i] = true;
091: }
092: }
093: }
094:
095: public synchronized boolean setPixels(int x, int y, int w, int h,
096: byte pix[], int srcoff, int scansize) {
097: recordPixels(x, y, w, h);
098: Object[] lines = (Object[]) get();
099: if (lines != null) {
100: int i = srcoff;
101: for (int Y = y; Y < y + h; Y++) {
102: byte ras[] = (byte[]) lines[Y];
103: int dstoff = offsets[Y] + x;
104: System.arraycopy(pix, i, ras, dstoff, w);
105: i += scansize;
106: }
107: availinfo |= ImageObserver.SOMEBITS;
108: }
109: return (lines != null);
110: }
111:
112: public synchronized boolean setPixels(int x, int y, int w, int h,
113: int pix[], int srcoff, int scansize) {
114: recordPixels(x, y, w, h);
115: Object[] lines = (Object[]) get();
116: if (lines != null) {
117: int i = srcoff;
118: for (int Y = y; Y < y + h; Y++) {
119: int ras[] = (int[]) lines[Y];
120: int dstoff = offsets[Y] + x;
121: System.arraycopy(pix, i, ras, dstoff, w);
122: i += scansize;
123: }
124: availinfo |= ImageObserver.SOMEBITS;
125: }
126: return (lines != null);
127: }
128:
129: public synchronized void imageComplete() {
130: if (get() != null && bit_state == BITS_ALLOCATED) {
131: hints = (ImageConsumer.TOPDOWNLEFTRIGHT
132: | ImageConsumer.COMPLETESCANLINES
133: | ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME);
134: availinfo |= ImageObserver.ALLBITS;
135: }
136: }
137:
138: public synchronized int getWidth() {
139: return width;
140: }
141:
142: public synchronized int getHeight() {
143: return height;
144: }
145:
146: public synchronized ColorModel getColorModel() {
147: return colormodel;
148: }
149:
150: public synchronized int getBitState() {
151: if (bit_state == BITS_ALLOCATED && numlines > 0) {
152: // Trigger a get() to make sure the bits are still there.
153: Object lines = get();
154: }
155: return bit_state;
156: }
157:
158: abstract void replayLines(ImageConsumer ic, int i, int cnt,
159: Object line);
160:
161: public synchronized boolean replay(ImageProducer ip,
162: ImageConsumer ic) {
163: return replay(ip, ic, true);
164: }
165:
166: public synchronized boolean replay(ImageProducer ip,
167: ImageConsumer ic, boolean full) {
168: if (full && (availinfo & ImageObserver.WIDTH) != 0
169: && (availinfo & ImageObserver.HEIGHT) != 0) {
170: ic.setDimensions(width, height);
171: if (!ip.isConsumer(ic)) {
172: return true;
173: }
174: }
175: if (full && (availinfo & ImageObserver.PROPERTIES) != 0) {
176: ic.setProperties(properties);
177: }
178: if (full && colormodel != null) {
179: ic.setColorModel(colormodel);
180: if (!ip.isConsumer(ic)) {
181: return true;
182: }
183: }
184: if (hints != 0) {
185: ic
186: .setHints(hints
187: & (ImageConsumer.TOPDOWNLEFTRIGHT
188: | ImageConsumer.COMPLETESCANLINES
189: | ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME));
190: if (!ip.isConsumer(ic)) {
191: return true;
192: }
193: }
194: Object lines[] = null;
195: if (bit_state == BITS_ALLOCATED && numlines > 0) {
196: lines = (Object[]) get();
197: }
198: if (bit_state == BITS_LOST) {
199: return false;
200: }
201: Thread me = Thread.currentThread();
202: if (ImageFetcher.isFetcher(me)
203: && me.getPriority() > ImageFetcher.LOW_PRIORITY) {
204: me.setPriority(ImageFetcher.LOW_PRIORITY);
205: //me.yield();
206: }
207: if (lines != null) {
208: Object prevline = null;
209: int prevcount = 0;
210: for (int i = 0; i < numlines; i++) {
211: if (seen != null && !seen[i]) {
212: if (prevline != null) {
213: replayLines(ic, i - prevcount, prevcount,
214: prevline);
215: if (!ip.isConsumer(ic)) {
216: return true;
217: }
218: prevline = null;
219: prevcount = 0;
220: }
221: continue;
222: }
223: Object line = lines[i];
224: if (prevline != line && prevline != null) {
225: replayLines(ic, i - prevcount, prevcount, prevline);
226: if (!ip.isConsumer(ic)) {
227: return true;
228: }
229: prevcount = 0;
230: }
231: prevline = line;
232: prevcount++;
233: }
234: if (prevline != null) {
235: replayLines(ic, numlines - prevcount, prevcount,
236: prevline);
237: if (!ip.isConsumer(ic)) {
238: return true;
239: }
240: }
241: }
242: if (full && bit_state == BITS_ALLOCATED
243: && (availinfo & ImageObserver.ALLBITS) != 0) {
244: ic.imageComplete(ImageConsumer.STATICIMAGEDONE);
245: }
246: return true;
247: }
248:
249: static final int NO_BITS_YET = 0;
250: static final int BITS_ALLOCATED = 1;
251: static final int BITS_LOST = 2;
252: int bit_state = NO_BITS_YET;
253: int offsets[];
254:
255: abstract Object allocateLines(int num);
256:
257: public Object reconstitute() {
258: Object[] lines = null;
259: if (bit_state == NO_BITS_YET) {
260: if (((availinfo & ImageObserver.HEIGHT) == 0)
261: || ((availinfo & ImageObserver.WIDTH) == 0)
262: || (colormodel == null)) {
263: return null;
264: }
265: // if the ImageProductionMonitor disallows
266: // production, do not reconstitue the
267: // pixelstore.
268: // image production is disallowed in situations
269: // where we are low in memory.
270: //
271: if (!ImageProductionMonitor.allowsProduction()) {
272: bit_state = BITS_LOST;
273: return null;
274: }
275: bit_state = BITS_ALLOCATED;
276: lines = new Object[height];
277: offsets = new int[height];
278: int i = 0;
279: // If we cannot make it fit in 8 chunks
280: // we should forget it. This is to prevent
281: // the machine from getting into serious
282: // GC turning in very low memory situations.
283: //
284: int bailoutPoint = height / 8;
285: while (i < height) {
286: int trylines = height - i;
287: Object chunk = null;
288: while (chunk == null && trylines > 0) {
289: try {
290: chunk = allocateLines(trylines);
291: if (chunk == null) {
292: break;
293: }
294: } catch (OutOfMemoryError e) {
295: chunk = null;
296: if (trylines / 2 <= bailoutPoint
297: || !ImageProductionMonitor
298: .allowsProduction()) {
299: break;
300: }
301: trylines /= 2;
302: }
303: }
304: if (chunk == null) {
305: bit_state = BITS_LOST;
306: return null;
307: }
308: int off = 0;
309: while (trylines > 0) {
310: lines[i] = chunk;
311: offsets[i] = off;
312: off += width;
313: i++;
314: trylines--;
315: }
316: }
317: } else if (bit_state == BITS_ALLOCATED) {
318: // We had some bits, but they're gone now.
319: bit_state = BITS_LOST;
320: }
321: return lines;
322: }
323: }
|