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 (CompositeType.SrcOverNoEa.equals(comptype) ||
 369              CompositeType.SrcNoEa.equals(comptype))
 370         {
 371             try {
 372                 SunToolkit.awtLock();
 373                 boolean needExposures = canSourceSendExposures(x, y, w, h);
 374                 validateCopyAreaGC(sg2d.getCompClip(), needExposures);
 375                 renderQueue.copyArea(xid, xid, xgc, x, y, w, h, x + dx, y + dy);
 376             } finally {
 377                 SunToolkit.awtUnlock();
 378             }
 379             return true;
 380         }
 381         return false;
 382     }
 383 
 384     /**
 385      * Returns the XRender SurfaceType which is able to fullfill the specified
 386      * transparency requirement.
 387      */
 388     public static SurfaceType getSurfaceType(XRGraphicsConfig gc,
 389                                              int transparency) {
 390         SurfaceType sType = null;
 391 
 392         switch (transparency) {
 393         case Transparency.OPAQUE:
 394             sType = XRSurfaceData.IntRgbX11;
 395             break;
 396 
 397         case Transparency.BITMASK:
 398         case Transparency.TRANSLUCENT:
 399             sType = XRSurfaceData.IntArgbPreX11;
 400             break;
 401         }
 402 
 403         return sType;
 404     }
 405 
 406     public void invalidate() {
 407         if (isValid()) {
 408             setInvalid();
 409             super.invalidate();
 410         }
 411     }
 412 
 413     private long xgc; // GC is still used for copyArea
 414     private int validatedGCForegroundPixel = 0;
 415     private XORComposite validatedXorComp;
 416     private int xid;
 417     public int picture;
 418     public XRCompositeManager maskBuffer;
 419 
 420     private Region validatedClip;
 421     private Region validatedGCClip;
 422     private boolean validatedExposures = true;
 423 
 424     boolean transformInUse = false;
 425     AffineTransform validatedSourceTransform = new AffineTransform();
 426     AffineTransform staticSrcTx = null;
 427     int validatedRepeat = XRUtils.RepeatNone;
 428     int validatedFilter = XRUtils.FAST;
 429 
 430     /**
 431      * Validates an XRSurfaceData when used as source. Note that the clip is
 432      * applied when used as source as well as destination.
 433      */
 434     void validateAsSource(AffineTransform sxForm, int repeat, int filter) {
 435 
 436         if (validatedClip != null) {
 437             validatedClip = null;
 438             renderQueue.setClipRectangles(picture, null);
 439         }
 440 
 441         if (validatedRepeat != repeat && repeat != -1) {
 442             validatedRepeat = repeat;
 443             renderQueue.setPictureRepeat(picture, repeat);
 444         }
 445 
 446         if (sxForm == null) {
 447             if (transformInUse) {
 448                 validatedSourceTransform.setToIdentity();
 449                 renderQueue.setPictureTransform(picture,
 450                                                 validatedSourceTransform);
 451                 transformInUse = false;
 452             }
 453         } else if (!transformInUse ||
 454                    (transformInUse && !sxForm.equals(validatedSourceTransform))) {
 455 
 456             validatedSourceTransform.setTransform(sxForm.getScaleX(),
 457                                                   sxForm.getShearY(),
 458                                                   sxForm.getShearX(),
 459                                                   sxForm.getScaleY(),
 460                                                   sxForm.getTranslateX(),
 461                                                   sxForm.getTranslateY());
 462 
 463             AffineTransform srcTransform = validatedSourceTransform;
 464             if(staticSrcTx != null) {
 465                 // Apply static transform set when used as texture or gradient.
 466                 // Create a copy to not modify validatedSourceTransform as
 467                 // this would confuse the validation logic.
 468                 srcTransform = new AffineTransform(validatedSourceTransform);
 469                 srcTransform.preConcatenate(staticSrcTx);
 470             }
 471 
 472             renderQueue.setPictureTransform(picture, srcTransform);
 473             transformInUse = true;
 474         }
 475 
 476         if (filter != validatedFilter && filter != -1) {
 477             renderQueue.setFilter(picture, filter);
 478             validatedFilter = filter;
 479         }
 480     }
 481 
 482     /**
 483      * Validates the Surface when used as destination.
 484      */
 485     public void validateAsDestination(SunGraphics2D sg2d, Region clip) {
 486         if (!isValid()) {
 487             throw new InvalidPipeException("bounds changed");
 488         }
 489 
 490         boolean updateGCClip = false;
 491         if (clip != validatedClip) {
 492             renderQueue.setClipRectangles(picture, clip);
 493             validatedClip = clip;
 494             updateGCClip = true;
 495         }
 496 
 497         if (sg2d != null && sg2d.compositeState == SunGraphics2D.COMP_XOR) {
 498             if (validatedXorComp != sg2d.getComposite()) {
 499                 validatedXorComp = (XORComposite) sg2d.getComposite();
 500                 renderQueue.setGCMode(xgc, false);
 501             }
 502 
 503             // validate pixel
 504             int pixel = sg2d.pixel;
 505             if (validatedGCForegroundPixel != pixel) {
 506                 int xorpixelmod = validatedXorComp.getXorPixel();
 507                 renderQueue.setGCForeground(xgc, pixel ^ xorpixelmod);
 508                 validatedGCForegroundPixel = pixel;
 509             }
 510 
 511             if (updateGCClip) {
 512                 renderQueue.setGCClipRectangles(xgc, clip);
 513             }
 514         }
 515     }
 516 
 517     public synchronized void makePipes() { /*
 518                                             * TODO: Why is this synchronized,
 519                                             * but access not?
 520                                             */
 521         if (xrpipe == null) {
 522             try {
 523                 SunToolkit.awtLock();
 524                 xgc = XCreateGC(getNativeOps());
 525 
 526                 xrpipe = new XRRenderer(maskBuffer.getMaskBuffer());
 527                 xrtxpipe = new PixelToShapeConverter(xrpipe);
 528                 xrtextpipe = maskBuffer.getTextRenderer();
 529                 xrDrawImage = new XRDrawImage();
 530 
 531                 if (JulesPathBuf.isCairoAvailable()) {
 532                     aaShapePipe =
 533                        new JulesShapePipe(XRCompositeManager.getInstance(this));
 534                     aaPixelToShapeConv = new PixelToShapeConverter(aaShapePipe);
 535                 }
 536             } finally {
 537                 SunToolkit.awtUnlock();
 538             }
 539         }
 540     }
 541 
 542     public static class XRWindowSurfaceData extends XRSurfaceData {
 543 
 544         protected final int scale;
 545 
 546         public XRWindowSurfaceData(X11ComponentPeer peer,
 547                                    XRGraphicsConfig gc, SurfaceType sType) {
 548             super(peer, gc, sType, peer.getColorModel(),
 549                   peer.getColorModel().getPixelSize(), Transparency.OPAQUE);
 550 
 551             this.scale = gc.getScale();
 552 
 553             if (isXRDrawableValid()) {
 554                 // If we have a 32 bit color model for the window it needs
 555                 // alpha to support translucency of the window so we need
 556                 // to get the ARGB32 XRender picture format else for
 557                 // 24 bit colormodel we need RGB24 or OPAQUE pictureformat.
 558                 if (peer.getColorModel().getPixelSize() == 32) {
 559                      initXRender(XRUtils.
 560                       getPictureFormatForTransparency(Transparency.TRANSLUCENT));
 561                  }
 562                  else {
 563                      initXRender(XRUtils.
 564                        getPictureFormatForTransparency(Transparency.OPAQUE));
 565                  }
 566                 makePipes();
 567             }
 568         }
 569 
 570         public SurfaceData getReplacement() {
 571             return peer.getSurfaceData();
 572         }
 573 
 574         public Rectangle getBounds() {
 575             Rectangle r = peer.getBounds();
 576             r.x = r.y = 0;
 577             r.width *= scale;
 578             r.height *= scale;
 579             return r;
 580         }
 581 
 582         @Override
 583         public boolean canSourceSendExposures(int x, int y, int w, int h) {
 584             return true;
 585         }
 586 
 587         /**
 588          * Returns destination Component associated with this SurfaceData.
 589          */
 590         public Object getDestination() {
 591             return peer.getTarget();
 592         }
 593 
 594        public void invalidate() {
 595            try {
 596                SunToolkit.awtLock();
 597                freeXSDOPicture(getNativeOps());
 598            }finally {
 599                SunToolkit.awtUnlock();
 600            }
 601 
 602            super.invalidate();
 603        }
 604 
 605         @Override
 606         public double getDefaultScaleX() {
 607             return scale;
 608         }
 609 
 610         @Override
 611         public double getDefaultScaleY() {
 612             return scale;
 613         }
 614     }
 615 
 616     public static class XRInternalSurfaceData extends XRSurfaceData {
 617         public XRInternalSurfaceData(XRBackend renderQueue, int pictXid) {
 618           super(renderQueue);
 619           this.picture = pictXid;
 620           this.transformInUse = false;
 621         }
 622 
 623         public boolean canSourceSendExposures(int x, int y, int w, int h) {
 624             return false;
 625         }
 626 
 627         public Rectangle getBounds() {
 628             return null;
 629         }
 630 
 631         public Object getDestination() {
 632             return null;
 633         }
 634 
 635         public SurfaceData getReplacement() {
 636             return null;
 637         }
 638     }
 639 
 640     public static class XRPixmapSurfaceData extends XRSurfaceData {
 641         Image offscreenImage;
 642         int width;
 643         int height;
 644         int transparency;
 645         private final int scale;
 646 
 647         public XRPixmapSurfaceData(XRGraphicsConfig gc, int width, int height,
 648                                    Image image, SurfaceType sType,
 649                                    ColorModel cm, long drawable,
 650                                    int transparency, int pictFormat,
 651                                    int depth, boolean isTexture) {
 652             super(null, gc, sType, cm, depth, transparency);
 653             this.scale = isTexture ? 1 : gc.getDevice().getScaleFactor();
 654             this.width = width * scale;
 655             this.height = height * scale;
 656             offscreenImage = image;
 657             this.transparency = transparency;
 658             initSurface(depth, this.width, this.height, drawable, pictFormat);
 659 
 660             initXRender(pictFormat);
 661             makePipes();
 662         }
 663 
 664         public void initSurface(int depth, int width, int height,
 665                                 long drawable, int pictFormat) {
 666             try {
 667                 SunToolkit.awtLock();
 668                 XRInitSurface(depth, width, height, drawable, pictFormat);
 669             } finally {
 670                 SunToolkit.awtUnlock();
 671             }
 672         }
 673 
 674         public SurfaceData getReplacement() {
 675             return restoreContents(offscreenImage);
 676         }
 677 
 678         /**
 679          * Need this since the surface data is created with the color model of
 680          * the target GC, which is always opaque. But in SunGraphics2D.blitSD we
 681          * choose loops based on the transparency on the source SD, so it could
 682          * choose wrong loop (blit instead of blitbg, for example).
 683          */
 684         public int getTransparency() {
 685             return transparency;
 686         }
 687 
 688         public Rectangle getBounds() {
 689             return new Rectangle(width, height);
 690         }
 691 
 692         @Override
 693         public boolean canSourceSendExposures(int x, int y, int w, int h) {
 694             return (x < 0 || y < 0 || (x + w) > width || (y + h) > height);
 695         }
 696 
 697         public void flush() {
 698             /*
 699              * We need to invalidate the surface before disposing the native
 700              * Drawable and Picture. This way if an application tries to render
 701              * to an already flushed XRSurfaceData, we will notice in the
 702              * validate() method above that it has been invalidated, and we will
 703              * avoid using those native resources that have already been
 704              * disposed.
 705              */
 706             invalidate();
 707             flushNativeSurface();
 708         }
 709 
 710         /**
 711          * Returns destination Image associated with this SurfaceData.
 712          */
 713         public Object getDestination() {
 714             return offscreenImage;
 715         }
 716 
 717         @Override
 718         public double getDefaultScaleX() {
 719             return scale;
 720         }
 721 
 722         @Override
 723         public double getDefaultScaleY() {
 724             return scale;
 725         }
 726     }
 727 
 728     public long getGC() {
 729         return xgc;
 730     }
 731 
 732     public static class LazyPipe extends ValidatePipe {
 733         public boolean validate(SunGraphics2D sg2d) {
 734             XRSurfaceData xsd = (XRSurfaceData) sg2d.surfaceData;
 735             if (!xsd.isXRDrawableValid()) {
 736                 return false;
 737             }
 738             xsd.makePipes();
 739             return super.validate(sg2d);
 740         }
 741     }
 742 
 743     public int getPicture() {
 744         return picture;
 745     }
 746 
 747     public int getXid() {
 748         return xid;
 749     }
 750 
 751     public XRGraphicsConfig getGraphicsConfig() {
 752         return graphicsConfig;
 753     }
 754 
 755     public void setStaticSrcTx(AffineTransform staticSrcTx) {
 756         this.staticSrcTx = staticSrcTx;
 757     }
 758 }