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