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