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