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 }