/* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.awt; import java.awt.AWTException; import java.awt.BufferCapabilities; import java.awt.BufferCapabilities.FlipContents; import java.awt.Component; import java.awt.Toolkit; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.Image; import java.awt.ImageCapabilities; import java.awt.Transparency; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.color.ColorSpace; import java.awt.image.ComponentColorModel; import java.awt.image.DirectColorModel; import java.awt.image.DataBuffer; import java.awt.image.VolatileImage; import java.awt.image.WritableRaster; import java.awt.geom.AffineTransform; import java.awt.Rectangle; import sun.java2d.Disposer; import sun.java2d.DisposerRecord; import sun.java2d.SurfaceData; import sun.java2d.loops.RenderLoops; import sun.java2d.loops.SurfaceType; import sun.java2d.loops.CompositeType; import sun.java2d.x11.X11SurfaceData; import sun.awt.image.OffScreenImage; import sun.awt.image.SunVolatileImage; import sun.awt.image.SurfaceManager; import sun.awt.X11ComponentPeer; /** * This is an implementation of a GraphicsConfiguration object for a * single X11 visual. * * @see java.awt.GraphicsEnvironment * @see GraphicsDevice */ public class X11GraphicsConfig extends GraphicsConfiguration implements SurfaceManager.ProxiedGraphicsConfig { protected X11GraphicsDevice screen; protected int visual; int depth; int colormap; ColorModel colorModel; long aData; boolean doubleBuffer; private Object disposerReferent = new Object(); private BufferCapabilities bufferCaps; private static ImageCapabilities imageCaps = new ImageCapabilities(X11SurfaceData.isAccelerationEnabled()); // will be set on native level from init() protected int bitsPerPixel; protected SurfaceType surfaceType; public RenderLoops solidloops; public static X11GraphicsConfig getConfig(X11GraphicsDevice device, int visualnum, int depth, int colormap, boolean doubleBuffer) { return new X11GraphicsConfig(device, visualnum, depth, colormap, doubleBuffer); } /* * Note this method is currently here for backward compatibility * as this was the method used in jdk 1.2 beta4 to create the * X11GraphicsConfig objects. Java3D code had called this method * explicitly so without this, if a user tries to use JDK1.2 fcs * with Java3D beta1, a NoSuchMethod execption is thrown and * the program exits. REMOVE this method after Java3D fcs is * released! */ public static X11GraphicsConfig getConfig(X11GraphicsDevice device, int visualnum, int depth, int colormap, int type) { return new X11GraphicsConfig(device, visualnum, depth, colormap, false); } private native int getNumColors(); private native void init(int visualNum, int screen); private native ColorModel makeColorModel(); protected X11GraphicsConfig(X11GraphicsDevice device, int visualnum, int depth, int colormap, boolean doubleBuffer) { this.screen = device; this.visual = visualnum; this.doubleBuffer = doubleBuffer; this.depth = depth; this.colormap = colormap; init (visualnum, screen.getScreen()); // add a record to the Disposer so that we destroy the native // AwtGraphicsConfigData when this object goes away (i.e. after a // display change event) long x11CfgData = getAData(); Disposer.addRecord(disposerReferent, new X11GCDisposerRecord(x11CfgData)); } /** * Return the graphics device associated with this configuration. */ public GraphicsDevice getDevice() { return screen; } /** * Returns the visual id associated with this configuration. */ public int getVisual () { return visual; } /** * Returns the depth associated with this configuration. */ public int getDepth () { return depth; } /** * Returns the colormap associated with this configuration. */ public int getColormap () { return colormap; } /** * Returns a number of bits allocated per pixel * (might be different from depth) */ public int getBitsPerPixel() { return bitsPerPixel; } public synchronized SurfaceType getSurfaceType() { if (surfaceType != null) { return surfaceType; } surfaceType = X11SurfaceData.getSurfaceType(this, Transparency.OPAQUE); return surfaceType; } public Object getProxyKey() { return screen.getProxyKeyFor(getSurfaceType()); } /** * Return the RenderLoops this type of destination uses for * solid fills and strokes. */ public synchronized RenderLoops getSolidLoops(SurfaceType stype) { if (solidloops == null) { solidloops = SurfaceData.makeRenderLoops(SurfaceType.OpaqueColor, CompositeType.SrcNoEa, stype); } return solidloops; } /** * Returns the color model associated with this configuration. */ public synchronized ColorModel getColorModel() { if (colorModel == null) { // Force SystemColors to be resolved before we create the CM java.awt.SystemColor.window.getRGB(); // This method, makeColorModel(), can return null if the // toolkit is not initialized yet. // The toolkit will then call back to this routine after it // is initialized and makeColorModel() should return a non-null // colorModel. colorModel = makeColorModel(); if (colorModel == null) colorModel = Toolkit.getDefaultToolkit ().getColorModel (); } return colorModel; } /** * Returns the color model associated with this configuration that * supports the specified transparency. */ public ColorModel getColorModel(int transparency) { switch (transparency) { case Transparency.OPAQUE: return getColorModel(); case Transparency.BITMASK: return new DirectColorModel(25, 0xff0000, 0xff00, 0xff, 0x1000000); case Transparency.TRANSLUCENT: return ColorModel.getRGBdefault(); default: return null; } } public static DirectColorModel createDCM32(int rMask, int gMask, int bMask, int aMask, boolean aPre) { return new DirectColorModel( ColorSpace.getInstance(ColorSpace.CS_sRGB), 32, rMask, gMask, bMask, aMask, aPre, DataBuffer.TYPE_INT); } public static ComponentColorModel createABGRCCM() { ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); int[] nBits = {8, 8, 8, 8}; int[] bOffs = {3, 2, 1, 0}; return new ComponentColorModel(cs, nBits, true, true, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE); } /** * Returns the default Transform for this configuration. This * Transform is typically the Identity transform for most normal * screens. Device coordinates for screen and printer devices will * have the origin in the upper left-hand corner of the target region of * the device, with X coordinates * increasing to the right and Y coordinates increasing downwards. * For image buffers, this Transform will be the Identity transform. */ public AffineTransform getDefaultTransform() { return new AffineTransform(); } /** * * Returns a Transform that can be composed with the default Transform * of a Graphics2D so that 72 units in user space will equal 1 inch * in device space. * Given a Graphics2D, g, one can reset the transformation to create * such a mapping by using the following pseudocode: *
     *      GraphicsConfiguration gc = g.getGraphicsConfiguration();
     *
     *      g.setTransform(gc.getDefaultTransform());
     *      g.transform(gc.getNormalizingTransform());
     * 
* Note that sometimes this Transform will be identity (e.g. for * printers or metafile output) and that this Transform is only * as accurate as the information supplied by the underlying system. * For image buffers, this Transform will be the Identity transform, * since there is no valid distance measurement. */ public AffineTransform getNormalizingTransform() { double xscale = getXResolution(screen.getScreen()) / 72.0; double yscale = getYResolution(screen.getScreen()) / 72.0; return new AffineTransform(xscale, 0.0, 0.0, yscale, 0.0, 0.0); } private native double getXResolution(int screen); private native double getYResolution(int screen); public long getAData() { return aData; } public String toString() { return ("X11GraphicsConfig[dev="+screen+ ",vis=0x"+Integer.toHexString(visual)+ "]"); } /* * Initialize JNI field and method IDs for fields that may be * accessed from C. */ private static native void initIDs(); static { initIDs (); } public Rectangle getBounds() { return pGetBounds(screen.getScreen()); } public native Rectangle pGetBounds(int screenNum); private static class XDBECapabilities extends BufferCapabilities { public XDBECapabilities() { super(imageCaps, imageCaps, FlipContents.UNDEFINED); } } public BufferCapabilities getBufferCapabilities() { if (bufferCaps == null) { if (doubleBuffer) { bufferCaps = new XDBECapabilities(); } else { bufferCaps = super.getBufferCapabilities(); } } return bufferCaps; } public ImageCapabilities getImageCapabilities() { return imageCaps; } public boolean isDoubleBuffered() { return doubleBuffer; } private static native void dispose(long x11ConfigData); private static class X11GCDisposerRecord implements DisposerRecord { private long x11ConfigData; public X11GCDisposerRecord(long x11CfgData) { this.x11ConfigData = x11CfgData; } public synchronized void dispose() { if (x11ConfigData != 0L) { X11GraphicsConfig.dispose(x11ConfigData); x11ConfigData = 0L; } } } /** * The following methods are invoked from {M,X}Toolkit.java and * X11ComponentPeer.java rather than having the X11-dependent * implementations hardcoded in those classes. This way the appropriate * actions are taken based on the peer's GraphicsConfig, whether it is * an X11GraphicsConfig or a GLXGraphicsConfig. */ /** * Creates a new SurfaceData that will be associated with the given * X11ComponentPeer. */ public SurfaceData createSurfaceData(X11ComponentPeer peer) { return X11SurfaceData.createData(peer); } /** * Creates a new hidden-acceleration image of the given width and height * that is associated with the target Component. */ public Image createAcceleratedImage(Component target, int width, int height) { // As of 1.7 we no longer create pmoffscreens here... ColorModel model = getColorModel(Transparency.OPAQUE); WritableRaster wr = model.createCompatibleWritableRaster(width, height); return new OffScreenImage(target, model, wr, model.isAlphaPremultiplied()); } /** * The following methods correspond to the multibuffering methods in * X11ComponentPeer.java... */ private native long createBackBuffer(long window, int swapAction); private native void swapBuffers(long window, int swapAction); /** * Attempts to create an XDBE-based backbuffer for the given peer. If * the requested configuration is not natively supported, an AWTException * is thrown. Otherwise, if the backbuffer creation is successful, a * handle to the native backbuffer is returned. */ public long createBackBuffer(X11ComponentPeer peer, int numBuffers, BufferCapabilities caps) throws AWTException { if (!X11GraphicsDevice.isDBESupported()) { throw new AWTException("Page flipping is not supported"); } if (numBuffers > 2) { throw new AWTException( "Only double or single buffering is supported"); } BufferCapabilities configCaps = getBufferCapabilities(); if (!configCaps.isPageFlipping()) { throw new AWTException("Page flipping is not supported"); } long window = peer.getContentWindow(); int swapAction = getSwapAction(caps.getFlipContents()); return createBackBuffer(window, swapAction); } /** * Destroys the backbuffer object represented by the given handle value. */ public native void destroyBackBuffer(long backBuffer); /** * Creates a VolatileImage that essentially wraps the target Component's * backbuffer, using the provided backbuffer handle. */ public VolatileImage createBackBufferImage(Component target, long backBuffer) { return new SunVolatileImage(target, target.getWidth(), target.getHeight(), Long.valueOf(backBuffer)); } /** * Performs the native XDBE flip operation for the given target Component. */ public void flip(X11ComponentPeer peer, Component target, VolatileImage xBackBuffer, int x1, int y1, int x2, int y2, BufferCapabilities.FlipContents flipAction) { long window = peer.getContentWindow(); int swapAction = getSwapAction(flipAction); swapBuffers(window, swapAction); } /** * Maps the given FlipContents constant to the associated XDBE swap * action constant. */ private static int getSwapAction( BufferCapabilities.FlipContents flipAction) { if (flipAction == BufferCapabilities.FlipContents.BACKGROUND) { return 0x01; } else if (flipAction == BufferCapabilities.FlipContents.PRIOR) { return 0x02; } else if (flipAction == BufferCapabilities.FlipContents.COPIED) { return 0x03; } else { return 0x00; // UNDEFINED } } @Override public boolean isTranslucencyCapable() { return isTranslucencyCapable(getAData()); } private native boolean isTranslucencyCapable(long x11ConfigData); }