1 /* 2 * Copyright (c) 2010, 2011, 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 int depth = transparency > Transparency.OPAQUE ? 32 : 24; 249 if (depth == 24) { 250 cm = new DirectColorModel(depth, 251 0x00FF0000, 0x0000FF00, 0x000000FF); 252 } else { 253 cm = new DirectColorModel(depth, 0x00FF0000, 0x0000FF00, 254 0x000000FF, 0xFF000000); 255 } 256 257 return new XRPixmapSurfaceData 258 (gc, width, height, image, getSurfaceType(gc, transparency), 259 cm, drawable, transparency, 260 XRUtils.getPictureFormatForTransparency(transparency), depth); 261 } 262 263 protected XRSurfaceData(X11ComponentPeer peer, XRGraphicsConfig gc, 264 SurfaceType sType, ColorModel cm, int depth, int transparency) 265 { 266 super(sType, cm); 267 this.peer = peer; 268 this.graphicsConfig = gc; 269 this.solidloops = graphicsConfig.getSolidLoops(sType); 270 this.depth = depth; 271 initOps(peer, graphicsConfig, depth); 272 273 setBlitProxyKey(gc.getProxyKey()); 274 } 275 276 protected XRSurfaceData(XRBackend renderQueue) { 277 super(XRSurfaceData.IntRgbX11, 278 new DirectColorModel(24, 0x00FF0000, 0x0000FF00, 0x000000FF)); 279 this.renderQueue = renderQueue; 280 } 281 282 /** 283 * Inits the XRender-data-structures which belong to the XRSurfaceData. 284 * 285 * @param pictureFormat 286 */ 287 public void initXRender(int pictureFormat) { 288 try { 289 SunToolkit.awtLock(); 290 initXRPicture(getNativeOps(), pictureFormat); 291 renderQueue = XRCompositeManager.getInstance(this).getBackend(); 292 maskBuffer = XRCompositeManager.getInstance(this); 293 } catch (Throwable ex) { 294 ex.printStackTrace(); 295 } finally { 296 SunToolkit.awtUnlock(); 297 } 298 } 299 300 public static XRGraphicsConfig getGC(X11ComponentPeer peer) { 301 if (peer != null) { 302 return (XRGraphicsConfig) peer.getGraphicsConfiguration(); 303 } else { 304 GraphicsEnvironment env = 305 GraphicsEnvironment.getLocalGraphicsEnvironment(); 306 GraphicsDevice gd = env.getDefaultScreenDevice(); 307 return (XRGraphicsConfig) gd.getDefaultConfiguration(); 308 } 309 } 310 311 /** 312 * Returns a boolean indicating whether or not a copyArea from the given 313 * rectangle source coordinates might be incomplete and result in X11 314 * GraphicsExposure events being generated from XCopyArea. This method 315 * allows the SurfaceData copyArea method to determine if it needs to set 316 * the GraphicsExposures attribute of the X11 GC to True or False to receive 317 * or avoid the events. 318 * 319 * @return true if there is any chance that an XCopyArea from the given 320 * source coordinates could produce any X11 Exposure events. 321 */ 322 public abstract boolean canSourceSendExposures(int x, int y, int w, int h); 323 324 /** 325 * CopyArea is implemented using the "old" X11 GC, therefor clip and 326 * needExposures have to be validated against that GC. Pictures and GCs 327 * don't share state. 328 */ 329 public void validateCopyAreaGC(Region gcClip, boolean needExposures) { 330 if (validatedGCClip != gcClip) { 331 if (gcClip != null) 332 renderQueue.setGCClipRectangles(xgc, gcClip); 333 validatedGCClip = gcClip; 334 } 335 336 if (validatedExposures != needExposures) { 337 validatedExposures = needExposures; 338 renderQueue.setGCExposures(xgc, needExposures); 339 } 340 341 if (validatedXorComp != null) { 342 renderQueue.setGCMode(xgc, true); 343 renderQueue.setGCForeground(xgc, validatedGCForegroundPixel); 344 validatedXorComp = null; 345 } 346 } 347 348 public boolean copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, 349 int dx, int dy) { 350 if (xrpipe == null) { 351 if (!isXRDrawableValid()) { 352 return true; 353 } 354 makePipes(); 355 } 356 CompositeType comptype = sg2d.imageComp; 357 if (sg2d.transformState < SunGraphics2D.TRANSFORM_TRANSLATESCALE && 358 (CompositeType.SrcOverNoEa.equals(comptype) || 359 CompositeType.SrcNoEa.equals(comptype))) 360 { 361 x += sg2d.transX; 362 y += sg2d.transY; 363 try { 364 SunToolkit.awtLock(); 365 boolean needExposures = canSourceSendExposures(x, y, w, h); 366 validateCopyAreaGC(sg2d.getCompClip(), needExposures); 367 renderQueue.copyArea(xid, xid, xgc, x, y, w, h, x + dx, y + dy); 368 } finally { 369 SunToolkit.awtUnlock(); 370 } 371 return true; 372 } 373 return false; 374 } 375 376 /** 377 * Returns the XRender SurfaceType which is able to fullfill the specified 378 * transparency requirement. 379 */ 380 public static SurfaceType getSurfaceType(XRGraphicsConfig gc, 381 int transparency) { 382 SurfaceType sType = null; 383 384 switch (transparency) { 385 case Transparency.OPAQUE: 386 sType = XRSurfaceData.IntRgbX11; 387 break; 388 389 case Transparency.BITMASK: 390 case Transparency.TRANSLUCENT: 391 sType = XRSurfaceData.IntArgbPreX11; 392 break; 393 } 394 395 return sType; 396 } 397 398 public void invalidate() { 399 if (isValid()) { 400 setInvalid(); 401 super.invalidate(); 402 } 403 } 404 405 private long xgc; // GC is still used for copyArea 406 private int validatedGCForegroundPixel = 0; 407 private XORComposite validatedXorComp; 408 private int xid; 409 public int picture; 410 public XRCompositeManager maskBuffer; 411 412 private Region validatedClip; 413 private Region validatedGCClip; 414 private boolean validatedExposures = true; 415 416 boolean transformInUse = false; 417 AffineTransform validatedSourceTransform = new AffineTransform(); 418 int validatedRepeat = XRUtils.RepeatNone; 419 int validatedFilter = XRUtils.FAST; 420 421 /** 422 * Validates an XRSurfaceData when used as source. Note that the clip is 423 * applied when used as source as well as destination. 424 */ 425 void validateAsSource(AffineTransform sxForm, int repeat, int filter) { 426 427 if (validatedClip != null) { 428 validatedClip = null; 429 renderQueue.setClipRectangles(picture, null); 430 } 431 432 if (validatedRepeat != repeat && repeat != -1) { 433 validatedRepeat = repeat; 434 renderQueue.setPictureRepeat(picture, repeat); 435 } 436 437 if (sxForm == null) { 438 if (transformInUse) { 439 validatedSourceTransform.setToIdentity(); 440 renderQueue.setPictureTransform(picture, 441 validatedSourceTransform); 442 transformInUse = false; 443 } 444 } else if (!transformInUse || 445 (transformInUse && !sxForm.equals(validatedSourceTransform))) { 446 validatedSourceTransform.setTransform(sxForm.getScaleX(), 447 sxForm.getShearY(), 448 sxForm.getShearX(), 449 sxForm.getScaleY(), 450 sxForm.getTranslateX(), 451 sxForm.getTranslateY()); 452 renderQueue.setPictureTransform(picture, validatedSourceTransform); 453 transformInUse = true; 454 } 455 456 if (filter != validatedFilter && filter != -1) { 457 renderQueue.setFilter(picture, filter); 458 validatedFilter = filter; 459 } 460 } 461 462 /** 463 * Validates the Surface when used as destination. 464 */ 465 public void validateAsDestination(SunGraphics2D sg2d, Region clip) { 466 if (!isValid()) { 467 throw new InvalidPipeException("bounds changed"); 468 } 469 470 boolean updateGCClip = false; 471 if (clip != validatedClip) { 472 renderQueue.setClipRectangles(picture, clip); 473 validatedClip = clip; 474 updateGCClip = true; 475 } 476 477 if (sg2d != null && sg2d.compositeState == SunGraphics2D.COMP_XOR) { 478 if (validatedXorComp != sg2d.getComposite()) { 479 validatedXorComp = (XORComposite) sg2d.getComposite(); 480 renderQueue.setGCMode(xgc, false); 481 } 482 483 // validate pixel 484 int pixel = sg2d.pixel; 485 if (validatedGCForegroundPixel != pixel) { 486 int xorpixelmod = validatedXorComp.getXorPixel(); 487 renderQueue.setGCForeground(xgc, pixel ^ xorpixelmod); 488 validatedGCForegroundPixel = pixel; 489 } 490 491 if (updateGCClip) { 492 renderQueue.setGCClipRectangles(xgc, clip); 493 } 494 } 495 } 496 497 public synchronized void makePipes() { /* 498 * TODO: Why is this synchronized, 499 * but access not? 500 */ 501 if (xrpipe == null) { 502 try { 503 SunToolkit.awtLock(); 504 xgc = XCreateGC(getNativeOps()); 505 506 xrpipe = new XRRenderer(maskBuffer.getMaskBuffer()); 507 xrtxpipe = new PixelToShapeConverter(xrpipe); 508 xrtextpipe = maskBuffer.getTextRenderer(); 509 xrDrawImage = new XRDrawImage(); 510 511 if (JulesPathBuf.isCairoAvailable()) { 512 aaShapePipe = 513 new JulesShapePipe(XRCompositeManager.getInstance(this)); 514 aaPixelToShapeConv = new PixelToShapeConverter(aaShapePipe); 515 } 516 } finally { 517 SunToolkit.awtUnlock(); 518 } 519 } 520 } 521 522 public static class XRWindowSurfaceData extends XRSurfaceData { 523 public XRWindowSurfaceData(X11ComponentPeer peer, 524 XRGraphicsConfig gc, SurfaceType sType) { 525 super(peer, gc, sType, peer.getColorModel(), 526 peer.getColorModel().getPixelSize(), Transparency.OPAQUE); 527 528 if (isXRDrawableValid()) { 529 initXRender(XRUtils. 530 getPictureFormatForTransparency(Transparency.OPAQUE)); 531 makePipes(); 532 } 533 } 534 535 public SurfaceData getReplacement() { 536 return peer.getSurfaceData(); 537 } 538 539 public Rectangle getBounds() { 540 Rectangle r = peer.getBounds(); 541 r.x = r.y = 0; 542 return r; 543 } 544 545 @Override 546 public boolean canSourceSendExposures(int x, int y, int w, int h) { 547 return true; 548 } 549 550 /** 551 * Returns destination Component associated with this SurfaceData. 552 */ 553 public Object getDestination() { 554 return peer.getTarget(); 555 } 556 557 public void invalidate() { 558 try { 559 SunToolkit.awtLock(); 560 freeXSDOPicture(getNativeOps()); 561 }finally { 562 SunToolkit.awtUnlock(); 563 } 564 565 super.invalidate(); 566 } 567 } 568 569 public static class XRInternalSurfaceData extends XRSurfaceData { 570 public XRInternalSurfaceData(XRBackend renderQueue, int pictXid, 571 AffineTransform transform) { 572 super(renderQueue); 573 this.picture = pictXid; 574 this.validatedSourceTransform = transform; 575 576 if (validatedSourceTransform != null) { 577 transformInUse = true; 578 } 579 } 580 581 public boolean canSourceSendExposures(int x, int y, int w, int h) { 582 return false; 583 } 584 585 public Rectangle getBounds() { 586 return null; 587 } 588 589 public Object getDestination() { 590 return null; 591 } 592 593 public SurfaceData getReplacement() { 594 return null; 595 } 596 } 597 598 public static class XRPixmapSurfaceData extends XRSurfaceData { 599 Image offscreenImage; 600 int width; 601 int height; 602 int transparency; 603 604 public XRPixmapSurfaceData(XRGraphicsConfig gc, int width, int height, 605 Image image, SurfaceType sType, 606 ColorModel cm, long drawable, 607 int transparency, int pictFormat, 608 int depth) { 609 super(null, gc, sType, cm, depth, transparency); 610 this.width = width; 611 this.height = height; 612 offscreenImage = image; 613 this.transparency = transparency; 614 initSurface(depth, width, height, drawable, pictFormat); 615 616 initXRender(pictFormat); 617 makePipes(); 618 } 619 620 public void initSurface(int depth, int width, int height, 621 long drawable, int pictFormat) { 622 try { 623 SunToolkit.awtLock(); 624 XRInitSurface(depth, width, height, drawable, pictFormat); 625 } finally { 626 SunToolkit.awtUnlock(); 627 } 628 } 629 630 public SurfaceData getReplacement() { 631 return restoreContents(offscreenImage); 632 } 633 634 /** 635 * Need this since the surface data is created with the color model of 636 * the target GC, which is always opaque. But in SunGraphics2D.blitSD we 637 * choose loops based on the transparency on the source SD, so it could 638 * choose wrong loop (blit instead of blitbg, for example). 639 */ 640 public int getTransparency() { 641 return transparency; 642 } 643 644 public Rectangle getBounds() { 645 return new Rectangle(width, height); 646 } 647 648 @Override 649 public boolean canSourceSendExposures(int x, int y, int w, int h) { 650 return (x < 0 || y < 0 || (x + w) > width || (y + h) > height); 651 } 652 653 public void flush() { 654 /* 655 * We need to invalidate the surface before disposing the native 656 * Drawable and Picture. This way if an application tries to render 657 * to an already flushed XRSurfaceData, we will notice in the 658 * validate() method above that it has been invalidated, and we will 659 * avoid using those native resources that have already been 660 * disposed. 661 */ 662 invalidate(); 663 flushNativeSurface(); 664 } 665 666 /** 667 * Returns destination Image associated with this SurfaceData. 668 */ 669 public Object getDestination() { 670 return offscreenImage; 671 } 672 } 673 674 public long getGC() { 675 return xgc; 676 } 677 678 public static class LazyPipe extends ValidatePipe { 679 public boolean validate(SunGraphics2D sg2d) { 680 XRSurfaceData xsd = (XRSurfaceData) sg2d.surfaceData; 681 if (!xsd.isXRDrawableValid()) { 682 return false; 683 } 684 xsd.makePipes(); 685 return super.validate(sg2d); 686 } 687 } 688 689 public int getPicture() { 690 return picture; 691 } 692 693 public int getXid() { 694 return xid; 695 } 696 697 public XRGraphicsConfig getGraphicsConfig() { 698 return graphicsConfig; 699 } 700 }