1 /*
   2  * Copyright (c) 2010, 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.java2d.xr;
  27 
  28 import java.awt.*;
  29 import java.awt.geom.*;
  30 import java.awt.image.*;
  31 import sun.awt.*;
  32 import sun.java2d.InvalidPipeException;
  33 import sun.java2d.SunGraphics2D;
  34 import sun.java2d.SurfaceData;
  35 import sun.java2d.SurfaceDataProxy;
  36 import sun.java2d.jules.*;
  37 import sun.java2d.loops.*;
  38 import sun.java2d.pipe.*;
  39 import sun.java2d.x11.*;
  40 import sun.font.FontManagerNativeLibrary;
  41 
  42 public abstract class XRSurfaceData extends XSurfaceData {
  43     X11ComponentPeer peer;
  44     XRGraphicsConfig graphicsConfig;
  45     XRBackend renderQueue;
  46 
  47     private RenderLoops solidloops;
  48 
  49     protected int depth;
  50 
  51     private static native void initIDs();
  52 
  53     protected native void XRInitSurface(int depth, int width, int height,
  54                                         long drawable, int pictFormat);
  55 
  56     native void initXRPicture(long xsdo, int pictForm);
  57 
  58     native void freeXSDOPicture(long xsdo);
  59 
  60     public static final String DESC_BYTE_A8_X11 = "Byte A8 Pixmap";
  61     public static final String DESC_INT_RGB_X11 = "Integer RGB Pixmap";
  62     public static final String DESC_INT_ARGB_X11 = "Integer ARGB-Pre Pixmap";
  63 
  64     public static final SurfaceType
  65         ByteA8X11 = SurfaceType.ByteGray.deriveSubType(DESC_BYTE_A8_X11);
  66     public static final SurfaceType
  67         IntRgbX11 = SurfaceType.IntRgb.deriveSubType(DESC_INT_RGB_X11);
  68     public static final SurfaceType
  69         IntArgbPreX11 = SurfaceType.IntArgbPre.deriveSubType(DESC_INT_ARGB_X11);
  70 
  71     public Raster getRaster(int x, int y, int w, int h) {
  72         throw new InternalError("not implemented yet");
  73     }
  74 
  75     protected XRRenderer xrpipe;
  76     protected PixelToShapeConverter xrtxpipe;
  77     protected TextPipe xrtextpipe;
  78     protected XRDrawImage xrDrawImage;
  79 
  80     protected ShapeDrawPipe aaShapePipe;
  81     protected PixelToShapeConverter aaPixelToShapeConv;
  82 
  83     public static void initXRSurfaceData() {
  84         if (!isX11SurfaceDataInitialized()) {
  85             FontManagerNativeLibrary.load();
  86             initIDs();
  87             XRPMBlitLoops.register();
  88             XRMaskFill.register();
  89             XRMaskBlit.register();
  90 
  91             setX11SurfaceDataInitialized();
  92         }
  93     }
  94 
  95     /**
  96      * Synchronized accessor method for isDrawableValid.
  97      */
  98     protected boolean isXRDrawableValid() {
  99         try {
 100             SunToolkit.awtLock();
 101             return isDrawableValid();
 102         } finally {
 103             SunToolkit.awtUnlock();
 104         }
 105     }
 106 
 107     @Override
 108     public SurfaceDataProxy makeProxyFor(SurfaceData srcData) {
 109         return XRSurfaceDataProxy.createProxy(srcData, graphicsConfig);
 110     }
 111 
 112     @Override
 113     public void validatePipe(SunGraphics2D sg2d) {
 114         TextPipe textpipe;
 115         boolean validated = false;
 116 
 117         /*
 118          * The textpipe for now can't handle TexturePaint when extra-alpha is
 119          * specified nore XOR mode
 120          */
 121         if ((textpipe = getTextPipe(sg2d)) == null)
 122         {
 123             super.validatePipe(sg2d);
 124             textpipe = sg2d.textpipe;
 125             validated = true;
 126         }
 127 
 128         PixelToShapeConverter txPipe = null;
 129         XRRenderer nonTxPipe = null;
 130 
 131         /*
 132          * TODO: Can we rely on the GC for ARGB32 surfaces?
 133          */
 134         if (sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON) {
 135             if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) {
 136                 if (sg2d.compositeState <= SunGraphics2D.COMP_XOR) {
 137                     txPipe = xrtxpipe;
 138                     nonTxPipe = xrpipe;
 139                 }
 140             } else if (sg2d.compositeState <= SunGraphics2D.COMP_ALPHA) {
 141                 if (XRPaints.isValid(sg2d)) {
 142                     txPipe = xrtxpipe;
 143                     nonTxPipe = xrpipe;
 144                 }
 145                 // custom paints handled by super.validatePipe() below
 146             }
 147         }
 148 
 149         if (sg2d.antialiasHint == SunHints.INTVAL_ANTIALIAS_ON &&
 150             JulesPathBuf.isCairoAvailable())
 151         {
 152             sg2d.shapepipe = aaShapePipe;
 153             sg2d.drawpipe = aaPixelToShapeConv;
 154             sg2d.fillpipe = aaPixelToShapeConv;
 155         } else {
 156             if (txPipe != null) {
 157                 if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) {
 158                     sg2d.drawpipe = txPipe;
 159                     sg2d.fillpipe = txPipe;
 160                 } else if (sg2d.strokeState != SunGraphics2D.STROKE_THIN) {
 161                     sg2d.drawpipe = txPipe;
 162                     sg2d.fillpipe = nonTxPipe;
 163                 } else {
 164                     sg2d.drawpipe = nonTxPipe;
 165                     sg2d.fillpipe = nonTxPipe;
 166                 }
 167                 sg2d.shapepipe = nonTxPipe;
 168             } else {
 169                 if (!validated) {
 170                     super.validatePipe(sg2d);
 171                 }
 172             }
 173         }
 174 
 175         // install the text pipe based on our earlier decision
 176         sg2d.textpipe = textpipe;
 177 
 178         // always override the image pipe with the specialized XRender pipe
 179         sg2d.imagepipe = xrDrawImage;
 180     }
 181 
 182     protected TextPipe getTextPipe(SunGraphics2D sg2d) {
 183         boolean supportedPaint = sg2d.compositeState <= SunGraphics2D.COMP_ALPHA
 184                 && (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR || sg2d.composite == null);
 185 
 186         boolean supportedCompOp = false;
 187         if (sg2d.composite instanceof AlphaComposite) {
 188             int compRule = ((AlphaComposite) sg2d.composite).getRule();
 189             supportedCompOp = XRUtils.isMaskEvaluated(XRUtils.j2dAlphaCompToXR(compRule))
 190                     || (compRule == AlphaComposite.SRC
 191                                 && sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR);
 192         }
 193 
 194         return (supportedPaint && supportedCompOp) ? xrtextpipe : null;
 195     }
 196 
 197     protected MaskFill getMaskFill(SunGraphics2D sg2d) {
 198         AlphaComposite aComp = null;
 199         if(sg2d.composite != null
 200                 && sg2d.composite instanceof AlphaComposite) {
 201             aComp = (AlphaComposite) sg2d.composite;
 202         }
 203 
 204         boolean supportedPaint = sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR
 205                 || XRPaints.isValid(sg2d);
 206 
 207         boolean supportedCompOp = false;
 208         if(aComp != null) {
 209             int rule = aComp.getRule();
 210             supportedCompOp = XRUtils.isMaskEvaluated(XRUtils.j2dAlphaCompToXR(rule));
 211         }
 212 
 213         return (supportedPaint && supportedCompOp) ?  super.getMaskFill(sg2d) : null;
 214     }
 215 
 216     public RenderLoops getRenderLoops(SunGraphics2D sg2d) {
 217         if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR &&
 218             sg2d.compositeState <= SunGraphics2D.COMP_ALPHA)
 219         {
 220             return solidloops;
 221         }
 222 
 223         return super.getRenderLoops(sg2d);
 224     }
 225 
 226     public GraphicsConfiguration getDeviceConfiguration() {
 227         return graphicsConfig;
 228     }
 229 
 230     /**
 231      * Method for instantiating a Window SurfaceData
 232      */
 233     public static XRWindowSurfaceData createData(X11ComponentPeer peer) {
 234         XRGraphicsConfig gc = getGC(peer);
 235         return new XRWindowSurfaceData(peer, gc, gc.getSurfaceType());
 236     }
 237 
 238     /**
 239      * Method for instantiating a Pixmap SurfaceData (offscreen).
 240      * If the surface * is opaque a 24-bit/RGB surface is chosen,
 241      * otherwise a 32-bit ARGB surface.
 242      */
 243     public static XRPixmapSurfaceData createData(XRGraphicsConfig gc,
 244                                                  int width, int height,
 245                                                  ColorModel cm, Image image,
 246                                                  long drawable,
 247                                                  int transparency) {
 248         int depth;
 249         // If we have a 32 bit color model for the window it needs
 250         // alpha to support translucency of the window so we need
 251         //  to upgrade what was requested for the surface.
 252         if (gc.getColorModel().getPixelSize() == 32) {
 253            depth = 32;
 254            transparency = Transparency.TRANSLUCENT;
 255         } else {
 256             depth = transparency > Transparency.OPAQUE ? 32 : 24;
 257         }
 258 
 259         if (depth == 24) {
 260             cm = new DirectColorModel(depth,
 261                                       0x00FF0000, 0x0000FF00, 0x000000FF);
 262         } else {
 263             cm = new DirectColorModel(depth, 0x00FF0000, 0x0000FF00,
 264                                       0x000000FF, 0xFF000000);
 265         }
 266 
 267         return new XRPixmapSurfaceData
 268             (gc, width, height, image, getSurfaceType(gc, transparency),
 269              cm, drawable, transparency,
 270              XRUtils.getPictureFormatForTransparency(transparency), depth);
 271     }
 272 
 273     protected XRSurfaceData(X11ComponentPeer peer, XRGraphicsConfig gc,
 274         SurfaceType sType, ColorModel cm, int depth, int transparency)
 275     {
 276         super(sType, cm);
 277         this.peer = peer;
 278         this.graphicsConfig = gc;
 279         this.solidloops = graphicsConfig.getSolidLoops(sType);
 280         this.depth = depth;
 281         initOps(peer, graphicsConfig, depth);
 282 
 283         setBlitProxyKey(gc.getProxyKey());
 284     }
 285 
 286     protected XRSurfaceData(XRBackend renderQueue) {
 287         super(XRSurfaceData.IntRgbX11,
 288               new DirectColorModel(24, 0x00FF0000, 0x0000FF00, 0x000000FF));
 289         this.renderQueue = renderQueue;
 290     }
 291 
 292     /**
 293      * Inits the XRender-data-structures which belong to the XRSurfaceData.
 294      *
 295      * @param pictureFormat
 296      */
 297     public void initXRender(int pictureFormat) {
 298         try {
 299             SunToolkit.awtLock();
 300             initXRPicture(getNativeOps(), pictureFormat);
 301             renderQueue = XRCompositeManager.getInstance(this).getBackend();
 302             maskBuffer = XRCompositeManager.getInstance(this);
 303         } catch (Throwable ex) {
 304             ex.printStackTrace();
 305         } finally {
 306             SunToolkit.awtUnlock();
 307         }
 308     }
 309 
 310     public static XRGraphicsConfig getGC(X11ComponentPeer peer) {
 311         if (peer != null) {
 312             return (XRGraphicsConfig) peer.getGraphicsConfiguration();
 313         } else {
 314             GraphicsEnvironment env =
 315                 GraphicsEnvironment.getLocalGraphicsEnvironment();
 316             GraphicsDevice gd = env.getDefaultScreenDevice();
 317             return (XRGraphicsConfig) gd.getDefaultConfiguration();
 318         }
 319     }
 320 
 321     /**
 322      * Returns a boolean indicating whether or not a copyArea from the given
 323      * rectangle source coordinates might be incomplete and result in X11
 324      * GraphicsExposure events being generated from XCopyArea. This method
 325      * allows the SurfaceData copyArea method to determine if it needs to set
 326      * the GraphicsExposures attribute of the X11 GC to True or False to receive
 327      * or avoid the events.
 328      *
 329      * @return true if there is any chance that an XCopyArea from the given
 330      *         source coordinates could produce any X11 Exposure events.
 331      */
 332     public abstract boolean canSourceSendExposures(int x, int y, int w, int h);
 333 
 334     /**
 335      * CopyArea is implemented using the "old" X11 GC, therefor clip and
 336      * needExposures have to be validated against that GC. Pictures and GCs
 337      * don't share state.
 338      */
 339     public void validateCopyAreaGC(Region gcClip, boolean needExposures) {
 340         if (validatedGCClip != gcClip) {
 341             if (gcClip != null)
 342                 renderQueue.setGCClipRectangles(xgc, gcClip);
 343             validatedGCClip = gcClip;
 344         }
 345 
 346         if (validatedExposures != needExposures) {
 347             validatedExposures = needExposures;
 348             renderQueue.setGCExposures(xgc, needExposures);
 349         }
 350 
 351         if (validatedXorComp != null) {
 352             renderQueue.setGCMode(xgc, true);
 353             renderQueue.setGCForeground(xgc, validatedGCForegroundPixel);
 354             validatedXorComp = null;
 355         }
 356     }
 357 
 358     public boolean copyArea(SunGraphics2D sg2d, int x, int y, int w, int h,
 359                             int dx, int dy) {
 360         if (xrpipe == null) {
 361             if (!isXRDrawableValid()) {
 362                 return true;
 363             }
 364             makePipes();
 365         }
 366         CompositeType comptype = sg2d.imageComp;
 367         if (sg2d.transformState < SunGraphics2D.TRANSFORM_TRANSLATESCALE &&
 368             (CompositeType.SrcOverNoEa.equals(comptype) ||
 369              CompositeType.SrcNoEa.equals(comptype)))
 370         {
 371             x += sg2d.transX;
 372             y += sg2d.transY;
 373             try {
 374                 SunToolkit.awtLock();
 375                 boolean needExposures = canSourceSendExposures(x, y, w, h);
 376                 validateCopyAreaGC(sg2d.getCompClip(), needExposures);
 377                 renderQueue.copyArea(xid, xid, xgc, x, y, w, h, x + dx, y + dy);
 378             } finally {
 379                 SunToolkit.awtUnlock();
 380             }
 381             return true;
 382         }
 383         return false;
 384     }
 385 
 386     /**
 387      * Returns the XRender SurfaceType which is able to fullfill the specified
 388      * transparency requirement.
 389      */
 390     public static SurfaceType getSurfaceType(XRGraphicsConfig gc,
 391                                              int transparency) {
 392         SurfaceType sType = null;
 393 
 394         switch (transparency) {
 395         case Transparency.OPAQUE:
 396             sType = XRSurfaceData.IntRgbX11;
 397             break;
 398 
 399         case Transparency.BITMASK:
 400         case Transparency.TRANSLUCENT:
 401             sType = XRSurfaceData.IntArgbPreX11;
 402             break;
 403         }
 404 
 405         return sType;
 406     }
 407 
 408     public void invalidate() {
 409         if (isValid()) {
 410             setInvalid();
 411             super.invalidate();
 412         }
 413     }
 414 
 415     private long xgc; // GC is still used for copyArea
 416     private int validatedGCForegroundPixel = 0;
 417     private XORComposite validatedXorComp;
 418     private int xid;
 419     public int picture;
 420     public XRCompositeManager maskBuffer;
 421 
 422     private Region validatedClip;
 423     private Region validatedGCClip;
 424     private boolean validatedExposures = true;
 425 
 426     boolean transformInUse = false;
 427     AffineTransform validatedSourceTransform = new AffineTransform();
 428     AffineTransform staticSrcTx = null;
 429     int validatedRepeat = XRUtils.RepeatNone;
 430     int validatedFilter = XRUtils.FAST;
 431 
 432     /**
 433      * Validates an XRSurfaceData when used as source. Note that the clip is
 434      * applied when used as source as well as destination.
 435      */
 436     void validateAsSource(AffineTransform sxForm, int repeat, int filter) {
 437 
 438         if (validatedClip != null) {
 439             validatedClip = null;
 440             renderQueue.setClipRectangles(picture, null);
 441         }
 442 
 443         if (validatedRepeat != repeat && repeat != -1) {
 444             validatedRepeat = repeat;
 445             renderQueue.setPictureRepeat(picture, repeat);
 446         }
 447 
 448         if (sxForm == null) {
 449             if (transformInUse) {
 450                 validatedSourceTransform.setToIdentity();
 451                 renderQueue.setPictureTransform(picture,
 452                                                 validatedSourceTransform);
 453                 transformInUse = false;
 454             }
 455         } else if (!transformInUse ||
 456                    (transformInUse && !sxForm.equals(validatedSourceTransform))) {
 457 
 458             validatedSourceTransform.setTransform(sxForm.getScaleX(),
 459                                                   sxForm.getShearY(),
 460                                                   sxForm.getShearX(),
 461                                                   sxForm.getScaleY(),
 462                                                   sxForm.getTranslateX(),
 463                                                   sxForm.getTranslateY());
 464 
 465             AffineTransform srcTransform = validatedSourceTransform;
 466             if(staticSrcTx != null) {
 467                 // Apply static transform set when used as texture or gradient.
 468                 // Create a copy to not modify validatedSourceTransform as
 469                 // this would confuse the validation logic.
 470                 srcTransform = new AffineTransform(validatedSourceTransform);
 471                 srcTransform.preConcatenate(staticSrcTx);
 472             }
 473 
 474             renderQueue.setPictureTransform(picture, srcTransform);
 475             transformInUse = true;
 476         }
 477 
 478         if (filter != validatedFilter && filter != -1) {
 479             renderQueue.setFilter(picture, filter);
 480             validatedFilter = filter;
 481         }
 482     }
 483 
 484     /**
 485      * Validates the Surface when used as destination.
 486      */
 487     public void validateAsDestination(SunGraphics2D sg2d, Region clip) {
 488         if (!isValid()) {
 489             throw new InvalidPipeException("bounds changed");
 490         }
 491 
 492         boolean updateGCClip = false;
 493         if (clip != validatedClip) {
 494             renderQueue.setClipRectangles(picture, clip);
 495             validatedClip = clip;
 496             updateGCClip = true;
 497         }
 498 
 499         if (sg2d != null && sg2d.compositeState == SunGraphics2D.COMP_XOR) {
 500             if (validatedXorComp != sg2d.getComposite()) {
 501                 validatedXorComp = (XORComposite) sg2d.getComposite();
 502                 renderQueue.setGCMode(xgc, false);
 503             }
 504 
 505             // validate pixel
 506             int pixel = sg2d.pixel;
 507             if (validatedGCForegroundPixel != pixel) {
 508                 int xorpixelmod = validatedXorComp.getXorPixel();
 509                 renderQueue.setGCForeground(xgc, pixel ^ xorpixelmod);
 510                 validatedGCForegroundPixel = pixel;
 511             }
 512 
 513             if (updateGCClip) {
 514                 renderQueue.setGCClipRectangles(xgc, clip);
 515             }
 516         }
 517     }
 518 
 519     public synchronized void makePipes() { /*
 520                                             * TODO: Why is this synchronized,
 521                                             * but access not?
 522                                             */
 523         if (xrpipe == null) {
 524             try {
 525                 SunToolkit.awtLock();
 526                 xgc = XCreateGC(getNativeOps());
 527 
 528                 xrpipe = new XRRenderer(maskBuffer.getMaskBuffer());
 529                 xrtxpipe = new PixelToShapeConverter(xrpipe);
 530                 xrtextpipe = maskBuffer.getTextRenderer();
 531                 xrDrawImage = new XRDrawImage();
 532 
 533                 if (JulesPathBuf.isCairoAvailable()) {
 534                     aaShapePipe =
 535                        new JulesShapePipe(XRCompositeManager.getInstance(this));
 536                     aaPixelToShapeConv = new PixelToShapeConverter(aaShapePipe);
 537                 }
 538             } finally {
 539                 SunToolkit.awtUnlock();
 540             }
 541         }
 542     }
 543 
 544     public static class XRWindowSurfaceData extends XRSurfaceData {
 545         public XRWindowSurfaceData(X11ComponentPeer peer,
 546                                    XRGraphicsConfig gc, SurfaceType sType) {
 547             super(peer, gc, sType, peer.getColorModel(),
 548                   peer.getColorModel().getPixelSize(), Transparency.OPAQUE);
 549 
 550             if (isXRDrawableValid()) {
 551                 // If we have a 32 bit color model for the window it needs
 552                 // alpha to support translucency of the window so we need
 553                 // to get the ARGB32 XRender picture format else for
 554                 // 24 bit colormodel we need RGB24 or OPAQUE pictureformat.
 555                 if (peer.getColorModel().getPixelSize() == 32) {
 556                     initXRender(XRUtils.
 557                      getPictureFormatForTransparency(Transparency.TRANSLUCENT));
 558                 }
 559                 else {
 560                     initXRender(XRUtils.
 561                       getPictureFormatForTransparency(Transparency.OPAQUE));
 562                 }  
 563                 makePipes();
 564             }
 565         }
 566 
 567         public SurfaceData getReplacement() {
 568             return peer.getSurfaceData();
 569         }
 570 
 571         public Rectangle getBounds() {
 572             Rectangle r = peer.getBounds();
 573             r.x = r.y = 0;
 574             return r;
 575         }
 576 
 577         @Override
 578         public boolean canSourceSendExposures(int x, int y, int w, int h) {
 579             return true;
 580         }
 581 
 582         /**
 583          * Returns destination Component associated with this SurfaceData.
 584          */
 585         public Object getDestination() {
 586             return peer.getTarget();
 587         }
 588 
 589        public void invalidate() {
 590            try {
 591                SunToolkit.awtLock();
 592                freeXSDOPicture(getNativeOps());
 593            }finally {
 594                SunToolkit.awtUnlock();
 595            }
 596 
 597            super.invalidate();
 598        }
 599     }
 600 
 601     public static class XRInternalSurfaceData extends XRSurfaceData {
 602         public XRInternalSurfaceData(XRBackend renderQueue, int pictXid) {
 603           super(renderQueue);
 604           this.picture = pictXid;
 605           this.transformInUse = false;
 606         }
 607 
 608         public boolean canSourceSendExposures(int x, int y, int w, int h) {
 609             return false;
 610         }
 611 
 612         public Rectangle getBounds() {
 613             return null;
 614         }
 615 
 616         public Object getDestination() {
 617             return null;
 618         }
 619 
 620         public SurfaceData getReplacement() {
 621             return null;
 622         }
 623     }
 624 
 625     public static class XRPixmapSurfaceData extends XRSurfaceData {
 626         Image offscreenImage;
 627         int width;
 628         int height;
 629         int transparency;
 630 
 631         public XRPixmapSurfaceData(XRGraphicsConfig gc, int width, int height,
 632                                    Image image, SurfaceType sType,
 633                                    ColorModel cm, long drawable,
 634                                    int transparency, int pictFormat,
 635                                    int depth) {
 636             super(null, gc, sType, cm, depth, transparency);
 637             this.width = width;
 638             this.height = height;
 639             offscreenImage = image;
 640             this.transparency = transparency;
 641             initSurface(depth, width, height, drawable, pictFormat);
 642 
 643             initXRender(pictFormat);
 644             makePipes();
 645         }
 646 
 647         public void initSurface(int depth, int width, int height,
 648                                 long drawable, int pictFormat) {
 649             try {
 650                 SunToolkit.awtLock();
 651                 XRInitSurface(depth, width, height, drawable, pictFormat);
 652             } finally {
 653                 SunToolkit.awtUnlock();
 654             }
 655         }
 656 
 657         public SurfaceData getReplacement() {
 658             return restoreContents(offscreenImage);
 659         }
 660 
 661         /**
 662          * Need this since the surface data is created with the color model of
 663          * the target GC, which is always opaque. But in SunGraphics2D.blitSD we
 664          * choose loops based on the transparency on the source SD, so it could
 665          * choose wrong loop (blit instead of blitbg, for example).
 666          */
 667         public int getTransparency() {
 668             return transparency;
 669         }
 670 
 671         public Rectangle getBounds() {
 672             return new Rectangle(width, height);
 673         }
 674 
 675         @Override
 676         public boolean canSourceSendExposures(int x, int y, int w, int h) {
 677             return (x < 0 || y < 0 || (x + w) > width || (y + h) > height);
 678         }
 679 
 680         public void flush() {
 681             /*
 682              * We need to invalidate the surface before disposing the native
 683              * Drawable and Picture. This way if an application tries to render
 684              * to an already flushed XRSurfaceData, we will notice in the
 685              * validate() method above that it has been invalidated, and we will
 686              * avoid using those native resources that have already been
 687              * disposed.
 688              */
 689             invalidate();
 690             flushNativeSurface();
 691         }
 692 
 693         /**
 694          * Returns destination Image associated with this SurfaceData.
 695          */
 696         public Object getDestination() {
 697             return offscreenImage;
 698         }
 699     }
 700 
 701     public long getGC() {
 702         return xgc;
 703     }
 704 
 705     public static class LazyPipe extends ValidatePipe {
 706         public boolean validate(SunGraphics2D sg2d) {
 707             XRSurfaceData xsd = (XRSurfaceData) sg2d.surfaceData;
 708             if (!xsd.isXRDrawableValid()) {
 709                 return false;
 710             }
 711             xsd.makePipes();
 712             return super.validate(sg2d);
 713         }
 714     }
 715 
 716     public int getPicture() {
 717         return picture;
 718     }
 719 
 720     public int getXid() {
 721         return xid;
 722     }
 723 
 724     public XRGraphicsConfig getGraphicsConfig() {
 725         return graphicsConfig;
 726     }
 727 
 728     public void setStaticSrcTx(AffineTransform staticSrcTx) {
 729         this.staticSrcTx = staticSrcTx;
 730     }
 731 }