1 /* 2 * Copyright (c) 1997, 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; 27 28 import java.awt.AWTException; 29 import java.awt.BufferCapabilities; 30 import java.awt.BufferCapabilities.FlipContents; 31 import java.awt.Component; 32 import java.awt.Toolkit; 33 import java.awt.GraphicsConfiguration; 34 import java.awt.GraphicsDevice; 35 import java.awt.Image; 36 import java.awt.ImageCapabilities; 37 import java.awt.Transparency; 38 import java.awt.image.BufferedImage; 39 import java.awt.image.ColorModel; 40 import java.awt.color.ColorSpace; 41 import java.awt.image.ComponentColorModel; 42 import java.awt.image.DirectColorModel; 43 import java.awt.image.DataBuffer; 44 import java.awt.image.VolatileImage; 45 import java.awt.image.WritableRaster; 46 import java.awt.geom.AffineTransform; 47 import java.awt.Rectangle; 48 import sun.java2d.Disposer; 49 import sun.java2d.DisposerRecord; 50 import sun.java2d.SurfaceData; 51 import sun.java2d.loops.RenderLoops; 52 import sun.java2d.loops.SurfaceType; 53 import sun.java2d.loops.CompositeType; 54 import sun.java2d.x11.X11SurfaceData; 55 import sun.awt.image.OffScreenImage; 56 import sun.awt.image.SunVolatileImage; 57 import sun.awt.image.SurfaceManager; 58 import sun.awt.X11ComponentPeer; 59 60 /** 61 * This is an implementation of a GraphicsConfiguration object for a 62 * single X11 visual. 63 * 64 * @see java.awt.GraphicsEnvironment 65 * @see GraphicsDevice 66 */ 67 public class X11GraphicsConfig extends GraphicsConfiguration 68 implements SurfaceManager.ProxiedGraphicsConfig 69 { 70 protected X11GraphicsDevice screen; 71 protected int visual; 72 int depth; 73 int colormap; 74 ColorModel colorModel; 75 long aData; 76 boolean doubleBuffer; 77 private Object disposerReferent = new Object(); 78 private BufferCapabilities bufferCaps; 79 private static ImageCapabilities imageCaps = 80 new ImageCapabilities(X11SurfaceData.isAccelerationEnabled()); 81 82 // will be set on native level from init() 83 protected int bitsPerPixel; 84 85 protected SurfaceType surfaceType; 86 87 public RenderLoops solidloops; 88 89 public static X11GraphicsConfig getConfig(X11GraphicsDevice device, 90 int visualnum, int depth, 91 int colormap, 92 boolean doubleBuffer) 93 { 94 return new X11GraphicsConfig(device, visualnum, depth, colormap, doubleBuffer); 95 } 96 97 /* 98 * Note this method is currently here for backward compatibility 99 * as this was the method used in jdk 1.2 beta4 to create the 100 * X11GraphicsConfig objects. Java3D code had called this method 101 * explicitly so without this, if a user tries to use JDK1.2 fcs 102 * with Java3D beta1, a NoSuchMethod execption is thrown and 103 * the program exits. REMOVE this method after Java3D fcs is 104 * released! 105 */ 106 public static X11GraphicsConfig getConfig(X11GraphicsDevice device, 107 int visualnum, int depth, 108 int colormap, int type) 109 { 110 return new X11GraphicsConfig(device, visualnum, depth, colormap, false); 111 } 112 113 private native int getNumColors(); 114 private native void init(int visualNum, int screen); 115 private native ColorModel makeColorModel(); 116 117 protected X11GraphicsConfig(X11GraphicsDevice device, 118 int visualnum, int depth, 119 int colormap, boolean doubleBuffer) 120 { 121 this.screen = device; 122 this.visual = visualnum; 123 this.doubleBuffer = doubleBuffer; 124 this.depth = depth; 125 this.colormap = colormap; 126 init (visualnum, screen.getScreen()); 127 128 // add a record to the Disposer so that we destroy the native 129 // AwtGraphicsConfigData when this object goes away (i.e. after a 130 // display change event) 131 long x11CfgData = getAData(); 132 Disposer.addRecord(disposerReferent, 133 new X11GCDisposerRecord(x11CfgData)); 134 } 135 136 /** 137 * Return the graphics device associated with this configuration. 138 */ 139 public GraphicsDevice getDevice() { 140 return screen; 141 } 142 143 /** 144 * Returns the visual id associated with this configuration. 145 */ 146 public int getVisual () { 147 return visual; 148 } 149 150 151 /** 152 * Returns the depth associated with this configuration. 153 */ 154 public int getDepth () { 155 return depth; 156 } 157 158 /** 159 * Returns the colormap associated with this configuration. 160 */ 161 public int getColormap () { 162 return colormap; 163 } 164 165 /** 166 * Returns a number of bits allocated per pixel 167 * (might be different from depth) 168 */ 169 public int getBitsPerPixel() { 170 return bitsPerPixel; 171 } 172 173 public synchronized SurfaceType getSurfaceType() { 174 if (surfaceType != null) { 175 return surfaceType; 176 } 177 178 surfaceType = X11SurfaceData.getSurfaceType(this, Transparency.OPAQUE); 179 return surfaceType; 180 } 181 182 public Object getProxyKey() { 183 return screen.getProxyKeyFor(getSurfaceType()); 184 } 185 186 /** 187 * Return the RenderLoops this type of destination uses for 188 * solid fills and strokes. 189 */ 190 public synchronized RenderLoops getSolidLoops(SurfaceType stype) { 191 if (solidloops == null) { 192 solidloops = SurfaceData.makeRenderLoops(SurfaceType.OpaqueColor, 193 CompositeType.SrcNoEa, 194 stype); 195 } 196 return solidloops; 197 } 198 199 /** 200 * Returns the color model associated with this configuration. 201 */ 202 public synchronized ColorModel getColorModel() { 203 if (colorModel == null) { 204 // Force SystemColors to be resolved before we create the CM 205 java.awt.SystemColor.window.getRGB(); 206 // This method, makeColorModel(), can return null if the 207 // toolkit is not initialized yet. 208 // The toolkit will then call back to this routine after it 209 // is initialized and makeColorModel() should return a non-null 210 // colorModel. 211 colorModel = makeColorModel(); 212 if (colorModel == null) 213 colorModel = Toolkit.getDefaultToolkit ().getColorModel (); 214 } 215 216 return colorModel; 217 } 218 219 /** 220 * Returns the color model associated with this configuration that 221 * supports the specified transparency. 222 */ 223 public ColorModel getColorModel(int transparency) { 224 switch (transparency) { 225 case Transparency.OPAQUE: 226 return getColorModel(); 227 case Transparency.BITMASK: 228 return new DirectColorModel(25, 0xff0000, 0xff00, 0xff, 0x1000000); 229 case Transparency.TRANSLUCENT: 230 return ColorModel.getRGBdefault(); 231 default: 232 return null; 233 } 234 } 235 236 public static DirectColorModel createDCM32(int rMask, int gMask, int bMask, 237 int aMask, boolean aPre) { 238 return new DirectColorModel( 239 ColorSpace.getInstance(ColorSpace.CS_sRGB), 240 32, rMask, gMask, bMask, aMask, aPre, DataBuffer.TYPE_INT); 241 } 242 243 public static ComponentColorModel createABGRCCM() { 244 ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); 245 int[] nBits = {8, 8, 8, 8}; 246 int[] bOffs = {3, 2, 1, 0}; 247 return new ComponentColorModel(cs, nBits, true, true, 248 Transparency.TRANSLUCENT, 249 DataBuffer.TYPE_BYTE); 250 } 251 252 /** 253 * Returns the default Transform for this configuration. This 254 * Transform is typically the Identity transform for most normal 255 * screens. Device coordinates for screen and printer devices will 256 * have the origin in the upper left-hand corner of the target region of 257 * the device, with X coordinates 258 * increasing to the right and Y coordinates increasing downwards. 259 * For image buffers, this Transform will be the Identity transform. 260 */ 261 public AffineTransform getDefaultTransform() { 262 return new AffineTransform(); 263 } 264 265 /** 266 * 267 * Returns a Transform that can be composed with the default Transform 268 * of a Graphics2D so that 72 units in user space will equal 1 inch 269 * in device space. 270 * Given a Graphics2D, g, one can reset the transformation to create 271 * such a mapping by using the following pseudocode: 272 * <pre> 273 * GraphicsConfiguration gc = g.getGraphicsConfiguration(); 274 * 275 * g.setTransform(gc.getDefaultTransform()); 276 * g.transform(gc.getNormalizingTransform()); 277 * </pre> 278 * Note that sometimes this Transform will be identity (e.g. for 279 * printers or metafile output) and that this Transform is only 280 * as accurate as the information supplied by the underlying system. 281 * For image buffers, this Transform will be the Identity transform, 282 * since there is no valid distance measurement. 283 */ 284 public AffineTransform getNormalizingTransform() { 285 double xscale = getXResolution(screen.getScreen()) / 72.0; 286 double yscale = getYResolution(screen.getScreen()) / 72.0; 287 return new AffineTransform(xscale, 0.0, 0.0, yscale, 0.0, 0.0); 288 } 289 290 private native double getXResolution(int screen); 291 private native double getYResolution(int screen); 292 293 public long getAData() { 294 return aData; 295 } 296 297 public String toString() { 298 return ("X11GraphicsConfig[dev="+screen+ 299 ",vis=0x"+Integer.toHexString(visual)+ 300 "]"); 301 } 302 303 /* 304 * Initialize JNI field and method IDs for fields that may be 305 * accessed from C. 306 */ 307 private static native void initIDs(); 308 309 static { 310 initIDs (); 311 } 312 313 public Rectangle getBounds() { 314 return pGetBounds(screen.getScreen()); 315 } 316 317 public native Rectangle pGetBounds(int screenNum); 318 319 private static class XDBECapabilities extends BufferCapabilities { 320 public XDBECapabilities() { 321 super(imageCaps, imageCaps, FlipContents.UNDEFINED); 322 } 323 } 324 325 public BufferCapabilities getBufferCapabilities() { 326 if (bufferCaps == null) { 327 if (doubleBuffer) { 328 bufferCaps = new XDBECapabilities(); 329 } else { 330 bufferCaps = super.getBufferCapabilities(); 331 } 332 } 333 return bufferCaps; 334 } 335 336 public ImageCapabilities getImageCapabilities() { 337 return imageCaps; 338 } 339 340 public boolean isDoubleBuffered() { 341 return doubleBuffer; 342 } 343 344 private static native void dispose(long x11ConfigData); 345 346 private static class X11GCDisposerRecord implements DisposerRecord { 347 private long x11ConfigData; 348 public X11GCDisposerRecord(long x11CfgData) { 349 this.x11ConfigData = x11CfgData; 350 } 351 public synchronized void dispose() { 352 if (x11ConfigData != 0L) { 353 X11GraphicsConfig.dispose(x11ConfigData); 354 x11ConfigData = 0L; 355 } 356 } 357 } 358 359 /** 360 * The following methods are invoked from {M,X}Toolkit.java and 361 * X11ComponentPeer.java rather than having the X11-dependent 362 * implementations hardcoded in those classes. This way the appropriate 363 * actions are taken based on the peer's GraphicsConfig, whether it is 364 * an X11GraphicsConfig or a GLXGraphicsConfig. 365 */ 366 367 /** 368 * Creates a new SurfaceData that will be associated with the given 369 * X11ComponentPeer. 370 */ 371 public SurfaceData createSurfaceData(X11ComponentPeer peer) { 372 return X11SurfaceData.createData(peer); 373 } 374 375 /** 376 * Creates a new hidden-acceleration image of the given width and height 377 * that is associated with the target Component. 378 */ 379 public Image createAcceleratedImage(Component target, 380 int width, int height) 381 { 382 // As of 1.7 we no longer create pmoffscreens here... 383 ColorModel model = getColorModel(Transparency.OPAQUE); 384 WritableRaster wr = 385 model.createCompatibleWritableRaster(width, height); 386 return new OffScreenImage(target, model, wr, 387 model.isAlphaPremultiplied()); 388 } 389 390 /** 391 * The following methods correspond to the multibuffering methods in 392 * X11ComponentPeer.java... 393 */ 394 395 private native long createBackBuffer(long window, int swapAction); 396 private native void swapBuffers(long window, int swapAction); 397 398 /** 399 * Attempts to create an XDBE-based backbuffer for the given peer. If 400 * the requested configuration is not natively supported, an AWTException 401 * is thrown. Otherwise, if the backbuffer creation is successful, a 402 * handle to the native backbuffer is returned. 403 */ 404 public long createBackBuffer(X11ComponentPeer peer, 405 int numBuffers, BufferCapabilities caps) 406 throws AWTException 407 { 408 if (!X11GraphicsDevice.isDBESupported()) { 409 throw new AWTException("Page flipping is not supported"); 410 } 411 if (numBuffers > 2) { 412 throw new AWTException( 413 "Only double or single buffering is supported"); 414 } 415 BufferCapabilities configCaps = getBufferCapabilities(); 416 if (!configCaps.isPageFlipping()) { 417 throw new AWTException("Page flipping is not supported"); 418 } 419 420 long window = peer.getContentWindow(); 421 int swapAction = getSwapAction(caps.getFlipContents()); 422 423 return createBackBuffer(window, swapAction); 424 } 425 426 /** 427 * Destroys the backbuffer object represented by the given handle value. 428 */ 429 public native void destroyBackBuffer(long backBuffer); 430 431 /** 432 * Creates a VolatileImage that essentially wraps the target Component's 433 * backbuffer, using the provided backbuffer handle. 434 */ 435 public VolatileImage createBackBufferImage(Component target, 436 long backBuffer) 437 { 438 return new SunVolatileImage(target, 439 target.getWidth(), target.getHeight(), 440 Long.valueOf(backBuffer)); 441 } 442 443 /** 444 * Performs the native XDBE flip operation for the given target Component. 445 */ 446 public void flip(X11ComponentPeer peer, 447 Component target, VolatileImage xBackBuffer, 448 int x1, int y1, int x2, int y2, 449 BufferCapabilities.FlipContents flipAction) 450 { 451 long window = peer.getContentWindow(); 452 int swapAction = getSwapAction(flipAction); 453 swapBuffers(window, swapAction); 454 } 455 456 /** 457 * Maps the given FlipContents constant to the associated XDBE swap 458 * action constant. 459 */ 460 private static int getSwapAction( 461 BufferCapabilities.FlipContents flipAction) { 462 if (flipAction == BufferCapabilities.FlipContents.BACKGROUND) { 463 return 0x01; 464 } else if (flipAction == BufferCapabilities.FlipContents.PRIOR) { 465 return 0x02; 466 } else if (flipAction == BufferCapabilities.FlipContents.COPIED) { 467 return 0x03; 468 } else { 469 return 0x00; // UNDEFINED 470 } 471 } 472 473 @Override 474 public boolean isTranslucencyCapable() { 475 return isTranslucencyCapable(getAData()); 476 } 477 478 private native boolean isTranslucencyCapable(long x11ConfigData); 479 }