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