1 /*
   2  * Copyright (c) 2010, 2011, 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 = transparency > Transparency.OPAQUE ? 32 : 24;
 249         if (depth == 24) {
 250             cm = new DirectColorModel(depth,
 251                                       0x00FF0000, 0x0000FF00, 0x000000FF);
 252         } else {
 253             cm = new DirectColorModel(depth, 0x00FF0000, 0x0000FF00,
 254                                       0x000000FF, 0xFF000000);
 255         }
 256 
 257         return new XRPixmapSurfaceData
 258             (gc, width, height, image, getSurfaceType(gc, transparency),
 259              cm, drawable, transparency,
 260              XRUtils.getPictureFormatForTransparency(transparency), depth);
 261     }
 262 
 263     protected XRSurfaceData(X11ComponentPeer peer, XRGraphicsConfig gc,
 264         SurfaceType sType, ColorModel cm, int depth, int transparency)
 265     {
 266         super(sType, cm);
 267         this.peer = peer;
 268         this.graphicsConfig = gc;
 269         this.solidloops = graphicsConfig.getSolidLoops(sType);
 270         this.depth = depth;
 271         initOps(peer, graphicsConfig, depth);
 272 
 273         setBlitProxyKey(gc.getProxyKey());
 274     }
 275 
 276     protected XRSurfaceData(XRBackend renderQueue) {
 277         super(XRSurfaceData.IntRgbX11,
 278               new DirectColorModel(24, 0x00FF0000, 0x0000FF00, 0x000000FF));
 279         this.renderQueue = renderQueue;
 280     }
 281 
 282     /**
 283      * Inits the XRender-data-structures which belong to the XRSurfaceData.
 284      *
 285      * @param pictureFormat
 286      */
 287     public void initXRender(int pictureFormat) {
 288         try {
 289             SunToolkit.awtLock();
 290             initXRPicture(getNativeOps(), pictureFormat);
 291             renderQueue = XRCompositeManager.getInstance(this).getBackend();
 292             maskBuffer = XRCompositeManager.getInstance(this);
 293         } catch (Throwable ex) {
 294             ex.printStackTrace();
 295         } finally {
 296             SunToolkit.awtUnlock();
 297         }
 298     }
 299 
 300     public static XRGraphicsConfig getGC(X11ComponentPeer peer) {
 301         if (peer != null) {
 302             return (XRGraphicsConfig) peer.getGraphicsConfiguration();
 303         } else {
 304             GraphicsEnvironment env =
 305                 GraphicsEnvironment.getLocalGraphicsEnvironment();
 306             GraphicsDevice gd = env.getDefaultScreenDevice();
 307             return (XRGraphicsConfig) gd.getDefaultConfiguration();
 308         }
 309     }
 310 
 311     /**
 312      * Returns a boolean indicating whether or not a copyArea from the given
 313      * rectangle source coordinates might be incomplete and result in X11
 314      * GraphicsExposure events being generated from XCopyArea. This method
 315      * allows the SurfaceData copyArea method to determine if it needs to set
 316      * the GraphicsExposures attribute of the X11 GC to True or False to receive
 317      * or avoid the events.
 318      *
 319      * @return true if there is any chance that an XCopyArea from the given
 320      *         source coordinates could produce any X11 Exposure events.
 321      */
 322     public abstract boolean canSourceSendExposures(int x, int y, int w, int h);
 323 
 324     /**
 325      * CopyArea is implemented using the "old" X11 GC, therefor clip and
 326      * needExposures have to be validated against that GC. Pictures and GCs
 327      * don't share state.
 328      */
 329     public void validateCopyAreaGC(Region gcClip, boolean needExposures) {
 330         if (validatedGCClip != gcClip) {
 331             if (gcClip != null)
 332                 renderQueue.setGCClipRectangles(xgc, gcClip);
 333             validatedGCClip = gcClip;
 334         }
 335 
 336         if (validatedExposures != needExposures) {
 337             validatedExposures = needExposures;
 338             renderQueue.setGCExposures(xgc, needExposures);
 339         }
 340 
 341         if (validatedXorComp != null) {
 342             renderQueue.setGCMode(xgc, true);
 343             renderQueue.setGCForeground(xgc, validatedGCForegroundPixel);
 344             validatedXorComp = null;
 345         }
 346     }
 347 
 348     public boolean copyArea(SunGraphics2D sg2d, int x, int y, int w, int h,
 349                             int dx, int dy) {
 350         if (xrpipe == null) {
 351             if (!isXRDrawableValid()) {
 352                 return true;
 353             }
 354             makePipes();
 355         }
 356         CompositeType comptype = sg2d.imageComp;
 357         if (sg2d.transformState < SunGraphics2D.TRANSFORM_TRANSLATESCALE &&
 358             (CompositeType.SrcOverNoEa.equals(comptype) ||
 359              CompositeType.SrcNoEa.equals(comptype)))
 360         {
 361             x += sg2d.transX;
 362             y += sg2d.transY;
 363             try {
 364                 SunToolkit.awtLock();
 365                 boolean needExposures = canSourceSendExposures(x, y, w, h);
 366                 validateCopyAreaGC(sg2d.getCompClip(), needExposures);
 367                 renderQueue.copyArea(xid, xid, xgc, x, y, w, h, x + dx, y + dy);
 368             } finally {
 369                 SunToolkit.awtUnlock();
 370             }
 371             return true;
 372         }
 373         return false;
 374     }
 375 
 376     /**
 377      * Returns the XRender SurfaceType which is able to fullfill the specified
 378      * transparency requirement.
 379      */
 380     public static SurfaceType getSurfaceType(XRGraphicsConfig gc,
 381                                              int transparency) {
 382         SurfaceType sType = null;
 383 
 384         switch (transparency) {
 385         case Transparency.OPAQUE:
 386             sType = XRSurfaceData.IntRgbX11;
 387             break;
 388 
 389         case Transparency.BITMASK:
 390         case Transparency.TRANSLUCENT:
 391             sType = XRSurfaceData.IntArgbPreX11;
 392             break;
 393         }
 394 
 395         return sType;
 396     }
 397 
 398     public void invalidate() {
 399         if (isValid()) {
 400             setInvalid();
 401             super.invalidate();
 402         }
 403     }
 404 
 405     private long xgc; // GC is still used for copyArea
 406     private int validatedGCForegroundPixel = 0;
 407     private XORComposite validatedXorComp;
 408     private int xid;
 409     public int picture;
 410     public XRCompositeManager maskBuffer;
 411 
 412     private Region validatedClip;
 413     private Region validatedGCClip;
 414     private boolean validatedExposures = true;
 415 
 416     boolean transformInUse = false;
 417     AffineTransform validatedSourceTransform = new AffineTransform();
 418     int validatedRepeat = XRUtils.RepeatNone;
 419     int validatedFilter = XRUtils.FAST;
 420 
 421     /**
 422      * Validates an XRSurfaceData when used as source. Note that the clip is
 423      * applied when used as source as well as destination.
 424      */
 425     void validateAsSource(AffineTransform sxForm, int repeat, int filter) {
 426 
 427         if (validatedClip != null) {
 428             validatedClip = null;
 429             renderQueue.setClipRectangles(picture, null);
 430         }
 431 
 432         if (validatedRepeat != repeat && repeat != -1) {
 433             validatedRepeat = repeat;
 434             renderQueue.setPictureRepeat(picture, repeat);
 435         }
 436 
 437         if (sxForm == null) {
 438             if (transformInUse) {
 439                 validatedSourceTransform.setToIdentity();
 440                 renderQueue.setPictureTransform(picture,
 441                                                 validatedSourceTransform);
 442                 transformInUse = false;
 443             }
 444         } else if (!transformInUse ||
 445                    (transformInUse && !sxForm.equals(validatedSourceTransform))) {
 446             validatedSourceTransform.setTransform(sxForm.getScaleX(),
 447                                                   sxForm.getShearY(),
 448                                                   sxForm.getShearX(),
 449                                                   sxForm.getScaleY(),
 450                                                   sxForm.getTranslateX(),
 451                                                   sxForm.getTranslateY());
 452             renderQueue.setPictureTransform(picture, validatedSourceTransform);
 453             transformInUse = true;
 454         }
 455 
 456         if (filter != validatedFilter && filter != -1) {
 457             renderQueue.setFilter(picture, filter);
 458             validatedFilter = filter;
 459         }
 460     }
 461 
 462     /**
 463      * Validates the Surface when used as destination.
 464      */
 465     public void validateAsDestination(SunGraphics2D sg2d, Region clip) {
 466         if (!isValid()) {
 467             throw new InvalidPipeException("bounds changed");
 468         }
 469 
 470         boolean updateGCClip = false;
 471         if (clip != validatedClip) {
 472             renderQueue.setClipRectangles(picture, clip);
 473             validatedClip = clip;
 474             updateGCClip = true;
 475         }
 476 
 477         if (sg2d != null && sg2d.compositeState == SunGraphics2D.COMP_XOR) {
 478             if (validatedXorComp != sg2d.getComposite()) {
 479                 validatedXorComp = (XORComposite) sg2d.getComposite();
 480                 renderQueue.setGCMode(xgc, false);
 481             }
 482 
 483             // validate pixel
 484             int pixel = sg2d.pixel;
 485             if (validatedGCForegroundPixel != pixel) {
 486                 int xorpixelmod = validatedXorComp.getXorPixel();
 487                 renderQueue.setGCForeground(xgc, pixel ^ xorpixelmod);
 488                 validatedGCForegroundPixel = pixel;
 489             }
 490 
 491             if (updateGCClip) {
 492                 renderQueue.setGCClipRectangles(xgc, clip);
 493             }
 494         }
 495     }
 496 
 497     public synchronized void makePipes() { /*
 498                                             * TODO: Why is this synchronized,
 499                                             * but access not?
 500                                             */
 501         if (xrpipe == null) {
 502             try {
 503                 SunToolkit.awtLock();
 504                 xgc = XCreateGC(getNativeOps());
 505 
 506                 xrpipe = new XRRenderer(maskBuffer.getMaskBuffer());
 507                 xrtxpipe = new PixelToShapeConverter(xrpipe);
 508                 xrtextpipe = maskBuffer.getTextRenderer();
 509                 xrDrawImage = new XRDrawImage();
 510 
 511                 if (JulesPathBuf.isCairoAvailable()) {
 512                     aaShapePipe =
 513                        new JulesShapePipe(XRCompositeManager.getInstance(this));
 514                     aaPixelToShapeConv = new PixelToShapeConverter(aaShapePipe);
 515                 }
 516             } finally {
 517                 SunToolkit.awtUnlock();
 518             }
 519         }
 520     }
 521 
 522     public static class XRWindowSurfaceData extends XRSurfaceData {
 523         public XRWindowSurfaceData(X11ComponentPeer peer,
 524                                    XRGraphicsConfig gc, SurfaceType sType) {
 525             super(peer, gc, sType, peer.getColorModel(),
 526                   peer.getColorModel().getPixelSize(), Transparency.OPAQUE);
 527 
 528             if (isXRDrawableValid()) {
 529                 initXRender(XRUtils.
 530                     getPictureFormatForTransparency(Transparency.OPAQUE));
 531                 makePipes();
 532             }
 533         }
 534 
 535         public SurfaceData getReplacement() {
 536             return peer.getSurfaceData();
 537         }
 538 
 539         public Rectangle getBounds() {
 540             Rectangle r = peer.getBounds();
 541             r.x = r.y = 0;
 542             return r;
 543         }
 544 
 545         @Override
 546         public boolean canSourceSendExposures(int x, int y, int w, int h) {
 547             return true;
 548         }
 549 
 550         /**
 551          * Returns destination Component associated with this SurfaceData.
 552          */
 553         public Object getDestination() {
 554             return peer.getTarget();
 555         }
 556 
 557        public void invalidate() {
 558            try {
 559                SunToolkit.awtLock();
 560                freeXSDOPicture(getNativeOps());
 561            }finally {
 562                SunToolkit.awtUnlock();
 563            }
 564 
 565            super.invalidate();
 566        }
 567     }
 568 
 569     public static class XRInternalSurfaceData extends XRSurfaceData {
 570         public XRInternalSurfaceData(XRBackend renderQueue, int pictXid,
 571                                      AffineTransform transform) {
 572           super(renderQueue);
 573           this.picture = pictXid;
 574           this.validatedSourceTransform = transform;
 575 
 576           if (validatedSourceTransform != null) {
 577               transformInUse = true;
 578           }
 579         }
 580 
 581         public boolean canSourceSendExposures(int x, int y, int w, int h) {
 582             return false;
 583         }
 584 
 585         public Rectangle getBounds() {
 586             return null;
 587         }
 588 
 589         public Object getDestination() {
 590             return null;
 591         }
 592 
 593         public SurfaceData getReplacement() {
 594             return null;
 595         }
 596     }
 597 
 598     public static class XRPixmapSurfaceData extends XRSurfaceData {
 599         Image offscreenImage;
 600         int width;
 601         int height;
 602         int transparency;
 603 
 604         public XRPixmapSurfaceData(XRGraphicsConfig gc, int width, int height,
 605                                    Image image, SurfaceType sType,
 606                                    ColorModel cm, long drawable,
 607                                    int transparency, int pictFormat,
 608                                    int depth) {
 609             super(null, gc, sType, cm, depth, transparency);
 610             this.width = width;
 611             this.height = height;
 612             offscreenImage = image;
 613             this.transparency = transparency;
 614             initSurface(depth, width, height, drawable, pictFormat);
 615 
 616             initXRender(pictFormat);
 617             makePipes();
 618         }
 619 
 620         public void initSurface(int depth, int width, int height,
 621                                 long drawable, int pictFormat) {
 622             try {
 623                 SunToolkit.awtLock();
 624                 XRInitSurface(depth, width, height, drawable, pictFormat);
 625             } finally {
 626                 SunToolkit.awtUnlock();
 627             }
 628         }
 629 
 630         public SurfaceData getReplacement() {
 631             return restoreContents(offscreenImage);
 632         }
 633 
 634         /**
 635          * Need this since the surface data is created with the color model of
 636          * the target GC, which is always opaque. But in SunGraphics2D.blitSD we
 637          * choose loops based on the transparency on the source SD, so it could
 638          * choose wrong loop (blit instead of blitbg, for example).
 639          */
 640         public int getTransparency() {
 641             return transparency;
 642         }
 643 
 644         public Rectangle getBounds() {
 645             return new Rectangle(width, height);
 646         }
 647 
 648         @Override
 649         public boolean canSourceSendExposures(int x, int y, int w, int h) {
 650             return (x < 0 || y < 0 || (x + w) > width || (y + h) > height);
 651         }
 652 
 653         public void flush() {
 654             /*
 655              * We need to invalidate the surface before disposing the native
 656              * Drawable and Picture. This way if an application tries to render
 657              * to an already flushed XRSurfaceData, we will notice in the
 658              * validate() method above that it has been invalidated, and we will
 659              * avoid using those native resources that have already been
 660              * disposed.
 661              */
 662             invalidate();
 663             flushNativeSurface();
 664         }
 665 
 666         /**
 667          * Returns destination Image associated with this SurfaceData.
 668          */
 669         public Object getDestination() {
 670             return offscreenImage;
 671         }
 672     }
 673 
 674     public long getGC() {
 675         return xgc;
 676     }
 677 
 678     public static class LazyPipe extends ValidatePipe {
 679         public boolean validate(SunGraphics2D sg2d) {
 680             XRSurfaceData xsd = (XRSurfaceData) sg2d.surfaceData;
 681             if (!xsd.isXRDrawableValid()) {
 682                 return false;
 683             }
 684             xsd.makePipes();
 685             return super.validate(sg2d);
 686         }
 687     }
 688 
 689     public int getPicture() {
 690         return picture;
 691     }
 692 
 693     public int getXid() {
 694         return xid;
 695     }
 696 
 697     public XRGraphicsConfig getGraphicsConfig() {
 698         return graphicsConfig;
 699     }
 700 }