1 /*
   2  * Copyright (c) 1999, 2010, 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.java2d.x11;
  27 
  28 import java.awt.Composite;
  29 import java.awt.GraphicsConfiguration;
  30 import java.awt.GraphicsDevice;
  31 import java.awt.GraphicsEnvironment;
  32 import java.awt.Image;
  33 import java.awt.Rectangle;
  34 import java.awt.Transparency;
  35 import java.awt.color.ColorSpace;
  36 import java.awt.image.ColorModel;
  37 import java.awt.image.ComponentColorModel;
  38 import java.awt.image.DirectColorModel;
  39 import java.awt.image.IndexColorModel;
  40 import java.awt.image.Raster;
  41 
  42 import sun.awt.SunHints;
  43 import sun.awt.SunToolkit;
  44 import sun.awt.X11ComponentPeer;
  45 import sun.awt.X11GraphicsConfig;
  46 import sun.awt.image.PixelConverter;
  47 import sun.font.X11TextRenderer;
  48 import sun.java2d.InvalidPipeException;
  49 import sun.java2d.SunGraphics2D;
  50 import sun.java2d.SunGraphicsEnvironment;
  51 import sun.java2d.SurfaceData;
  52 import sun.java2d.SurfaceDataProxy;
  53 import sun.java2d.loops.CompositeType;
  54 import sun.java2d.loops.GraphicsPrimitive;
  55 import sun.java2d.loops.RenderLoops;
  56 import sun.java2d.loops.SurfaceType;
  57 import sun.java2d.loops.XORComposite;
  58 import sun.java2d.pipe.PixelToShapeConverter;
  59 import sun.java2d.pipe.Region;
  60 import sun.java2d.pipe.TextPipe;
  61 import sun.java2d.pipe.ValidatePipe;
  62 
  63 public abstract class X11SurfaceData extends XSurfaceData {
  64     X11ComponentPeer peer;
  65     X11GraphicsConfig graphicsConfig;
  66     private RenderLoops solidloops;
  67 
  68     protected int depth;
  69 
  70     private static native void initIDs(Class xorComp, boolean tryDGA);
  71     protected native void initSurface(int depth, int width, int height,
  72                                       long drawable);
  73 
  74     public static final String
  75         DESC_INT_BGR_X11        = "Integer BGR Pixmap";
  76     public static final String
  77         DESC_INT_RGB_X11        = "Integer RGB Pixmap";
  78 
  79     public static final String
  80         DESC_4BYTE_ABGR_PRE_X11 = "4 byte ABGR Pixmap with pre-multplied alpha";
  81     public static final String
  82         DESC_INT_ARGB_PRE_X11   = "Integer ARGB Pixmap with pre-multiplied " +
  83                                   "alpha";
  84 
  85     public static final String
  86         DESC_BYTE_IND_OPQ_X11   = "Byte Indexed Opaque Pixmap";
  87 
  88     public static final String
  89         DESC_INT_BGR_X11_BM     = "Integer BGR Pixmap with 1-bit transp";
  90     public static final String
  91         DESC_INT_RGB_X11_BM     = "Integer RGB Pixmap with 1-bit transp";
  92     public static final String
  93         DESC_BYTE_IND_X11_BM    = "Byte Indexed Pixmap with 1-bit transp";
  94 
  95     public static final String
  96         DESC_BYTE_GRAY_X11      = "Byte Gray Opaque Pixmap";
  97     public static final String
  98         DESC_INDEX8_GRAY_X11    = "Index8 Gray Opaque Pixmap";
  99 
 100     public static final String
 101         DESC_BYTE_GRAY_X11_BM   = "Byte Gray Opaque Pixmap with 1-bit transp";
 102     public static final String
 103         DESC_INDEX8_GRAY_X11_BM = "Index8 Gray Opaque Pixmap with 1-bit transp";
 104 
 105     public static final String
 106         DESC_3BYTE_RGB_X11      = "3 Byte RGB Pixmap";
 107     public static final String
 108         DESC_3BYTE_BGR_X11      = "3 Byte BGR Pixmap";
 109 
 110     public static final String
 111         DESC_3BYTE_RGB_X11_BM   = "3 Byte RGB Pixmap with 1-bit transp";
 112     public static final String
 113         DESC_3BYTE_BGR_X11_BM   = "3 Byte BGR Pixmap with 1-bit transp";
 114 
 115     public static final String
 116         DESC_USHORT_555_RGB_X11 = "Ushort 555 RGB Pixmap";
 117     public static final String
 118         DESC_USHORT_565_RGB_X11 = "Ushort 565 RGB Pixmap";
 119 
 120     public static final String
 121         DESC_USHORT_555_RGB_X11_BM
 122                                 = "Ushort 555 RGB Pixmap with 1-bit transp";
 123     public static final String
 124         DESC_USHORT_565_RGB_X11_BM
 125                                 = "Ushort 565 RGB Pixmap with 1-bit transp";
 126     public static final String
 127         DESC_USHORT_INDEXED_X11 = "Ushort Indexed Pixmap";
 128 
 129     public static final String
 130         DESC_USHORT_INDEXED_X11_BM = "Ushort Indexed Pixmap with 1-bit transp";
 131 
 132     public static final SurfaceType IntBgrX11 =
 133         SurfaceType.IntBgr.deriveSubType(DESC_INT_BGR_X11);
 134     public static final SurfaceType IntRgbX11 =
 135         SurfaceType.IntRgb.deriveSubType(DESC_INT_RGB_X11);
 136 
 137     public static final SurfaceType FourByteAbgrPreX11 =
 138         SurfaceType.FourByteAbgrPre.deriveSubType(DESC_4BYTE_ABGR_PRE_X11);
 139     public static final SurfaceType IntArgbPreX11 =
 140         SurfaceType.IntArgbPre.deriveSubType(DESC_INT_ARGB_PRE_X11);
 141 
 142     public static final SurfaceType ThreeByteRgbX11 =
 143         SurfaceType.ThreeByteRgb.deriveSubType(DESC_3BYTE_RGB_X11);
 144     public static final SurfaceType ThreeByteBgrX11 =
 145         SurfaceType.ThreeByteBgr.deriveSubType(DESC_3BYTE_BGR_X11);
 146 
 147     public static final SurfaceType UShort555RgbX11 =
 148         SurfaceType.Ushort555Rgb.deriveSubType(DESC_USHORT_555_RGB_X11);
 149     public static final SurfaceType UShort565RgbX11 =
 150         SurfaceType.Ushort565Rgb.deriveSubType(DESC_USHORT_565_RGB_X11);
 151 
 152     public static final SurfaceType UShortIndexedX11 =
 153         SurfaceType.UshortIndexed.deriveSubType(DESC_USHORT_INDEXED_X11);
 154 
 155     public static final SurfaceType ByteIndexedOpaqueX11 =
 156         SurfaceType.ByteIndexedOpaque.deriveSubType(DESC_BYTE_IND_OPQ_X11);
 157 
 158     public static final SurfaceType ByteGrayX11 =
 159         SurfaceType.ByteGray.deriveSubType(DESC_BYTE_GRAY_X11);
 160     public static final SurfaceType Index8GrayX11 =
 161         SurfaceType.Index8Gray.deriveSubType(DESC_INDEX8_GRAY_X11);
 162 
 163     // Bitmap surface types
 164     public static final SurfaceType IntBgrX11_BM =
 165         SurfaceType.Custom.deriveSubType(DESC_INT_BGR_X11_BM,
 166                                          PixelConverter.Xbgr.instance);
 167     public static final SurfaceType IntRgbX11_BM =
 168         SurfaceType.Custom.deriveSubType(DESC_INT_RGB_X11_BM,
 169                                          PixelConverter.Xrgb.instance);
 170 
 171     public static final SurfaceType ThreeByteRgbX11_BM =
 172         SurfaceType.Custom.deriveSubType(DESC_3BYTE_RGB_X11_BM,
 173                                          PixelConverter.Xbgr.instance);
 174     public static final SurfaceType ThreeByteBgrX11_BM =
 175         SurfaceType.Custom.deriveSubType(DESC_3BYTE_BGR_X11_BM,
 176                                          PixelConverter.Xrgb.instance);
 177 
 178     public static final SurfaceType UShort555RgbX11_BM =
 179         SurfaceType.Custom.deriveSubType(DESC_USHORT_555_RGB_X11_BM,
 180                                          PixelConverter.Ushort555Rgb.instance);
 181     public static final SurfaceType UShort565RgbX11_BM =
 182         SurfaceType.Custom.deriveSubType(DESC_USHORT_565_RGB_X11_BM,
 183                                          PixelConverter.Ushort565Rgb.instance);
 184 
 185     public static final SurfaceType UShortIndexedX11_BM =
 186         SurfaceType.Custom.deriveSubType(DESC_USHORT_INDEXED_X11_BM);
 187 
 188     public static final SurfaceType ByteIndexedX11_BM =
 189         SurfaceType.Custom.deriveSubType(DESC_BYTE_IND_X11_BM);
 190 
 191     public static final SurfaceType ByteGrayX11_BM =
 192         SurfaceType.Custom.deriveSubType(DESC_BYTE_GRAY_X11_BM);
 193     public static final SurfaceType Index8GrayX11_BM =
 194         SurfaceType.Custom.deriveSubType(DESC_INDEX8_GRAY_X11_BM);
 195 
 196 
 197     private static Boolean accelerationEnabled = null;
 198 
 199     public Raster getRaster(int x, int y, int w, int h) {
 200         throw new InternalError("not implemented yet");
 201     }
 202 
 203     protected X11Renderer x11pipe;
 204     protected PixelToShapeConverter x11txpipe;
 205     protected static TextPipe x11textpipe;
 206     protected static boolean dgaAvailable;
 207 
 208     static {
 209        if (!isX11SurfaceDataInitialized() &&
 210            !GraphicsEnvironment.isHeadless()) {
 211             // If a screen magnifier is present, don't attempt to use DGA
 212             String magPresent = (String) java.security.AccessController.doPrivileged
 213                 (new sun.security.action.GetPropertyAction("javax.accessibility.screen_magnifier_present"));
 214             boolean tryDGA = magPresent == null || !"true".equals(magPresent);
 215 
 216             initIDs(XORComposite.class, tryDGA);
 217 
 218             String xtextpipe = (String) java.security.AccessController.doPrivileged
 219                 (new sun.security.action.GetPropertyAction("sun.java2d.xtextpipe"));
 220             if (xtextpipe == null || "true".startsWith(xtextpipe)) {
 221                 if ("true".equals(xtextpipe)) {
 222                     // Only verbose if they use the full string "true"
 223                     System.out.println("using X11 text renderer");
 224                 }
 225                 x11textpipe = new X11TextRenderer();
 226                 if (GraphicsPrimitive.tracingEnabled()) {
 227                     x11textpipe = ((X11TextRenderer) x11textpipe).traceWrap();
 228                 }
 229             } else {
 230                 if ("false".equals(xtextpipe)) {
 231                     // Only verbose if they use the full string "false"
 232                     System.out.println("using DGA text renderer");
 233                 }
 234                 x11textpipe = solidTextRenderer;
 235             }
 236 
 237             dgaAvailable = isDgaAvailable();
 238 
 239             if (isAccelerationEnabled()) {
 240                 X11PMBlitLoops.register();
 241                 X11PMBlitBgLoops.register();
 242             }
 243        }
 244     }
 245 
 246     /**
 247      * Returns true if we can use DGA on any of the screens
 248      */
 249     public static native boolean isDgaAvailable();
 250 
 251     /**
 252      * Returns true if shared memory pixmaps are available
 253      */
 254     private static native boolean isShmPMAvailable();
 255 
 256     public static boolean isAccelerationEnabled() {
 257         if (accelerationEnabled == null) {
 258 
 259             if (GraphicsEnvironment.isHeadless()) {
 260                 accelerationEnabled = Boolean.FALSE;
 261             } else {
 262                 String prop =
 263                     (String) java.security.AccessController.doPrivileged(
 264                         new sun.security.action.GetPropertyAction("sun.java2d.pmoffscreen"));
 265                 if (prop != null) {
 266                     // true iff prop==true, false otherwise
 267                     accelerationEnabled = Boolean.valueOf(prop);
 268                 } else {
 269                     boolean isDisplayLocal = false;
 270                     GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
 271                     if (ge instanceof SunGraphicsEnvironment) {
 272                         isDisplayLocal = ((SunGraphicsEnvironment) ge).isDisplayLocal();
 273                      }
 274 
 275                     // EXA based drivers tend to place pixmaps in VRAM, slowing down readbacks.
 276                     // Don't use pixmaps if dga is available,
 277                     // or we are local and shared memory Pixmaps are not available.
 278                     accelerationEnabled =
 279                         !(isDgaAvailable() || (isDisplayLocal && !isShmPMAvailable()));
 280                 }
 281             }
 282         }
 283         return accelerationEnabled.booleanValue();
 284     }
 285 
 286     @Override
 287     public SurfaceDataProxy makeProxyFor(SurfaceData srcData) {
 288         return X11SurfaceDataProxy.createProxy(srcData, graphicsConfig);
 289     }
 290 
 291     public void validatePipe(SunGraphics2D sg2d) {
 292         if (sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON &&
 293             sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR &&
 294             (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY ||
 295              sg2d.compositeState == SunGraphics2D.COMP_XOR))
 296         {
 297             if (x11txpipe == null) {
 298                 /*
 299                  * Note: this is thread-safe since x11txpipe is the
 300                  * second of the two pipes constructed in makePipes().
 301                  * In the rare case we are racing against another
 302                  * thread making new pipes, setting lazypipe is a
 303                  * safe alternative to waiting for the other thread.
 304                  */
 305                 sg2d.drawpipe = lazypipe;
 306                 sg2d.fillpipe = lazypipe;
 307                 sg2d.shapepipe = lazypipe;
 308                 sg2d.imagepipe = lazypipe;
 309                 sg2d.textpipe = lazypipe;
 310                 return;
 311             }
 312 
 313             if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) {
 314                 // Do this to init textpipe correctly; we will override the
 315                 // other non-text pipes below
 316                 // REMIND: we should clean this up eventually instead of
 317                 // having this work duplicated.
 318                 super.validatePipe(sg2d);
 319             } else {
 320                 switch (sg2d.textAntialiasHint) {
 321 
 322                 case SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT:
 323                     /* equating to OFF which it is for us */
 324                 case SunHints.INTVAL_TEXT_ANTIALIAS_OFF:
 325                     // Use X11 pipe even if DGA is available since DGA
 326                     // text slows everything down when mixed with X11 calls
 327                     if (sg2d.compositeState == SunGraphics2D.COMP_ISCOPY) {
 328                         sg2d.textpipe = x11textpipe;
 329                     } else {
 330                         sg2d.textpipe = solidTextRenderer;
 331                     }
 332                     break;
 333 
 334                 case SunHints.INTVAL_TEXT_ANTIALIAS_ON:
 335                     // Remind: may use Xrender for these when composite is
 336                     // copy as above, or if remote X11.
 337                     sg2d.textpipe = aaTextRenderer;
 338                     break;
 339 
 340                 default:
 341                     switch (sg2d.getFontInfo().aaHint) {
 342 
 343                     case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB:
 344                     case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VRGB:
 345                         sg2d.textpipe = lcdTextRenderer;
 346                         break;
 347 
 348                     case SunHints.INTVAL_TEXT_ANTIALIAS_OFF:
 349                     // Use X11 pipe even if DGA is available since DGA
 350                     // text slows everything down when mixed with X11 calls
 351                     if (sg2d.compositeState == SunGraphics2D.COMP_ISCOPY) {
 352                         sg2d.textpipe = x11textpipe;
 353                     } else {
 354                         sg2d.textpipe = solidTextRenderer;
 355                     }
 356                     break;
 357 
 358                     case SunHints.INTVAL_TEXT_ANTIALIAS_ON:
 359                         sg2d.textpipe = aaTextRenderer;
 360                         break;
 361 
 362                     default:
 363                         sg2d.textpipe = solidTextRenderer;
 364                     }
 365                 }
 366             }
 367 
 368             if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) {
 369                 sg2d.drawpipe = x11txpipe;
 370                 sg2d.fillpipe = x11txpipe;
 371             } else if (sg2d.strokeState != SunGraphics2D.STROKE_THIN){
 372                 sg2d.drawpipe = x11txpipe;
 373                 sg2d.fillpipe = x11pipe;
 374             } else {
 375                 sg2d.drawpipe = x11pipe;
 376                 sg2d.fillpipe = x11pipe;
 377             }
 378             sg2d.shapepipe = x11pipe;
 379             sg2d.imagepipe = imagepipe;
 380 
 381             // This is needed for AA text.
 382             // Note that even an X11TextRenderer can dispatch AA text
 383             // if a GlyphVector overrides the AA setting.
 384             // We use getRenderLoops() rather than setting solidloops
 385             // directly so that we get the appropriate loops in XOR mode.
 386             if (sg2d.loops == null) {
 387                 // assert(some pipe will always be a LoopBasedPipe)
 388                 sg2d.loops = getRenderLoops(sg2d);
 389             }
 390         } else {
 391             super.validatePipe(sg2d);
 392         }
 393     }
 394 
 395     public RenderLoops getRenderLoops(SunGraphics2D sg2d) {
 396         if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR &&
 397             sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY)
 398         {
 399             return solidloops;
 400         }
 401         return super.getRenderLoops(sg2d);
 402     }
 403 
 404     public GraphicsConfiguration getDeviceConfiguration() {
 405         return graphicsConfig;
 406     }
 407 
 408     /**
 409      * Method for instantiating a Window SurfaceData
 410      */
 411     public static X11WindowSurfaceData createData(X11ComponentPeer peer) {
 412        X11GraphicsConfig gc = getGC(peer);
 413        return new X11WindowSurfaceData(peer, gc, gc.getSurfaceType());
 414     }
 415 
 416     /**
 417      * Method for instantiating a Pixmap SurfaceData (offscreen)
 418      */
 419     public static X11PixmapSurfaceData createData(X11GraphicsConfig gc,
 420                                                   int width, int height,
 421                                                   ColorModel cm, Image image,
 422                                                   long drawable,
 423                                                   int transparency)
 424     {
 425         return new X11PixmapSurfaceData(gc, width, height, image,
 426                                         getSurfaceType(gc, transparency, true),
 427                                         cm, drawable, transparency);
 428     }
 429 
 430 //    /**
 431 //     * Initializes the native Ops pointer.
 432 //     */
 433 //    private native void initOps(X11ComponentPeer peer,
 434 //                                X11GraphicsConfig gc, int depth);
 435 
 436     protected X11SurfaceData(X11ComponentPeer peer,
 437                              X11GraphicsConfig gc,
 438                              SurfaceType sType,
 439                              ColorModel cm) {
 440         super(sType, cm);
 441         this.peer = peer;
 442         this.graphicsConfig = gc;
 443         this.solidloops = graphicsConfig.getSolidLoops(sType);
 444         this.depth = cm.getPixelSize();
 445         initOps(peer, graphicsConfig, depth);
 446         if (isAccelerationEnabled()) {
 447             setBlitProxyKey(gc.getProxyKey());
 448         }
 449     }
 450 
 451     public static X11GraphicsConfig getGC(X11ComponentPeer peer) {
 452         if (peer != null) {
 453             return (X11GraphicsConfig) peer.getGraphicsConfiguration();
 454         } else {
 455             GraphicsEnvironment env =
 456                 GraphicsEnvironment.getLocalGraphicsEnvironment();
 457             GraphicsDevice gd = env.getDefaultScreenDevice();
 458             return (X11GraphicsConfig)gd.getDefaultConfiguration();
 459         }
 460     }
 461 
 462     /**
 463      * Returns a boolean indicating whether or not a copyArea from
 464      * the given rectangle source coordinates might be incomplete
 465      * and result in X11 GraphicsExposure events being generated
 466      * from XCopyArea.
 467      * This method allows the SurfaceData copyArea method to determine
 468      * if it needs to set the GraphicsExposures attribute of the X11 GC
 469      * to True or False to receive or avoid the events.
 470      * @return true if there is any chance that an XCopyArea from the
 471      *              given source coordinates could produce any X11
 472      *              Exposure events.
 473      */
 474     public abstract boolean canSourceSendExposures(int x, int y, int w, int h);
 475 
 476     public boolean copyArea(SunGraphics2D sg2d,
 477                             int x, int y, int w, int h, int dx, int dy)
 478     {
 479         if (x11pipe == null) {
 480             if (!isDrawableValid()) {
 481                 return true;
 482             }
 483             makePipes();
 484         }
 485         CompositeType comptype = sg2d.imageComp;
 486         if (sg2d.transformState < SunGraphics2D.TRANSFORM_TRANSLATESCALE &&
 487             (CompositeType.SrcOverNoEa.equals(comptype) ||
 488              CompositeType.SrcNoEa.equals(comptype)))
 489         {
 490             x += sg2d.transX;
 491             y += sg2d.transY;
 492             SunToolkit.awtLock();
 493             try {
 494                 boolean needExposures = canSourceSendExposures(x, y, w, h);
 495                 long xgc = getBlitGC(sg2d.getCompClip(), needExposures);
 496                 x11pipe.devCopyArea(getNativeOps(), xgc,
 497                                     x, y,
 498                                     x + dx, y + dy,
 499                                     w, h);
 500             } finally {
 501                 SunToolkit.awtUnlock();
 502             }
 503             return true;
 504         }
 505         return false;
 506     }
 507 
 508     public static SurfaceType getSurfaceType(X11GraphicsConfig gc,
 509                                              int transparency)
 510     {
 511         return getSurfaceType(gc, transparency, false);
 512     }
 513 
 514     public static SurfaceType getSurfaceType(X11GraphicsConfig gc,
 515                                              int transparency,
 516                                              boolean pixmapSurface)
 517     {
 518         boolean transparent = (transparency == Transparency.BITMASK);
 519         SurfaceType sType;
 520         ColorModel cm = gc.getColorModel();
 521         switch (cm.getPixelSize()) {
 522         case 24:
 523             if (gc.getBitsPerPixel() == 24) {
 524                 if (cm instanceof DirectColorModel) {
 525                     // 4517321: We will always use ThreeByteBgr for 24 bpp
 526                     // surfaces, regardless of the pixel masks reported by
 527                     // X11.  Despite ambiguity in the X11 spec in how 24 bpp
 528                     // surfaces are treated, it appears that the best
 529                     // SurfaceType for these configurations (including
 530                     // some Matrox Millenium and ATI Radeon boards) is
 531                     // ThreeByteBgr.
 532                     sType = transparent ? X11SurfaceData.ThreeByteBgrX11_BM : X11SurfaceData.ThreeByteBgrX11;
 533                 } else {
 534                     throw new sun.java2d.InvalidPipeException("Unsupported bit " +
 535                                                               "depth/cm combo: " +
 536                                                               cm.getPixelSize()  +
 537                                                               ", " + cm);
 538                 }
 539                 break;
 540             }
 541             // Fall through for 32 bit case
 542         case 32:
 543             if (cm instanceof DirectColorModel) {
 544                 if (((SunToolkit)java.awt.Toolkit.getDefaultToolkit()
 545                      ).isTranslucencyCapable(gc) && !pixmapSurface)
 546                 {
 547                     sType = X11SurfaceData.IntArgbPreX11;
 548                 } else {
 549                     if (((DirectColorModel)cm).getRedMask() == 0xff0000) {
 550                         sType = transparent ? X11SurfaceData.IntRgbX11_BM :
 551                                               X11SurfaceData.IntRgbX11;
 552                     } else {
 553                         sType = transparent ? X11SurfaceData.IntBgrX11_BM :
 554                                               X11SurfaceData.IntBgrX11;
 555                     }
 556                 }
 557             } else if (cm instanceof ComponentColorModel) {
 558                    sType = X11SurfaceData.FourByteAbgrPreX11;
 559             } else {
 560 
 561                 throw new sun.java2d.InvalidPipeException("Unsupported bit " +
 562                                                           "depth/cm combo: " +
 563                                                           cm.getPixelSize()  +
 564                                                           ", " + cm);
 565             }
 566             break;
 567         case 15:
 568             sType = transparent ? X11SurfaceData.UShort555RgbX11_BM : X11SurfaceData.UShort555RgbX11;
 569             break;
 570         case 16:
 571             if ((cm instanceof DirectColorModel) &&
 572                 (((DirectColorModel)cm).getGreenMask() == 0x3e0))
 573             {
 574                 // fix for 4352984: Riva128 on Linux
 575                 sType = transparent ? X11SurfaceData.UShort555RgbX11_BM : X11SurfaceData.UShort555RgbX11;
 576             } else {
 577                 sType = transparent ? X11SurfaceData.UShort565RgbX11_BM : X11SurfaceData.UShort565RgbX11;
 578             }
 579             break;
 580         case  12:
 581             if (cm instanceof IndexColorModel) {
 582                 sType = transparent ?
 583                     X11SurfaceData.UShortIndexedX11_BM :
 584                     X11SurfaceData.UShortIndexedX11;
 585             } else {
 586                 throw new sun.java2d.InvalidPipeException("Unsupported bit " +
 587                                                           "depth: " +
 588                                                           cm.getPixelSize() +
 589                                                           " cm="+cm);
 590             }
 591             break;
 592         case 8:
 593             if (cm.getColorSpace().getType() == ColorSpace.TYPE_GRAY &&
 594                 cm instanceof ComponentColorModel) {
 595                 sType = transparent ? X11SurfaceData.ByteGrayX11_BM : X11SurfaceData.ByteGrayX11;
 596             } else if (cm instanceof IndexColorModel &&
 597                        isOpaqueGray((IndexColorModel)cm)) {
 598                 sType = transparent ? X11SurfaceData.Index8GrayX11_BM : X11SurfaceData.Index8GrayX11;
 599             } else {
 600                 sType = transparent ? X11SurfaceData.ByteIndexedX11_BM : X11SurfaceData.ByteIndexedOpaqueX11;
 601             }
 602             break;
 603         default:
 604             throw new sun.java2d.InvalidPipeException("Unsupported bit " +
 605                                                       "depth: " +
 606                                                       cm.getPixelSize());
 607         }
 608         return sType;
 609     }
 610 
 611     public void invalidate() {
 612         if (isValid()) {
 613             setInvalid();
 614             super.invalidate();
 615         }
 616     }
 617 
 618     /**
 619      * The following methods and variables are used to keep the Java-level
 620      * context state in sync with the native X11 GC associated with this
 621      * X11SurfaceData object.
 622      */
 623 
 624     private static native void XSetCopyMode(long xgc);
 625     private static native void XSetXorMode(long xgc);
 626     private static native void XSetForeground(long xgc, int pixel);
 627 
 628     private long xgc;
 629     private Region validatedClip;
 630     private XORComposite validatedXorComp;
 631     private int xorpixelmod;
 632     private int validatedPixel;
 633     private boolean validatedExposures = true;
 634 
 635     public final long getRenderGC(Region clip,
 636                                   int compState, Composite comp,
 637                                   int pixel)
 638     {
 639         return getGC(clip, compState, comp, pixel, validatedExposures);
 640     }
 641 
 642     public final long getBlitGC(Region clip, boolean needExposures) {
 643         return getGC(clip, SunGraphics2D.COMP_ISCOPY, null,
 644                      validatedPixel, needExposures);
 645     }
 646 
 647     final long getGC(Region clip,
 648                      int compState, Composite comp,
 649                      int pixel, boolean needExposures)
 650     {
 651         // assert SunToolkit.isAWTLockHeldByCurrentThread();
 652 
 653         if (!isValid()) {
 654             throw new InvalidPipeException("bounds changed");
 655         }
 656 
 657         // validate clip
 658         if (clip != validatedClip) {
 659             validatedClip = clip;
 660             if (clip != null) {
 661                 XSetClip(xgc,
 662                          clip.getLoX(), clip.getLoY(),
 663                          clip.getHiX(), clip.getHiY(),
 664                          (clip.isRectangular() ? null : clip));
 665             } else {
 666                 XResetClip(xgc);
 667             }
 668         }
 669 
 670         // validate composite
 671         if (compState == SunGraphics2D.COMP_ISCOPY) {
 672             if (validatedXorComp != null) {
 673                 validatedXorComp = null;
 674                 xorpixelmod = 0;
 675                 XSetCopyMode(xgc);
 676             }
 677         } else {
 678             if (validatedXorComp != comp) {
 679                 validatedXorComp = (XORComposite)comp;
 680                 xorpixelmod = validatedXorComp.getXorPixel();
 681                 XSetXorMode(xgc);
 682             }
 683         }
 684 
 685         // validate pixel
 686         pixel ^= xorpixelmod;
 687         if (pixel != validatedPixel) {
 688             validatedPixel = pixel;
 689             XSetForeground(xgc, pixel);
 690         }
 691 
 692         if (validatedExposures != needExposures) {
 693             validatedExposures = needExposures;
 694             XSetGraphicsExposures(xgc, needExposures);
 695         }
 696 
 697         return xgc;
 698     }
 699 
 700     public synchronized void makePipes() {
 701         if (x11pipe == null) {
 702             SunToolkit.awtLock();
 703             try {
 704                 xgc = XCreateGC(getNativeOps());
 705             } finally {
 706                 SunToolkit.awtUnlock();
 707             }
 708             x11pipe = X11Renderer.getInstance();
 709             x11txpipe = new PixelToShapeConverter(x11pipe);
 710         }
 711     }
 712 
 713     public static class X11WindowSurfaceData extends X11SurfaceData {
 714         public X11WindowSurfaceData(X11ComponentPeer peer,
 715                                     X11GraphicsConfig gc,
 716                                     SurfaceType sType) {
 717             super(peer, gc, sType, peer.getColorModel());
 718             if (isDrawableValid()) {
 719                 makePipes();
 720             }
 721         }
 722 
 723         public SurfaceData getReplacement() {
 724             return peer.getSurfaceData();
 725         }
 726 
 727         public Rectangle getBounds() {
 728             Rectangle r = peer.getBounds();
 729             r.x = r.y = 0;
 730             return r;
 731         }
 732 
 733         @Override
 734         public boolean canSourceSendExposures(int x, int y, int w, int h) {
 735             return true;
 736         }
 737 
 738         /**
 739          * Returns destination Component associated with this SurfaceData.
 740          */
 741         public Object getDestination() {
 742             return peer.getTarget();
 743         }
 744     }
 745 
 746     public static class X11PixmapSurfaceData extends X11SurfaceData {
 747 
 748         Image                   offscreenImage;
 749         int                     width;
 750         int                     height;
 751         int                     transparency;
 752 
 753         public X11PixmapSurfaceData(X11GraphicsConfig gc,
 754                                     int width, int height,
 755                                     Image image,
 756                                     SurfaceType sType, ColorModel cm,
 757                                     long drawable, int transparency)
 758         {
 759             super(null, gc, sType, cm);
 760             this.width = width;
 761             this.height = height;
 762             offscreenImage = image;
 763             this.transparency = transparency;
 764             initSurface(depth, width, height, drawable);
 765             makePipes();
 766         }
 767 
 768         public SurfaceData getReplacement() {
 769             return restoreContents(offscreenImage);
 770         }
 771 
 772         /**
 773          * Need this since the surface data is created with
 774          * the color model of the target GC, which is always
 775          * opaque. But in SunGraphics2D.blitSD we choose loops
 776          * based on the transparency on the source SD, so
 777          * it could choose wrong loop (blit instead of blitbg,
 778          * for example).
 779          */
 780         public int getTransparency() {
 781             return transparency;
 782         }
 783 
 784         public Rectangle getBounds() {
 785             return new Rectangle(width, height);
 786         }
 787 
 788         @Override
 789         public boolean canSourceSendExposures(int x, int y, int w, int h) {
 790             return (x < 0 || y < 0 || (x+w) > width || (y+h) > height);
 791         }
 792 
 793         public void flush() {
 794             /*
 795              * We need to invalidate the surface before disposing the
 796              * native Drawable and GC.  This way if an application tries
 797              * to render to an already flushed X11SurfaceData, we will notice
 798              * in the validate() method above that it has been invalidated,
 799              * and we will avoid using those native resources that have
 800              * already been disposed.
 801              */
 802             invalidate();
 803             flushNativeSurface();
 804         }
 805 
 806         /**
 807          * Returns destination Image associated with this SurfaceData.
 808          */
 809         public Object getDestination() {
 810             return offscreenImage;
 811         }
 812     }
 813 
 814     private static LazyPipe lazypipe = new LazyPipe();
 815 
 816     public static class LazyPipe extends ValidatePipe {
 817         public boolean validate(SunGraphics2D sg2d) {
 818             X11SurfaceData xsd = (X11SurfaceData) sg2d.surfaceData;
 819             if (!xsd.isDrawableValid()) {
 820                 return false;
 821             }
 822             xsd.makePipes();
 823             return super.validate(sg2d);
 824         }
 825     }
 826 }