1/*
2 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26/* ****************************************************************
27 ******************************************************************
28 ******************************************************************
29 *** COPYRIGHT (c) Eastman Kodak Company, 1997
30 *** As  an unpublished  work pursuant to Title 17 of the United
31 *** States Code.  All rights reserved.
32 ******************************************************************
33 ******************************************************************
34 ******************************************************************/
35
36package java.awt.image;
37
38import sun.java2d.StateTrackable.State;
39import static sun.java2d.StateTrackable.State.*;
40import sun.java2d.StateTrackableDelegate;
41
42import sun.awt.image.SunWritableRaster;
43
44import java.lang.annotation.Native;
45
46/**
47 * This class exists to wrap one or more data arrays.  Each data array in
48 * the DataBuffer is referred to as a bank.  Accessor methods for getting
49 * and setting elements of the DataBuffer's banks exist with and without
50 * a bank specifier.  The methods without a bank specifier use the default 0th
51 * bank.  The DataBuffer can optionally take an offset per bank, so that
52 * data in an existing array can be used even if the interesting data
53 * doesn't start at array location zero.  Getting or setting the 0th
54 * element of a bank, uses the (0+offset)th element of the array.  The
55 * size field specifies how much of the data array is available for
56 * use.  Size + offset for a given bank should never be greater
57 * than the length of the associated data array.  The data type of
58 * a data buffer indicates the type of the data array(s) and may also
59 * indicate additional semantics, e.g. storing unsigned 8-bit data
60 * in elements of a byte array.  The data type may be TYPE_UNDEFINED
61 * or one of the types defined below.  Other types may be added in
62 * the future.  Generally, an object of class DataBuffer will be cast down
63 * to one of its data type specific subclasses to access data type specific
64 * methods for improved performance.  Currently, the Java 2D(tm) API
65 * image classes use TYPE_BYTE, TYPE_USHORT, TYPE_INT, TYPE_SHORT,
66 * TYPE_FLOAT, and TYPE_DOUBLE DataBuffers to store image data.
67 * @see java.awt.image.Raster
68 * @see java.awt.image.SampleModel
69 */
70public abstract class DataBuffer {
71
72    /** Tag for unsigned byte data. */
73    @Native public static final int TYPE_BYTE  = 0;
74
75    /** Tag for unsigned short data. */
76    @Native public static final int TYPE_USHORT = 1;
77
78    /** Tag for signed short data.  Placeholder for future use. */
79    @Native public static final int TYPE_SHORT = 2;
80
81    /** Tag for int data. */
82    @Native public static final int TYPE_INT   = 3;
83
84    /** Tag for float data.  Placeholder for future use. */
85    @Native public static final int TYPE_FLOAT  = 4;
86
87    /** Tag for double data.  Placeholder for future use. */
88    @Native public static final int TYPE_DOUBLE  = 5;
89
90    /** Tag for undefined data. */
91    @Native public static final int TYPE_UNDEFINED = 32;
92
93    /** The data type of this DataBuffer. */
94    protected int dataType;
95
96    /** The number of banks in this DataBuffer. */
97    protected int banks;
98
99    /** Offset into default (first) bank from which to get the first element. */
100    protected int offset;
101
102    /** Usable size of all banks. */
103    protected int size;
104
105    /** Offsets into all banks. */
106    protected int offsets[];
107
108    /* The current StateTrackable state. */
109    StateTrackableDelegate theTrackable;
110
111    /** Size of the data types indexed by DataType tags defined above. */
112    private static final int dataTypeSize[] = {8,16,16,32,32,64};
113
114    /** Returns the size (in bits) of the data type, given a datatype tag.
115      * @param type the value of one of the defined datatype tags
116      * @return the size of the data type
117      * @throws IllegalArgumentException if {@code type} is less than
118      *         zero or greater than {@link #TYPE_DOUBLE}
119      */
120    public static int getDataTypeSize(int type) {
121        if (type < TYPE_BYTE || type > TYPE_DOUBLE) {
122            throw new IllegalArgumentException("Unknown data type "+type);
123        }
124        return dataTypeSize[type];
125    }
126
127    /**
128     *  Constructs a DataBuffer containing one bank of the specified
129     *  data type and size.
130     *
131     *  @param dataType the data type of this {@code DataBuffer}
132     *  @param size the size of the banks
133     */
134    protected DataBuffer(int dataType, int size) {
135        this(UNTRACKABLE, dataType, size);
136    }
137
138    /**
139     *  Constructs a DataBuffer containing one bank of the specified
140     *  data type and size with the indicated initial {@link State State}.
141     *
142     *  @param initialState the initial {@link State State} state of the data
143     *  @param dataType the data type of this {@code DataBuffer}
144     *  @param size the size of the banks
145     *  @since 1.7
146     */
147    DataBuffer(State initialState,
148               int dataType, int size)
149    {
150        this.theTrackable = StateTrackableDelegate.createInstance(initialState);
151        this.dataType = dataType;
152        this.banks = 1;
153        this.size = size;
154        this.offset = 0;
155        this.offsets = new int[1];  // init to 0 by new
156    }
157
158    /**
159     *  Constructs a DataBuffer containing the specified number of
160     *  banks.  Each bank has the specified size and an offset of 0.
161     *
162     *  @param dataType the data type of this {@code DataBuffer}
163     *  @param size the size of the banks
164     *  @param numBanks the number of banks in this
165     *         {@code DataBuffer}
166     */
167    protected DataBuffer(int dataType, int size, int numBanks) {
168        this(UNTRACKABLE, dataType, size, numBanks);
169    }
170
171    /**
172     *  Constructs a DataBuffer containing the specified number of
173     *  banks with the indicated initial {@link State State}.
174     *  Each bank has the specified size and an offset of 0.
175     *
176     *  @param initialState the initial {@link State State} state of the data
177     *  @param dataType the data type of this {@code DataBuffer}
178     *  @param size the size of the banks
179     *  @param numBanks the number of banks in this
180     *         {@code DataBuffer}
181     *  @since 1.7
182     */
183    DataBuffer(State initialState,
184               int dataType, int size, int numBanks)
185    {
186        this.theTrackable = StateTrackableDelegate.createInstance(initialState);
187        this.dataType = dataType;
188        this.banks = numBanks;
189        this.size = size;
190        this.offset = 0;
191        this.offsets = new int[banks]; // init to 0 by new
192    }
193
194    /**
195     *  Constructs a DataBuffer that contains the specified number
196     *  of banks.  Each bank has the specified datatype, size and offset.
197     *
198     *  @param dataType the data type of this {@code DataBuffer}
199     *  @param size the size of the banks
200     *  @param numBanks the number of banks in this
201     *         {@code DataBuffer}
202     *  @param offset the offset for each bank
203     */
204    protected DataBuffer(int dataType, int size, int numBanks, int offset) {
205        this(UNTRACKABLE, dataType, size, numBanks, offset);
206    }
207
208    /**
209     *  Constructs a DataBuffer that contains the specified number
210     *  of banks with the indicated initial {@link State State}.
211     *  Each bank has the specified datatype, size and offset.
212     *
213     *  @param initialState the initial {@link State State} state of the data
214     *  @param dataType the data type of this {@code DataBuffer}
215     *  @param size the size of the banks
216     *  @param numBanks the number of banks in this
217     *         {@code DataBuffer}
218     *  @param offset the offset for each bank
219     *  @since 1.7
220     */
221    DataBuffer(State initialState,
222               int dataType, int size, int numBanks, int offset)
223    {
224        this.theTrackable = StateTrackableDelegate.createInstance(initialState);
225        this.dataType = dataType;
226        this.banks = numBanks;
227        this.size = size;
228        this.offset = offset;
229        this.offsets = new int[numBanks];
230        for (int i = 0; i < numBanks; i++) {
231            this.offsets[i] = offset;
232        }
233    }
234
235    /**
236     *  Constructs a DataBuffer which contains the specified number
237     *  of banks.  Each bank has the specified datatype and size.  The
238     *  offset for each bank is specified by its respective entry in
239     *  the offsets array.
240     *
241     *  @param dataType the data type of this {@code DataBuffer}
242     *  @param size the size of the banks
243     *  @param numBanks the number of banks in this
244     *         {@code DataBuffer}
245     *  @param offsets an array containing an offset for each bank.
246     *  @throws ArrayIndexOutOfBoundsException if {@code numBanks}
247     *          does not equal the length of {@code offsets}
248     */
249    protected DataBuffer(int dataType, int size, int numBanks, int offsets[]) {
250        this(UNTRACKABLE, dataType, size, numBanks, offsets);
251    }
252
253    /**
254     *  Constructs a DataBuffer which contains the specified number
255     *  of banks with the indicated initial {@link State State}.
256     *  Each bank has the specified datatype and size.  The
257     *  offset for each bank is specified by its respective entry in
258     *  the offsets array.
259     *
260     *  @param initialState the initial {@link State State} state of the data
261     *  @param dataType the data type of this {@code DataBuffer}
262     *  @param size the size of the banks
263     *  @param numBanks the number of banks in this
264     *         {@code DataBuffer}
265     *  @param offsets an array containing an offset for each bank.
266     *  @throws ArrayIndexOutOfBoundsException if {@code numBanks}
267     *          does not equal the length of {@code offsets}
268     *  @since 1.7
269     */
270    DataBuffer(State initialState,
271               int dataType, int size, int numBanks, int offsets[])
272    {
273        if (numBanks != offsets.length) {
274            throw new ArrayIndexOutOfBoundsException("Number of banks" +
275                 " does not match number of bank offsets");
276        }
277        this.theTrackable = StateTrackableDelegate.createInstance(initialState);
278        this.dataType = dataType;
279        this.banks = numBanks;
280        this.size = size;
281        this.offset = offsets[0];
282        this.offsets = offsets.clone();
283    }
284
285    /**  Returns the data type of this DataBuffer.
286     *   @return the data type of this {@code DataBuffer}.
287     */
288    public int getDataType() {
289        return dataType;
290    }
291
292    /**  Returns the size (in array elements) of all banks.
293     *   @return the size of all banks.
294     */
295    public int getSize() {
296        return size;
297    }
298
299    /** Returns the offset of the default bank in array elements.
300     *  @return the offset of the default bank.
301     */
302    public int getOffset() {
303        return offset;
304    }
305
306    /** Returns the offsets (in array elements) of all the banks.
307     *  @return the offsets of all banks.
308     */
309    public int[] getOffsets() {
310        return offsets.clone();
311    }
312
313    /** Returns the number of banks in this DataBuffer.
314     *  @return the number of banks.
315     */
316    public int getNumBanks() {
317        return banks;
318    }
319
320    /**
321     * Returns the requested data array element from the first (default) bank
322     * as an integer.
323     * @param i the index of the requested data array element
324     * @return the data array element at the specified index.
325     * @see #setElem(int, int)
326     * @see #setElem(int, int, int)
327     */
328    public int getElem(int i) {
329        return getElem(0,i);
330    }
331
332    /**
333     * Returns the requested data array element from the specified bank
334     * as an integer.
335     * @param bank the specified bank
336     * @param i the index of the requested data array element
337     * @return the data array element at the specified index from the
338     *         specified bank at the specified index.
339     * @see #setElem(int, int)
340     * @see #setElem(int, int, int)
341     */
342    public abstract int getElem(int bank, int i);
343
344    /**
345     * Sets the requested data array element in the first (default) bank
346     * from the given integer.
347     * @param i the specified index into the data array
348     * @param val the data to set the element at the specified index in
349     * the data array
350     * @see #getElem(int)
351     * @see #getElem(int, int)
352     */
353    public void  setElem(int i, int val) {
354        setElem(0,i,val);
355    }
356
357    /**
358     * Sets the requested data array element in the specified bank
359     * from the given integer.
360     * @param bank the specified bank
361     * @param i the specified index into the data array
362     * @param val  the data to set the element in the specified bank
363     * at the specified index in the data array
364     * @see #getElem(int)
365     * @see #getElem(int, int)
366     */
367    public abstract void setElem(int bank, int i, int val);
368
369    /**
370     * Returns the requested data array element from the first (default) bank
371     * as a float.  The implementation in this class is to cast getElem(i)
372     * to a float.  Subclasses may override this method if another
373     * implementation is needed.
374     * @param i the index of the requested data array element
375     * @return a float value representing the data array element at the
376     *  specified index.
377     * @see #setElemFloat(int, float)
378     * @see #setElemFloat(int, int, float)
379     */
380    public float getElemFloat(int i) {
381        return (float)getElem(i);
382    }
383
384    /**
385     * Returns the requested data array element from the specified bank
386     * as a float.  The implementation in this class is to cast
387     * {@link #getElem(int, int)}
388     * to a float.  Subclasses can override this method if another
389     * implementation is needed.
390     * @param bank the specified bank
391     * @param i the index of the requested data array element
392     * @return a float value representing the data array element from the
393     * specified bank at the specified index.
394     * @see #setElemFloat(int, float)
395     * @see #setElemFloat(int, int, float)
396     */
397    public float getElemFloat(int bank, int i) {
398        return (float)getElem(bank,i);
399    }
400
401    /**
402     * Sets the requested data array element in the first (default) bank
403     * from the given float.  The implementation in this class is to cast
404     * val to an int and call {@link #setElem(int, int)}.  Subclasses
405     * can override this method if another implementation is needed.
406     * @param i the specified index
407     * @param val the value to set the element at the specified index in
408     * the data array
409     * @see #getElemFloat(int)
410     * @see #getElemFloat(int, int)
411     */
412    public void setElemFloat(int i, float val) {
413        setElem(i,(int)val);
414    }
415
416    /**
417     * Sets the requested data array element in the specified bank
418     * from the given float.  The implementation in this class is to cast
419     * val to an int and call {@link #setElem(int, int)}.  Subclasses can
420     * override this method if another implementation is needed.
421     * @param bank the specified bank
422     * @param i the specified index
423     * @param val the value to set the element in the specified bank at
424     * the specified index in the data array
425     * @see #getElemFloat(int)
426     * @see #getElemFloat(int, int)
427     */
428    public void setElemFloat(int bank, int i, float val) {
429        setElem(bank,i,(int)val);
430    }
431
432    /**
433     * Returns the requested data array element from the first (default) bank
434     * as a double.  The implementation in this class is to cast
435     * {@link #getElem(int)}
436     * to a double.  Subclasses can override this method if another
437     * implementation is needed.
438     * @param i the specified index
439     * @return a double value representing the element at the specified
440     * index in the data array.
441     * @see #setElemDouble(int, double)
442     * @see #setElemDouble(int, int, double)
443     */
444    public double getElemDouble(int i) {
445        return (double)getElem(i);
446    }
447
448    /**
449     * Returns the requested data array element from the specified bank as
450     * a double.  The implementation in this class is to cast getElem(bank, i)
451     * to a double.  Subclasses may override this method if another
452     * implementation is needed.
453     * @param bank the specified bank
454     * @param i the specified index
455     * @return a double value representing the element from the specified
456     * bank at the specified index in the data array.
457     * @see #setElemDouble(int, double)
458     * @see #setElemDouble(int, int, double)
459     */
460    public double getElemDouble(int bank, int i) {
461        return (double)getElem(bank,i);
462    }
463
464    /**
465     * Sets the requested data array element in the first (default) bank
466     * from the given double.  The implementation in this class is to cast
467     * val to an int and call {@link #setElem(int, int)}.  Subclasses can
468     * override this method if another implementation is needed.
469     * @param i the specified index
470     * @param val the value to set the element at the specified index
471     * in the data array
472     * @see #getElemDouble(int)
473     * @see #getElemDouble(int, int)
474     */
475    public void setElemDouble(int i, double val) {
476        setElem(i,(int)val);
477    }
478
479    /**
480     * Sets the requested data array element in the specified bank
481     * from the given double.  The implementation in this class is to cast
482     * val to an int and call {@link #setElem(int, int)}.  Subclasses can
483     * override this method if another implementation is needed.
484     * @param bank the specified bank
485     * @param i the specified index
486     * @param val the value to set the element in the specified bank
487     * at the specified index of the data array
488     * @see #getElemDouble(int)
489     * @see #getElemDouble(int, int)
490     */
491    public void setElemDouble(int bank, int i, double val) {
492        setElem(bank,i,(int)val);
493    }
494
495    static int[] toIntArray(Object obj) {
496        if (obj instanceof int[]) {
497            return (int[])obj;
498        } else if (obj == null) {
499            return null;
500        } else if (obj instanceof short[]) {
501            short sdata[] = (short[])obj;
502            int idata[] = new int[sdata.length];
503            for (int i = 0; i < sdata.length; i++) {
504                idata[i] = (int)sdata[i] & 0xffff;
505            }
506            return idata;
507        } else if (obj instanceof byte[]) {
508            byte bdata[] = (byte[])obj;
509            int idata[] = new int[bdata.length];
510            for (int i = 0; i < bdata.length; i++) {
511                idata[i] = 0xff & (int)bdata[i];
512            }
513            return idata;
514        }
515        return null;
516    }
517
518    static {
519        SunWritableRaster.setDataStealer(new SunWritableRaster.DataStealer() {
520            public byte[] getData(DataBufferByte dbb, int bank) {
521                return dbb.bankdata[bank];
522            }
523
524            public short[] getData(DataBufferUShort dbus, int bank) {
525                return dbus.bankdata[bank];
526            }
527
528            public int[] getData(DataBufferInt dbi, int bank) {
529                return dbi.bankdata[bank];
530            }
531
532            public StateTrackableDelegate getTrackable(DataBuffer db) {
533                return db.theTrackable;
534            }
535
536            public void setTrackable(DataBuffer db,
537                                     StateTrackableDelegate trackable)
538            {
539                db.theTrackable = trackable;
540            }
541        });
542    }
543}
544