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