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 = createData(raster.getDataBuffer(), bufImg, SurfaceType.Custom); 240 } 241 break; 242 } 243 ((BufImgSurfaceData) sData).initSolidLoops(); 244 return sData; 245 } 246 247 private static BufImgSurfaceData createData(DataBuffer db, BufferedImage bufImg, 248 SurfaceType sType) 249 { 250 if (bufImg instanceof OffScreenImage) { 251 return ((OffScreenImage)bufImg).new SurfaceData(db, sType); 252 } 253 return new BufImgSurfaceData(db, bufImg, sType); 254 } 255 256 public static SurfaceData createData(Raster ras, ColorModel cm) { 257 throw new InternalError("SurfaceData not implemented for Raster/CM"); 258 } 259 260 public static SurfaceData createDataIC(BufferedImage bImg, 261 SurfaceType sType) { 262 IntegerComponentRaster icRaster = 263 (IntegerComponentRaster)bImg.getRaster(); 264 BufImgSurfaceData bisd = createData(icRaster.getDataBuffer(), bImg, sType); 265 bisd.initRaster(icRaster.getDataStorage(), 266 icRaster.getDataOffset(0) * 4, 0, 267 icRaster.getWidth(), 268 icRaster.getHeight(), 269 icRaster.getPixelStride() * 4, 270 icRaster.getScanlineStride() * 4, 271 null); 272 return bisd; 273 } 274 275 public static SurfaceData createDataSC(BufferedImage bImg, 276 SurfaceType sType, 277 IndexColorModel icm) { 278 ShortComponentRaster scRaster = 279 (ShortComponentRaster)bImg.getRaster(); 280 BufImgSurfaceData bisd = createData(scRaster.getDataBuffer(), bImg, sType); 281 bisd.initRaster(scRaster.getDataStorage(), 282 scRaster.getDataOffset(0) * 2, 0, 283 scRaster.getWidth(), 284 scRaster.getHeight(), 285 scRaster.getPixelStride() * 2, 286 scRaster.getScanlineStride() * 2, 287 icm); 288 return bisd; 289 } 290 291 public static SurfaceData createDataBC(BufferedImage bImg, 292 SurfaceType sType, 293 int primaryBank) { 294 ByteComponentRaster bcRaster = 295 (ByteComponentRaster)bImg.getRaster(); 296 BufImgSurfaceData bisd = createData(bcRaster.getDataBuffer(), bImg, sType); 297 ColorModel cm = bImg.getColorModel(); 298 IndexColorModel icm = ((cm instanceof IndexColorModel) 299 ? (IndexColorModel) cm 300 : null); 301 bisd.initRaster(bcRaster.getDataStorage(), 302 bcRaster.getDataOffset(primaryBank), 0, 303 bcRaster.getWidth(), 304 bcRaster.getHeight(), 305 bcRaster.getPixelStride(), 306 bcRaster.getScanlineStride(), 307 icm); 308 return bisd; 309 } 310 311 public static SurfaceData createDataBP(BufferedImage bImg, 312 SurfaceType sType) { 313 BytePackedRaster bpRaster = 314 (BytePackedRaster)bImg.getRaster(); 315 BufImgSurfaceData bisd = createData(bpRaster.getDataBuffer(), bImg, sType); 316 ColorModel cm = bImg.getColorModel(); 317 IndexColorModel icm = ((cm instanceof IndexColorModel) 318 ? (IndexColorModel) cm 319 : null); 320 bisd.initRaster(bpRaster.getDataStorage(), 321 bpRaster.getDataBitOffset() / 8, 322 bpRaster.getDataBitOffset() & 7, 323 bpRaster.getWidth(), 324 bpRaster.getHeight(), 325 0, 326 bpRaster.getScanlineStride(), 327 icm); 328 return bisd; 329 } 330 331 public RenderLoops getRenderLoops(SunGraphics2D sg2d) { 332 if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR && 333 sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY) 334 { 335 return solidloops; 336 } 337 return super.getRenderLoops(sg2d); 338 } 339 340 public java.awt.image.Raster getRaster(int x, int y, int w, int h) { 341 return bufImg.getRaster(); 342 } 343 344 /** 345 * Initializes the native Ops pointer. 346 */ 347 protected native void initRaster(Object theArray, 348 int offset, 349 int bitoffset, 350 int width, 351 int height, 352 int pixStr, 353 int scanStr, 354 IndexColorModel icm); 355 356 public BufImgSurfaceData(DataBuffer db, 357 BufferedImage bufImg, SurfaceType sType) 358 { 359 super(SunWritableRaster.stealTrackable(db), 360 sType, bufImg.getColorModel()); 361 this.bufImg = bufImg; 362 } 363 364 protected BufImgSurfaceData(SurfaceType surfaceType, ColorModel cm) { 365 super(surfaceType, cm); 366 } 367 368 public void initSolidLoops() { 369 this.solidloops = getSolidLoops(getSurfaceType()); 370 } 371 372 private static final int CACHE_SIZE = 5; 373 private static RenderLoops loopcache[] = new RenderLoops[CACHE_SIZE]; 374 private static SurfaceType typecache[] = new SurfaceType[CACHE_SIZE]; 375 public static synchronized RenderLoops getSolidLoops(SurfaceType type) { 376 for (int i = CACHE_SIZE - 1; i >= 0; i--) { 377 SurfaceType t = typecache[i]; 378 if (t == type) { 379 return loopcache[i]; 380 } else if (t == null) { 381 break; 382 } 383 } 384 RenderLoops l = makeRenderLoops(SurfaceType.OpaqueColor, 385 CompositeType.SrcNoEa, 386 type); 387 System.arraycopy(loopcache, 1, loopcache, 0, CACHE_SIZE-1); 388 System.arraycopy(typecache, 1, typecache, 0, CACHE_SIZE-1); 389 loopcache[CACHE_SIZE - 1] = l; 390 typecache[CACHE_SIZE - 1] = type; 391 return l; 392 } 393 394 public SurfaceData getReplacement() { 395 // BufImgSurfaceData objects should never lose their contents, 396 // so this method should never be called. 397 return restoreContents(bufImg); 398 } 399 400 public synchronized GraphicsConfiguration getDeviceConfiguration() { 401 if (graphicsConfig == null) { 402 graphicsConfig = BufferedImageGraphicsConfig.getConfig(bufImg); 403 } 404 return graphicsConfig; 405 } 406 407 public java.awt.Rectangle getBounds() { 408 return new Rectangle(bufImg.getWidth(), bufImg.getHeight()); 409 } 410 411 protected void checkCustomComposite() { 412 // BufferedImages always allow Custom Composite objects since 413 // their pixels are immediately retrievable anyway. 414 } 415 416 private static native void freeNativeICMData(long pData); 417 418 /** 419 * Returns destination Image associated with this SurfaceData. 420 */ 421 public Object getDestination() { 422 return bufImg; 423 } 424 425 public static final class ICMColorData { 426 private long pData = 0L; 427 428 private ICMColorData(long pData) { 429 this.pData = pData; 430 } 431 432 public void finalize() { 433 if (pData != 0L) { 434 BufImgSurfaceData.freeNativeICMData(pData); 435 pData = 0L; 436 } 437 } 438 } 439 }