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