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 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 return createData(bufImg, 1, 1); 75 } 76 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 260 public static SurfaceData createData(Raster ras, ColorModel cm) { 261 throw new InternalError("SurfaceData not implemented for Raster/CM"); 262 } 263 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 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 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 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 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 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 */ 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 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 390 protected BufImgSurfaceData(SurfaceType surfaceType, ColorModel cm) { 391 super(surfaceType, cm); 392 this.scaleX = 1; 393 this.scaleY = 1; 394 } 395 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]; 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 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 428 public synchronized GraphicsConfiguration getDeviceConfiguration() { 429 if (graphicsConfig == null) { 430 graphicsConfig = BufferedImageGraphicsConfig 431 .getConfig(bufImg, scaleX, scaleY); 432 } 433 return graphicsConfig; 434 } 435 436 public java.awt.Rectangle getBounds() { 437 return new Rectangle(bufImg.getWidth(), bufImg.getHeight()); 438 } 439 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 */ 448 public Object getDestination() { 449 return bufImg; 450 } 451 452 @Override 453 public double getDefaultScaleX() { 454 return scaleX; 455 } 456 457 @Override 458 public double getDefaultScaleY() { 459 return scaleY; 460 } 461 462 public static final class ICMColorData { 463 private long pData = 0L; 464 465 private ICMColorData(long pData) { 466 this.pData = pData; 467 } 468 } 469 }