# HG changeset patch # User serb # Date 1341398294 -14400 # Node ID 4d45f7ebc0d7f874afe38422b6a3e685e0df270e # Parent eada40c7d74db15afdc570482268771f19de0155 7124244: [macosx] Shaped windows support Reviewed-by: anthony, art diff -r eada40c7d74d -r 4d45f7ebc0d7 jdk/src/macosx/classes/sun/java2d/opengl/CGLLayer.java --- a/jdk/src/macosx/classes/sun/java2d/opengl/CGLLayer.java Thu Jun 28 14:05:06 2012 +0400 +++ b/jdk/src/macosx/classes/sun/java2d/opengl/CGLLayer.java Wed Jul 04 14:38:14 2012 +0400 @@ -68,11 +68,12 @@ } public boolean isOpaque() { - return peer.isOpaque(); + return !peer.isTranslucent(); } public int getTransparency() { - return (peer.isOpaque() ? Transparency.OPAQUE : Transparency.TRANSLUCENT); + return peer.isTranslucent() ? Transparency.TRANSLUCENT : + Transparency.OPAQUE; } public Object getDestination() { diff -r eada40c7d74d -r 4d45f7ebc0d7 jdk/src/macosx/classes/sun/lwawt/LWComponentPeer.java --- a/jdk/src/macosx/classes/sun/lwawt/LWComponentPeer.java Thu Jun 28 14:05:06 2012 +0400 +++ b/jdk/src/macosx/classes/sun/lwawt/LWComponentPeer.java Wed Jul 04 14:38:14 2012 +0400 @@ -424,8 +424,7 @@ @Override public final Graphics getGraphics() { - Graphics g = getWindowPeerOrSelf().isOpaque() ? getOnscreenGraphics() - : getOffscreenGraphics(); + final Graphics g = getOnscreenGraphics(); if (g != null) { synchronized (getPeerTreeLock()){ applyConstrain(g); @@ -443,13 +442,7 @@ final LWWindowPeer wp = getWindowPeerOrSelf(); return wp.getOnscreenGraphics(getForeground(), getBackground(), getFont()); - } - public final Graphics getOffscreenGraphics() { - final LWWindowPeer wp = getWindowPeerOrSelf(); - - return wp.getOffscreenGraphics(getForeground(), getBackground(), - getFont()); } private void applyConstrain(final Graphics g) { @@ -463,7 +456,7 @@ } //TODO Move this method to SG2D? - private void SG2DConstraint(final SunGraphics2D sg2d, Region r) { + void SG2DConstraint(final SunGraphics2D sg2d, Region r) { sg2d.constrainX = sg2d.transX; sg2d.constrainY = sg2d.transY; @@ -710,7 +703,7 @@ // Obtain the metrics from the offscreen window where this peer is // mostly drawn to. // TODO: check for "use platform metrics" settings - Graphics g = getWindowPeer().getOffscreenGraphics(); + Graphics g = getWindowPeer().getGraphics(); try { if (g != null) { return g.getFontMetrics(f); @@ -1011,14 +1004,33 @@ @Override public final void applyShape(final Region shape) { synchronized (getStateLock()) { - region = shape; + if (region == shape || (region != null && region.equals(shape))) { + return; + } + } + applyShapeImpl(shape); + } + + void applyShapeImpl(final Region shape) { + synchronized (getStateLock()) { + if (shape != null) { + region = Region.WHOLE_REGION.getIntersection(shape); + } else { + region = null; + } } repaintParent(getBounds()); } protected final Region getRegion() { synchronized (getStateLock()) { - return region == null ? Region.getInstance(getSize()) : region; + return isShaped() ? region : Region.getInstance(getSize()); + } + } + + public boolean isShaped() { + synchronized (getStateLock()) { + return region != null; } } @@ -1386,11 +1398,6 @@ } } - // Just a helper method, thus final - protected final void flushOffscreenGraphics() { - flushOffscreenGraphics(getSize()); - } - protected static final void flushOnscreenGraphics(){ final OGLRenderQueue rq = OGLRenderQueue.getInstance(); rq.lock(); @@ -1401,36 +1408,6 @@ } } - /* - * Flushes the given rectangle from the back buffer to the screen. - */ - protected void flushOffscreenGraphics(Rectangle r) { - flushOffscreenGraphics(r.x, r.y, r.width, r.height); - } - - private void flushOffscreenGraphics(int x, int y, int width, int height) { - Image bb = getWindowPeerOrSelf().getBackBuffer(); - if (bb != null) { - // g is a screen Graphics from the delegate - final Graphics g = getOnscreenGraphics(); - - if (g != null && g instanceof Graphics2D) { - try { - Graphics2D g2d = (Graphics2D)g; - Point p = localToWindow(new Point(0, 0)); - Composite composite = g2d.getComposite(); - g2d.setComposite(AlphaComposite.Src); - g.drawImage(bb, x, y, x + width, y + height, p.x + x, - p.y + y, p.x + x + width, p.y + y + height, - null); - g2d.setComposite(composite); - } finally { - g.dispose(); - } - } - } - } - /** * Used by ContainerPeer to skip all the paint events during layout. * diff -r eada40c7d74d -r 4d45f7ebc0d7 jdk/src/macosx/classes/sun/lwawt/LWRepaintArea.java --- a/jdk/src/macosx/classes/sun/lwawt/LWRepaintArea.java Thu Jun 28 14:05:06 2012 +0400 +++ b/jdk/src/macosx/classes/sun/lwawt/LWRepaintArea.java Wed Jul 04 14:38:14 2012 +0400 @@ -58,9 +58,6 @@ private static void flushBuffers(final LWComponentPeer peer) { if (peer != null) { - if (!peer.getWindowPeerOrSelf().isOpaque()) { - peer.flushOffscreenGraphics(); - } peer.flushOnscreenGraphics(); } } diff -r eada40c7d74d -r 4d45f7ebc0d7 jdk/src/macosx/classes/sun/lwawt/LWToolkit.java --- a/jdk/src/macosx/classes/sun/lwawt/LWToolkit.java Thu Jun 28 14:05:06 2012 +0400 +++ b/jdk/src/macosx/classes/sun/lwawt/LWToolkit.java Wed Jul 04 14:38:14 2012 +0400 @@ -522,12 +522,6 @@ postEvent(targetToAppContext(event.getSource()), event); } - // use peer's back buffer to implement non-opaque windows. - @Override - public boolean needUpdateWindow() { - return true; - } - @Override public void grab(Window w) { if (w.getPeer() != null) { diff -r eada40c7d74d -r 4d45f7ebc0d7 jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java --- a/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java Thu Jun 28 14:05:06 2012 +0400 +++ b/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java Wed Jul 04 14:38:14 2012 +0400 @@ -37,6 +37,7 @@ import sun.java2d.*; import sun.java2d.loops.Blit; import sun.java2d.loops.CompositeType; +import sun.java2d.pipe.Region; import sun.util.logging.PlatformLogger; public class LWWindowPeer @@ -109,6 +110,8 @@ private volatile boolean skipNextFocusChange; + private static final Color nonOpaqueBackground = new Color(0, 0, 0, 0); + /** * Current modal blocker or null. * @@ -169,6 +172,11 @@ setAlwaysOnTop(getTarget().isAlwaysOnTop()); updateMinimumSize(); + final Shape shape = getTarget().getShape(); + if (shape != null) { + applyShape(Region.getInstance(shape, null)); + } + final float opacity = getTarget().getOpacity(); if (opacity < 1.0f) { setOpacity(opacity); @@ -178,7 +186,7 @@ updateInsets(platformWindow.getInsets()); if (getSurfaceData() == null) { - replaceSurfaceData(); + replaceSurfaceData(false); } } @@ -280,7 +288,7 @@ // "buffer", that's why numBuffers - 1 assert numBuffers > 1; - replaceSurfaceData(numBuffers - 1, caps); + replaceSurfaceData(numBuffers - 1, caps, false); } catch (InvalidPipeException z) { throw new AWTException(z.toString()); } @@ -420,19 +428,30 @@ public final void setOpaque(final boolean isOpaque) { if (this.isOpaque != isOpaque) { this.isOpaque = isOpaque; - getPlatformWindow().setOpaque(isOpaque); - replaceSurfaceData(); - repaintPeer(); + updateOpaque(); } } - public final boolean isOpaque() { - return isOpaque; + private void updateOpaque() { + getPlatformWindow().setOpaque(!isTranslucent()); + replaceSurfaceData(false); + repaintPeer(); } @Override public void updateWindow() { - flushOffscreenGraphics(); + } + + public final boolean isTranslucent() { + synchronized (getStateLock()) { + return !isOpaque || isShaped(); + } + } + + @Override + final void applyShapeImpl(final Region shape) { + super.applyShapeImpl(shape); + updateOpaque(); } @Override @@ -587,7 +606,18 @@ getFont()); if (g != null) { try { - g.clearRect(0, 0, w, h); + if (g instanceof Graphics2D) { + ((Graphics2D) g).setComposite(AlphaComposite.Src); + } + if (isTranslucent()) { + g.setColor(nonOpaqueBackground); + g.fillRect(0, 0, w, h); + } + if (g instanceof SunGraphics2D) { + SG2DConstraint((SunGraphics2D) g, getRegion()); + } + g.setColor(getBackground()); + g.fillRect(0, 0, w, h); } finally { g.dispose(); } @@ -894,35 +924,6 @@ }); } - /** - * This method returns a back buffer Graphics to render all the - * peers to. After the peer is painted, the back buffer contents - * should be flushed to the screen. All the target painting - * (Component.paint() method) should be done directly to the screen. - */ - protected final Graphics getOffscreenGraphics(Color fg, Color bg, Font f) { - final Image bb = getBackBuffer(); - if (bb == null) { - return null; - } - if (fg == null) { - fg = SystemColor.windowText; - } - if (bg == null) { - bg = SystemColor.window; - } - if (f == null) { - f = DEFAULT_FONT; - } - final Graphics2D g = (Graphics2D) bb.getGraphics(); - if (g != null) { - g.setColor(fg); - g.setBackground(bg); - g.setFont(f); - } - return g; - } - /* * May be called by delegate to provide SD to Java2D code. */ @@ -933,11 +934,16 @@ } private void replaceSurfaceData() { - replaceSurfaceData(backBufferCount, backBufferCaps); + replaceSurfaceData(true); + } + + private void replaceSurfaceData(boolean blit) { + replaceSurfaceData(backBufferCount, backBufferCaps, blit); } private void replaceSurfaceData(int newBackBufferCount, - BufferCapabilities newBackBufferCaps) { + BufferCapabilities newBackBufferCaps, + boolean blit) { synchronized (surfaceDataLock) { final SurfaceData oldData = getSurfaceData(); surfaceData = platformWindow.replaceSurfaceData(); @@ -950,7 +956,10 @@ if (getSurfaceData() != null && oldData != getSurfaceData()) { clearBackground(size.width, size.height); } - blitSurfaceData(oldData, getSurfaceData()); + + if (blit) { + blitSurfaceData(oldData, getSurfaceData()); + } if (oldData != null && oldData != getSurfaceData()) { // TODO: drop oldData for D3D/WGL pipelines @@ -965,10 +974,15 @@ Graphics g = backBuffer.getGraphics(); try { Rectangle r = getBounds(); - g.setColor(getBackground()); if (g instanceof Graphics2D) { ((Graphics2D) g).setComposite(AlphaComposite.Src); } + g.setColor(nonOpaqueBackground); + g.fillRect(0, 0, r.width, r.height); + if (g instanceof SunGraphics2D) { + SG2DConstraint((SunGraphics2D) g, getRegion()); + } + g.setColor(getBackground()); g.fillRect(0, 0, r.width, r.height); if (oldBB != null) { // Draw the old back buffer to the new one @@ -993,7 +1007,7 @@ CompositeType.Src, dst.getSurfaceType()); if (blit != null) { - blit.Blit(src, dst, ((Graphics2D) getGraphics()).getComposite(), + blit.Blit(src, dst, AlphaComposite.Src, getRegion(), 0, 0, 0, 0, size.width, size.height); } } diff -r eada40c7d74d -r 4d45f7ebc0d7 jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformEmbeddedFrame.java --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformEmbeddedFrame.java Thu Jun 28 14:05:06 2012 +0400 +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformEmbeddedFrame.java Wed Jul 04 14:38:14 2012 +0400 @@ -117,7 +117,7 @@ Rectangle r = peer.getBounds(); Image im = null; if (!r.isEmpty()) { - int transparency = (peer.isOpaque() ? Transparency.OPAQUE : Transparency.TRANSLUCENT); + int transparency = peer.isTranslucent() ? Transparency.TRANSLUCENT : Transparency.OPAQUE; im = peer.getGraphicsConfiguration().createCompatibleImage(r.width, r.height, transparency); } return im; diff -r eada40c7d74d -r 4d45f7ebc0d7 jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformView.java --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformView.java Thu Jun 28 14:05:06 2012 +0400 +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformView.java Wed Jul 04 14:38:14 2012 +0400 @@ -64,7 +64,7 @@ } public boolean isOpaque() { - return peer.isOpaque(); + return !peer.isTranslucent(); } /* diff -r eada40c7d74d -r 4d45f7ebc0d7 jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java Thu Jun 28 14:05:06 2012 +0400 +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java Wed Jul 04 14:38:14 2012 +0400 @@ -737,6 +737,15 @@ long clearColor = CWrapper.NSColor.clearColor(); CWrapper.NSWindow.setBackgroundColor(getNSWindowPtr(), clearColor); } + + //This is a temporary workaround. Looks like after 7124236 will be fixed + //the correct place for invalidateShadow() is CGLayer.drawInCGLContext. + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + invalidateShadow(); + } + }); } @Override @@ -805,6 +814,10 @@ nativeSetEnabled(getNSWindowPtr(), !blocked); } + public final void invalidateShadow(){ + nativeRevalidateNSWindowShadow(getNSWindowPtr()); + } + // ---------------------------------------------------------------------- // UTILITY METHODS // ---------------------------------------------------------------------- diff -r eada40c7d74d -r 4d45f7ebc0d7 jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java --- a/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java Thu Jun 28 14:05:06 2012 +0400 +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java Wed Jul 04 14:38:14 2012 +0400 @@ -750,6 +750,11 @@ } @Override + public boolean isWindowShapingSupported() { + return true; + } + + @Override public boolean isWindowTranslucencySupported() { return true; } @@ -759,6 +764,10 @@ return true; } + public boolean isSwingBackbufferTranslucencySupported() { + return true; + } + @Override public boolean enableInputMethodsForTextComponent() { return true; diff -r eada40c7d74d -r 4d45f7ebc0d7 jdk/src/macosx/native/sun/awt/AWTWindow.m --- a/jdk/src/macosx/native/sun/awt/AWTWindow.m Thu Jun 28 14:05:06 2012 +0400 +++ b/jdk/src/macosx/native/sun/awt/AWTWindow.m Wed Jul 04 14:38:14 2012 +0400 @@ -941,14 +941,17 @@ (JNIEnv *env, jclass clazz, jlong windowPtr) { JNF_COCOA_ENTER(env); -AWT_ASSERT_NOT_APPKIT_THREAD; NSWindow *nsWindow = OBJC(windowPtr); - [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ - AWT_ASSERT_APPKIT_THREAD; + if ([NSThread isMainThread]) { + [nsWindow invalidateShadow]; + } else { + [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ + AWT_ASSERT_APPKIT_THREAD; - [nsWindow invalidateShadow]; - }]; + [nsWindow invalidateShadow]; + }]; + } JNF_COCOA_EXIT(env); } diff -r eada40c7d74d -r 4d45f7ebc0d7 jdk/src/share/classes/javax/swing/RepaintManager.java --- a/jdk/src/share/classes/javax/swing/RepaintManager.java Thu Jun 28 14:05:06 2012 +0400 +++ b/jdk/src/share/classes/javax/swing/RepaintManager.java Wed Jul 04 14:38:14 2012 +0400 @@ -119,6 +119,11 @@ // Whether or not a VolatileImage should be used for double-buffered painting static boolean volatileImageBufferEnabled = true; /** + * Type of VolatileImage which should be used for double-buffered + * painting. + */ + private static final int volatileBufferType; + /** * Value of the system property awt.nativeDoubleBuffering. */ private static boolean nativeDoubleBuffering; @@ -204,6 +209,13 @@ ((SunGraphicsEnvironment)ge).addDisplayChangedListener( new DisplayChangedHandler()); } + Toolkit tk = Toolkit.getDefaultToolkit(); + if ((tk instanceof SunToolkit) + && ((SunToolkit) tk).isSwingBackbufferTranslucencySupported()) { + volatileBufferType = Transparency.TRANSLUCENT; + } else { + volatileBufferType = Transparency.OPAQUE; + } } /** @@ -989,7 +1001,8 @@ if (image != null) { image.flush(); } - image = config.createCompatibleVolatileImage(width, height); + image = config.createCompatibleVolatileImage(width, height, + volatileBufferType); volatileMap.put(config, image); } return image; @@ -1483,9 +1496,26 @@ for(y=clipY, maxy = clipY + clipH; y < maxy ; y += bh) { osg.translate(-x, -y); osg.setClip(x,y,bw,bh); + if (volatileBufferType != Transparency.OPAQUE + && osg instanceof Graphics2D) { + final Graphics2D g2d = (Graphics2D) osg; + final Color oldBg = g2d.getBackground(); + g2d.setBackground(c.getBackground()); + g2d.clearRect(x, y, bw, bh); + g2d.setBackground(oldBg); + } c.paintToOffscreen(osg, x, y, bw, bh, maxx, maxy); g.setClip(x, y, bw, bh); - g.drawImage(image, x, y, c); + if (volatileBufferType != Transparency.OPAQUE + && g instanceof Graphics2D) { + final Graphics2D g2d = (Graphics2D) g; + final Composite oldComposite = g2d.getComposite(); + g2d.setComposite(AlphaComposite.Src); + g2d.drawImage(image, x, y, c); + g2d.setComposite(oldComposite); + } else { + g.drawImage(image, x, y, c); + } osg.translate(x, y); } } diff -r eada40c7d74d -r 4d45f7ebc0d7 jdk/src/share/classes/sun/awt/SunToolkit.java --- a/jdk/src/share/classes/sun/awt/SunToolkit.java Thu Jun 28 14:05:06 2012 +0400 +++ b/jdk/src/share/classes/sun/awt/SunToolkit.java Wed Jul 04 14:38:14 2012 +0400 @@ -1985,6 +1985,13 @@ } /** + * Returns true if swing backbuffer should be translucent. + */ + public boolean isSwingBackbufferTranslucencySupported() { + return false; + } + + /** * Returns whether or not a containing top level window for the passed * component is * {@link GraphicsDevice.WindowTranslucency#PERPIXEL_TRANSLUCENT PERPIXEL_TRANSLUCENT}.