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