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 
  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 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  */
  70 public 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</code> 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</code>
 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</code>
 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</code>
 163      *  @param size the size of the banks
 164      *  @param numBanks the number of banks in this
 165      *         <code>DataBuffer</code>
 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</code>
 178      *  @param size the size of the banks
 179      *  @param numBanks the number of banks in this
 180      *         <code>DataBuffer</code>
 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</code>
 199      *  @param size the size of the banks
 200      *  @param numBanks the number of banks in this
 201      *         <code>DataBuffer</code>
 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</code>
 215      *  @param size the size of the banks
 216      *  @param numBanks the number of banks in this
 217      *         <code>DataBuffer</code>
 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</code>
 242      *  @param size the size of the banks
 243      *  @param numBanks the number of banks in this
 244      *         <code>DataBuffer</code>
 245      *  @param offsets an array containing an offset for each bank.
 246      *  @throws ArrayIndexOutOfBoundsException if <code>numBanks</code>
 247      *          does not equal the length of <code>offsets</code>
 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</code>
 262      *  @param size the size of the banks
 263      *  @param numBanks the number of banks in this
 264      *         <code>DataBuffer</code>
 265      *  @param offsets an array containing an offset for each bank.
 266      *  @throws ArrayIndexOutOfBoundsException if <code>numBanks</code>
 267      *          does not equal the length of <code>offsets</code>
 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</code>.
 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 }