1 /* 2 * Copyright (c) 1999, 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 26 package sun.awt.image; 27 28 import java.awt.Color; 29 import java.awt.Rectangle; 30 import java.awt.GraphicsConfiguration; 31 import java.awt.image.ColorModel; 32 import java.awt.image.SampleModel; 33 import java.awt.image.DirectColorModel; 34 import java.awt.image.IndexColorModel; 35 import java.awt.image.Raster; 36 import java.awt.image.BufferedImage; 37 import java.awt.image.DataBuffer; 38 39 import sun.java2d.SurfaceData; 40 import sun.java2d.SunGraphics2D; 41 import sun.java2d.StateTrackable; 42 import sun.java2d.StateTrackable.*; 43 import sun.java2d.StateTracker; 44 import sun.java2d.loops.SurfaceType; 45 import sun.java2d.loops.CompositeType; 46 import sun.java2d.loops.RenderLoops; 47 48 49 public class BufImgSurfaceData extends SurfaceData { 50 BufferedImage bufImg; 51 private BufferedImageGraphicsConfig graphicsConfig; 52 RenderLoops solidloops; 53 54 private static native void initIDs(Class<?> ICM, Class<?> ICMColorData); 55 56 private static final int DCM_RGBX_RED_MASK = 0xff000000; 57 private static final int DCM_RGBX_GREEN_MASK = 0x00ff0000; 58 private static final int DCM_RGBX_BLUE_MASK = 0x0000ff00; 59 private static final int DCM_555X_RED_MASK = 0xF800; 60 private static final int DCM_555X_GREEN_MASK = 0x07C0; 61 private static final int DCM_555X_BLUE_MASK = 0x003E; 62 private static final int DCM_4444_RED_MASK = 0x0f00; 63 private static final int DCM_4444_GREEN_MASK = 0x00f0; 64 private static final int DCM_4444_BLUE_MASK = 0x000f; 65 private static final int DCM_4444_ALPHA_MASK = 0xf000; 66 private static final int DCM_ARGBBM_ALPHA_MASK = 0x01000000; 67 private static final int DCM_ARGBBM_RED_MASK = 0x00ff0000; 68 private static final int DCM_ARGBBM_GREEN_MASK = 0x0000ff00; 69 private static final int DCM_ARGBBM_BLUE_MASK = 0x000000ff; 70 71 static { 72 initIDs(IndexColorModel.class, ICMColorData.class); 73 } 74 75 public static SurfaceData createData(BufferedImage bufImg) { 76 if (bufImg == null) { 77 throw new NullPointerException("BufferedImage cannot be null"); 78 } 79 SurfaceData sData; 80 ColorModel cm = bufImg.getColorModel(); 81 int type = bufImg.getType(); 82 // REMIND: Check the image type and pick an appropriate subclass 83 switch (type) { 84 case BufferedImage.TYPE_INT_BGR: 85 sData = createDataIC(bufImg, SurfaceType.IntBgr); 86 break; 87 case BufferedImage.TYPE_INT_RGB: 88 sData = createDataIC(bufImg, SurfaceType.IntRgb); 89 break; 90 case BufferedImage.TYPE_INT_ARGB: 91 sData = createDataIC(bufImg, SurfaceType.IntArgb); 92 break; 93 case BufferedImage.TYPE_INT_ARGB_PRE: 94 sData = createDataIC(bufImg, SurfaceType.IntArgbPre); 95 break; 96 case BufferedImage.TYPE_3BYTE_BGR: 97 sData = createDataBC(bufImg, SurfaceType.ThreeByteBgr, 2); 98 break; 99 case BufferedImage.TYPE_4BYTE_ABGR: 100 sData = createDataBC(bufImg, SurfaceType.FourByteAbgr, 3); 101 break; 102 case BufferedImage.TYPE_4BYTE_ABGR_PRE: 103 sData = createDataBC(bufImg, SurfaceType.FourByteAbgrPre, 3); 104 break; 105 case BufferedImage.TYPE_USHORT_565_RGB: 106 sData = createDataSC(bufImg, SurfaceType.Ushort565Rgb, null); 107 break; 108 case BufferedImage.TYPE_USHORT_555_RGB: 109 sData = createDataSC(bufImg, SurfaceType.Ushort555Rgb, null); 110 break; 111 case BufferedImage.TYPE_BYTE_INDEXED: 112 { 113 SurfaceType sType; 114 switch (cm.getTransparency()) { 115 case OPAQUE: 116 if (isOpaqueGray((IndexColorModel)cm)) { 117 sType = SurfaceType.Index8Gray; 118 } else { 119 sType = SurfaceType.ByteIndexedOpaque; 120 } 121 break; 122 case BITMASK: 123 sType = SurfaceType.ByteIndexedBm; 124 break; 125 case TRANSLUCENT: 126 sType = SurfaceType.ByteIndexed; 127 break; 128 default: 129 throw new InternalError("Unrecognized transparency"); 130 } 131 sData = createDataBC(bufImg, sType, 0); 132 } 133 break; 134 case BufferedImage.TYPE_BYTE_GRAY: 135 sData = createDataBC(bufImg, SurfaceType.ByteGray, 0); 136 break; 137 case BufferedImage.TYPE_USHORT_GRAY: 138 sData = createDataSC(bufImg, SurfaceType.UshortGray, null); 139 break; 140 case BufferedImage.TYPE_BYTE_BINARY: 141 { 142 SurfaceType sType; 143 SampleModel sm = bufImg.getRaster().getSampleModel(); 144 switch (sm.getSampleSize(0)) { 145 case 1: 146 sType = SurfaceType.ByteBinary1Bit; 147 break; 148 case 2: 149 sType = SurfaceType.ByteBinary2Bit; 150 break; 151 case 4: 152 sType = SurfaceType.ByteBinary4Bit; 153 break; 154 default: 155 throw new InternalError("Unrecognized pixel size"); 156 } 157 sData = createDataBP(bufImg, sType); 158 } 159 break; 160 case BufferedImage.TYPE_CUSTOM: 161 default: 162 { 163 Raster raster = bufImg.getRaster(); 164 int numBands = raster.getNumBands(); 165 if (raster instanceof IntegerComponentRaster && 166 raster.getNumDataElements() == 1 && 167 ((IntegerComponentRaster)raster).getPixelStride() == 1) 168 { 169 SurfaceType sType = SurfaceType.AnyInt; 170 if (cm instanceof DirectColorModel) { 171 DirectColorModel dcm = (DirectColorModel) cm; 172 int aMask = dcm.getAlphaMask(); 173 int rMask = dcm.getRedMask(); 174 int gMask = dcm.getGreenMask(); 175 int bMask = dcm.getBlueMask(); 176 if (numBands == 3 && 177 aMask == 0 && 178 rMask == DCM_RGBX_RED_MASK && 179 gMask == DCM_RGBX_GREEN_MASK && 180 bMask == DCM_RGBX_BLUE_MASK) 181 { 182 sType = SurfaceType.IntRgbx; 183 } else if (numBands == 4 && 184 aMask == DCM_ARGBBM_ALPHA_MASK && 185 rMask == DCM_ARGBBM_RED_MASK && 186 gMask == DCM_ARGBBM_GREEN_MASK && 187 bMask == DCM_ARGBBM_BLUE_MASK) 188 { 189 sType = SurfaceType.IntArgbBm; 190 } else { 191 sType = SurfaceType.AnyDcm; 192 } 193 } 194 sData = createDataIC(bufImg, sType); 195 break; 196 } else if (raster instanceof ShortComponentRaster && 197 raster.getNumDataElements() == 1 && 198 ((ShortComponentRaster)raster).getPixelStride() == 1) 199 { 200 SurfaceType sType = SurfaceType.AnyShort; 201 IndexColorModel icm = null; 202 if (cm instanceof DirectColorModel) { 203 DirectColorModel dcm = (DirectColorModel) cm; 204 int aMask = dcm.getAlphaMask(); 205 int rMask = dcm.getRedMask(); 206 int gMask = dcm.getGreenMask(); 207 int bMask = dcm.getBlueMask(); 208 if (numBands == 3 && 209 aMask == 0 && 210 rMask == DCM_555X_RED_MASK && 211 gMask == DCM_555X_GREEN_MASK && 212 bMask == DCM_555X_BLUE_MASK) 213 { 214 sType = SurfaceType.Ushort555Rgbx; 215 } else 216 if (numBands == 4 && 217 aMask == DCM_4444_ALPHA_MASK && 218 rMask == DCM_4444_RED_MASK && 219 gMask == DCM_4444_GREEN_MASK && 220 bMask == DCM_4444_BLUE_MASK) 221 { 222 sType = SurfaceType.Ushort4444Argb; 223 } 224 } else if (cm instanceof IndexColorModel) { 225 icm = (IndexColorModel)cm; 226 if (icm.getPixelSize() == 12) { 227 if (isOpaqueGray(icm)) { 228 sType = SurfaceType.Index12Gray; 229 } else { 230 sType = SurfaceType.UshortIndexed; 231 } 232 } else { 233 icm = null; 234 } 235 } 236 sData = createDataSC(bufImg, sType, icm); 237 break; 238 } 239 sData = new BufImgSurfaceData(raster.getDataBuffer(), 240 bufImg, SurfaceType.Custom); 241 } 242 break; 243 } 244 ((BufImgSurfaceData) sData).initSolidLoops(); 245 return sData; 246 } 247 248 public static SurfaceData createData(Raster ras, ColorModel cm) { 249 throw new InternalError("SurfaceData not implemented for Raster/CM"); 250 } 251 252 public static SurfaceData createDataIC(BufferedImage bImg, 253 SurfaceType sType) { 254 IntegerComponentRaster icRaster = 255 (IntegerComponentRaster)bImg.getRaster(); 256 BufImgSurfaceData bisd = 257 new BufImgSurfaceData(icRaster.getDataBuffer(), bImg, sType); 258 bisd.initRaster(icRaster.getDataStorage(), 259 icRaster.getDataOffset(0) * 4, 0, 260 icRaster.getWidth(), 261 icRaster.getHeight(), 262 icRaster.getPixelStride() * 4, 263 icRaster.getScanlineStride() * 4, 264 null); 265 return bisd; 266 } 267 268 public static SurfaceData createDataSC(BufferedImage bImg, 269 SurfaceType sType, 270 IndexColorModel icm) { 271 ShortComponentRaster scRaster = 272 (ShortComponentRaster)bImg.getRaster(); 273 BufImgSurfaceData bisd = 274 new BufImgSurfaceData(scRaster.getDataBuffer(), bImg, sType); 275 bisd.initRaster(scRaster.getDataStorage(), 276 scRaster.getDataOffset(0) * 2, 0, 277 scRaster.getWidth(), 278 scRaster.getHeight(), 279 scRaster.getPixelStride() * 2, 280 scRaster.getScanlineStride() * 2, 281 icm); 282 return bisd; 283 } 284 285 public static SurfaceData createDataBC(BufferedImage bImg, 286 SurfaceType sType, 287 int primaryBank) { 288 ByteComponentRaster bcRaster = 289 (ByteComponentRaster)bImg.getRaster(); 290 BufImgSurfaceData bisd = 291 new BufImgSurfaceData(bcRaster.getDataBuffer(), bImg, sType); 292 ColorModel cm = bImg.getColorModel(); 293 IndexColorModel icm = ((cm instanceof IndexColorModel) 294 ? (IndexColorModel) cm 295 : null); 296 bisd.initRaster(bcRaster.getDataStorage(), 297 bcRaster.getDataOffset(primaryBank), 0, 298 bcRaster.getWidth(), 299 bcRaster.getHeight(), 300 bcRaster.getPixelStride(), 301 bcRaster.getScanlineStride(), 302 icm); 303 return bisd; 304 } 305 306 public static SurfaceData createDataBP(BufferedImage bImg, 307 SurfaceType sType) { 308 BytePackedRaster bpRaster = 309 (BytePackedRaster)bImg.getRaster(); 310 BufImgSurfaceData bisd = 311 new BufImgSurfaceData(bpRaster.getDataBuffer(), bImg, sType); 312 ColorModel cm = bImg.getColorModel(); 313 IndexColorModel icm = ((cm instanceof IndexColorModel) 314 ? (IndexColorModel) cm 315 : null); 316 bisd.initRaster(bpRaster.getDataStorage(), 317 bpRaster.getDataBitOffset() / 8, 318 bpRaster.getDataBitOffset() & 7, 319 bpRaster.getWidth(), 320 bpRaster.getHeight(), 321 0, 322 bpRaster.getScanlineStride(), 323 icm); 324 return bisd; 325 } 326 327 public RenderLoops getRenderLoops(SunGraphics2D sg2d) { 328 if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR && 329 sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY) 330 { 331 return solidloops; 332 } 333 return super.getRenderLoops(sg2d); 334 } 335 336 public java.awt.image.Raster getRaster(int x, int y, int w, int h) { 337 return bufImg.getRaster(); 338 } 339 340 /** 341 * Initializes the native Ops pointer. 342 */ 343 protected native void initRaster(Object theArray, 344 int offset, 345 int bitoffset, 346 int width, 347 int height, 348 int pixStr, 349 int scanStr, 350 IndexColorModel icm); 351 352 public BufImgSurfaceData(DataBuffer db, 353 BufferedImage bufImg, SurfaceType sType) 354 { 355 super(SunWritableRaster.stealTrackable(db), 356 sType, bufImg.getColorModel()); 357 this.bufImg = bufImg; 358 } 359 360 protected BufImgSurfaceData(SurfaceType surfaceType, ColorModel cm) { 361 super(surfaceType, cm); 362 } 363 364 public void initSolidLoops() { 365 this.solidloops = getSolidLoops(getSurfaceType()); 366 } 367 368 private static final int CACHE_SIZE = 5; 369 private static RenderLoops loopcache[] = new RenderLoops[CACHE_SIZE]; 370 private static SurfaceType typecache[] = new SurfaceType[CACHE_SIZE]; 371 public static synchronized RenderLoops getSolidLoops(SurfaceType type) { 372 for (int i = CACHE_SIZE - 1; i >= 0; i--) { 373 SurfaceType t = typecache[i]; 374 if (t == type) { 375 return loopcache[i]; 376 } else if (t == null) { 377 break; 378 } 379 } 380 RenderLoops l = makeRenderLoops(SurfaceType.OpaqueColor, 381 CompositeType.SrcNoEa, 382 type); 383 System.arraycopy(loopcache, 1, loopcache, 0, CACHE_SIZE-1); 384 System.arraycopy(typecache, 1, typecache, 0, CACHE_SIZE-1); 385 loopcache[CACHE_SIZE - 1] = l; 386 typecache[CACHE_SIZE - 1] = type; 387 return l; 388 } 389 390 public SurfaceData getReplacement() { 391 // BufImgSurfaceData objects should never lose their contents, 392 // so this method should never be called. 393 return restoreContents(bufImg); 394 } 395 396 public synchronized GraphicsConfiguration getDeviceConfiguration() { 397 if (graphicsConfig == null) { 398 graphicsConfig = BufferedImageGraphicsConfig.getConfig(bufImg); 399 } 400 return graphicsConfig; 401 } 402 403 public java.awt.Rectangle getBounds() { 404 return new Rectangle(bufImg.getWidth(), bufImg.getHeight()); 405 } 406 407 protected void checkCustomComposite() { 408 // BufferedImages always allow Custom Composite objects since 409 // their pixels are immediately retrievable anyway. 410 } 411 412 private static native void freeNativeICMData(long pData); 413 414 /** 415 * Returns destination Image associated with this SurfaceData. 416 */ 417 public Object getDestination() { 418 return bufImg; 419 } 420 421 public static final class ICMColorData { 422 private long pData = 0L; 423 424 private ICMColorData(long pData) { 425 this.pData = pData; 426 } 427 428 public void finalize() { 429 if (pData != 0L) { 430 BufImgSurfaceData.freeNativeICMData(pData); 431 pData = 0L; 432 } 433 } 434 } 435 }