1 /*
   2  * Copyright (c) 1997, 2008, 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 
  36 package java.awt.image;
  37 
  38 import sun.java2d.StateTrackable.State;
  39 import static sun.java2d.StateTrackable.State.*;
  40 import sun.java2d.StateTrackableDelegate;
  41 
  42 import sun.awt.image.SunWritableRaster;
  43 
  44 import javax.tools.annotation.GenerateNativeHeader;
  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  */
  70 /* No native methods here, but the constants are needed in the supporting JNI code */
  71 @GenerateNativeHeader
  72 public abstract class DataBuffer {
  73 
  74     /** Tag for unsigned byte data. */
  75     public static final int TYPE_BYTE  = 0;
  76 
  77     /** Tag for unsigned short data. */
  78     public static final int TYPE_USHORT = 1;
  79 
  80     /** Tag for signed short data.  Placeholder for future use. */
  81     public static final int TYPE_SHORT = 2;
  82 
  83     /** Tag for int data. */
  84     public static final int TYPE_INT   = 3;
  85 
  86     /** Tag for float data.  Placeholder for future use. */
  87     public static final int TYPE_FLOAT  = 4;
  88 
  89     /** Tag for double data.  Placeholder for future use. */
  90     public static final int TYPE_DOUBLE  = 5;
  91 
  92     /** Tag for undefined data. */
  93     public static final int TYPE_UNDEFINED = 32;
  94 
  95     /** The data type of this DataBuffer. */
  96     protected int dataType;
  97 
  98     /** The number of banks in this DataBuffer. */
  99     protected int banks;
 100 
 101     /** Offset into default (first) bank from which to get the first element. */
 102     protected int offset;
 103 
 104     /** Usable size of all banks. */
 105     protected int size;
 106 
 107     /** Offsets into all banks. */
 108     protected int offsets[];
 109 
 110     /* The current StateTrackable state. */
 111     StateTrackableDelegate theTrackable;
 112 
 113     /** Size of the data types indexed by DataType tags defined above. */
 114     private static final int dataTypeSize[] = {8,16,16,32,32,64};
 115 
 116     /** Returns the size (in bits) of the data type, given a datatype tag.
 117       * @param type the value of one of the defined datatype tags
 118       * @return the size of the data type
 119       * @throws IllegalArgumentException if <code>type</code> is less than
 120       *         zero or greater than {@link #TYPE_DOUBLE}
 121       */
 122     public static int getDataTypeSize(int type) {
 123         if (type < TYPE_BYTE || type > TYPE_DOUBLE) {
 124             throw new IllegalArgumentException("Unknown data type "+type);
 125         }
 126         return dataTypeSize[type];
 127     }
 128 
 129     /**
 130      *  Constructs a DataBuffer containing one bank of the specified
 131      *  data type and size.
 132      *
 133      *  @param dataType the data type of this <code>DataBuffer</code>
 134      *  @param size the size of the banks
 135      */
 136     protected DataBuffer(int dataType, int size) {
 137         this(UNTRACKABLE, dataType, size);
 138     }
 139 
 140     /**
 141      *  Constructs a DataBuffer containing one bank of the specified
 142      *  data type and size with the indicated initial {@link State State}.
 143      *
 144      *  @param initialState the initial {@link State State} state of the data
 145      *  @param dataType the data type of this <code>DataBuffer</code>
 146      *  @param size the size of the banks
 147      *  @since 1.7
 148      */
 149     DataBuffer(State initialState,
 150                int dataType, int size)
 151     {
 152         this.theTrackable = StateTrackableDelegate.createInstance(initialState);
 153         this.dataType = dataType;
 154         this.banks = 1;
 155         this.size = size;
 156         this.offset = 0;
 157         this.offsets = new int[1];  // init to 0 by new
 158     }
 159 
 160     /**
 161      *  Constructs a DataBuffer containing the specified number of
 162      *  banks.  Each bank has the specified size and an offset of 0.
 163      *
 164      *  @param dataType the data type of this <code>DataBuffer</code>
 165      *  @param size the size of the banks
 166      *  @param numBanks the number of banks in this
 167      *         <code>DataBuffer</code>
 168      */
 169     protected DataBuffer(int dataType, int size, int numBanks) {
 170         this(UNTRACKABLE, dataType, size, numBanks);
 171     }
 172 
 173     /**
 174      *  Constructs a DataBuffer containing the specified number of
 175      *  banks with the indicated initial {@link State State}.
 176      *  Each bank has the specified size and an offset of 0.
 177      *
 178      *  @param initialState the initial {@link State State} state of the data
 179      *  @param dataType the data type of this <code>DataBuffer</code>
 180      *  @param size the size of the banks
 181      *  @param numBanks the number of banks in this
 182      *         <code>DataBuffer</code>
 183      *  @since 1.7
 184      */
 185     DataBuffer(State initialState,
 186                int dataType, int size, int numBanks)
 187     {
 188         this.theTrackable = StateTrackableDelegate.createInstance(initialState);
 189         this.dataType = dataType;
 190         this.banks = numBanks;
 191         this.size = size;
 192         this.offset = 0;
 193         this.offsets = new int[banks]; // init to 0 by new
 194     }
 195 
 196     /**
 197      *  Constructs a DataBuffer that contains the specified number
 198      *  of banks.  Each bank has the specified datatype, size and offset.
 199      *
 200      *  @param dataType the data type of this <code>DataBuffer</code>
 201      *  @param size the size of the banks
 202      *  @param numBanks the number of banks in this
 203      *         <code>DataBuffer</code>
 204      *  @param offset the offset for each bank
 205      */
 206     protected DataBuffer(int dataType, int size, int numBanks, int offset) {
 207         this(UNTRACKABLE, dataType, size, numBanks, offset);
 208     }
 209 
 210     /**
 211      *  Constructs a DataBuffer that contains the specified number
 212      *  of banks with the indicated initial {@link State State}.
 213      *  Each bank has the specified datatype, size and offset.
 214      *
 215      *  @param initialState the initial {@link State State} state of the data
 216      *  @param dataType the data type of this <code>DataBuffer</code>
 217      *  @param size the size of the banks
 218      *  @param numBanks the number of banks in this
 219      *         <code>DataBuffer</code>
 220      *  @param offset the offset for each bank
 221      *  @since 1.7
 222      */
 223     DataBuffer(State initialState,
 224                int dataType, int size, int numBanks, int offset)
 225     {
 226         this.theTrackable = StateTrackableDelegate.createInstance(initialState);
 227         this.dataType = dataType;
 228         this.banks = numBanks;
 229         this.size = size;
 230         this.offset = offset;
 231         this.offsets = new int[numBanks];
 232         for (int i = 0; i < numBanks; i++) {
 233             this.offsets[i] = offset;
 234         }
 235     }
 236 
 237     /**
 238      *  Constructs a DataBuffer which contains the specified number
 239      *  of banks.  Each bank has the specified datatype and size.  The
 240      *  offset for each bank is specified by its respective entry in
 241      *  the offsets array.
 242      *
 243      *  @param dataType the data type of this <code>DataBuffer</code>
 244      *  @param size the size of the banks
 245      *  @param numBanks the number of banks in this
 246      *         <code>DataBuffer</code>
 247      *  @param offsets an array containing an offset for each bank.
 248      *  @throws ArrayIndexOutOfBoundsException if <code>numBanks</code>
 249      *          does not equal the length of <code>offsets</code>
 250      */
 251     protected DataBuffer(int dataType, int size, int numBanks, int offsets[]) {
 252         this(UNTRACKABLE, dataType, size, numBanks, offsets);
 253     }
 254 
 255     /**
 256      *  Constructs a DataBuffer which contains the specified number
 257      *  of banks with the indicated initial {@link State State}.
 258      *  Each bank has the specified datatype and size.  The
 259      *  offset for each bank is specified by its respective entry in
 260      *  the offsets array.
 261      *
 262      *  @param initialState the initial {@link State State} state of the data
 263      *  @param dataType the data type of this <code>DataBuffer</code>
 264      *  @param size the size of the banks
 265      *  @param numBanks the number of banks in this
 266      *         <code>DataBuffer</code>
 267      *  @param offsets an array containing an offset for each bank.
 268      *  @throws ArrayIndexOutOfBoundsException if <code>numBanks</code>
 269      *          does not equal the length of <code>offsets</code>
 270      *  @since 1.7
 271      */
 272     DataBuffer(State initialState,
 273                int dataType, int size, int numBanks, int offsets[])
 274     {
 275         if (numBanks != offsets.length) {
 276             throw new ArrayIndexOutOfBoundsException("Number of banks" +
 277                  " does not match number of bank offsets");
 278         }
 279         this.theTrackable = StateTrackableDelegate.createInstance(initialState);
 280         this.dataType = dataType;
 281         this.banks = numBanks;
 282         this.size = size;
 283         this.offset = offsets[0];
 284         this.offsets = (int[])offsets.clone();
 285     }
 286 
 287     /**  Returns the data type of this DataBuffer.
 288      *   @return the data type of this <code>DataBuffer</code>.
 289      */
 290     public int getDataType() {
 291         return dataType;
 292     }
 293 
 294     /**  Returns the size (in array elements) of all banks.
 295      *   @return the size of all banks.
 296      */
 297     public int getSize() {
 298         return size;
 299     }
 300 
 301     /** Returns the offset of the default bank in array elements.
 302      *  @return the offset of the default bank.
 303      */
 304     public int getOffset() {
 305         return offset;
 306     }
 307 
 308     /** Returns the offsets (in array elements) of all the banks.
 309      *  @return the offsets of all banks.
 310      */
 311     public int[] getOffsets() {
 312         return (int[])offsets.clone();
 313     }
 314 
 315     /** Returns the number of banks in this DataBuffer.
 316      *  @return the number of banks.
 317      */
 318     public int getNumBanks() {
 319         return banks;
 320     }
 321 
 322     /**
 323      * Returns the requested data array element from the first (default) bank
 324      * as an integer.
 325      * @param i the index of the requested data array element
 326      * @return the data array element at the specified index.
 327      * @see #setElem(int, int)
 328      * @see #setElem(int, int, int)
 329      */
 330     public int getElem(int i) {
 331         return getElem(0,i);
 332     }
 333 
 334     /**
 335      * Returns the requested data array element from the specified bank
 336      * as an integer.
 337      * @param bank the specified bank
 338      * @param i the index of the requested data array element
 339      * @return the data array element at the specified index from the
 340      *         specified bank at the specified index.
 341      * @see #setElem(int, int)
 342      * @see #setElem(int, int, int)
 343      */
 344     public abstract int getElem(int bank, int i);
 345 
 346     /**
 347      * Sets the requested data array element in the first (default) bank
 348      * from the given integer.
 349      * @param i the specified index into the data array
 350      * @param val the data to set the element at the specified index in
 351      * the data array
 352      * @see #getElem(int)
 353      * @see #getElem(int, int)
 354      */
 355     public void  setElem(int i, int val) {
 356         setElem(0,i,val);
 357     }
 358 
 359     /**
 360      * Sets the requested data array element in the specified bank
 361      * from the given integer.
 362      * @param bank the specified bank
 363      * @param i the specified index into the data array
 364      * @param val  the data to set the element in the specified bank
 365      * at the specified index in the data array
 366      * @see #getElem(int)
 367      * @see #getElem(int, int)
 368      */
 369     public abstract void setElem(int bank, int i, int val);
 370 
 371     /**
 372      * Returns the requested data array element from the first (default) bank
 373      * as a float.  The implementation in this class is to cast getElem(i)
 374      * to a float.  Subclasses may override this method if another
 375      * implementation is needed.
 376      * @param i the index of the requested data array element
 377      * @return a float value representing the data array element at the
 378      *  specified index.
 379      * @see #setElemFloat(int, float)
 380      * @see #setElemFloat(int, int, float)
 381      */
 382     public float getElemFloat(int i) {
 383         return (float)getElem(i);
 384     }
 385 
 386     /**
 387      * Returns the requested data array element from the specified bank
 388      * as a float.  The implementation in this class is to cast
 389      * {@link #getElem(int, int)}
 390      * to a float.  Subclasses can override this method if another
 391      * implementation is needed.
 392      * @param bank the specified bank
 393      * @param i the index of the requested data array element
 394      * @return a float value representing the data array element from the
 395      * specified bank at the specified index.
 396      * @see #setElemFloat(int, float)
 397      * @see #setElemFloat(int, int, float)
 398      */
 399     public float getElemFloat(int bank, int i) {
 400         return (float)getElem(bank,i);
 401     }
 402 
 403     /**
 404      * Sets the requested data array element in the first (default) bank
 405      * from the given float.  The implementation in this class is to cast
 406      * val to an int and call {@link #setElem(int, int)}.  Subclasses
 407      * can override this method if another implementation is needed.
 408      * @param i the specified index
 409      * @param val the value to set the element at the specified index in
 410      * the data array
 411      * @see #getElemFloat(int)
 412      * @see #getElemFloat(int, int)
 413      */
 414     public void setElemFloat(int i, float val) {
 415         setElem(i,(int)val);
 416     }
 417 
 418     /**
 419      * Sets the requested data array element in the specified bank
 420      * from the given float.  The implementation in this class is to cast
 421      * val to an int and call {@link #setElem(int, int)}.  Subclasses can
 422      * override this method if another implementation is needed.
 423      * @param bank the specified bank
 424      * @param i the specified index
 425      * @param val the value to set the element in the specified bank at
 426      * the specified index in the data array
 427      * @see #getElemFloat(int)
 428      * @see #getElemFloat(int, int)
 429      */
 430     public void setElemFloat(int bank, int i, float val) {
 431         setElem(bank,i,(int)val);
 432     }
 433 
 434     /**
 435      * Returns the requested data array element from the first (default) bank
 436      * as a double.  The implementation in this class is to cast
 437      * {@link #getElem(int)}
 438      * to a double.  Subclasses can override this method if another
 439      * implementation is needed.
 440      * @param i the specified index
 441      * @return a double value representing the element at the specified
 442      * index in the data array.
 443      * @see #setElemDouble(int, double)
 444      * @see #setElemDouble(int, int, double)
 445      */
 446     public double getElemDouble(int i) {
 447         return (double)getElem(i);
 448     }
 449 
 450     /**
 451      * Returns the requested data array element from the specified bank as
 452      * a double.  The implementation in this class is to cast getElem(bank, i)
 453      * to a double.  Subclasses may override this method if another
 454      * implementation is needed.
 455      * @param bank the specified bank
 456      * @param i the specified index
 457      * @return a double value representing the element from the specified
 458      * bank at the specified index in the data array.
 459      * @see #setElemDouble(int, double)
 460      * @see #setElemDouble(int, int, double)
 461      */
 462     public double getElemDouble(int bank, int i) {
 463         return (double)getElem(bank,i);
 464     }
 465 
 466     /**
 467      * Sets the requested data array element in the first (default) bank
 468      * from the given double.  The implementation in this class is to cast
 469      * val to an int and call {@link #setElem(int, int)}.  Subclasses can
 470      * override this method if another implementation is needed.
 471      * @param i the specified index
 472      * @param val the value to set the element at the specified index
 473      * in the data array
 474      * @see #getElemDouble(int)
 475      * @see #getElemDouble(int, int)
 476      */
 477     public void setElemDouble(int i, double val) {
 478         setElem(i,(int)val);
 479     }
 480 
 481     /**
 482      * Sets the requested data array element in the specified bank
 483      * from the given double.  The implementation in this class is to cast
 484      * val to an int and call {@link #setElem(int, int)}.  Subclasses can
 485      * override this method if another implementation is needed.
 486      * @param bank the specified bank
 487      * @param i the specified index
 488      * @param val the value to set the element in the specified bank
 489      * at the specified index of the data array
 490      * @see #getElemDouble(int)
 491      * @see #getElemDouble(int, int)
 492      */
 493     public void setElemDouble(int bank, int i, double val) {
 494         setElem(bank,i,(int)val);
 495     }
 496 
 497     static int[] toIntArray(Object obj) {
 498         if (obj instanceof int[]) {
 499             return (int[])obj;
 500         } else if (obj == null) {
 501             return null;
 502         } else if (obj instanceof short[]) {
 503             short sdata[] = (short[])obj;
 504             int idata[] = new int[sdata.length];
 505             for (int i = 0; i < sdata.length; i++) {
 506                 idata[i] = (int)sdata[i] & 0xffff;
 507             }
 508             return idata;
 509         } else if (obj instanceof byte[]) {
 510             byte bdata[] = (byte[])obj;
 511             int idata[] = new int[bdata.length];
 512             for (int i = 0; i < bdata.length; i++) {
 513                 idata[i] = 0xff & (int)bdata[i];
 514             }
 515             return idata;
 516         }
 517         return null;
 518     }
 519 
 520     static {
 521         SunWritableRaster.setDataStealer(new SunWritableRaster.DataStealer() {
 522             public byte[] getData(DataBufferByte dbb, int bank) {
 523                 return dbb.bankdata[bank];
 524             }
 525 
 526             public short[] getData(DataBufferUShort dbus, int bank) {
 527                 return dbus.bankdata[bank];
 528             }
 529 
 530             public int[] getData(DataBufferInt dbi, int bank) {
 531                 return dbi.bankdata[bank];
 532             }
 533 
 534             public StateTrackableDelegate getTrackable(DataBuffer db) {
 535                 return db.theTrackable;
 536             }
 537 
 538             public void setTrackable(DataBuffer db,
 539                                      StateTrackableDelegate trackable)
 540             {
 541                 db.theTrackable = trackable;
 542             }
 543         });
 544     }
 545 }