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 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 
getConfig(X11GraphicsDevice device, int visualnum, int depth, int colormap, boolean doubleBuffer)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      */
getConfig(X11GraphicsDevice device, int visualnum, int depth, int colormap, int type)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 
getNumColors()113     private native int getNumColors();
init(int visualNum, int screen)114     private native void init(int visualNum, int screen);
makeColorModel()115     private native ColorModel makeColorModel();
116 
X11GraphicsConfig(X11GraphicsDevice device, int visualnum, int depth, int colormap, boolean doubleBuffer)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      */
getDevice()139     public GraphicsDevice getDevice() {
140         return screen;
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 
getProxyKey()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      */
getSolidLoops(SurfaceType stype)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      */
getColorModel()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      */
getColorModel(int transparency)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 
createDCM32(int rMask, int gMask, int bMask, int aMask, boolean aPre)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 
createABGRCCM()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      */
getDefaultTransform()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      */
getNormalizingTransform()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 
getXResolution(int screen)290     private native double getXResolution(int screen);
getYResolution(int screen)291     private native double getYResolution(int screen);
292 
getAData()293     public long getAData() {
294         return aData;
295     }
296 
toString()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      */
initIDs()307     private static native void initIDs();
308 
309     static {
initIDs()310         initIDs ();
311     }
312 
getBounds()313     public Rectangle getBounds() {
314         return pGetBounds(screen.getScreen());
315     }
316 
pGetBounds(int screenNum)317     public native Rectangle pGetBounds(int screenNum);
318 
319     private static class XDBECapabilities extends BufferCapabilities {
XDBECapabilities()320         public XDBECapabilities() {
321             super(imageCaps, imageCaps, FlipContents.UNDEFINED);
322         }
323     }
324 
getBufferCapabilities()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 
getImageCapabilities()336     public ImageCapabilities getImageCapabilities() {
337         return imageCaps;
338     }
339 
isDoubleBuffered()340     public boolean isDoubleBuffered() {
341         return doubleBuffer;
342     }
343 
dispose(long x11ConfigData)344     private static native void dispose(long x11ConfigData);
345 
346     private static class X11GCDisposerRecord implements DisposerRecord {
347         private long x11ConfigData;
X11GCDisposerRecord(long x11CfgData)348         public X11GCDisposerRecord(long x11CfgData) {
349             this.x11ConfigData = x11CfgData;
350         }
dispose()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      */
createSurfaceData(X11ComponentPeer peer)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      */
createAcceleratedImage(Component target, int width, int height)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 
createBackBuffer(long window, int swapAction)395     private native long createBackBuffer(long window, int swapAction);
swapBuffers(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      */
createBackBuffer(X11ComponentPeer peer, int numBuffers, BufferCapabilities caps)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      */
destroyBackBuffer(long backBuffer)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      */
createBackBufferImage(Component target, long backBuffer)435     public VolatileImage createBackBufferImage(Component target,
436                                                long backBuffer)
437     {
438         // it is possible for the component to have size 0x0, adjust it to
439         // be at least 1x1 to avoid IAE
440         int w = Math.max(1, target.getWidth());
441         int h = Math.max(1, target.getHeight());
442         return new SunVolatileImage(target,
443                                     w, h,
444                                     Long.valueOf(backBuffer));
445     }
446 
447     /**
448      * Performs the native XDBE flip operation for the given target Component.
449      */
flip(X11ComponentPeer peer, Component target, VolatileImage xBackBuffer, int x1, int y1, int x2, int y2, BufferCapabilities.FlipContents flipAction)450     public void flip(X11ComponentPeer peer,
451                      Component target, VolatileImage xBackBuffer,
452                      int x1, int y1, int x2, int y2,
453                      BufferCapabilities.FlipContents flipAction)
454     {
455         long window = peer.getContentWindow();
456         int swapAction = getSwapAction(flipAction);
457         swapBuffers(window, swapAction);
458     }
459 
460     /**
461      * Maps the given FlipContents constant to the associated XDBE swap
462      * action constant.
463      */
getSwapAction( BufferCapabilities.FlipContents flipAction)464     private static int getSwapAction(
465         BufferCapabilities.FlipContents flipAction) {
466         if (flipAction == BufferCapabilities.FlipContents.BACKGROUND) {
467             return 0x01;
468         } else if (flipAction == BufferCapabilities.FlipContents.PRIOR) {
469             return 0x02;
470         } else if (flipAction == BufferCapabilities.FlipContents.COPIED) {
471             return 0x03;
472         } else {
473             return 0x00; // UNDEFINED
474         }
475     }
476 
477     @Override
isTranslucencyCapable()478     public boolean isTranslucencyCapable() {
479         return isTranslucencyCapable(getAData());
480     }
481 
isTranslucencyCapable(long x11ConfigData)482     private native boolean isTranslucencyCapable(long x11ConfigData);
483 }
484