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 }