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