jdk/src/solaris/classes/sun/java2d/x11/X11SurfaceData.java
changeset 2 90ce3da70b43
child 1739 ed98610896e7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/java2d/x11/X11SurfaceData.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,792 @@
+/*
+ * Copyright 1999-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.java2d.x11;
+
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.Rectangle;
+import java.awt.GraphicsConfiguration;
+import java.awt.Image;
+import java.awt.color.ColorSpace;
+import java.awt.Transparency;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.DirectColorModel;
+import java.awt.image.IndexColorModel;
+import java.awt.image.Raster;
+import java.awt.peer.ComponentPeer;
+
+import sun.awt.SunHints;
+import sun.awt.SunToolkit;
+import sun.awt.X11ComponentPeer;
+import sun.awt.X11GraphicsConfig;
+import sun.awt.image.PixelConverter;
+import sun.font.X11TextRenderer;
+import sun.java2d.InvalidPipeException;
+import sun.java2d.SunGraphics2D;
+import sun.java2d.SurfaceData;
+import sun.java2d.SurfaceDataProxy;
+import sun.java2d.loops.SurfaceType;
+import sun.java2d.loops.CompositeType;
+import sun.java2d.loops.RenderLoops;
+import sun.java2d.loops.GraphicsPrimitive;
+import sun.java2d.loops.XORComposite;
+import sun.java2d.loops.Blit;
+import sun.java2d.pipe.ValidatePipe;
+import sun.java2d.pipe.PixelToShapeConverter;
+import sun.java2d.pipe.TextPipe;
+import sun.java2d.pipe.Region;
+
+public abstract class X11SurfaceData extends SurfaceData {
+    X11ComponentPeer peer;
+    X11GraphicsConfig graphicsConfig;
+    private RenderLoops solidloops;
+
+    protected int depth;
+
+    private static native void initIDs(Class xorComp, boolean tryDGA);
+    protected native void initSurface(int depth, int width, int height,
+                                      long drawable);
+    native boolean isDrawableValid();
+    protected native void flushNativeSurface();
+
+    public static final String
+        DESC_INT_BGR_X11        = "Integer BGR Pixmap";
+    public static final String
+        DESC_INT_RGB_X11        = "Integer RGB Pixmap";
+    public static final String
+        DESC_BYTE_IND_OPQ_X11   = "Byte Indexed Opaque Pixmap";
+
+    public static final String
+        DESC_INT_BGR_X11_BM     = "Integer BGR Pixmap with 1-bit transp";
+    public static final String
+        DESC_INT_RGB_X11_BM     = "Integer RGB Pixmap with 1-bit transp";
+    public static final String
+        DESC_BYTE_IND_X11_BM    = "Byte Indexed Pixmap with 1-bit transp";
+
+    public static final String
+        DESC_BYTE_GRAY_X11      = "Byte Gray Opaque Pixmap";
+    public static final String
+        DESC_INDEX8_GRAY_X11    = "Index8 Gray Opaque Pixmap";
+
+    public static final String
+        DESC_BYTE_GRAY_X11_BM   = "Byte Gray Opaque Pixmap with 1-bit transp";
+    public static final String
+        DESC_INDEX8_GRAY_X11_BM = "Index8 Gray Opaque Pixmap with 1-bit transp";
+
+    public static final String
+        DESC_3BYTE_RGB_X11      = "3 Byte RGB Pixmap";
+    public static final String
+        DESC_3BYTE_BGR_X11      = "3 Byte BGR Pixmap";
+
+    public static final String
+        DESC_3BYTE_RGB_X11_BM   = "3 Byte RGB Pixmap with 1-bit transp";
+    public static final String
+        DESC_3BYTE_BGR_X11_BM   = "3 Byte BGR Pixmap with 1-bit transp";
+
+    public static final String
+        DESC_USHORT_555_RGB_X11 = "Ushort 555 RGB Pixmap";
+    public static final String
+        DESC_USHORT_565_RGB_X11 = "Ushort 565 RGB Pixmap";
+
+    public static final String
+        DESC_USHORT_555_RGB_X11_BM
+                                = "Ushort 555 RGB Pixmap with 1-bit transp";
+    public static final String
+        DESC_USHORT_565_RGB_X11_BM
+                                = "Ushort 565 RGB Pixmap with 1-bit transp";
+    public static final String
+        DESC_USHORT_INDEXED_X11 = "Ushort Indexed Pixmap";
+
+    public static final String
+        DESC_USHORT_INDEXED_X11_BM = "Ushort Indexed Pixmap with 1-bit transp";
+
+    public static final SurfaceType IntBgrX11 =
+        SurfaceType.IntBgr.deriveSubType(DESC_INT_BGR_X11);
+    public static final SurfaceType IntRgbX11 =
+        SurfaceType.IntRgb.deriveSubType(DESC_INT_RGB_X11);
+
+    public static final SurfaceType ThreeByteRgbX11 =
+        SurfaceType.ThreeByteRgb.deriveSubType(DESC_3BYTE_RGB_X11);
+    public static final SurfaceType ThreeByteBgrX11 =
+        SurfaceType.ThreeByteBgr.deriveSubType(DESC_3BYTE_BGR_X11);
+
+    public static final SurfaceType UShort555RgbX11 =
+        SurfaceType.Ushort555Rgb.deriveSubType(DESC_USHORT_555_RGB_X11);
+    public static final SurfaceType UShort565RgbX11 =
+        SurfaceType.Ushort565Rgb.deriveSubType(DESC_USHORT_565_RGB_X11);
+
+    public static final SurfaceType UShortIndexedX11 =
+        SurfaceType.UshortIndexed.deriveSubType(DESC_USHORT_INDEXED_X11);
+
+    public static final SurfaceType ByteIndexedOpaqueX11 =
+        SurfaceType.ByteIndexedOpaque.deriveSubType(DESC_BYTE_IND_OPQ_X11);
+
+    public static final SurfaceType ByteGrayX11 =
+        SurfaceType.ByteGray.deriveSubType(DESC_BYTE_GRAY_X11);
+    public static final SurfaceType Index8GrayX11 =
+        SurfaceType.Index8Gray.deriveSubType(DESC_INDEX8_GRAY_X11);
+
+    // Bitmap surface types
+    public static final SurfaceType IntBgrX11_BM =
+        SurfaceType.Custom.deriveSubType(DESC_INT_BGR_X11_BM,
+                                         PixelConverter.Xbgr.instance);
+    public static final SurfaceType IntRgbX11_BM =
+        SurfaceType.Custom.deriveSubType(DESC_INT_RGB_X11_BM,
+                                         PixelConverter.Xrgb.instance);
+
+    public static final SurfaceType ThreeByteRgbX11_BM =
+        SurfaceType.Custom.deriveSubType(DESC_3BYTE_RGB_X11_BM,
+                                         PixelConverter.Xbgr.instance);
+    public static final SurfaceType ThreeByteBgrX11_BM =
+        SurfaceType.Custom.deriveSubType(DESC_3BYTE_BGR_X11_BM,
+                                         PixelConverter.Xrgb.instance);
+
+    public static final SurfaceType UShort555RgbX11_BM =
+        SurfaceType.Custom.deriveSubType(DESC_USHORT_555_RGB_X11_BM,
+                                         PixelConverter.Ushort555Rgb.instance);
+    public static final SurfaceType UShort565RgbX11_BM =
+        SurfaceType.Custom.deriveSubType(DESC_USHORT_565_RGB_X11_BM,
+                                         PixelConverter.Ushort565Rgb.instance);
+
+    public static final SurfaceType UShortIndexedX11_BM =
+        SurfaceType.Custom.deriveSubType(DESC_USHORT_INDEXED_X11_BM);
+
+    public static final SurfaceType ByteIndexedX11_BM =
+        SurfaceType.Custom.deriveSubType(DESC_BYTE_IND_X11_BM);
+
+    public static final SurfaceType ByteGrayX11_BM =
+        SurfaceType.Custom.deriveSubType(DESC_BYTE_GRAY_X11_BM);
+    public static final SurfaceType Index8GrayX11_BM =
+        SurfaceType.Custom.deriveSubType(DESC_INDEX8_GRAY_X11_BM);
+
+
+    private static Boolean accelerationEnabled = null;
+
+    public Raster getRaster(int x, int y, int w, int h) {
+        throw new InternalError("not implemented yet");
+    }
+
+    protected X11Renderer x11pipe;
+    protected PixelToShapeConverter x11txpipe;
+    protected static TextPipe x11textpipe;
+    protected static boolean dgaAvailable;
+
+    static {
+        if (!GraphicsEnvironment.isHeadless()) {
+            // If a screen magnifier is present, don't attempt to use DGA
+            String magPresent = (String) java.security.AccessController.doPrivileged
+                (new sun.security.action.GetPropertyAction("javax.accessibility.screen_magnifier_present"));
+            boolean tryDGA = magPresent == null || !"true".equals(magPresent);
+
+            initIDs(XORComposite.class, tryDGA);
+
+            String xtextpipe = (String) java.security.AccessController.doPrivileged
+                (new sun.security.action.GetPropertyAction("sun.java2d.xtextpipe"));
+            if (xtextpipe == null || "true".startsWith(xtextpipe)) {
+                if ("true".equals(xtextpipe)) {
+                    // Only verbose if they use the full string "true"
+                    System.out.println("using X11 text renderer");
+                }
+                x11textpipe = new X11TextRenderer();
+                if (GraphicsPrimitive.tracingEnabled()) {
+                    x11textpipe = ((X11TextRenderer) x11textpipe).traceWrap();
+                }
+            } else {
+                if ("false".equals(xtextpipe)) {
+                    // Only verbose if they use the full string "false"
+                    System.out.println("using DGA text renderer");
+                }
+                x11textpipe = solidTextRenderer;
+            }
+
+            dgaAvailable = isDgaAvailable();
+
+            if (isAccelerationEnabled()) {
+                X11PMBlitLoops.register();
+                X11PMBlitBgLoops.register();
+            }
+        }
+    }
+
+    /**
+     * Returns true if we can use DGA on any of the screens
+     */
+    public static native boolean isDgaAvailable();
+
+    public static boolean isAccelerationEnabled() {
+        if (accelerationEnabled == null) {
+
+            if (GraphicsEnvironment.isHeadless()) {
+                accelerationEnabled = Boolean.FALSE;
+            } else {
+                String prop =
+                    (String) java.security.AccessController.doPrivileged(
+                        new sun.security.action.GetPropertyAction("sun.java2d.pmoffscreen"));
+                if (prop != null) {
+                    // true iff prop==true, false otherwise
+                    accelerationEnabled = Boolean.valueOf(prop);
+                } else {
+                    // use pixmaps if there is no dga, no matter local or remote
+                    accelerationEnabled = Boolean.valueOf(!isDgaAvailable());
+                }
+            }
+        }
+        return accelerationEnabled.booleanValue();
+    }
+
+    @Override
+    public SurfaceDataProxy makeProxyFor(SurfaceData srcData) {
+        return X11SurfaceDataProxy.createProxy(srcData, graphicsConfig);
+    }
+
+    public void validatePipe(SunGraphics2D sg2d) {
+        if (sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON &&
+            sg2d.paintState <= sg2d.PAINT_ALPHACOLOR &&
+            (sg2d.compositeState <= sg2d.COMP_ISCOPY ||
+             sg2d.compositeState == sg2d.COMP_XOR))
+        {
+            if (x11txpipe == null) {
+                /*
+                 * Note: this is thread-safe since x11txpipe is the
+                 * second of the two pipes constructed in makePipes().
+                 * In the rare case we are racing against another
+                 * thread making new pipes, setting lazypipe is a
+                 * safe alternative to waiting for the other thread.
+                 */
+                sg2d.drawpipe = lazypipe;
+                sg2d.fillpipe = lazypipe;
+                sg2d.shapepipe = lazypipe;
+                sg2d.imagepipe = lazypipe;
+                sg2d.textpipe = lazypipe;
+                return;
+            }
+
+            if (sg2d.clipState == sg2d.CLIP_SHAPE) {
+                // Do this to init textpipe correctly; we will override the
+                // other non-text pipes below
+                // REMIND: we should clean this up eventually instead of
+                // having this work duplicated.
+                super.validatePipe(sg2d);
+            } else {
+                switch (sg2d.textAntialiasHint) {
+
+                case SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT:
+                    /* equating to OFF which it is for us */
+                case SunHints.INTVAL_TEXT_ANTIALIAS_OFF:
+                    // Use X11 pipe even if DGA is available since DGA
+                    // text slows everything down when mixed with X11 calls
+                    if (sg2d.compositeState == sg2d.COMP_ISCOPY) {
+                        sg2d.textpipe = x11textpipe;
+                    } else {
+                        sg2d.textpipe = solidTextRenderer;
+                    }
+                    break;
+
+                case SunHints.INTVAL_TEXT_ANTIALIAS_ON:
+                    // Remind: may use Xrender for these when composite is
+                    // copy as above, or if remote X11.
+                    sg2d.textpipe = aaTextRenderer;
+                    break;
+
+                default:
+                    switch (sg2d.getFontInfo().aaHint) {
+
+                    case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB:
+                    case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VRGB:
+                        sg2d.textpipe = lcdTextRenderer;
+                        break;
+
+                    case SunHints.INTVAL_TEXT_ANTIALIAS_OFF:
+                    // Use X11 pipe even if DGA is available since DGA
+                    // text slows everything down when mixed with X11 calls
+                    if (sg2d.compositeState == sg2d.COMP_ISCOPY) {
+                        sg2d.textpipe = x11textpipe;
+                    } else {
+                        sg2d.textpipe = solidTextRenderer;
+                    }
+                    break;
+
+                    case SunHints.INTVAL_TEXT_ANTIALIAS_ON:
+                        sg2d.textpipe = aaTextRenderer;
+                        break;
+
+                    default:
+                        sg2d.textpipe = solidTextRenderer;
+                    }
+                }
+            }
+
+            if (sg2d.transformState >= sg2d.TRANSFORM_TRANSLATESCALE) {
+                sg2d.drawpipe = x11txpipe;
+                sg2d.fillpipe = x11txpipe;
+            } else if (sg2d.strokeState != sg2d.STROKE_THIN){
+                sg2d.drawpipe = x11txpipe;
+                sg2d.fillpipe = x11pipe;
+            } else {
+                sg2d.drawpipe = x11pipe;
+                sg2d.fillpipe = x11pipe;
+            }
+            sg2d.shapepipe = x11pipe;
+            sg2d.imagepipe = imagepipe;
+
+            // This is needed for AA text.
+            // Note that even an X11TextRenderer can dispatch AA text
+            // if a GlyphVector overrides the AA setting.
+            // We use getRenderLoops() rather than setting solidloops
+            // directly so that we get the appropriate loops in XOR mode.
+            sg2d.loops = getRenderLoops(sg2d);
+        } else {
+            super.validatePipe(sg2d);
+        }
+    }
+
+    public RenderLoops getRenderLoops(SunGraphics2D sg2d) {
+        if (sg2d.paintState <= sg2d.PAINT_ALPHACOLOR &&
+            sg2d.compositeState <= sg2d.COMP_ISCOPY)
+        {
+            return solidloops;
+        }
+        return super.getRenderLoops(sg2d);
+    }
+
+    public GraphicsConfiguration getDeviceConfiguration() {
+        return graphicsConfig;
+    }
+
+    /**
+     * Method for instantiating a Window SurfaceData
+     */
+    public static X11WindowSurfaceData createData(X11ComponentPeer peer) {
+       X11GraphicsConfig gc = getGC(peer);
+       return new X11WindowSurfaceData(peer, gc, gc.getSurfaceType());
+    }
+
+    /**
+     * Method for instantiating a Pixmap SurfaceData (offscreen)
+     */
+    public static X11PixmapSurfaceData createData(X11GraphicsConfig gc,
+                                                  int width, int height,
+                                                  ColorModel cm, Image image,
+                                                  long drawable,
+                                                  int transparency)
+    {
+        return new X11PixmapSurfaceData(gc, width, height, image,
+                                        getSurfaceType(gc, transparency),
+                                        cm, drawable, transparency);
+    }
+
+    /**
+     * Initializes the native Ops pointer.
+     */
+    private native void initOps(X11ComponentPeer peer,
+                                X11GraphicsConfig gc, int depth);
+
+    protected X11SurfaceData(X11ComponentPeer peer,
+                             X11GraphicsConfig gc,
+                             SurfaceType sType,
+                             ColorModel cm) {
+        super(sType, cm);
+        this.peer = peer;
+        this.graphicsConfig = gc;
+        this.solidloops = graphicsConfig.getSolidLoops(sType);
+        this.depth = cm.getPixelSize();
+        initOps(peer, graphicsConfig, depth);
+        if (isAccelerationEnabled()) {
+            setBlitProxyKey(gc.getProxyKey());
+        }
+    }
+
+    public static X11GraphicsConfig getGC(X11ComponentPeer peer) {
+        if (peer != null) {
+            return (X11GraphicsConfig) peer.getGraphicsConfiguration();
+        } else {
+            GraphicsEnvironment env =
+                GraphicsEnvironment.getLocalGraphicsEnvironment();
+            GraphicsDevice gd = env.getDefaultScreenDevice();
+            return (X11GraphicsConfig)gd.getDefaultConfiguration();
+        }
+    }
+
+    /**
+     * Returns a boolean indicating whether or not a copyArea from
+     * the given rectangle source coordinates might be incomplete
+     * and result in X11 GraphicsExposure events being generated
+     * from XCopyArea.
+     * This method allows the SurfaceData copyArea method to determine
+     * if it needs to set the GraphicsExposures attribute of the X11 GC
+     * to True or False to receive or avoid the events.
+     * @return true if there is any chance that an XCopyArea from the
+     *              given source coordinates could produce any X11
+     *              Exposure events.
+     */
+    public abstract boolean canSourceSendExposures(int x, int y, int w, int h);
+
+    public boolean copyArea(SunGraphics2D sg2d,
+                            int x, int y, int w, int h, int dx, int dy)
+    {
+        if (x11pipe == null) {
+            if (!isDrawableValid()) {
+                return true;
+            }
+            makePipes();
+        }
+        CompositeType comptype = sg2d.imageComp;
+        if (sg2d.transformState < sg2d.TRANSFORM_TRANSLATESCALE &&
+            (CompositeType.SrcOverNoEa.equals(comptype) ||
+             CompositeType.SrcNoEa.equals(comptype)))
+        {
+            x += sg2d.transX;
+            y += sg2d.transY;
+            SunToolkit.awtLock();
+            try {
+                boolean needExposures = canSourceSendExposures(x, y, w, h);
+                long xgc = getBlitGC(sg2d.getCompClip(), needExposures);
+                x11pipe.devCopyArea(getNativeOps(), xgc,
+                                    x, y,
+                                    x + dx, y + dy,
+                                    w, h);
+            } finally {
+                SunToolkit.awtUnlock();
+            }
+            return true;
+        }
+        return false;
+    }
+
+    public static SurfaceType getSurfaceType(X11GraphicsConfig gc,
+                                             int transparency)
+    {
+        boolean transparent = (transparency == Transparency.BITMASK);
+        SurfaceType sType;
+        ColorModel cm = gc.getColorModel();
+        switch (cm.getPixelSize()) {
+        case 24:
+            if (gc.getBitsPerPixel() == 24) {
+                if (cm instanceof DirectColorModel) {
+                    // 4517321: We will always use ThreeByteBgr for 24 bpp
+                    // surfaces, regardless of the pixel masks reported by
+                    // X11.  Despite ambiguity in the X11 spec in how 24 bpp
+                    // surfaces are treated, it appears that the best
+                    // SurfaceType for these configurations (including
+                    // some Matrox Millenium and ATI Radeon boards) is
+                    // ThreeByteBgr.
+                    sType = transparent ? X11SurfaceData.ThreeByteBgrX11_BM : X11SurfaceData.ThreeByteBgrX11;
+                } else {
+                    throw new sun.java2d.InvalidPipeException("Unsupported bit " +
+                                                              "depth/cm combo: " +
+                                                              cm.getPixelSize()  +
+                                                              ", " + cm);
+                }
+                break;
+            }
+            // Fall through for 32 bit case
+        case 32:
+            if (cm instanceof DirectColorModel) {
+                if (((DirectColorModel)cm).getRedMask() == 0xff0000) {
+                    sType = transparent ? X11SurfaceData.IntRgbX11_BM : X11SurfaceData.IntRgbX11;
+                } else {
+                    sType = transparent ? X11SurfaceData.IntBgrX11_BM : X11SurfaceData.IntBgrX11;
+                }
+            } else {
+                throw new sun.java2d.InvalidPipeException("Unsupported bit " +
+                                                          "depth/cm combo: " +
+                                                          cm.getPixelSize()  +
+                                                          ", " + cm);
+            }
+            break;
+        case 15:
+            sType = transparent ? X11SurfaceData.UShort555RgbX11_BM : X11SurfaceData.UShort555RgbX11;
+            break;
+        case 16:
+            if ((cm instanceof DirectColorModel) &&
+                (((DirectColorModel)cm).getGreenMask() == 0x3e0))
+            {
+                // fix for 4352984: Riva128 on Linux
+                sType = transparent ? X11SurfaceData.UShort555RgbX11_BM : X11SurfaceData.UShort555RgbX11;
+            } else {
+                sType = transparent ? X11SurfaceData.UShort565RgbX11_BM : X11SurfaceData.UShort565RgbX11;
+            }
+            break;
+        case  12:
+            if (cm instanceof IndexColorModel) {
+                sType = transparent ?
+                    X11SurfaceData.UShortIndexedX11_BM :
+                    X11SurfaceData.UShortIndexedX11;
+            } else {
+                throw new sun.java2d.InvalidPipeException("Unsupported bit " +
+                                                          "depth: " +
+                                                          cm.getPixelSize() +
+                                                          " cm="+cm);
+            }
+            break;
+        case 8:
+            if (cm.getColorSpace().getType() == ColorSpace.TYPE_GRAY &&
+                cm instanceof ComponentColorModel) {
+                sType = transparent ? X11SurfaceData.ByteGrayX11_BM : X11SurfaceData.ByteGrayX11;
+            } else if (cm instanceof IndexColorModel &&
+                       isOpaqueGray((IndexColorModel)cm)) {
+                sType = transparent ? X11SurfaceData.Index8GrayX11_BM : X11SurfaceData.Index8GrayX11;
+            } else {
+                sType = transparent ? X11SurfaceData.ByteIndexedX11_BM : X11SurfaceData.ByteIndexedOpaqueX11;
+            }
+            break;
+        default:
+            throw new sun.java2d.InvalidPipeException("Unsupported bit " +
+                                                      "depth: " +
+                                                      cm.getPixelSize());
+        }
+        return sType;
+    }
+
+    public native void setInvalid();
+
+    public void invalidate() {
+        if (isValid()) {
+            setInvalid();
+            super.invalidate();
+        }
+    }
+
+    /**
+     * The following methods and variables are used to keep the Java-level
+     * context state in sync with the native X11 GC associated with this
+     * X11SurfaceData object.
+     */
+
+    private static native long XCreateGC(long pXSData);
+    private static native void XResetClip(long xgc);
+    private static native void XSetClip(long xgc,
+                                        int lox, int loy, int hix, int hiy,
+                                        Region complexclip);
+    private static native void XSetCopyMode(long xgc);
+    private static native void XSetXorMode(long xgc);
+    private static native void XSetForeground(long xgc, int pixel);
+    private static native void XSetGraphicsExposures(long xgc,
+                                                     boolean needExposures);
+
+    private long xgc;
+    private Region validatedClip;
+    private XORComposite validatedXorComp;
+    private int xorpixelmod;
+    private int validatedPixel;
+    private boolean validatedExposures = true;
+
+    public final long getRenderGC(Region clip,
+                                  int compState, Composite comp,
+                                  int pixel)
+    {
+        return getGC(clip, compState, comp, pixel, validatedExposures);
+    }
+
+    public final long getBlitGC(Region clip, boolean needExposures) {
+        return getGC(clip, SunGraphics2D.COMP_ISCOPY, null,
+                     validatedPixel, needExposures);
+    }
+
+    final long getGC(Region clip,
+                     int compState, Composite comp,
+                     int pixel, boolean needExposures)
+    {
+        // assert SunToolkit.isAWTLockHeldByCurrentThread();
+
+        if (!isValid()) {
+            throw new InvalidPipeException("bounds changed");
+        }
+
+        // validate clip
+        if (clip != validatedClip) {
+            validatedClip = clip;
+            if (clip != null) {
+                XSetClip(xgc,
+                         clip.getLoX(), clip.getLoY(),
+                         clip.getHiX(), clip.getHiY(),
+                         (clip.isRectangular() ? null : clip));
+            } else {
+                XResetClip(xgc);
+            }
+        }
+
+        // validate composite
+        if (compState == SunGraphics2D.COMP_ISCOPY) {
+            if (validatedXorComp != null) {
+                validatedXorComp = null;
+                xorpixelmod = 0;
+                XSetCopyMode(xgc);
+            }
+        } else {
+            if (validatedXorComp != comp) {
+                validatedXorComp = (XORComposite)comp;
+                xorpixelmod = validatedXorComp.getXorPixel();
+                XSetXorMode(xgc);
+            }
+        }
+
+        // validate pixel
+        pixel ^= xorpixelmod;
+        if (pixel != validatedPixel) {
+            validatedPixel = pixel;
+            XSetForeground(xgc, pixel);
+        }
+
+        if (validatedExposures != needExposures) {
+            validatedExposures = needExposures;
+            XSetGraphicsExposures(xgc, needExposures);
+        }
+
+        return xgc;
+    }
+
+    public synchronized void makePipes() {
+        if (x11pipe == null) {
+            SunToolkit.awtLock();
+            try {
+                xgc = XCreateGC(getNativeOps());
+            } finally {
+                SunToolkit.awtUnlock();
+            }
+            x11pipe = X11Renderer.getInstance();
+            x11txpipe = new PixelToShapeConverter(x11pipe);
+        }
+    }
+
+    public static class X11WindowSurfaceData extends X11SurfaceData {
+        public X11WindowSurfaceData(X11ComponentPeer peer,
+                                    X11GraphicsConfig gc,
+                                    SurfaceType sType) {
+            super(peer, gc, sType, peer.getColorModel());
+            if (isDrawableValid()) {
+                makePipes();
+            }
+        }
+
+        public SurfaceData getReplacement() {
+            return peer.getSurfaceData();
+        }
+
+        public Rectangle getBounds() {
+            Rectangle r = peer.getBounds();
+            r.x = r.y = 0;
+            return r;
+        }
+
+        @Override
+        public boolean canSourceSendExposures(int x, int y, int w, int h) {
+            return true;
+        }
+
+        /**
+         * Returns destination Component associated with this SurfaceData.
+         */
+        public Object getDestination() {
+            return peer.getTarget();
+        }
+    }
+
+    public static class X11PixmapSurfaceData extends X11SurfaceData {
+
+        Image                   offscreenImage;
+        int                     width;
+        int                     height;
+        int                     transparency;
+
+        public X11PixmapSurfaceData(X11GraphicsConfig gc,
+                                    int width, int height,
+                                    Image image,
+                                    SurfaceType sType, ColorModel cm,
+                                    long drawable, int transparency)
+        {
+            super(null, gc, sType, cm);
+            this.width = width;
+            this.height = height;
+            offscreenImage = image;
+            this.transparency = transparency;
+            initSurface(depth, width, height, drawable);
+            makePipes();
+        }
+
+        public SurfaceData getReplacement() {
+            return restoreContents(offscreenImage);
+        }
+
+        /**
+         * Need this since the surface data is created with
+         * the color model of the target GC, which is always
+         * opaque. But in SunGraphics2D.blitSD we choose loops
+         * based on the transparency on the source SD, so
+         * it could choose wrong loop (blit instead of blitbg,
+         * for example).
+         */
+        public int getTransparency() {
+            return transparency;
+        }
+
+        public Rectangle getBounds() {
+            return new Rectangle(width, height);
+        }
+
+        @Override
+        public boolean canSourceSendExposures(int x, int y, int w, int h) {
+            return (x < 0 || y < 0 || (x+w) > width || (y+h) > height);
+        }
+
+        public void flush() {
+            /*
+             * We need to invalidate the surface before disposing the
+             * native Drawable and GC.  This way if an application tries
+             * to render to an already flushed X11SurfaceData, we will notice
+             * in the validate() method above that it has been invalidated,
+             * and we will avoid using those native resources that have
+             * already been disposed.
+             */
+            invalidate();
+            flushNativeSurface();
+        }
+
+        /**
+         * Returns destination Image associated with this SurfaceData.
+         */
+        public Object getDestination() {
+            return offscreenImage;
+        }
+    }
+
+    private static LazyPipe lazypipe = new LazyPipe();
+
+    public static class LazyPipe extends ValidatePipe {
+        public boolean validate(SunGraphics2D sg2d) {
+            X11SurfaceData xsd = (X11SurfaceData) sg2d.surfaceData;
+            if (!xsd.isDrawableValid()) {
+                return false;
+            }
+            xsd.makePipes();
+            return super.validate(sg2d);
+        }
+    }
+}