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