1 /* 2 * Copyright (c) 2010, 2013, 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 package com.sun.glass.ui; 26 27 import java.nio.Buffer; 28 import java.nio.ByteBuffer; 29 import java.nio.IntBuffer; 30 import java.nio.ByteOrder; 31 32 /** 33 * The object wraps the given raw pixels data. 34 * 35 * Pixels class is NOT thread safe. 36 */ 37 public abstract class Pixels { 38 /** 39 * The Format specifies the native byte order of the 40 * underlying chunk of image data. 41 * The data may be either INTs or BYTEs depending on 42 * the constructor used. 43 * The format ABCD implies the following byte order: 44 * BYTE[0] = A 45 * BYTE[1] = B 46 * BYTE[2] = C 47 * BYTE[3] = D 48 * BYTE[4] = A 49 * ... 50 * Calling code should take care of endianness of the platform 51 * when passing image data as ints. 52 */ 53 public static class Format { 54 public static final int BYTE_BGRA_PRE = 1; 55 public static final int BYTE_ARGB = 2; 56 } 57 58 public static int getNativeFormat() { 59 Application.checkEventThread(); 60 return Application.GetApplication().staticPixels_getNativeFormat(); 61 } 62 63 // Need: 64 // Clipboard: 65 // public Pixels(final int width, final int height, final byte[] data) 66 // 67 // Robot: 68 // public Pixels(final int width, final int height, final int[] data) 69 // 70 // PixelUtils == Prism == GlassToolkit : 71 // public Pixels(final int width, final int height, final ByteBuffer) 72 // public Pixels(final int width, final int height, final IntBuffer) 73 74 // The following fields are safe to be protected, since they are final 75 protected final int width; 76 protected final int height; 77 protected final int bytesPerComponent; 78 79 // The following fields are safe to be protected, since they are final 80 protected final ByteBuffer bytes; 81 protected final IntBuffer ints; 82 83 private final float scalex; 84 private final float scaley; 85 86 protected Pixels(final int width, final int height, final ByteBuffer pixels) { 87 this.width = width; 88 this.height = height; 89 this.bytesPerComponent = 1; 90 this.bytes = pixels.slice(); 91 if ((this.width <= 0) || (this.height <= 0) || ((this.width * this.height * 4) > this.bytes.capacity())) { 92 throw new IllegalArgumentException("Too small byte buffer size "+this.width+"x"+this.height+" ["+(this.width*this.height*4)+"] > "+this.bytes.capacity()); 93 } 94 95 this.ints = null; 96 this.scalex = 1.0f; 97 this.scaley = 1.0f; 98 } 99 100 protected Pixels(final int width, final int height, IntBuffer pixels) { 101 this.width = width; 102 this.height = height; 103 this.bytesPerComponent = 4; 104 this.ints = pixels.slice(); 105 if ((this.width <= 0) || (this.height <= 0) || ((this.width * this.height) > this.ints.capacity())) { 106 throw new IllegalArgumentException("Too small int buffer size "+this.width+"x"+this.height+" ["+(this.width*this.height)+"] > "+this.ints.capacity()); 107 } 108 109 this.bytes = null; 110 this.scalex = 1.0f; 111 this.scaley = 1.0f; 112 } 113 114 protected Pixels(final int width, final int height, IntBuffer pixels, float scalex, float scaley) { 115 this.width = width; 116 this.height = height; 117 this.bytesPerComponent = 4; 118 this.ints = pixels.slice(); 119 if ((this.width <= 0) || (this.height <= 0) || ((this.width * this.height) > this.ints.capacity())) { 120 throw new IllegalArgumentException("Too small int buffer size "+this.width+"x"+this.height+" ["+(this.width*this.height)+"] > "+this.ints.capacity()); 121 } 122 123 this.bytes = null; 124 this.scalex = scalex; 125 this.scaley = scaley; 126 } 127 128 public final float getScaleX() { 129 Application.checkEventThread(); 130 return this.scalex; 131 } 132 133 public final float getScaleY() { 134 Application.checkEventThread(); 135 return this.scaley; 136 } 137 138 public final float getScaleXUnsafe() { 139 return this.scalex; 140 } 141 142 public final float getScaleYUnsafe() { 143 return this.scaley; 144 } 145 146 public final int getWidth() { 147 Application.checkEventThread(); 148 return this.width; 149 } 150 151 public final int getWidthUnsafe() { 152 return this.width; 153 } 154 155 public final int getHeight() { 156 Application.checkEventThread(); 157 return this.height; 158 } 159 160 public final int getHeightUnsafe() { 161 return this.height; 162 } 163 164 public final int getBytesPerComponent() { 165 Application.checkEventThread(); 166 return this.bytesPerComponent; 167 } 168 169 /* 170 * Return the original pixels buffer. 171 */ 172 public final Buffer getPixels() { 173 if (this.bytes != null) { 174 this.bytes.rewind(); 175 return this.bytes; 176 } else if (this.ints != null) { 177 this.ints.rewind(); 178 return this.ints; 179 } else { 180 throw new RuntimeException("Unexpected Pixels state."); 181 } 182 } 183 184 /* 185 * Return a copy of pixels as bytes. 186 */ 187 public final ByteBuffer asByteBuffer() { 188 Application.checkEventThread(); 189 ByteBuffer bb = ByteBuffer.allocateDirect(getWidth()*getHeight()*4); 190 bb.order(ByteOrder.nativeOrder()); 191 bb.rewind(); 192 asByteBuffer(bb); 193 return bb; 194 } 195 196 /* 197 * Copy pixels into provided byte buffer. 198 * The ByteBuffer must be direct. 199 */ 200 public final void asByteBuffer(ByteBuffer bb) { 201 Application.checkEventThread(); 202 if (!bb.isDirect()) { 203 throw new RuntimeException("Expected direct buffer."); 204 } else if (bb.remaining() < (getWidth()*getHeight()*4)) { 205 throw new RuntimeException("Too small buffer."); 206 } 207 _fillDirectByteBuffer(bb); 208 } 209 210 // This method is called from the native code to reduce the number of JNI up-calls. 211 private void attachData(long ptr) { 212 if (this.ints != null) { 213 int[] array = !this.ints.isDirect() ? this.ints.array() : null; 214 _attachInt(ptr, this.width, this.height, this.ints, array, array != null ? this.ints.arrayOffset() : 0); 215 } 216 if (this.bytes != null) { 217 byte[] array = !this.bytes.isDirect() ? this.bytes.array() : null; 218 _attachByte(ptr, this.width, this.height, this.bytes, array, array != null ? this.bytes.arrayOffset() : 0); 219 } 220 } 221 222 protected abstract void _fillDirectByteBuffer(ByteBuffer bb); 223 protected abstract void _attachInt(long ptr, int w, int h, IntBuffer ints, int[] array, int offset); 224 protected abstract void _attachByte(long ptr, int w, int h, ByteBuffer bytes, byte[] array, int offset); 225 226 @Override public final boolean equals(Object object) { 227 Application.checkEventThread(); 228 boolean equals = ((object != null) && (getClass().equals(object.getClass()))); 229 if (equals) { 230 Pixels pixels = (Pixels)object; 231 equals = ((getWidth() == pixels.getWidth()) && (getHeight() == pixels.getHeight())); 232 if (equals) { 233 ByteBuffer b1 = asByteBuffer(); 234 ByteBuffer b2 = pixels.asByteBuffer(); 235 equals = (b1.compareTo(b2) == 0); 236 } 237 } 238 return equals; 239 } 240 241 @Override public final int hashCode() { 242 Application.checkEventThread(); 243 int val = getWidth(); 244 val = 31*val + getHeight(); 245 val = 17*val + asByteBuffer().hashCode(); 246 return val; 247 } 248 }