From 3fa31de79197d70e8819d31161331c4952eabae5 Mon Sep 17 00:00:00 2001 From: Igor Nekrestyanov Date: Fri, 2 Oct 2009 10:15:12 -0700 Subject: [PATCH 01/36] 6887292: memory leak in freetypeScaler.c Reviewed-by: bae, prr --- jdk/src/share/native/sun/font/freetypeScaler.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/jdk/src/share/native/sun/font/freetypeScaler.c b/jdk/src/share/native/sun/font/freetypeScaler.c index 4028d4d97c4..93baaea47cd 100644 --- a/jdk/src/share/native/sun/font/freetypeScaler.c +++ b/jdk/src/share/native/sun/font/freetypeScaler.c @@ -102,9 +102,21 @@ Java_sun_font_FreetypeFontScaler_initIDs( } static void freeNativeResources(JNIEnv *env, FTScalerInfo* scalerInfo) { + void *stream; + if (scalerInfo == NULL) return; + //apparently Done_Face will only close the stream + // but will not relase the memory of stream structure. + // We need to free it explicitly to avoid leak. + //Direct access to the stream field might be not ideal solution as + // it is considred to be "private". + //Alternatively we could have stored pointer to the structure + // in the scalerInfo but this will increase size of the structure + // for no good reason + stream = scalerInfo->face->stream; + FT_Done_Face(scalerInfo->face); FT_Done_FreeType(scalerInfo->library); @@ -116,6 +128,10 @@ static void freeNativeResources(JNIEnv *env, FTScalerInfo* scalerInfo) { free(scalerInfo->fontData); } + if (stream != NULL) { + free(stream); + } + free(scalerInfo); } From a64ba16c4fda0e7e0f05494d4c89e1f2e9659d52 Mon Sep 17 00:00:00 2001 From: Roman Kennke Date: Mon, 5 Oct 2009 23:12:22 +0200 Subject: [PATCH 02/36] 6887494: NPE in pisces Renderer Only recreate crossings array, if there actually exists one before. Reviewed-by: flar, tdv --- .../classes/sun/java2d/pisces/Renderer.java | 6 +- .../sun/java2d/pisces/Renderer/TestNPE.java | 59 +++++++++++++++++++ 2 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 jdk/test/sun/java2d/pisces/Renderer/TestNPE.java diff --git a/jdk/src/share/classes/sun/java2d/pisces/Renderer.java b/jdk/src/share/classes/sun/java2d/pisces/Renderer.java index 3ada6c73600..2aba4112161 100644 --- a/jdk/src/share/classes/sun/java2d/pisces/Renderer.java +++ b/jdk/src/share/classes/sun/java2d/pisces/Renderer.java @@ -775,10 +775,12 @@ public class Renderer extends LineSink { // Free sorting arrays if larger than maximum size private void crossingListFinished() { - if (crossings.length > DEFAULT_CROSSINGS_SIZE) { + if (crossings != null && crossings.length > DEFAULT_CROSSINGS_SIZE) { crossings = new int[DEFAULT_CROSSINGS_SIZE]; } - if (crossingIndices.length > DEFAULT_INDICES_SIZE) { + if (crossingIndices != null && + crossingIndices.length > DEFAULT_INDICES_SIZE) + { crossingIndices = new int[DEFAULT_INDICES_SIZE]; } } diff --git a/jdk/test/sun/java2d/pisces/Renderer/TestNPE.java b/jdk/test/sun/java2d/pisces/Renderer/TestNPE.java new file mode 100644 index 00000000000..440860c9272 --- /dev/null +++ b/jdk/test/sun/java2d/pisces/Renderer/TestNPE.java @@ -0,0 +1,59 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6887494 + * + * @summary Verifies that no NullPointerException is thrown in Pisces Renderer + * under certain circumstances. + * + * @run main TestNPE + */ + +import java.awt.*; +import java.awt.geom.*; +import java.awt.image.BufferedImage; + +public class TestNPE { + + private static void paint(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setClip(0, 0, 0, 0); + g2d.setTransform( + new AffineTransform(4.0f, 0.0f, 0.0f, 4.0f, -1248.0f, -744.0f)); + g2d.draw(new Line2D.Float(131.21428571428572f, 33.0f, + 131.21428571428572f, 201.0f)); + } + + public static void main(String[] args) { + BufferedImage im = new BufferedImage(100, 100, + BufferedImage.TYPE_INT_ARGB); + + // Trigger exception in main thread. + Graphics g = im.getGraphics(); + paint(g); + } +} From 7628a594141102e8ed200ea483af496b024bdf9b Mon Sep 17 00:00:00 2001 From: Dmitry Cherepanov Date: Mon, 12 Oct 2009 19:07:43 +0400 Subject: [PATCH 03/36] 6796915: Deadlock in XAWT when switching virtual desktops Reviewed-by: art, anthony --- .../sun/awt/X11/XDropTargetRegistry.java | 88 +++++++++---------- .../classes/sun/awt/X11/XWindowPeer.java | 52 +++++++---- 2 files changed, 78 insertions(+), 62 deletions(-) diff --git a/jdk/src/solaris/classes/sun/awt/X11/XDropTargetRegistry.java b/jdk/src/solaris/classes/sun/awt/X11/XDropTargetRegistry.java index 1678d92a6bd..84f67fb01b2 100644 --- a/jdk/src/solaris/classes/sun/awt/X11/XDropTargetRegistry.java +++ b/jdk/src/solaris/classes/sun/awt/X11/XDropTargetRegistry.java @@ -534,71 +534,71 @@ final class XDropTargetRegistry { return entry.getSite(x, y); } + /* + * Note: this method should be called under AWT lock. + */ public void registerDropSite(long window) { + assert XToolkit.isAWTLockHeldByCurrentThread(); + if (window == 0) { throw new IllegalArgumentException(); } XDropTargetEventProcessor.activate(); - XToolkit.awtLock(); - try { - long toplevel = getToplevelWindow(window); + long toplevel = getToplevelWindow(window); - /* - * No window with WM_STATE property is found. - * Since the window can be a plugin window reparented to the browser - * toplevel, we cannot determine which window will eventually have - * WM_STATE property set. So we schedule a timer callback that will - * periodically attempt to find an ancestor with WM_STATE and - * register the drop site appropriately. - */ - if (toplevel == 0) { - addDelayedRegistrationEntry(window); - return; + /* + * No window with WM_STATE property is found. + * Since the window can be a plugin window reparented to the browser + * toplevel, we cannot determine which window will eventually have + * WM_STATE property set. So we schedule a timer callback that will + * periodically attempt to find an ancestor with WM_STATE and + * register the drop site appropriately. + */ + if (toplevel == 0) { + addDelayedRegistrationEntry(window); + return; + } + + if (toplevel == window) { + Iterator dropTargetProtocols = + XDragAndDropProtocols.getDropTargetProtocols(); + + while (dropTargetProtocols.hasNext()) { + XDropTargetProtocol dropTargetProtocol = + (XDropTargetProtocol)dropTargetProtocols.next(); + dropTargetProtocol.registerDropTarget(toplevel); } - - if (toplevel == window) { - Iterator dropTargetProtocols = - XDragAndDropProtocols.getDropTargetProtocols(); - - while (dropTargetProtocols.hasNext()) { - XDropTargetProtocol dropTargetProtocol = - (XDropTargetProtocol)dropTargetProtocols.next(); - dropTargetProtocol.registerDropTarget(toplevel); - } - } else { - registerEmbeddedDropSite(toplevel, window); - } - } finally { - XToolkit.awtUnlock(); + } else { + registerEmbeddedDropSite(toplevel, window); } } + /* + * Note: this method should be called under AWT lock. + */ public void unregisterDropSite(long window) { + assert XToolkit.isAWTLockHeldByCurrentThread(); + if (window == 0) { throw new IllegalArgumentException(); } - XToolkit.awtLock(); - try { - long toplevel = getToplevelWindow(window); + long toplevel = getToplevelWindow(window); - if (toplevel == window) { - Iterator dropProtocols = - XDragAndDropProtocols.getDropTargetProtocols(); + if (toplevel == window) { + Iterator dropProtocols = + XDragAndDropProtocols.getDropTargetProtocols(); - removeDelayedRegistrationEntry(window); + removeDelayedRegistrationEntry(window); - while (dropProtocols.hasNext()) { - XDropTargetProtocol dropProtocol = (XDropTargetProtocol)dropProtocols.next(); - dropProtocol.unregisterDropTarget(window); - } - } else { - unregisterEmbeddedDropSite(toplevel, window); + while (dropProtocols.hasNext()) { + XDropTargetProtocol dropProtocol = (XDropTargetProtocol)dropProtocols.next(); + dropProtocol.unregisterDropTarget(window); } - } finally { - XToolkit.awtUnlock(); + } else { + unregisterEmbeddedDropSite(toplevel, window); } } diff --git a/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java b/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java index b1646413b79..076526fd653 100644 --- a/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java +++ b/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java @@ -1757,25 +1757,36 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, } } + // should be synchronized on awtLock private int dropTargetCount = 0; - public synchronized void addDropTarget() { - if (dropTargetCount == 0) { - long window = getWindow(); - if (window != 0) { - XDropTargetRegistry.getRegistry().registerDropSite(window); + public void addDropTarget() { + XToolkit.awtLock(); + try { + if (dropTargetCount == 0) { + long window = getWindow(); + if (window != 0) { + XDropTargetRegistry.getRegistry().registerDropSite(window); + } } + dropTargetCount++; + } finally { + XToolkit.awtUnlock(); } - dropTargetCount++; } - public synchronized void removeDropTarget() { - dropTargetCount--; - if (dropTargetCount == 0) { - long window = getWindow(); - if (window != 0) { - XDropTargetRegistry.getRegistry().unregisterDropSite(window); + public void removeDropTarget() { + XToolkit.awtLock(); + try { + dropTargetCount--; + if (dropTargetCount == 0) { + long window = getWindow(); + if (window != 0) { + XDropTargetRegistry.getRegistry().unregisterDropSite(window); + } } + } finally { + XToolkit.awtUnlock(); } } void addRootPropertyEventDispatcher() { @@ -1838,13 +1849,18 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, } } - protected synchronized void updateDropTarget() { - if (dropTargetCount > 0) { - long window = getWindow(); - if (window != 0) { - XDropTargetRegistry.getRegistry().unregisterDropSite(window); - XDropTargetRegistry.getRegistry().registerDropSite(window); + protected void updateDropTarget() { + XToolkit.awtLock(); + try { + if (dropTargetCount > 0) { + long window = getWindow(); + if (window != 0) { + XDropTargetRegistry.getRegistry().unregisterDropSite(window); + XDropTargetRegistry.getRegistry().registerDropSite(window); + } } + } finally { + XToolkit.awtUnlock(); } } From 99d8a50297bb8489d0b11b4dc6a452d9f64f021b Mon Sep 17 00:00:00 2001 From: Anthony Petrov Date: Wed, 14 Oct 2009 15:46:13 +0400 Subject: [PATCH 04/36] 6684916: jframe.setMaximizedBounds() has no effect in linux Specification should indicate that the feature may be unsupported on some platforms. Reviewed-by: art, dcherepanov --- jdk/src/share/classes/java/awt/Frame.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/jdk/src/share/classes/java/awt/Frame.java b/jdk/src/share/classes/java/awt/Frame.java index 761b9b8420b..ea8c6154cf1 100644 --- a/jdk/src/share/classes/java/awt/Frame.java +++ b/jdk/src/share/classes/java/awt/Frame.java @@ -845,8 +845,11 @@ public class Frame extends Window implements MenuContainer { * others by setting those fields you want to accept from system * to Integer.MAX_VALUE. *

- * On some systems only the size portion of the bounds is taken - * into account. + * Note, the given maximized bounds are used as a hint for the native + * system, because the underlying platform may not support setting the + * location and/or size of the maximized windows. If that is the case, the + * provided values do not affect the appearance of the frame in the + * maximized state. * * @param bounds bounds for the maximized state * @see #getMaximizedBounds() From 370b3a923b84cc59cf3258544c25b31ed0ceeac0 Mon Sep 17 00:00:00 2001 From: Anthony Petrov Date: Wed, 14 Oct 2009 16:19:46 +0400 Subject: [PATCH 05/36] 6711717: PIT: Security Icon is hidden for FullScreen apps, WinXP Force hiding the security warning in FS exclusive mode. Reviewed-by: art, tdv --- .../share/classes/java/awt/AWTPermission.java | 12 ++++- .../solaris/classes/sun/awt/X11/XWindow.java | 20 ++++++++ .../classes/sun/awt/X11/XWindowPeer.java | 38 ++++++++------ .../classes/sun/awt/X11ComponentPeer.java | 3 +- .../classes/sun/awt/X11GraphicsDevice.java | 4 +- .../classes/sun/awt/Win32GraphicsDevice.java | 16 +++--- .../classes/sun/awt/windows/WWindowPeer.java | 3 ++ .../windows/native/sun/windows/awt_Window.cpp | 51 ++++++++++++++++++- .../windows/native/sun/windows/awt_Window.h | 11 ++++ 9 files changed, 132 insertions(+), 26 deletions(-) diff --git a/jdk/src/share/classes/java/awt/AWTPermission.java b/jdk/src/share/classes/java/awt/AWTPermission.java index b6eb03f62c7..84b400f53d9 100644 --- a/jdk/src/share/classes/java/awt/AWTPermission.java +++ b/jdk/src/share/classes/java/awt/AWTPermission.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -92,7 +92,15 @@ import java.security.BasicPermission; * Enter full-screen exclusive mode * Entering full-screen exclusive mode allows direct access to * low-level graphics card memory. This could be used to spoof the - * system, since the program is in direct control of rendering. + * system, since the program is in direct control of rendering. Depending on + * the implementation, the security warning may not be shown for the windows + * used to enter the full-screen exclusive mode (assuming that the {@code + * fullScreenExclusive} permission has been granted to this application). Note + * that this behavior does not mean that the {@code + * showWindowWithoutWarningBanner} permission will be automatically granted to + * the application which has the {@code fullScreenExclusive} permission: + * non-full-screen windows will continue to be shown with the security + * warning. * * * diff --git a/jdk/src/solaris/classes/sun/awt/X11/XWindow.java b/jdk/src/solaris/classes/sun/awt/X11/XWindow.java index f1c3c675b6c..9081aa5e545 100644 --- a/jdk/src/solaris/classes/sun/awt/X11/XWindow.java +++ b/jdk/src/solaris/classes/sun/awt/X11/XWindow.java @@ -1510,4 +1510,24 @@ public class XWindow extends XBaseWindow implements X11ComponentPeer { return new XAtomList(); } + /** + * Indicates if the window is currently in the FSEM. + * Synchronization: state lock. + */ + private boolean fullScreenExclusiveModeState = false; + + // Implementation of the X11ComponentPeer + @Override + public void setFullScreenExclusiveModeState(boolean state) { + synchronized (getStateLock()) { + fullScreenExclusiveModeState = state; + } + } + + public final boolean isFullScreenExclusiveMode() { + synchronized (getStateLock()) { + return fullScreenExclusiveModeState; + } + } + } diff --git a/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java b/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java index 076526fd653..51c55b96c2b 100644 --- a/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java +++ b/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java @@ -1080,31 +1080,39 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, updateSecurityWarningVisibility(); } + @Override + public void setFullScreenExclusiveModeState(boolean state) { + super.setFullScreenExclusiveModeState(state); + updateSecurityWarningVisibility(); + } + public void updateSecurityWarningVisibility() { if (warningWindow == null) { return; } - boolean show = false; - - int state = getWMState(); - if (!isVisible()) { return; // The warning window should already be hidden. } - // getWMState() always returns 0 (Withdrawn) for simple windows. Hence - // we ignore the state for such windows. - if (isVisible() && (state == XUtilConstants.NormalState || isSimpleWindow())) { - if (XKeyboardFocusManagerPeer.getCurrentNativeFocusedWindow() == - getTarget()) - { - show = true; - } + boolean show = false; - if (isMouseAbove() || warningWindow.isMouseAbove()) - { - show = true; + if (!isFullScreenExclusiveMode()) { + int state = getWMState(); + + // getWMState() always returns 0 (Withdrawn) for simple windows. Hence + // we ignore the state for such windows. + if (isVisible() && (state == XUtilConstants.NormalState || isSimpleWindow())) { + if (XKeyboardFocusManagerPeer.getCurrentNativeFocusedWindow() == + getTarget()) + { + show = true; + } + + if (isMouseAbove() || warningWindow.isMouseAbove()) + { + show = true; + } } } diff --git a/jdk/src/solaris/classes/sun/awt/X11ComponentPeer.java b/jdk/src/solaris/classes/sun/awt/X11ComponentPeer.java index a4a07506894..24b24809285 100644 --- a/jdk/src/solaris/classes/sun/awt/X11ComponentPeer.java +++ b/jdk/src/solaris/classes/sun/awt/X11ComponentPeer.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,4 +39,5 @@ public interface X11ComponentPeer { Rectangle getBounds(); Graphics getGraphics(); Object getTarget(); + void setFullScreenExclusiveModeState(boolean state); } diff --git a/jdk/src/solaris/classes/sun/awt/X11GraphicsDevice.java b/jdk/src/solaris/classes/sun/awt/X11GraphicsDevice.java index ed495b177ec..a009a16e234 100644 --- a/jdk/src/solaris/classes/sun/awt/X11GraphicsDevice.java +++ b/jdk/src/solaris/classes/sun/awt/X11GraphicsDevice.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -306,12 +306,14 @@ public class X11GraphicsDevice X11ComponentPeer peer = (X11ComponentPeer)w.getPeer(); if (peer != null) { enterFullScreenExclusive(peer.getContentWindow()); + peer.setFullScreenExclusiveModeState(true); } } private static void exitFullScreenExclusive(Window w) { X11ComponentPeer peer = (X11ComponentPeer)w.getPeer(); if (peer != null) { + peer.setFullScreenExclusiveModeState(false); exitFullScreenExclusive(peer.getContentWindow()); } } diff --git a/jdk/src/windows/classes/sun/awt/Win32GraphicsDevice.java b/jdk/src/windows/classes/sun/awt/Win32GraphicsDevice.java index 1da339ce9f1..7d8c17e6987 100644 --- a/jdk/src/windows/classes/sun/awt/Win32GraphicsDevice.java +++ b/jdk/src/windows/classes/sun/awt/Win32GraphicsDevice.java @@ -353,6 +353,7 @@ public class Win32GraphicsDevice extends GraphicsDevice implements } WWindowPeer peer = (WWindowPeer)old.getPeer(); if (peer != null) { + peer.setFullScreenExclusiveModeState(false); // we used to destroy the buffers on exiting fs mode, this // is no longer needed since fs change will cause a surface // data replacement @@ -370,12 +371,15 @@ public class Win32GraphicsDevice extends GraphicsDevice implements addFSWindowListener(w); // Enter full screen exclusive mode. WWindowPeer peer = (WWindowPeer)w.getPeer(); - synchronized(peer) { - enterFullScreenExclusive(screen, peer); - // Note: removed replaceSurfaceData() call because - // changing the window size or making it visible - // will cause this anyway, and both of these events happen - // as part of switching into fullscreen mode. + if (peer != null) { + synchronized(peer) { + enterFullScreenExclusive(screen, peer); + // Note: removed replaceSurfaceData() call because + // changing the window size or making it visible + // will cause this anyway, and both of these events happen + // as part of switching into fullscreen mode. + } + peer.setFullScreenExclusiveModeState(true); } // fix for 4868278 diff --git a/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java b/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java index fbb7442ba7d..3f11839e8cc 100644 --- a/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java +++ b/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java @@ -510,6 +510,9 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer, private native int getScreenImOn(); + // Used in Win32GraphicsDevice. + public final native void setFullScreenExclusiveModeState(boolean state); + /* * ----END DISPLAY CHANGE SUPPORT---- */ diff --git a/jdk/src/windows/native/sun/windows/awt_Window.cpp b/jdk/src/windows/native/sun/windows/awt_Window.cpp index 4c902c3fb47..8bb5c900219 100644 --- a/jdk/src/windows/native/sun/windows/awt_Window.cpp +++ b/jdk/src/windows/native/sun/windows/awt_Window.cpp @@ -143,6 +143,11 @@ struct RepositionSecurityWarningStruct { jobject window; }; +struct SetFullScreenExclusiveModeStateStruct { + jobject window; + jboolean isFSEMState; +}; + /************************************************************************ * AwtWindow fields @@ -915,7 +920,9 @@ void AwtWindow::UpdateSecurityWarningVisibility() bool show = false; - if (IsVisible() && currentWmSizeState != SIZE_MINIMIZED) { + if (IsVisible() && currentWmSizeState != SIZE_MINIMIZED && + !isFullScreenExclusiveMode()) + { if (AwtComponent::GetFocusedWindow() == GetHWnd()) { show = true; } @@ -2954,6 +2961,25 @@ void AwtWindow::_UpdateWindow(void* param) delete uws; } +void AwtWindow::_SetFullScreenExclusiveModeState(void *param) +{ + JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); + + SetFullScreenExclusiveModeStateStruct * data = + (SetFullScreenExclusiveModeStateStruct*)param; + jobject self = data->window; + jboolean state = data->isFSEMState; + + PDATA pData; + JNI_CHECK_PEER_GOTO(self, ret); + AwtWindow *window = (AwtWindow *)pData; + + window->setFullScreenExclusiveModeState(state != 0); + + ret: + env->DeleteGlobalRef(self); + delete data; +} extern "C" { @@ -3333,6 +3359,29 @@ Java_sun_awt_windows_WWindowPeer_getScreenImOn(JNIEnv *env, jobject self) CATCH_BAD_ALLOC_RET(-1); } +/* + * Class: sun_awt_windows_WWindowPeer + * Method: setFullScreenExclusiveModeState + * Signature: (Z)V + */ +JNIEXPORT void JNICALL +Java_sun_awt_windows_WWindowPeer_setFullScreenExclusiveModeState(JNIEnv *env, + jobject self, jboolean state) +{ + TRY; + + SetFullScreenExclusiveModeStateStruct *data = + new SetFullScreenExclusiveModeStateStruct; + data->window = env->NewGlobalRef(self); + data->isFSEMState = state; + + AwtToolkit::GetInstance().SyncCall( + AwtWindow::_SetFullScreenExclusiveModeState, data); + // global ref and data are deleted in the invoked method + + CATCH_BAD_ALLOC; +} + /* * Class: sun_awt_windows_WWindowPeer * Method: modalDisable diff --git a/jdk/src/windows/native/sun/windows/awt_Window.h b/jdk/src/windows/native/sun/windows/awt_Window.h index 1d238b44dac..001062835e3 100644 --- a/jdk/src/windows/native/sun/windows/awt_Window.h +++ b/jdk/src/windows/native/sun/windows/awt_Window.h @@ -229,6 +229,7 @@ public: static void _SetOpaque(void* param); static void _UpdateWindow(void* param); static void _RepositionSecurityWarning(void* param); + static void _SetFullScreenExclusiveModeState(void* param); inline static BOOL IsResizing() { return sm_resizing; @@ -331,6 +332,16 @@ private: static void SetLayered(HWND window, bool layered); static bool IsLayered(HWND window); + BOOL fullScreenExclusiveModeState; + inline void setFullScreenExclusiveModeState(BOOL isEntered) { + fullScreenExclusiveModeState = isEntered; + UpdateSecurityWarningVisibility(); + } + inline BOOL isFullScreenExclusiveMode() { + return fullScreenExclusiveModeState; + } + + public: void UpdateSecurityWarningVisibility(); static bool IsWarningWindow(HWND hWnd); From b32d27a2532735a5508ec748c0e530bdee7f7fd0 Mon Sep 17 00:00:00 2001 From: Anthony Petrov Date: Wed, 14 Oct 2009 16:32:38 +0400 Subject: [PATCH 06/36] 6885735: closed/java/awt/Component/DisablingLWDisabledHW/DisablingLWDisabledHW.html fails Use isRecursivelyVisibleUpToHeavyweightContainer() instead of isRecursivelyVisible() to determine if the peer needs to be hidden. Reviewed-by: art, dcherepanov --- jdk/src/share/classes/java/awt/Component.java | 11 +++++----- jdk/src/share/classes/java/awt/Container.java | 21 +++++++++++++++---- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/jdk/src/share/classes/java/awt/Component.java b/jdk/src/share/classes/java/awt/Component.java index 59a43e7fe80..2c1d08596be 100644 --- a/jdk/src/share/classes/java/awt/Component.java +++ b/jdk/src/share/classes/java/awt/Component.java @@ -6720,12 +6720,13 @@ public abstract class Component implements ImageObserver, MenuContainer, } } } else { - // It's native. If the parent is lightweight it - // will need some help. - Container parent = this.parent; - if (parent != null && parent.peer instanceof LightweightPeer) { + // It's native. If the parent is lightweight it will need some + // help. + Container parent = getContainer(); + if (parent != null && parent.isLightweight()) { relocateComponent(); - if (!isRecursivelyVisible()) { + if (!parent.isRecursivelyVisibleUpToHeavyweightContainer()) + { peer.setVisible(false); } } diff --git a/jdk/src/share/classes/java/awt/Container.java b/jdk/src/share/classes/java/awt/Container.java index e3372409c06..5d4e95d9df5 100644 --- a/jdk/src/share/classes/java/awt/Container.java +++ b/jdk/src/share/classes/java/awt/Container.java @@ -4092,16 +4092,29 @@ public class Container extends Component { } } - /* + /** + * Checks if the container and its direct lightweight containers are + * visible. + * * Consider the heavyweight container hides or shows the HW descendants * automatically. Therefore we care of LW containers' visibility only. + * + * This method MUST be invoked under the TreeLock. */ - private boolean isRecursivelyVisibleUpToHeavyweightContainer() { + final boolean isRecursivelyVisibleUpToHeavyweightContainer() { if (!isLightweight()) { return true; } - return isVisible() && (getContainer() == null || - getContainer().isRecursivelyVisibleUpToHeavyweightContainer()); + + for (Container cont = getContainer(); + cont != null && cont.isLightweight(); + cont = cont.getContainer()) + { + if (!cont.isVisible()) { + return false; + } + } + return true; } @Override From e507e02d67793bcadc4a527adccd2f5aa1190a6d Mon Sep 17 00:00:00 2001 From: Anthony Petrov Date: Wed, 14 Oct 2009 19:23:15 +0400 Subject: [PATCH 07/36] 6884960: java/awt/Window/TranslucentJAppletTest/TranslucentJAppletTest.java fails Support painting heavyweight components in transparent windows. Reviewed-by: art, alexp --- .../share/classes/javax/swing/JComponent.java | 20 +++++++++---- .../sun/awt/windows/WComponentPeer.java | 28 ++++++++++++++++++- .../classes/sun/awt/windows/WWindowPeer.java | 8 +++++- 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/jdk/src/share/classes/javax/swing/JComponent.java b/jdk/src/share/classes/javax/swing/JComponent.java index f0be74509f9..6c97ebd5e71 100644 --- a/jdk/src/share/classes/javax/swing/JComponent.java +++ b/jdk/src/share/classes/javax/swing/JComponent.java @@ -795,7 +795,6 @@ public abstract class JComponent extends Container implements Serializable, * @see java.awt.Container#paint */ protected void paintChildren(Graphics g) { - boolean isJComponent; Graphics sg = g; synchronized(getTreeLock()) { @@ -826,12 +825,21 @@ public abstract class JComponent extends Container implements Serializable, } } boolean printing = getFlag(IS_PRINTING); + final Window window = SwingUtilities.getWindowAncestor(this); + final boolean isWindowOpaque = window == null || window.isOpaque(); for (; i >= 0 ; i--) { Component comp = getComponent(i); - isJComponent = (comp instanceof JComponent); - if (comp != null && - (isJComponent || isLightweightComponent(comp)) && - (comp.isVisible() == true)) { + if (comp == null) { + continue; + } + + final boolean isJComponent = comp instanceof JComponent; + + // Enable painting of heavyweights in non-opaque windows. + // See 6884960 + if ((!isWindowOpaque || isJComponent || + isLightweightComponent(comp)) && comp.isVisible()) + { Rectangle cr; cr = comp.getBounds(tmpRect); @@ -887,6 +895,8 @@ public abstract class JComponent extends Container implements Serializable, } } } else { + // The component is either lightweight, or + // heavyweight in a non-opaque window if (!printing) { comp.paint(cg); } diff --git a/jdk/src/windows/classes/sun/awt/windows/WComponentPeer.java b/jdk/src/windows/classes/sun/awt/windows/WComponentPeer.java index 04b3e99c26b..66ec4558f1e 100644 --- a/jdk/src/windows/classes/sun/awt/windows/WComponentPeer.java +++ b/jdk/src/windows/classes/sun/awt/windows/WComponentPeer.java @@ -551,8 +551,34 @@ public abstract class WComponentPeer extends WObjectPeer final static Font defaultFont = new Font(Font.DIALOG, Font.PLAIN, 12); public Graphics getGraphics() { + if (isDisposed()) { + return null; + } + + Component target = (Component)getTarget(); + Window window = SunToolkit.getContainingWindow(target); + if (window != null && !window.isOpaque()) { + // Non-opaque windows do not support heavyweight children. + // Redirect all painting to the Window's Graphics instead. + // The caller is responsible for calling the + // WindowPeer.updateWindow() after painting has finished. + int x = 0, y = 0; + for (Component c = target; c != window; c = c.getParent()) { + x += c.getX(); + y += c.getY(); + } + + Graphics g = + ((WWindowPeer)window.getPeer()).getTranslucentGraphics(); + + g.translate(x, y); + g.clipRect(0, 0, target.getWidth(), target.getHeight()); + + return g; + } + SurfaceData surfaceData = this.surfaceData; - if (!isDisposed() && surfaceData != null) { + if (surfaceData != null) { /* Fix for bug 4746122. Color and Font shouldn't be null */ Color bgColor = background; if (bgColor == null) { diff --git a/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java b/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java index 3f11839e8cc..26fe048cdca 100644 --- a/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java +++ b/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java @@ -578,11 +578,17 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer, } } + public final Graphics getTranslucentGraphics() { + synchronized (getStateLock()) { + return isOpaque ? null : painter.getBackBuffer(false).getGraphics(); + } + } + @Override public Graphics getGraphics() { synchronized (getStateLock()) { if (!isOpaque) { - return painter.getBackBuffer(false).getGraphics(); + return getTranslucentGraphics(); } } return super.getGraphics(); From 6b576be53ca726c3569365fd94cbda68e2646d53 Mon Sep 17 00:00:00 2001 From: Jennifer Godinez Date: Wed, 14 Oct 2009 10:44:32 -0700 Subject: [PATCH 08/36] 6890945: Typo in sentence about thread safety Reviewed-by: prr --- .../javax/print/attribute/standard/PrinterStateReasons.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/share/classes/javax/print/attribute/standard/PrinterStateReasons.java b/jdk/src/share/classes/javax/print/attribute/standard/PrinterStateReasons.java index 14225b90e46..2b0e8d2ab0c 100644 --- a/jdk/src/share/classes/javax/print/attribute/standard/PrinterStateReasons.java +++ b/jdk/src/share/classes/javax/print/attribute/standard/PrinterStateReasons.java @@ -65,7 +65,7 @@ import javax.print.attribute.PrintServiceAttribute; * PrinterStateReason PrinterStateReason} objects to an existing * PrinterStateReasons object and remove them again. However, like class * {@link java.util.HashMap java.util.HashMap}, class PrinterStateReasons is - * bot multiple thread safe. If a PrinterStateReasons object will be used by + * not multiple thread safe. If a PrinterStateReasons object will be used by * multiple threads, be sure to synchronize its operations (e.g., using a * synchronized map view obtained from class {@link java.util.Collections * java.util.Collections}). From ac9bcbd819ccf620c73ff9964f39323ad9b8d2f6 Mon Sep 17 00:00:00 2001 From: Jennifer Godinez Date: Fri, 16 Oct 2009 09:32:29 -0700 Subject: [PATCH 09/36] 6680634: Printing: "Collate" is ignored under Windows Vista x64 Reviewed-by: campbell, prr --- jdk/src/windows/native/sun/windows/awt_PrintControl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/windows/native/sun/windows/awt_PrintControl.cpp b/jdk/src/windows/native/sun/windows/awt_PrintControl.cpp index cc562ec0056..b68bb5f3bdd 100644 --- a/jdk/src/windows/native/sun/windows/awt_PrintControl.cpp +++ b/jdk/src/windows/native/sun/windows/awt_PrintControl.cpp @@ -687,7 +687,7 @@ BOOL AwtPrintControl::InitPrintDialog(JNIEnv *env, // Now, set-up the struct for the real calls to ::PrintDlg and ::CreateDC pd.hwndOwner = hwndOwner; - pd.Flags = PD_ENABLEPRINTHOOK | PD_RETURNDC; + pd.Flags = PD_ENABLEPRINTHOOK | PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE; pd.lpfnPrintHook = (LPPRINTHOOKPROC)PrintDlgHook; if (env->CallBooleanMethod(printCtrl, AwtPrintControl::getCollateID)) { From a77b6a72e03c2b151af3ecab5e73c1c759fd46ad Mon Sep 17 00:00:00 2001 From: Anthony Petrov Date: Mon, 19 Oct 2009 16:06:41 +0400 Subject: [PATCH 10/36] 6891483: XToolkit.getEnv() checks for NULL on a wrong symbol Reviewed-by: dcherepanov --- jdk/src/solaris/native/sun/xawt/XToolkit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/solaris/native/sun/xawt/XToolkit.c b/jdk/src/solaris/native/sun/xawt/XToolkit.c index 6ce5876c544..a4323b31995 100644 --- a/jdk/src/solaris/native/sun/xawt/XToolkit.c +++ b/jdk/src/solaris/native/sun/xawt/XToolkit.c @@ -677,7 +677,7 @@ JNIEXPORT jstring JNICALL Java_sun_awt_X11_XToolkit_getEnv jstring ret = NULL; keystr = JNU_GetStringPlatformChars(env, key, NULL); - if (key) { + if (keystr) { ptr = getenv(keystr); if (ptr) { ret = JNU_NewStringPlatform(env, (const char *) ptr); From c1bf8506f117aa5c252003f550964a2666d9dc54 Mon Sep 17 00:00:00 2001 From: Pavel Porvatov Date: Wed, 21 Oct 2009 14:25:25 +0400 Subject: [PATCH 11/36] 6892340: Part of the CR 6741890 should be forwardported Reviewed-by: malenkov --- .../sun/awt/shell/Win32ShellFolder2.java | 4 +- .../JFileChooser/6741890/bug6741890.java | 100 ++++++++++++++++++ 2 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 jdk/test/javax/swing/JFileChooser/6741890/bug6741890.java diff --git a/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java b/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java index 36636aef64c..90d008625cc 100644 --- a/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java +++ b/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java @@ -524,7 +524,7 @@ final class Win32ShellFolder2 extends ShellFolder { // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private static native int compareIDs(long pParentIShellFolder, long pidl1, long pidl2); - private Boolean cachedIsFileSystem; + private volatile Boolean cachedIsFileSystem; /** * @return Whether this is a file system shell folder @@ -759,7 +759,7 @@ final class Win32ShellFolder2 extends ShellFolder { }, InterruptedException.class); } - private Boolean cachedIsLink; + private volatile Boolean cachedIsLink; /** * @return Whether this shell folder is a link diff --git a/jdk/test/javax/swing/JFileChooser/6741890/bug6741890.java b/jdk/test/javax/swing/JFileChooser/6741890/bug6741890.java new file mode 100644 index 00000000000..1253acb1f6a --- /dev/null +++ b/jdk/test/javax/swing/JFileChooser/6741890/bug6741890.java @@ -0,0 +1,100 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @bug 6741890 + @summary Deadlock in Win32ShellFolderManager2 + @author Pavel Porvatov + @run main bug6741890 +*/ + +import sun.awt.shell.ShellFolder; + +import java.io.File; +import java.lang.reflect.Field; +import java.util.concurrent.Callable; + +public class bug6741890 { + /** + * This mux is used to prevent NPE in the isLink and isFileSystem methods + */ + private static final Object mux = new Object(); + + private static final int COUNT = 100000; + + public static void main(String[] args) throws Exception { + String tmpDir = System.getProperty("java.io.tmpdir"); + + if (tmpDir.length() == 0) { //'java.io.tmpdir' isn't guaranteed to be defined + tmpDir = System.getProperty("user.home"); + } + + final ShellFolder tmpFile = ShellFolder.getShellFolder(new File(tmpDir)); + + System.out.println("Temp directory: " + tmpDir); + + System.out.println("Stress test was run"); + + Thread thread = new Thread() { + public void run() { + while (!isInterrupted()) { + ShellFolder.invoke(new Callable() { + public Void call() throws Exception { + synchronized (mux) { + tmpFile.isFileSystem(); + tmpFile.isLink(); + } + + return null; + } + }); + } + } + }; + + thread.start(); + + for (int i = 0; i < COUNT; i++) { + synchronized (mux) { + clearField(tmpFile, "cachedIsLink"); + clearField(tmpFile, "cachedIsFileSystem"); + } + + tmpFile.isFileSystem(); + tmpFile.isLink(); + } + + thread.interrupt(); + thread.join(); + + System.out.println("Test passed successfully"); + } + + private static void clearField(Object o, String fieldName) throws Exception { + Field field = o.getClass().getDeclaredField(fieldName); + + field.setAccessible(true); + + field.set(o, null); + } +} From b50342c24e1b9b32b9fa5d747efa9e688a27adaf Mon Sep 17 00:00:00 2001 From: Anthony Petrov Date: Wed, 21 Oct 2009 17:06:41 +0400 Subject: [PATCH 12/36] 6852592: invalidate() must be smarter Introduce validate roots in AWT Reviewed-by: alexp, art, dcherepanov --- jdk/src/share/classes/java/applet/Applet.java | 15 ++ jdk/src/share/classes/java/awt/Component.java | 40 ++++- jdk/src/share/classes/java/awt/Container.java | 144 ++++++++++++++---- jdk/src/share/classes/java/awt/Window.java | 19 ++- .../share/classes/javax/swing/JComponent.java | 2 + .../share/classes/javax/swing/JRootPane.java | 2 + .../classes/javax/swing/JScrollPane.java | 2 + .../share/classes/javax/swing/JSplitPane.java | 2 + .../share/classes/javax/swing/JTextField.java | 2 + .../share/classes/javax/swing/JViewport.java | 39 +---- .../classes/javax/swing/RepaintManager.java | 38 +---- .../classes/javax/swing/SwingUtilities.java | 50 ++++++ .../InvalidateMustRespectValidateRoots.java | 114 ++++++++++++++ 13 files changed, 355 insertions(+), 114 deletions(-) create mode 100644 jdk/test/java/awt/Container/ValidateRoot/InvalidateMustRespectValidateRoots.java diff --git a/jdk/src/share/classes/java/applet/Applet.java b/jdk/src/share/classes/java/applet/Applet.java index 0e2bcb87b56..b12e6fb3081 100644 --- a/jdk/src/share/classes/java/applet/Applet.java +++ b/jdk/src/share/classes/java/applet/Applet.java @@ -229,6 +229,21 @@ public class Applet extends Panel { resize(d.width, d.height); } + /** + * Indicates if this container is a validate root. + *

+ * {@code Applet} objects are the validate roots, and, therefore, they + * override this method to return {@code true}. + * + * @return {@code true} + * @since 1.7 + * @see java.awt.Container#isValidateRoot + */ + @Override + public boolean isValidateRoot() { + return true; + } + /** * Requests that the argument string be displayed in the * "status window". Many browsers and applet viewers diff --git a/jdk/src/share/classes/java/awt/Component.java b/jdk/src/share/classes/java/awt/Component.java index 42093d16c9c..6a942e9ec5d 100644 --- a/jdk/src/share/classes/java/awt/Component.java +++ b/jdk/src/share/classes/java/awt/Component.java @@ -2764,8 +2764,11 @@ public abstract class Component implements ImageObserver, MenuContainer, } /** - * Ensures that this component has a valid layout. This method is - * primarily intended to operate on instances of Container. + * Validates this component. + *

+ * The meaning of the term validating is defined by the ancestors of + * this class. See {@link Container#validate} for more details. + * * @see #invalidate * @see #doLayout() * @see LayoutManager @@ -2794,12 +2797,24 @@ public abstract class Component implements ImageObserver, MenuContainer, } /** - * Invalidates this component. This component and all parents - * above it are marked as needing to be laid out. This method can - * be called often, so it needs to execute quickly. + * Invalidates this component and its ancestors. + *

+ * All the ancestors of this component up to the nearest validate root are + * marked invalid also. If there is no a validate root container for this + * component, all of its ancestors up to the root of the hierarchy are + * marked invalid as well. Marking a container invalid indicates + * that the container needs to be laid out. + *

+ * This method is called automatically when any layout-related information + * changes (e.g. setting the bounds of the component, or adding the + * component to a container). + *

+ * This method might be called often, so it should work fast. + * * @see #validate * @see #doLayout * @see LayoutManager + * @see java.awt.Container#isValidateRoot * @since JDK1.0 */ public void invalidate() { @@ -2818,9 +2833,18 @@ public abstract class Component implements ImageObserver, MenuContainer, if (!isMaximumSizeSet()) { maxSize = null; } - if (parent != null) { - parent.invalidateIfValid(); - } + invalidateParent(); + } + } + + /** + * Invalidates the parent of this component if any. + * + * This method MUST BE invoked under the TreeLock. + */ + void invalidateParent() { + if (parent != null) { + parent.invalidateIfValid(); } } diff --git a/jdk/src/share/classes/java/awt/Container.java b/jdk/src/share/classes/java/awt/Container.java index 706cffa89dc..84334c9973e 100644 --- a/jdk/src/share/classes/java/awt/Container.java +++ b/jdk/src/share/classes/java/awt/Container.java @@ -1492,20 +1492,59 @@ public class Container extends Component { } /** - * Invalidates the container. The container and all parents - * above it are marked as needing to be laid out. This method can - * be called often, so it needs to execute quickly. + * Indicates if this container is a validate root. + *

+ * Layout-related changes, such as bounds of the validate root descendants, + * do not affect the layout of the validate root parent. This peculiarity + * enables the {@code invalidate()} method to stop invalidating the + * component hierarchy when the method encounters a validate root. + *

+ * If a component hierarchy contains validate roots, the {@code validate()} + * method must be invoked on the validate root of a previously invalidated + * component, rather than on the top-level container (such as a {@code + * Frame} object) to restore the validity of the hierarchy later. + *

+ * The {@code Window} class and the {@code Applet} class are the validate + * roots in AWT. Swing introduces more validate roots. * - *

If the {@code LayoutManager} installed on this container is - * an instance of {@code LayoutManager2}, then - * {@link LayoutManager2#invalidateLayout(Container)} is invoked on - * it supplying this {@code Container} as the argument. + * @return whether this container is a validate root + * @see #invalidate + * @see java.awt.Component#invalidate + * @see javax.swing.JComponent#isValidateRoot + * @see javax.swing.JComponent#revalidate + * @since 1.7 + */ + public boolean isValidateRoot() { + return false; + } + + /** + * Invalidates the parent of the container unless the container + * is a validate root. + */ + @Override + void invalidateParent() { + if (!isValidateRoot()) { + super.invalidateParent(); + } + } + + /** + * Invalidates the container. + *

+ * If the {@code LayoutManager} installed on this container is an instance + * of the {@code LayoutManager2} interface, then + * the {@link LayoutManager2#invalidateLayout(Container)} method is invoked + * on it supplying this {@code Container} as the argument. + *

+ * Afterwards this method marks this container invalid, and invalidates its + * ancestors. See the {@link Component#invalidate} method for more details. * * @see #validate * @see #layout - * @see LayoutManager - * @see LayoutManager2#invalidateLayout(Container) + * @see LayoutManager2 */ + @Override public void invalidate() { LayoutManager layoutMgr = this.layoutMgr; if (layoutMgr instanceof LayoutManager2) { @@ -1518,35 +1557,39 @@ public class Container extends Component { /** * Validates this container and all of its subcomponents. *

- * The validate method is used to cause a container - * to lay out its subcomponents again. It should be invoked when - * this container's subcomponents are modified (added to or - * removed from the container, or layout-related information - * changed) after the container has been displayed. - * - *

If this {@code Container} is not valid, this method invokes + * Validating a container means laying out its subcomponents. + * Layout-related changes, such as setting the bounds of a component, or + * adding a component to the container, invalidate the container + * automatically. Note that the ancestors of the container may be + * invalidated also (see {@link Component#invalidate} for details.) + * Therefore, to restore the validity of the hierarchy, the {@code + * validate()} method should be invoked on a validate root of an + * invalidated component, or on the top-most container if the hierarchy + * does not contain validate roots. + *

+ * Validating the container may be a quite time-consuming operation. For + * performance reasons a developer may postpone the validation of the + * hierarchy till a set of layout-related operations completes, e.g. after + * adding all the children to the container. + *

+ * If this {@code Container} is not valid, this method invokes * the {@code validateTree} method and marks this {@code Container} * as valid. Otherwise, no action is performed. - *

- * Note that the {@code invalidate()} method may invalidate not only the - * component it is called upon, but also the parents of the component. - * Therefore, to restore the validity of the hierarchy, the {@code - * validate()} method must be invoked on the top-most invalid container of - * the hierarchy. For performance reasons a developer may postpone the - * validation of the hierarchy till a bunch of layout-related operations - * completes, e.g. after adding all the children to the container. * * @see #add(java.awt.Component) * @see #invalidate + * @see Container#isValidateRoot * @see javax.swing.JComponent#revalidate() * @see #validateTree */ public void validate() { /* Avoid grabbing lock unless really necessary. */ - if (!isValid()) { + if (!isValid() || descendUnconditionallyWhenValidating) { boolean updateCur = false; synchronized (getTreeLock()) { - if (!isValid() && peer != null) { + if ((!isValid() || descendUnconditionallyWhenValidating) + && peer != null) + { ContainerPeer p = null; if (peer instanceof ContainerPeer) { p = (ContainerPeer) peer; @@ -1557,7 +1600,11 @@ public class Container extends Component { validateTree(); if (p != null) { p.endValidate(); - updateCur = isVisible(); + // Avoid updating cursor if this is an internal call. + // See validateUnconditionally() for details. + if (!descendUnconditionallyWhenValidating) { + updateCur = isVisible(); + } } } } @@ -1567,6 +1614,39 @@ public class Container extends Component { } } + /** + * Indicates whether valid containers should also traverse their + * children and call the validateTree() method on them. + * + * Synchronization: TreeLock. + * + * The field is allowed to be static as long as the TreeLock itself is + * static. + * + * @see #validateUnconditionally() + */ + private static boolean descendUnconditionallyWhenValidating = false; + + /** + * Unconditionally validate the component hierarchy. + */ + final void validateUnconditionally() { + boolean updateCur = false; + synchronized (getTreeLock()) { + descendUnconditionallyWhenValidating = true; + + validate(); + if (peer instanceof ContainerPeer) { + updateCur = isVisible(); + } + + descendUnconditionallyWhenValidating = false; + } + if (updateCur) { + updateCursorImmediately(); + } + } + /** * Recursively descends the container tree and recomputes the * layout for any subtrees marked as needing it (those marked as @@ -1578,16 +1658,20 @@ public class Container extends Component { */ protected void validateTree() { checkTreeLock(); - if (!isValid()) { + if (!isValid() || descendUnconditionallyWhenValidating) { if (peer instanceof ContainerPeer) { ((ContainerPeer)peer).beginLayout(); } - doLayout(); + if (!isValid()) { + doLayout(); + } for (int i = 0; i < component.size(); i++) { Component comp = component.get(i); if ( (comp instanceof Container) && !(comp instanceof Window) - && !comp.isValid()) { + && (!comp.isValid() || + descendUnconditionallyWhenValidating)) + { ((Container)comp).validateTree(); } else { comp.validate(); diff --git a/jdk/src/share/classes/java/awt/Window.java b/jdk/src/share/classes/java/awt/Window.java index 8ea9ec821d8..c039a717984 100644 --- a/jdk/src/share/classes/java/awt/Window.java +++ b/jdk/src/share/classes/java/awt/Window.java @@ -767,7 +767,7 @@ public class Window extends Container implements Accessible { isPacked = true; } - validate(); + validateUnconditionally(); } /** @@ -943,7 +943,7 @@ public class Window extends Container implements Accessible { if (peer == null) { addNotify(); } - validate(); + validateUnconditionally(); isInShow = true; if (visible) { @@ -2599,6 +2599,21 @@ public class Window extends Container implements Accessible { super.addPropertyChangeListener(propertyName, listener); } + /** + * Indicates if this container is a validate root. + *

+ * {@code Window} objects are the validate roots, and, therefore, they + * override this method to return {@code true}. + * + * @return {@code true} + * @since 1.7 + * @see java.awt.Container#isValidateRoot + */ + @Override + public boolean isValidateRoot() { + return true; + } + /** * Dispatches an event to this window or one of its sub components. * @param e the event diff --git a/jdk/src/share/classes/javax/swing/JComponent.java b/jdk/src/share/classes/javax/swing/JComponent.java index 6c97ebd5e71..37f7e7d4730 100644 --- a/jdk/src/share/classes/javax/swing/JComponent.java +++ b/jdk/src/share/classes/javax/swing/JComponent.java @@ -4878,7 +4878,9 @@ public abstract class JComponent extends Container implements Serializable, * @see #revalidate * @see java.awt.Component#invalidate * @see java.awt.Container#validate + * @see java.awt.Container#isValidateRoot */ + @Override public boolean isValidateRoot() { return false; } diff --git a/jdk/src/share/classes/javax/swing/JRootPane.java b/jdk/src/share/classes/javax/swing/JRootPane.java index a210c3791c4..f6964f728ef 100644 --- a/jdk/src/share/classes/javax/swing/JRootPane.java +++ b/jdk/src/share/classes/javax/swing/JRootPane.java @@ -725,8 +725,10 @@ public class JRootPane extends JComponent implements Accessible { * because both classes override isValidateRoot to return true. * * @see JComponent#isValidateRoot + * @see java.awt.Container#isValidateRoot * @return true */ + @Override public boolean isValidateRoot() { return true; } diff --git a/jdk/src/share/classes/javax/swing/JScrollPane.java b/jdk/src/share/classes/javax/swing/JScrollPane.java index b2be43cd15f..b813d4fccdc 100644 --- a/jdk/src/share/classes/javax/swing/JScrollPane.java +++ b/jdk/src/share/classes/javax/swing/JScrollPane.java @@ -453,10 +453,12 @@ public class JScrollPane extends JComponent implements ScrollPaneConstants, Acce * @see java.awt.Container#validate * @see JComponent#revalidate * @see JComponent#isValidateRoot + * @see java.awt.Container#isValidateRoot * * @beaninfo * hidden: true */ + @Override public boolean isValidateRoot() { return true; } diff --git a/jdk/src/share/classes/javax/swing/JSplitPane.java b/jdk/src/share/classes/javax/swing/JSplitPane.java index b5d8ec7d2b5..f3baff66492 100644 --- a/jdk/src/share/classes/javax/swing/JSplitPane.java +++ b/jdk/src/share/classes/javax/swing/JSplitPane.java @@ -947,10 +947,12 @@ public class JSplitPane extends JComponent implements Accessible * * @return true * @see JComponent#revalidate + * @see java.awt.Container#isValidateRoot * * @beaninfo * hidden: true */ + @Override public boolean isValidateRoot() { return true; } diff --git a/jdk/src/share/classes/javax/swing/JTextField.java b/jdk/src/share/classes/javax/swing/JTextField.java index de408914d22..12fc0a70c4f 100644 --- a/jdk/src/share/classes/javax/swing/JTextField.java +++ b/jdk/src/share/classes/javax/swing/JTextField.java @@ -288,7 +288,9 @@ public class JTextField extends JTextComponent implements SwingConstants { * * @see JComponent#revalidate * @see JComponent#isValidateRoot + * @see java.awt.Container#isValidateRoot */ + @Override public boolean isValidateRoot() { return SwingUtilities2.getViewport(this) == null; } diff --git a/jdk/src/share/classes/javax/swing/JViewport.java b/jdk/src/share/classes/javax/swing/JViewport.java index 734e80a0557..5073a891af4 100644 --- a/jdk/src/share/classes/javax/swing/JViewport.java +++ b/jdk/src/share/classes/javax/swing/JViewport.java @@ -469,49 +469,12 @@ public class JViewport extends JComponent implements Accessible * is the synchronous version of a revalidate. */ private void validateView() { - Component validateRoot = null; + Component validateRoot = SwingUtilities.getValidateRoot(this, false); - /* Find the first JComponent ancestor of this component whose - * isValidateRoot() method returns true. - */ - for(Component c = this; c != null; c = c.getParent()) { - if ((c instanceof CellRendererPane) || (c.getPeer() == null)) { - return; - } - if ((c instanceof JComponent) && - (((JComponent)c).isValidateRoot())) { - validateRoot = c; - break; - } - } - - // If no validateRoot, nothing to validate from. if (validateRoot == null) { return; } - // Make sure all ancestors are visible. - Component root = null; - - for(Component c = validateRoot; c != null; c = c.getParent()) { - // We don't check isVisible here, otherwise if the component - // is contained in something like a JTabbedPane when the - // component is made visible again it won't have scrolled - // to the correct location. - if (c.getPeer() == null) { - return; - } - if ((c instanceof Window) || (c instanceof Applet)) { - root = c; - break; - } - } - - // Make sure there is a Window ancestor. - if (root == null) { - return; - } - // Validate the root. validateRoot.validate(); diff --git a/jdk/src/share/classes/javax/swing/RepaintManager.java b/jdk/src/share/classes/javax/swing/RepaintManager.java index a988b99fbd3..c8607d2e4b9 100644 --- a/jdk/src/share/classes/javax/swing/RepaintManager.java +++ b/jdk/src/share/classes/javax/swing/RepaintManager.java @@ -310,47 +310,13 @@ public class RepaintManager delegate.addInvalidComponent(invalidComponent); return; } - Component validateRoot = null; + Component validateRoot = + SwingUtilities.getValidateRoot(invalidComponent, true); - /* Find the first JComponent ancestor of this component whose - * isValidateRoot() method returns true. - */ - for(Component c = invalidComponent; c != null; c = c.getParent()) { - if ((c instanceof CellRendererPane) || (c.getPeer() == null)) { - return; - } - if ((c instanceof JComponent) && (((JComponent)c).isValidateRoot())) { - validateRoot = c; - break; - } - } - - /* There's no validateRoot to apply validate to, so we're done. - */ if (validateRoot == null) { return; } - /* If the validateRoot and all of its ancestors aren't visible - * then we don't do anything. While we're walking up the tree - * we find the root Window or Applet. - */ - Component root = null; - - for(Component c = validateRoot; c != null; c = c.getParent()) { - if (!c.isVisible() || (c.getPeer() == null)) { - return; - } - if ((c instanceof Window) || (c instanceof Applet)) { - root = c; - break; - } - } - - if (root == null) { - return; - } - /* Lazily create the invalidateComponents vector and add the * validateRoot if it's not there already. If this validateRoot * is already in the vector, we're done. diff --git a/jdk/src/share/classes/javax/swing/SwingUtilities.java b/jdk/src/share/classes/javax/swing/SwingUtilities.java index d7a26a0dd72..54ac2f55680 100644 --- a/jdk/src/share/classes/javax/swing/SwingUtilities.java +++ b/jdk/src/share/classes/javax/swing/SwingUtilities.java @@ -1967,4 +1967,54 @@ public class SwingUtilities implements SwingConstants SwingUtilities.updateComponentTreeUI(component); } } + + /** + * Retrieves the validate root of a given container. + * + * If the container is contained within a {@code CellRendererPane}, this + * method returns {@code null} due to the synthetic nature of the {@code + * CellRendererPane}. + *

+ * The component hierarchy must be displayable up to the toplevel component + * (either a {@code Frame} or an {@code Applet} object.) Otherwise this + * method returns {@code null}. + *

+ * If the {@code visibleOnly} argument is {@code true}, the found validate + * root and all its parents up to the toplevel component must also be + * visible. Otherwise this method returns {@code null}. + * + * @return the validate root of the given container or null + * @see java.awt.Component#isDisplayable() + * @see java.awt.Component#isVisible() + * @since 1.7 + */ + static Container getValidateRoot(Container c, boolean visibleOnly) { + Container root = null; + + for (; c != null; c = c.getParent()) + { + if (!c.isDisplayable() || c instanceof CellRendererPane) { + return null; + } + if (c.isValidateRoot()) { + root = c; + break; + } + } + + if (root == null) { + return null; + } + + for (; c != null; c = c.getParent()) { + if (!c.isDisplayable() || (visibleOnly && !c.isVisible())) { + return null; + } + if (c instanceof Window || c instanceof Applet) { + return root; + } + } + + return null; + } } diff --git a/jdk/test/java/awt/Container/ValidateRoot/InvalidateMustRespectValidateRoots.java b/jdk/test/java/awt/Container/ValidateRoot/InvalidateMustRespectValidateRoots.java new file mode 100644 index 00000000000..7bf34012dd9 --- /dev/null +++ b/jdk/test/java/awt/Container/ValidateRoot/InvalidateMustRespectValidateRoots.java @@ -0,0 +1,114 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + @test + @bug 6852592 + @summary invalidate() must stop when it encounters a validate root + @author anthony.petrov@sun.com + @run main InvalidateMustRespectValidateRoots +*/ + +import javax.swing.*; +import java.awt.event.*; + +public class InvalidateMustRespectValidateRoots { + private static volatile JRootPane rootPane; + + public static void main(String args[]) throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + // The JRootPane is a validate root. We'll check if + // invalidate() stops on the root pane, or goes further + // up to the frame. + JFrame frame = new JFrame(); + final JButton button = new JButton(); + + frame.add(button); + + // To enable running the test manually: use the Ctrl-Shift-F1 + // to print the component hierarchy to the console + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ev) { + if (button.isValid()) { + button.invalidate(); + } else { + button.revalidate(); + } + } + }); + + rootPane = frame.getRootPane(); + + // Now the component hierarchy looks like: + // frame + // --> rootPane + // --> layered pane + // --> content pane + // --> button + + // Make all components valid first via showing the frame + // We have to make the frame visible. Otherwise revalidate() is + // useless (see RepaintManager.addInvalidComponent()). + frame.pack(); // To enable running this test manually + frame.setVisible(true); + + if (!frame.isValid()) { + throw new RuntimeException( + "setVisible(true) failed to validate the frame"); + } + + // Now invalidate the button + button.invalidate(); + + // Check if the 'valid' status is what we expect it to be + if (rootPane.isValid()) { + throw new RuntimeException( + "invalidate() failed to invalidate the root pane"); + } + + if (!frame.isValid()) { + throw new RuntimeException( + "invalidate() invalidated the frame"); + } + + // Now validate the hierarchy again + button.revalidate(); + + // Now let the validation happen on the EDT + } + }); + + Thread.sleep(1000); + + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + // Check if the root pane finally became valid + if (!rootPane.isValid()) { + throw new RuntimeException( + "revalidate() failed to validate the hierarchy"); + } + } + }); + } +} From 4b2a80c711ff59b3ae082df54ad8571f47566f7d Mon Sep 17 00:00:00 2001 From: Dmitry Cherepanov Date: Thu, 22 Oct 2009 13:27:28 +0400 Subject: [PATCH 13/36] 6707273: TrayIcon does not support 8-bit alpha channel in Windows XP Reviewed-by: uta, ant --- .../native/sun/windows/awt_TrayIcon.cpp | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/jdk/src/windows/native/sun/windows/awt_TrayIcon.cpp b/jdk/src/windows/native/sun/windows/awt_TrayIcon.cpp index 9165314bbc5..6b4f8b6bcfc 100644 --- a/jdk/src/windows/native/sun/windows/awt_TrayIcon.cpp +++ b/jdk/src/windows/native/sun/windows/awt_TrayIcon.cpp @@ -59,7 +59,7 @@ struct DisplayMessageStruct { }; typedef struct tagBitmapheader { - BITMAPINFOHEADER bmiHeader; + BITMAPV5HEADER bmiHeader; DWORD dwMasks[256]; } Bitmapheader, *LPBITMAPHEADER; @@ -638,12 +638,12 @@ void AwtTrayIcon::UnlinkObjects() HBITMAP AwtTrayIcon::CreateBMP(HWND hW,int* imageData,int nSS, int nW, int nH) { - Bitmapheader bmhHeader; + Bitmapheader bmhHeader = {0}; HDC hDC; char *ptrImageData; HBITMAP hbmpBitmap; HBITMAP hBitmap; - int nNumChannels = 3; + int nNumChannels = 4; if (!hW) { hW = ::GetDesktopWindow(); @@ -653,14 +653,20 @@ HBITMAP AwtTrayIcon::CreateBMP(HWND hW,int* imageData,int nSS, int nW, int nH) return NULL; } - memset(&bmhHeader, 0, sizeof(Bitmapheader)); - bmhHeader.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmhHeader.bmiHeader.biWidth = nW; - bmhHeader.bmiHeader.biHeight = -nH; - bmhHeader.bmiHeader.biPlanes = 1; + bmhHeader.bmiHeader.bV5Size = sizeof(BITMAPV5HEADER); + bmhHeader.bmiHeader.bV5Width = nW; + bmhHeader.bmiHeader.bV5Height = -nH; + bmhHeader.bmiHeader.bV5Planes = 1; - bmhHeader.bmiHeader.biBitCount = 24; - bmhHeader.bmiHeader.biCompression = BI_RGB; + bmhHeader.bmiHeader.bV5BitCount = 32; + bmhHeader.bmiHeader.bV5Compression = BI_BITFIELDS; + + // The following mask specification specifies a supported 32 BPP + // alpha format for Windows XP. + bmhHeader.bmiHeader.bV5RedMask = 0x00FF0000; + bmhHeader.bmiHeader.bV5GreenMask = 0x0000FF00; + bmhHeader.bmiHeader.bV5BlueMask = 0x000000FF; + bmhHeader.bmiHeader.bV5AlphaMask = 0xFF000000; hbmpBitmap = ::CreateDIBSection(hDC, (BITMAPINFO*)&(bmhHeader), DIB_RGB_COLORS, @@ -674,6 +680,7 @@ HBITMAP AwtTrayIcon::CreateBMP(HWND hW,int* imageData,int nSS, int nW, int nH) } for (int nOutern = 0; nOutern < nH; nOutern++) { for (int nInner = 0; nInner < nSS; nInner++) { + dstPtr[3] = (*srcPtr >> 0x18) & 0xFF; dstPtr[2] = (*srcPtr >> 0x10) & 0xFF; dstPtr[1] = (*srcPtr >> 0x08) & 0xFF; dstPtr[0] = *srcPtr & 0xFF; From ec86441a47b4c48f8b20ad0bd239f886a125be25 Mon Sep 17 00:00:00 2001 From: Peter Zhelezniakov Date: Thu, 22 Oct 2009 15:43:25 +0400 Subject: [PATCH 14/36] 6893704: Potential memory leak in gtk2_interface.c Reviewed-by: stayer --- jdk/src/solaris/native/sun/awt/gtk2_interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/solaris/native/sun/awt/gtk2_interface.c b/jdk/src/solaris/native/sun/awt/gtk2_interface.c index 1afeeef173b..e6ede306824 100644 --- a/jdk/src/solaris/native/sun/awt/gtk2_interface.c +++ b/jdk/src/solaris/native/sun/awt/gtk2_interface.c @@ -637,13 +637,13 @@ gboolean gtk2_load() if (gtk_modules_env && strstr (gtk_modules_env, "atk-bridge") || gtk_modules_env && strstr (gtk_modules_env, "gail")) { - gchar *tmp_env = strdup (gtk_modules_env); /* the new env will be smaller than the old one */ gchar *s, *new_env = malloc (sizeof(ENV_PREFIX)+strlen (gtk_modules_env)); if (new_env != NULL ) { /* careful, strtok modifies its args */ + gchar *tmp_env = strdup (gtk_modules_env); strcpy(new_env, ENV_PREFIX); /* strip out 'atk-bridge' and 'gail' */ From e7de83e1e2ce67b52172ee076c975af4102d3ea0 Mon Sep 17 00:00:00 2001 From: Pavel Porvatov Date: Thu, 22 Oct 2009 16:39:29 +0400 Subject: [PATCH 15/36] 6550546: Win LAF: JFileChooser -> Look in Drop down should not display any shortcuts created on desktop Reviewed-by: peterz --- .../awt/shell/Win32ShellFolderManager2.java | 2 +- .../JFileChooser/6550546/bug6550546.java | 57 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 jdk/test/javax/swing/JFileChooser/6550546/bug6550546.java diff --git a/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java b/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java index 97cc532d369..abd49d3960b 100644 --- a/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java +++ b/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java @@ -269,7 +269,7 @@ public class Win32ShellFolderManager2 extends ShellFolderManager { Arrays.sort(secondLevelFolders); for (File secondLevelFolder : secondLevelFolders) { Win32ShellFolder2 folder = (Win32ShellFolder2) secondLevelFolder; - if (!folder.isFileSystem() || folder.isDirectory()) { + if (!folder.isFileSystem() || (folder.isDirectory() && !folder.isLink())) { folders.add(folder); // Add third level for "My Computer" if (folder.equals(drives)) { diff --git a/jdk/test/javax/swing/JFileChooser/6550546/bug6550546.java b/jdk/test/javax/swing/JFileChooser/6550546/bug6550546.java new file mode 100644 index 00000000000..84277edf54a --- /dev/null +++ b/jdk/test/javax/swing/JFileChooser/6550546/bug6550546.java @@ -0,0 +1,57 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @bug 6550546 + @summary Win LAF: JFileChooser -> Look in Drop down should not display any shortcuts created on desktop + @author Pavel Porvatov + @run main bug6550546 +*/ + +import sun.awt.OSInfo; +import sun.awt.shell.ShellFolder; + +import javax.swing.*; +import java.io.File; + +public class bug6550546 { + public static void main(String[] args) throws Exception { + if (OSInfo.getOSType() != OSInfo.OSType.WINDOWS) { + System.out.println("The test is suitable only for Windows, skipped."); + + return; + } + + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + File[] files = (File[]) ShellFolder.get("fileChooserComboBoxFolders"); + + for (File file : files) { + if (file instanceof ShellFolder && ((ShellFolder) file).isLink()) { + throw new RuntimeException("Link shouldn't be in FileChooser combobox, " + file.getPath()); + } + } + } + }); + } +} From 5b04b875ea7823ef0ac55e67143088066c84ab3c Mon Sep 17 00:00:00 2001 From: Alexander Potochkin Date: Thu, 22 Oct 2009 18:42:18 +0400 Subject: [PATCH 16/36] 6795356: Leak caused by javax.swing.UIDefaults.ProxyLazyValue.acc Reviewed-by: hawtin --- jdk/src/share/classes/javax/swing/JTable.java | 3 +- .../javax/swing/plaf/metal/OceanTheme.java | 3 +- .../classes/sun/swing/SwingLazyValue.java | 16 ++- .../6795356/SwingLazyValueTest.java | 44 ++++++++ .../swing/UIDefaults/6795356/TableTest.java | 52 +++++++++ .../swing/UIDefaults/6795356/bug6795356.java | 100 ++++++++++++++++++ 6 files changed, 215 insertions(+), 3 deletions(-) create mode 100644 jdk/test/javax/swing/UIDefaults/6795356/SwingLazyValueTest.java create mode 100644 jdk/test/javax/swing/UIDefaults/6795356/TableTest.java create mode 100644 jdk/test/javax/swing/UIDefaults/6795356/bug6795356.java diff --git a/jdk/src/share/classes/javax/swing/JTable.java b/jdk/src/share/classes/javax/swing/JTable.java index 521f17ab8a5..28b38ce0c6a 100644 --- a/jdk/src/share/classes/javax/swing/JTable.java +++ b/jdk/src/share/classes/javax/swing/JTable.java @@ -57,6 +57,7 @@ import sun.swing.SwingUtilities2; import sun.swing.SwingUtilities2.Section; import static sun.swing.SwingUtilities2.Section.*; import sun.swing.PrintingStatus; +import sun.swing.SwingLazyValue; /** * The JTable is used to display and edit regular two-dimensional tables @@ -5316,7 +5317,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable } private void setLazyValue(Hashtable h, Class c, String s) { - h.put(c, new UIDefaults.ProxyLazyValue(s)); + h.put(c, new SwingLazyValue(s)); } private void setLazyRenderer(Class c, String s) { diff --git a/jdk/src/share/classes/javax/swing/plaf/metal/OceanTheme.java b/jdk/src/share/classes/javax/swing/plaf/metal/OceanTheme.java index 2aa299fe5cc..2e1a8b2b4bf 100644 --- a/jdk/src/share/classes/javax/swing/plaf/metal/OceanTheme.java +++ b/jdk/src/share/classes/javax/swing/plaf/metal/OceanTheme.java @@ -32,6 +32,7 @@ import javax.swing.*; import javax.swing.plaf.*; import sun.swing.SwingUtilities2; import sun.swing.PrintColorUIResource; +import sun.swing.SwingLazyValue; /** * The default theme for the {@code MetalLookAndFeel}. @@ -128,7 +129,7 @@ public class OceanTheme extends DefaultMetalTheme { * @throws NullPointerException if {@code table} is {@code null} */ public void addCustomEntriesToTable(UIDefaults table) { - Object focusBorder = new UIDefaults.ProxyLazyValue( + Object focusBorder = new SwingLazyValue( "javax.swing.plaf.BorderUIResource$LineBorderUIResource", new Object[] {getPrimary1()}); // .30 0 DDE8F3 white secondary2 diff --git a/jdk/src/share/classes/sun/swing/SwingLazyValue.java b/jdk/src/share/classes/sun/swing/SwingLazyValue.java index f5587282abb..02236ddff73 100644 --- a/jdk/src/share/classes/sun/swing/SwingLazyValue.java +++ b/jdk/src/share/classes/sun/swing/SwingLazyValue.java @@ -26,6 +26,9 @@ package sun.swing; import java.lang.reflect.Constructor; import java.lang.reflect.Method; +import java.lang.reflect.AccessibleObject; +import java.security.AccessController; +import java.security.PrivilegedAction; import javax.swing.UIDefaults; /** @@ -65,13 +68,15 @@ public class SwingLazyValue implements UIDefaults.LazyValue { if (methodName != null) { Class[] types = getClassArray(args); Method m = c.getMethod(methodName, types); + makeAccessible(m); return m.invoke(c, args); } else { Class[] types = getClassArray(args); Constructor constructor = c.getConstructor(types); + makeAccessible(constructor); return constructor.newInstance(args); } - } catch(Exception e) { + } catch (Exception e) { // Ideally we would throw an exception, unfortunately // often times there are errors as an initial look and // feel is loaded before one can be switched. Perhaps a @@ -81,6 +86,15 @@ public class SwingLazyValue implements UIDefaults.LazyValue { return null; } + private void makeAccessible(final AccessibleObject object) { + AccessController.doPrivileged(new PrivilegedAction() { + public Void run() { + object.setAccessible(true); + return null; + } + }); + } + private Class[] getClassArray(Object[] args) { Class[] types = null; if (args!=null) { diff --git a/jdk/test/javax/swing/UIDefaults/6795356/SwingLazyValueTest.java b/jdk/test/javax/swing/UIDefaults/6795356/SwingLazyValueTest.java new file mode 100644 index 00000000000..4211e53cd8e --- /dev/null +++ b/jdk/test/javax/swing/UIDefaults/6795356/SwingLazyValueTest.java @@ -0,0 +1,44 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6795356 + * @summary Checks that SwingLazyValue class correclty works + * @author Alexander Potochkin + * @run main SwingLazyValueTest + */ + +import sun.swing.SwingLazyValue; + +import javax.swing.*; + +public class SwingLazyValueTest { + + public static void main(String[] args) throws Exception { + if(new SwingLazyValue("javax.swing.JTable$DoubleRenderer"). + createValue(null) == null) { + throw new RuntimeException("SwingLazyValue doesn't work"); + } + } +} diff --git a/jdk/test/javax/swing/UIDefaults/6795356/TableTest.java b/jdk/test/javax/swing/UIDefaults/6795356/TableTest.java new file mode 100644 index 00000000000..6002f816979 --- /dev/null +++ b/jdk/test/javax/swing/UIDefaults/6795356/TableTest.java @@ -0,0 +1,52 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6795356 + * @summary Checks that SwingLazyValue class correclty works + * @author Alexander Potochkin + * @run main/othervm TableTest + */ + +import sun.applet.AppletSecurity; + +import javax.swing.*; +import javax.swing.table.TableCellEditor; +import java.awt.*; + +public class TableTest { + + public static void main(String[] args) throws Exception { + + KeyboardFocusManager.getCurrentKeyboardFocusManager(); + System.setSecurityManager(new AppletSecurity()); + + JTable table = new JTable(); + TableCellEditor de = table.getDefaultEditor(Double.class); + if (de == null) { + throw new RuntimeException("Table default editor is null"); + } + } +} + diff --git a/jdk/test/javax/swing/UIDefaults/6795356/bug6795356.java b/jdk/test/javax/swing/UIDefaults/6795356/bug6795356.java new file mode 100644 index 00000000000..89e33f1cf82 --- /dev/null +++ b/jdk/test/javax/swing/UIDefaults/6795356/bug6795356.java @@ -0,0 +1,100 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6795356 + * @summary Leak caused by javax.swing.UIDefaults.ProxyLazyValue.acc + * @author Alexander Potochkin + * @run main bug6795356 + */ + +import java.lang.ref.WeakReference; +import java.security.ProtectionDomain; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.AccessControlContext; +import java.util.LinkedList; +import java.util.List; +import javax.swing.*; + +public class bug6795356 { + volatile static WeakReference weakRef; + + public static void main(String[] args) throws Exception { + + ProtectionDomain domain = new ProtectionDomain(null, null); + + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + + // this initialize ProxyLazyValues + UIManager.getLookAndFeel(); + + return null; + } + }, new AccessControlContext(new ProtectionDomain[]{domain})); + + weakRef = new WeakReference(domain); + domain = null; + + // Generate OutOfMemory and check the weak ref + generateOOME(); + + if (weakRef.get() != null) { + throw new RuntimeException("Memory leak found!"); + } + System.out.println("Test passed"); + } + + static void generateOOME() { + List bigLeak = new LinkedList(); + boolean oome = false; + System.out.print("Filling the heap"); + try { + for(int i = 0; true ; i++) { + // Now, use up all RAM + bigLeak.add(new byte[1024 * 1024]); + System.out.print("."); + + // Give the GC a change at that weakref + if (i % 10 == 0) { + System.gc(); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } catch (OutOfMemoryError e) { + bigLeak = null; + oome = true; + } + System.out.println(""); + if (!oome) { + throw new RuntimeException("Problem with test case - never got OOME"); + } + System.out.println("Got OOME"); + } +} From 85e10718ce8960f347340a549bdfce17151797cb Mon Sep 17 00:00:00 2001 From: Anthony Petrov Date: Fri, 23 Oct 2009 14:52:55 +0400 Subject: [PATCH 17/36] 6887249: Get rid of double-check for isValid() idiom in validate() methods Reviewed-by: art, dcherepanov --- jdk/src/share/classes/java/awt/Container.java | 47 +++++++++---------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/jdk/src/share/classes/java/awt/Container.java b/jdk/src/share/classes/java/awt/Container.java index 84334c9973e..94273ade4cb 100644 --- a/jdk/src/share/classes/java/awt/Container.java +++ b/jdk/src/share/classes/java/awt/Container.java @@ -1583,34 +1583,31 @@ public class Container extends Component { * @see #validateTree */ public void validate() { - /* Avoid grabbing lock unless really necessary. */ - if (!isValid() || descendUnconditionallyWhenValidating) { - boolean updateCur = false; - synchronized (getTreeLock()) { - if ((!isValid() || descendUnconditionallyWhenValidating) - && peer != null) - { - ContainerPeer p = null; - if (peer instanceof ContainerPeer) { - p = (ContainerPeer) peer; - } - if (p != null) { - p.beginValidate(); - } - validateTree(); - if (p != null) { - p.endValidate(); - // Avoid updating cursor if this is an internal call. - // See validateUnconditionally() for details. - if (!descendUnconditionallyWhenValidating) { - updateCur = isVisible(); - } + boolean updateCur = false; + synchronized (getTreeLock()) { + if ((!isValid() || descendUnconditionallyWhenValidating) + && peer != null) + { + ContainerPeer p = null; + if (peer instanceof ContainerPeer) { + p = (ContainerPeer) peer; + } + if (p != null) { + p.beginValidate(); + } + validateTree(); + if (p != null) { + p.endValidate(); + // Avoid updating cursor if this is an internal call. + // See validateUnconditionally() for details. + if (!descendUnconditionallyWhenValidating) { + updateCur = isVisible(); } } } - if (updateCur) { - updateCursorImmediately(); - } + } + if (updateCur) { + updateCursorImmediately(); } } From f9f22a5e0b61658b3c42b3a03fea4c03fb181475 Mon Sep 17 00:00:00 2001 From: Andrew Brygin Date: Fri, 23 Oct 2009 15:59:51 +0400 Subject: [PATCH 18/36] 6888215: memory leak in jpeg plugin Reviewed-by: igor, prr --- jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c b/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c index 7d39c61e02f..e25c07a6a0d 100644 --- a/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c +++ b/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c @@ -1437,6 +1437,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_initJPEGImageReader JNU_ThrowByName( env, "java/lang/OutOfMemoryError", "Initializing Reader"); + free(cinfo); return 0; } @@ -1473,6 +1474,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_initJPEGImageReader JNU_ThrowByName(env, "java/lang/OutOfMemoryError", "Initializing Reader"); + imageio_dispose((j_common_ptr)cinfo); return 0; } cinfo->src->bytes_in_buffer = 0; @@ -1489,6 +1491,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_initJPEGImageReader JNU_ThrowByName( env, "java/lang/OutOfMemoryError", "Initializing Reader"); + imageio_dispose((j_common_ptr)cinfo); return 0; } return (jlong) ret; @@ -2420,8 +2423,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_initJPEGImageWriter JNU_ThrowByName( env, "java/lang/OutOfMemoryError", "Initializing Writer"); - free(cinfo); - free(jerr); + imageio_dispose((j_common_ptr)cinfo); return 0; } @@ -2439,8 +2441,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_initJPEGImageWriter JNU_ThrowByName( env, "java/lang/OutOfMemoryError", "Initializing Writer"); - free(cinfo); - free(jerr); + imageio_dispose((j_common_ptr)cinfo); return 0; } return (jlong) ret; From 32f47acd27e8cd4c23337f9af174e537ce2bd091 Mon Sep 17 00:00:00 2001 From: Andrew Brygin Date: Fri, 23 Oct 2009 16:21:50 +0400 Subject: [PATCH 19/36] 6888167: memory leaks in the medialib glue code Reviewed-by: igor, prr --- .../native/sun/awt/medialib/awt_ImagingLib.c | 51 ++++++++++++++----- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/jdk/src/share/native/sun/awt/medialib/awt_ImagingLib.c b/jdk/src/share/native/sun/awt/medialib/awt_ImagingLib.c index 157827fef29..07f9187ffc8 100644 --- a/jdk/src/share/native/sun/awt/medialib/awt_ImagingLib.c +++ b/jdk/src/share/native/sun/awt/medialib/awt_ImagingLib.c @@ -960,21 +960,15 @@ Java_sun_awt_image_ImagingLib_transformRaster(JNIEnv *env, jobject this, mlib_filter filter; unsigned int *dP; - if ((srcRasterP = (RasterS_t *) calloc(1, sizeof(RasterS_t))) == NULL) { - JNU_ThrowOutOfMemoryError(env, "Out of memory"); - return -1; - } - - if ((dstRasterP = (RasterS_t *) calloc(1, sizeof(RasterS_t))) == NULL) { - JNU_ThrowOutOfMemoryError(env, "Out of memory"); - free(srcRasterP); - return -1; - } - /* This function requires a lot of local refs ??? Is 64 enough ??? */ if ((*env)->EnsureLocalCapacity(env, 64) < 0) return 0; + if (s_nomlib) return 0; + if (s_timeIt) { + (*start_timer)(3600); + } + switch(interpType) { case java_awt_image_AffineTransformOp_TYPE_BILINEAR: filter = MLIB_BILINEAR; @@ -990,9 +984,15 @@ Java_sun_awt_image_ImagingLib_transformRaster(JNIEnv *env, jobject this, return -1; } - if (s_nomlib) return 0; - if (s_timeIt) { - (*start_timer)(3600); + if ((srcRasterP = (RasterS_t *) calloc(1, sizeof(RasterS_t))) == NULL) { + JNU_ThrowOutOfMemoryError(env, "Out of memory"); + return -1; + } + + if ((dstRasterP = (RasterS_t *) calloc(1, sizeof(RasterS_t))) == NULL) { + JNU_ThrowOutOfMemoryError(env, "Out of memory"); + free(srcRasterP); + return -1; } if ((*env)->GetArrayLength(env, jmatrix) < 6) { @@ -1215,6 +1215,9 @@ Java_sun_awt_image_ImagingLib_lookupByteBI(JNIEnv *env, jobject this, } if (tbl == NULL || table == NULL || jtable == NULL) { + if (tbl != NULL) free(tbl); + if (table != NULL) free(table); + if (jtable != NULL) free(jtable); awt_freeParsedImage(srcImageP, TRUE); awt_freeParsedImage(dstImageP, TRUE); JNU_ThrowNullPointerException(env, "NULL LUT"); @@ -1224,6 +1227,11 @@ Java_sun_awt_image_ImagingLib_lookupByteBI(JNIEnv *env, jobject this, for (i=0; i < jlen; i++) { jtable[i] = (*env)->GetObjectArrayElement(env, jtableArrays, i); if (jtable[i] == NULL) { + free(tbl); + free(table); + free(jtable); + awt_freeParsedImage(srcImageP, TRUE); + awt_freeParsedImage(dstImageP, TRUE); return 0; } } @@ -1232,6 +1240,9 @@ Java_sun_awt_image_ImagingLib_lookupByteBI(JNIEnv *env, jobject this, FALSE, &hint); if (nbands < 1) { /* Can't handle any custom images */ + free(tbl); + free(table); + free(jtable); awt_freeParsedImage(srcImageP, TRUE); awt_freeParsedImage(dstImageP, TRUE); return 0; @@ -1240,12 +1251,18 @@ Java_sun_awt_image_ImagingLib_lookupByteBI(JNIEnv *env, jobject this, /* Allocate the arrays */ if (allocateArray(env, srcImageP, &src, &sdata, TRUE, FALSE, FALSE) < 0) { /* Must be some problem */ + free(tbl); + free(table); + free(jtable); awt_freeParsedImage(srcImageP, TRUE); awt_freeParsedImage(dstImageP, TRUE); return 0; } if (allocateArray(env, dstImageP, &dst, &ddata, FALSE, FALSE, FALSE) < 0) { /* Must be some problem */ + free(tbl); + free(table); + free(jtable); freeArray(env, srcImageP, src, sdata, NULL, NULL, NULL); awt_freeParsedImage(srcImageP, TRUE); awt_freeParsedImage(dstImageP, TRUE); @@ -1284,6 +1301,9 @@ Java_sun_awt_image_ImagingLib_lookupByteBI(JNIEnv *env, jobject this, (jbyte *) table[j], JNI_ABORT); } + free(tbl); + free(table); + free(jtable); freeArray(env, srcImageP, src, sdata, NULL, NULL, NULL); awt_freeParsedImage(srcImageP, TRUE); awt_freeParsedImage(dstImageP, TRUE); @@ -1413,12 +1433,15 @@ Java_sun_awt_image_ImagingLib_lookupByteRaster(JNIEnv *env, /* Parse the source raster - reject custom images */ if ((status = awt_parseRaster(env, jsrc, srcRasterP)) <= 0) { + free(srcRasterP); + free(dstRasterP); return 0; } /* Parse the destination image - reject custom images */ if ((status = awt_parseRaster(env, jdst, dstRasterP)) <= 0) { awt_freeParsedRaster(srcRasterP, TRUE); + free(dstRasterP); return 0; } From ce0d94ffec1923e25f488d42a1f30dfeabf15a90 Mon Sep 17 00:00:00 2001 From: Pavel Porvatov Date: Fri, 30 Oct 2009 14:05:48 +0300 Subject: [PATCH 20/36] 6894504: javax/swing/JFileChooser/6741890/bug6741890.java fails w/ RuntimeException Reviewed-by: malenkov --- jdk/test/javax/swing/JFileChooser/6741890/bug6741890.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/jdk/test/javax/swing/JFileChooser/6741890/bug6741890.java b/jdk/test/javax/swing/JFileChooser/6741890/bug6741890.java index 1253acb1f6a..1e670e70404 100644 --- a/jdk/test/javax/swing/JFileChooser/6741890/bug6741890.java +++ b/jdk/test/javax/swing/JFileChooser/6741890/bug6741890.java @@ -29,6 +29,7 @@ */ import sun.awt.shell.ShellFolder; +import sun.awt.OSInfo; import java.io.File; import java.lang.reflect.Field; @@ -43,6 +44,12 @@ public class bug6741890 { private static final int COUNT = 100000; public static void main(String[] args) throws Exception { + if (OSInfo.getOSType() != OSInfo.OSType.WINDOWS) { + System.out.println("The test is applicable only for Windows. Skipped."); + + return; + } + String tmpDir = System.getProperty("java.io.tmpdir"); if (tmpDir.length() == 0) { //'java.io.tmpdir' isn't guaranteed to be defined From fcfa835d860e9d1cf0b9df6f01d84908df1abf3e Mon Sep 17 00:00:00 2001 From: Pavel Porvatov Date: Fri, 30 Oct 2009 14:18:23 +0300 Subject: [PATCH 21/36] 6891412: The sun.awt.shell.ShellFolder#getInvoker method should be synchronized Reviewed-by: peterz --- .../classes/sun/awt/shell/ShellFolder.java | 21 +++++-------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/jdk/src/share/classes/sun/awt/shell/ShellFolder.java b/jdk/src/share/classes/sun/awt/shell/ShellFolder.java index cf3c7893384..c5b2296b2b7 100644 --- a/jdk/src/share/classes/sun/awt/shell/ShellFolder.java +++ b/jdk/src/share/classes/sun/awt/shell/ShellFolder.java @@ -201,6 +201,8 @@ public abstract class ShellFolder extends File { private static ShellFolderManager shellFolderManager; + private static Invoker invoker; + static { String managerClassName = (String)Toolkit.getDefaultToolkit(). getDesktopProperty("Shell.shellFolderManager"); @@ -225,6 +227,8 @@ public abstract class ShellFolder extends File { throw new Error ("Could not access Shell Folder Manager: " + managerClass.getName()); } + + invoker = shellFolderManager.createInvoker(); } /** @@ -486,21 +490,6 @@ public abstract class ShellFolder extends File { return null; } - private static Invoker invoker; - - /** - * Provides the single access point to the {@link Invoker}. It is guaranteed that the value - * returned by this method will be always the same. - * - * @return the singleton instance of {@link Invoker} - */ - public static Invoker getInvoker() { - if (invoker == null) { - invoker = shellFolderManager.createInvoker(); - } - return invoker; - } - /** * Invokes the {@code task} which doesn't throw checked exceptions * from its {@code call} method. If invokation is interrupted then Thread.currentThread().isInterrupted() will @@ -522,7 +511,7 @@ public abstract class ShellFolder extends File { public static T invoke(Callable task, Class exceptionClass) throws InterruptedException, E { try { - return getInvoker().invoke(task); + return invoker.invoke(task); } catch (Exception e) { if (e instanceof RuntimeException) { // Rethrow unchecked exceptions From 041e6cb96718723f4d8389b7f029cf5322e5738a Mon Sep 17 00:00:00 2001 From: Mario Torre Date: Fri, 30 Oct 2009 19:19:35 +0100 Subject: [PATCH 22/36] 6896068: SunGraphics2D exposes a reference to itself while non fully initialised Introduce a new Interface to mark the Loops based pipes and initialise the loops accordingly. Reviewed-by: flar, rkennke --- .../classes/sun/java2d/SunGraphics2D.java | 2 +- .../share/classes/sun/java2d/SurfaceData.java | 13 ++++++- .../sun/java2d/pipe/AATextRenderer.java | 5 ++- .../sun/java2d/pipe/GlyphListLoopPipe.java | 5 ++- .../sun/java2d/pipe/LoopBasedPipe.java | 37 +++++++++++++++++++ .../classes/sun/java2d/pipe/LoopPipe.java | 3 +- .../sun/java2d/pipe/SolidTextRenderer.java | 5 ++- .../sun/java2d/pipe/SpanShapeRenderer.java | 4 +- .../sun/java2d/x11/X11SurfaceData.java | 5 ++- .../java2d/windows/GDIWindowSurfaceData.java | 5 ++- 10 files changed, 71 insertions(+), 13 deletions(-) create mode 100644 jdk/src/share/classes/sun/java2d/pipe/LoopBasedPipe.java diff --git a/jdk/src/share/classes/sun/java2d/SunGraphics2D.java b/jdk/src/share/classes/sun/java2d/SunGraphics2D.java index c63db02e756..951876eb237 100644 --- a/jdk/src/share/classes/sun/java2d/SunGraphics2D.java +++ b/jdk/src/share/classes/sun/java2d/SunGraphics2D.java @@ -257,7 +257,6 @@ public final class SunGraphics2D font = defaultFont; } - loops = sd.getRenderLoops(this); setDevClip(sd.getBounds()); invalidatePipe(); } @@ -367,6 +366,7 @@ public final class SunGraphics2D shapepipe = invalidpipe; textpipe = invalidpipe; imagepipe = invalidpipe; + loops = null; } public void validatePipe() { diff --git a/jdk/src/share/classes/sun/java2d/SurfaceData.java b/jdk/src/share/classes/sun/java2d/SurfaceData.java index 65a04c23220..95ef18c85f4 100644 --- a/jdk/src/share/classes/sun/java2d/SurfaceData.java +++ b/jdk/src/share/classes/sun/java2d/SurfaceData.java @@ -69,6 +69,7 @@ import sun.java2d.pipe.DrawImagePipe; import sun.java2d.pipe.DrawImage; import sun.awt.SunHints; import sun.awt.image.SurfaceManager; +import sun.java2d.pipe.LoopBasedPipe; /** * This class provides various pieces of information relevant to a @@ -506,7 +507,6 @@ public abstract class SurfaceData sg2d.textpipe = solidTextRenderer; } sg2d.shapepipe = colorPrimitives; - sg2d.loops = getRenderLoops(sg2d); // assert(sg2d.surfaceData == this); } } else if (sg2d.compositeState == sg2d.COMP_CUSTOM) { @@ -603,9 +603,18 @@ public abstract class SurfaceData sg2d.textpipe = getTextPipe(sg2d, false /* AA==OFF */); sg2d.shapepipe = colorPrimitives; - sg2d.loops = getRenderLoops(sg2d); // assert(sg2d.surfaceData == this); } + + // check for loops + if (sg2d.textpipe instanceof LoopBasedPipe || + sg2d.shapepipe instanceof LoopBasedPipe || + sg2d.fillpipe instanceof LoopBasedPipe || + sg2d.drawpipe instanceof LoopBasedPipe || + sg2d.imagepipe instanceof LoopBasedPipe) + { + sg2d.loops = getRenderLoops(sg2d); + } } /* Return the text pipe to be used based on the graphics AA hint setting, diff --git a/jdk/src/share/classes/sun/java2d/pipe/AATextRenderer.java b/jdk/src/share/classes/sun/java2d/pipe/AATextRenderer.java index 389db9cbefd..602e5be5ef8 100644 --- a/jdk/src/share/classes/sun/java2d/pipe/AATextRenderer.java +++ b/jdk/src/share/classes/sun/java2d/pipe/AATextRenderer.java @@ -34,8 +34,9 @@ import sun.font.GlyphList; * a solid source colour to an opaque destination. */ -public class AATextRenderer extends GlyphListLoopPipe { - +public class AATextRenderer extends GlyphListLoopPipe + implements LoopBasedPipe +{ protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) { sg2d.loops.drawGlyphListAALoop.DrawGlyphListAA(sg2d, sg2d.surfaceData, gl); diff --git a/jdk/src/share/classes/sun/java2d/pipe/GlyphListLoopPipe.java b/jdk/src/share/classes/sun/java2d/pipe/GlyphListLoopPipe.java index cbe76016cf7..385a768cf9e 100644 --- a/jdk/src/share/classes/sun/java2d/pipe/GlyphListLoopPipe.java +++ b/jdk/src/share/classes/sun/java2d/pipe/GlyphListLoopPipe.java @@ -36,8 +36,9 @@ import sun.font.GlyphList; * the installed loop may not match the glyphvector. */ -public abstract class GlyphListLoopPipe extends GlyphListPipe { - +public abstract class GlyphListLoopPipe extends GlyphListPipe + implements LoopBasedPipe +{ protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl, int aaHint) { switch (aaHint) { diff --git a/jdk/src/share/classes/sun/java2d/pipe/LoopBasedPipe.java b/jdk/src/share/classes/sun/java2d/pipe/LoopBasedPipe.java new file mode 100644 index 00000000000..34b9067335c --- /dev/null +++ b/jdk/src/share/classes/sun/java2d/pipe/LoopBasedPipe.java @@ -0,0 +1,37 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.java2d.pipe; + +/** + * This is a marker interface used by Pipes that need RenderLoops. + * RenderLoops are validated in SurfaceData when a pipe is recognised to + * implement this interface. + * + * @author Mario Torre + */ +public interface LoopBasedPipe { + +} diff --git a/jdk/src/share/classes/sun/java2d/pipe/LoopPipe.java b/jdk/src/share/classes/sun/java2d/pipe/LoopPipe.java index 93334e56fac..a7d2c1dae23 100644 --- a/jdk/src/share/classes/sun/java2d/pipe/LoopPipe.java +++ b/jdk/src/share/classes/sun/java2d/pipe/LoopPipe.java @@ -46,7 +46,8 @@ import sun.awt.SunHints; public class LoopPipe implements PixelDrawPipe, PixelFillPipe, - ShapeDrawPipe + ShapeDrawPipe, + LoopBasedPipe { final static RenderingEngine RenderEngine = RenderingEngine.getInstance(); diff --git a/jdk/src/share/classes/sun/java2d/pipe/SolidTextRenderer.java b/jdk/src/share/classes/sun/java2d/pipe/SolidTextRenderer.java index 52d1a709a53..bb8778aba93 100644 --- a/jdk/src/share/classes/sun/java2d/pipe/SolidTextRenderer.java +++ b/jdk/src/share/classes/sun/java2d/pipe/SolidTextRenderer.java @@ -35,8 +35,9 @@ import sun.font.GlyphList; * a solid source colour to an opaque destination. */ -public class SolidTextRenderer extends GlyphListLoopPipe { - +public class SolidTextRenderer extends GlyphListLoopPipe + implements LoopBasedPipe +{ protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) { sg2d.loops.drawGlyphListLoop.DrawGlyphList(sg2d, sg2d.surfaceData, gl); } diff --git a/jdk/src/share/classes/sun/java2d/pipe/SpanShapeRenderer.java b/jdk/src/share/classes/sun/java2d/pipe/SpanShapeRenderer.java index 574ebed8188..a02b761c8dc 100644 --- a/jdk/src/share/classes/sun/java2d/pipe/SpanShapeRenderer.java +++ b/jdk/src/share/classes/sun/java2d/pipe/SpanShapeRenderer.java @@ -65,7 +65,9 @@ public abstract class SpanShapeRenderer implements ShapeDrawPipe { } } - public static class Simple extends SpanShapeRenderer { + public static class Simple extends SpanShapeRenderer + implements LoopBasedPipe + { public Object startSequence(SunGraphics2D sg, Shape s, Rectangle devR, int[] bbox) { return sg; diff --git a/jdk/src/solaris/classes/sun/java2d/x11/X11SurfaceData.java b/jdk/src/solaris/classes/sun/java2d/x11/X11SurfaceData.java index f613c118831..943f6e73a06 100644 --- a/jdk/src/solaris/classes/sun/java2d/x11/X11SurfaceData.java +++ b/jdk/src/solaris/classes/sun/java2d/x11/X11SurfaceData.java @@ -388,7 +388,10 @@ public abstract class X11SurfaceData extends SurfaceData { // if a GlyphVector overrides the AA setting. // We use getRenderLoops() rather than setting solidloops // directly so that we get the appropriate loops in XOR mode. - sg2d.loops = getRenderLoops(sg2d); + if (sg2d.loops == null) { + // assert(some pipe will always be a LoopBasedPipe) + sg2d.loops = getRenderLoops(sg2d); + } } else { super.validatePipe(sg2d); } diff --git a/jdk/src/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java b/jdk/src/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java index e246a7fc63d..c55b54d9f6b 100644 --- a/jdk/src/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java +++ b/jdk/src/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java @@ -210,7 +210,10 @@ public class GDIWindowSurfaceData extends SurfaceData { // if a GlyphVector overrides the AA setting. // We use getRenderLoops() rather than setting solidloops // directly so that we get the appropriate loops in XOR mode. - sg2d.loops = getRenderLoops(sg2d); + if (sg2d.loops == null) { + // assert(some pipe will always be a LoopBasedPipe) + sg2d.loops = getRenderLoops(sg2d); + } } else { super.validatePipe(sg2d); } From d45297718d40d317ee777cd94ee530a277060517 Mon Sep 17 00:00:00 2001 From: Andrew John Hughes Date: Tue, 3 Nov 2009 23:23:15 +0000 Subject: [PATCH 23/36] 6897844: Fix broken build on newer versions of X11 (libXext >= 1.1.0) Recent changes to X11's header structure break the build Reviewed-by: prr, flar --- jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.h b/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.h index 224c5540444..330b605143d 100644 --- a/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.h +++ b/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.h @@ -42,6 +42,10 @@ #include #include #include +#ifndef X_ShmAttach +#include +#include +#endif extern int XShmQueryExtension(); From e918d4b8607964e66f5c189bb8172e75e3a797df Mon Sep 17 00:00:00 2001 From: Pavel Porvatov Date: Fri, 6 Nov 2009 12:44:41 +0300 Subject: [PATCH 24/36] 6621569: Win32ShellFolder2 and Win32ShellFolderManager2 may leak native resources Reviewed-by: malenkov --- .../sun/awt/shell/Win32ShellFolder2.java | 47 ++++++++++--------- .../awt/shell/Win32ShellFolderManager2.java | 9 ++-- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java b/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java index 90d008625cc..f9b2f4c4280 100644 --- a/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java +++ b/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java @@ -693,29 +693,32 @@ final class Win32ShellFolder2 extends ShellFolder { ArrayList list = new ArrayList(); long pEnumObjects = getEnumObjects(includeHiddenFiles); if (pEnumObjects != 0) { - long childPIDL; - int testedAttrs = ATTRIB_FILESYSTEM | ATTRIB_FILESYSANCESTOR; - do { - childPIDL = getNextChild(pEnumObjects); - boolean releasePIDL = true; - if (childPIDL != 0 && - (getAttributes0(pIShellFolder, childPIDL, testedAttrs) & testedAttrs) != 0) { - Win32ShellFolder2 childFolder; - if (Win32ShellFolder2.this.equals(desktop) - && personal != null - && pidlsEqual(pIShellFolder, childPIDL, personal.disposer.relativePIDL)) { - childFolder = personal; - } else { - childFolder = new Win32ShellFolder2(Win32ShellFolder2.this, childPIDL); - releasePIDL = false; + try { + long childPIDL; + int testedAttrs = ATTRIB_FILESYSTEM | ATTRIB_FILESYSANCESTOR; + do { + childPIDL = getNextChild(pEnumObjects); + boolean releasePIDL = true; + if (childPIDL != 0 && + (getAttributes0(pIShellFolder, childPIDL, testedAttrs) & testedAttrs) != 0) { + Win32ShellFolder2 childFolder; + if (Win32ShellFolder2.this.equals(desktop) + && personal != null + && pidlsEqual(pIShellFolder, childPIDL, personal.disposer.relativePIDL)) { + childFolder = personal; + } else { + childFolder = new Win32ShellFolder2(Win32ShellFolder2.this, childPIDL); + releasePIDL = false; + } + list.add(childFolder); } - list.add(childFolder); - } - if (releasePIDL) { - releasePIDL(childPIDL); - } - } while (childPIDL != 0 && !Thread.currentThread().isInterrupted()); - releaseEnumObjects(pEnumObjects); + if (releasePIDL) { + releasePIDL(childPIDL); + } + } while (childPIDL != 0 && !Thread.currentThread().isInterrupted()); + } finally { + releaseEnumObjects(pEnumObjects); + } } return Thread.currentThread().isInterrupted() ? new File[0] diff --git a/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java b/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java index abd49d3960b..b7639fa77bb 100644 --- a/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java +++ b/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java @@ -79,9 +79,12 @@ public class Win32ShellFolderManager2 extends ShellFolderManager { // Shouldn't happen but watch for it anyway throw new FileNotFoundException("File " + file.getAbsolutePath() + " not found"); } - Win32ShellFolder2 folder = createShellFolderFromRelativePIDL(parent, pIDL); - Win32ShellFolder2.releasePIDL(pIDL); - return folder; + + try { + return createShellFolderFromRelativePIDL(parent, pIDL); + } finally { + Win32ShellFolder2.releasePIDL(pIDL); + } } static Win32ShellFolder2 createShellFolderFromRelativePIDL(Win32ShellFolder2 parent, long pIDL) From e0b6c6ec3fa6ab7a3dc1d9dc834368f25bd396ab Mon Sep 17 00:00:00 2001 From: Alexander Potochkin Date: Fri, 6 Nov 2009 22:26:37 +0300 Subject: [PATCH 25/36] 6879228: LayerUI should be extended Reviewed-by: peterz --- .../classes/javax/swing/plaf/LayerUI.java | 412 +++++++++++++++++- 1 file changed, 402 insertions(+), 10 deletions(-) diff --git a/jdk/src/share/classes/javax/swing/plaf/LayerUI.java b/jdk/src/share/classes/javax/swing/plaf/LayerUI.java index cf64687421a..7f2967bf465 100644 --- a/jdk/src/share/classes/javax/swing/plaf/LayerUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/LayerUI.java @@ -71,33 +71,410 @@ public class LayerUI * Subclasses should override this method and use * the specified {@code Graphics} object to * render the content of the component. + *

+ * If {@code g} is not an instance of {@code Graphics2D}, + * this method is no-op. * * @param g the {@code Graphics} context in which to paint; * @param c the component being painted; - * it can be safely cast to the {@code JLayer} + * it can be safely cast to {@code JLayer} + * + * @see #configureGraphics(Graphics2D, JLayer) + * @see #paintLayer(Graphics2D, JLayer) */ - @Override public void paint(Graphics g, JComponent c) { - c.paint(g); + if (g instanceof Graphics2D) { + Graphics2D g2 = (Graphics2D) g.create(); + JLayer l = (JLayer) c; + configureGraphics(g2, l); + paintLayer(g2, l); + g2.dispose(); + } + } + + /** + * This method is called by the {@link #paint} method prior to + * {@link #paintLayer} to configure the {@code Graphics2D} object. + * The default implementation is empty. + * + * @param g2 the {@code Graphics2D} object to configure + * @param l the {@code JLayer} being painted + * + * @see #paintLayer(Graphics2D, JLayer) + */ + protected void configureGraphics(Graphics2D g2, JLayer l) { + } + + /** + * Called by the {@link #paint} method, + * subclasses should override this method + * to perform any custom painting operations. + *

+ * The default implementation paints the passed {@code JLayer} as is. + * + * @param g2 the {@code Graphics2D} context in which to paint + * @param l the {@code JLayer} being painted + * + * @see #configureGraphics(Graphics2D, JLayer) + */ + protected void paintLayer(Graphics2D g2, JLayer l) { + l.paint(g2); } /** * Dispatches {@code AWTEvent}s for {@code JLayer} - * and all it subcomponents to this {@code LayerUI} instance. - *

- * To enable the {@code AWTEvent} of the particular type, - * you call {@link javax.swing.JLayer#setLayerEventMask} + * and all its subcomponents to this {@code LayerUI} instance. + *

+ * To enable the {@code AWTEvent}s of a particular type, + * you call {@link JLayer#setLayerEventMask} * in {@link #installUI(javax.swing.JComponent)} * and set the layer event mask to {@code 0} - * in {@link #uninstallUI(javax.swing.JComponent)} after that + * in {@link #uninstallUI(javax.swing.JComponent)} after that. + * By default this method calls the appropriate + * {@code process<event type>Event} + * method for the given class of event. * * @param e the event to be dispatched * @param l the layer this LayerUI is set to * * @see JLayer#setLayerEventMask(long) - * @see javax.swing.JLayer#getLayerEventMask() + * @see #installUI(javax.swing.JComponent) + * @see #uninstallUI(javax.swing.JComponent) + * @see #processComponentEvent + * @see #processFocusEvent + * @see #processKeyEvent + * @see #processMouseEvent + * @see #processMouseMotionEvent + * @see #processInputMethodEvent + * @see #processHierarchyEvent + * @see #processMouseWheelEvent */ public void eventDispatched(AWTEvent e, JLayer l){ + if (e instanceof FocusEvent) { + processFocusEvent((FocusEvent)e, l); + + } else if (e instanceof MouseEvent) { + switch(e.getID()) { + case MouseEvent.MOUSE_PRESSED: + case MouseEvent.MOUSE_RELEASED: + case MouseEvent.MOUSE_CLICKED: + case MouseEvent.MOUSE_ENTERED: + case MouseEvent.MOUSE_EXITED: + processMouseEvent((MouseEvent)e, l); + break; + case MouseEvent.MOUSE_MOVED: + case MouseEvent.MOUSE_DRAGGED: + processMouseMotionEvent((MouseEvent)e, l); + break; + case MouseEvent.MOUSE_WHEEL: + processMouseWheelEvent((MouseWheelEvent)e, l); + break; + } + } else if (e instanceof KeyEvent) { + processKeyEvent((KeyEvent)e, l); + } else if (e instanceof ComponentEvent) { + processComponentEvent((ComponentEvent)e, l); + } else if (e instanceof InputMethodEvent) { + processInputMethodEvent((InputMethodEvent)e, l); + } else if (e instanceof HierarchyEvent) { + switch (e.getID()) { + case HierarchyEvent.HIERARCHY_CHANGED: + processHierarchyEvent((HierarchyEvent)e, l); + break; + case HierarchyEvent.ANCESTOR_MOVED: + case HierarchyEvent.ANCESTOR_RESIZED: + processHierarchyBoundsEvent((HierarchyEvent)e, l); + break; + } + } + } + + /** + * Processes component events occurring on the {@link JLayer} + * or any of its subcomponents. + *

+ * This method is not called unless component events are + * enabled for the {@code JLayer} objects, this {@code LayerUI} is set to. + * Component events are enabled in the overridden {@link #installUI} method + * and should be disabled in the {@link #uninstallUI} method after that. + *

+     * public void installUI(JComponent c) {
+     *    super.installUI(c);
+     *    JLayer l = (JLayer) c;
+     *    l.setLayerEventMask(AWTEvent.COMPONENT_EVENT_MASK);
+     * }
+     *
+     * public void unistallUI(JComponent c) {
+     *     super.uninstallUI(c);
+     *     JLayer l = (JLayer) c;
+     *     l.setLayerEventMask(0);
+     * }
+     * 
+ * + * @param e the {@code ComponentEvent} to be processed + * @param l the layer this {@code LayerUI} instance is set to + * + * @see JLayer#setLayerEventMask(long) + * @see #installUI(javax.swing.JComponent) + * @see #uninstallUI(javax.swing.JComponent) + */ + protected void processComponentEvent(ComponentEvent e, JLayer l) { + } + + /** + * Processes focus events occurring on the {@link JLayer} + * or any of its subcomponents. + *

+ * This method is not called unless focus events are + * enabled for the {@code JLayer} objects, this {@code LayerUI} is set to. + * Focus events are enabled in the overridden {@link #installUI} method + * and should be disabled in the {@link #uninstallUI} method after that. + *

+     * public void installUI(JComponent c) {
+     *    super.installUI(c);
+     *    JLayer l = (JLayer) c;
+     *    l.setLayerEventMask(AWTEvent.FOCUS_EVENT_MASK);
+     * }
+     *
+     * public void unistallUI(JComponent c) {
+     *     super.uninstallUI(c);
+     *     JLayer l = (JLayer) c;
+     *     l.setLayerEventMask(0);
+     * }
+     * 
+ * + * @param e the {@code FocusEvent} to be processed + * @param l the layer this {@code LayerUI} instance is set to + * + * @see JLayer#setLayerEventMask(long) + * @see #installUI(javax.swing.JComponent) + * @see #uninstallUI(javax.swing.JComponent) + */ + protected void processFocusEvent(FocusEvent e, JLayer l) { + } + + /** + * Processes key events occurring on the {@link JLayer} + * or any of its subcomponents. + *

+ * This method is not called unless key events are + * enabled for the {@code JLayer} objects, this {@code LayerUI} is set to. + * Key events are enabled in the overridden {@link #installUI} method + * and should be disabled in the {@link #uninstallUI} method after that. + *

+     * public void installUI(JComponent c) {
+     *    super.installUI(c);
+     *    JLayer l = (JLayer) c;
+     *    l.setLayerEventMask(AWTEvent.KEY_EVENT_MASK);
+     * }
+     *
+     * public void unistallUI(JComponent c) {
+     *     super.uninstallUI(c);
+     *     JLayer l = (JLayer) c;
+     *     l.setLayerEventMask(0);
+     * }
+     * 
+ * + * @param e the {@code KeyEvent} to be processed + * @param l the layer this {@code LayerUI} instance is set to + * + * @see JLayer#setLayerEventMask(long) + * @see #installUI(javax.swing.JComponent) + * @see #uninstallUI(javax.swing.JComponent) + */ + protected void processKeyEvent(KeyEvent e, JLayer l) { + } + + /** + * Processes mouse events occurring on the {@link JLayer} + * or any of its subcomponents. + *

+ * This method is not called unless mouse events are + * enabled for the {@code JLayer} objects, this {@code LayerUI} is set to. + * Mouse events are enabled in the overridden {@link #installUI} method + * and should be disabled in the {@link #uninstallUI} method after that. + *

+     * public void installUI(JComponent c) {
+     *    super.installUI(c);
+     *    JLayer l = (JLayer) c;
+     *    l.setLayerEventMask(AWTEvent.MOUSE_EVENT_MASK);
+     * }
+     *
+     * public void unistallUI(JComponent c) {
+     *     super.uninstallUI(c);
+     *     JLayer l = (JLayer) c;
+     *     l.setLayerEventMask(0);
+     * }
+     * 
+ * + * @param e the {@code MouseEvent} to be processed + * @param l the layer this {@code LayerUI} instance is set to + * + * @see JLayer#setLayerEventMask(long) + * @see #installUI(javax.swing.JComponent) + * @see #uninstallUI(javax.swing.JComponent) + */ + protected void processMouseEvent(MouseEvent e, JLayer l) { + } + + /** + * Processes mouse motion event occurring on the {@link JLayer} + * or any of its subcomponents. + *

+ * This method is not called unless mouse motion events are + * enabled for the {@code JLayer} objects, this {@code LayerUI} is set to. + * Mouse motion events are enabled in the overridden {@link #installUI} method + * and should be disabled in the {@link #uninstallUI} method after that. + *

+     * public void installUI(JComponent c) {
+     *    super.installUI(c);
+     *    JLayer l = (JLayer) c;
+     *    l.setLayerEventMask(AWTEvent.MOUSE_MOTION_EVENT_MASK);
+     * }
+     *
+     * public void unistallUI(JComponent c) {
+     *     super.uninstallUI(c);
+     *     JLayer l = (JLayer) c;
+     *     l.setLayerEventMask(0);
+     * }
+     * 
+ * + * @param e the {@code MouseEvent} to be processed + * @param l the layer this {@code LayerUI} instance is set to + * + * @see JLayer#setLayerEventMask(long) + * @see #installUI(javax.swing.JComponent) + * @see #uninstallUI(javax.swing.JComponent) + */ + protected void processMouseMotionEvent(MouseEvent e, JLayer l) { + } + + /** + * Processes mouse wheel event occurring on the {@link JLayer} + * or any of its subcomponents. + *

+ * This method is not called unless mouse wheel events are + * enabled for the {@code JLayer} objects, this {@code LayerUI} is set to. + * Mouse wheel events are enabled in the overridden {@link #installUI} method + * and should be disabled in the {@link #uninstallUI} method after that. + *

+     * public void installUI(JComponent c) {
+     *    super.installUI(c);
+     *    JLayer l = (JLayer) c;
+     *    l.setLayerEventMask(AWTEvent.MOUSE_WHEEL_EVENT_MASK);
+     * }
+     *
+     * public void unistallUI(JComponent c) {
+     *     super.uninstallUI(c);
+     *     JLayer l = (JLayer) c;
+     *     l.setLayerEventMask(0);
+     * }
+     * 
+ * + * @param e the {@code MouseEvent} to be processed + * @param l the layer this {@code LayerUI} instance is set to + * + * @see JLayer#setLayerEventMask(long) + * @see #installUI(javax.swing.JComponent) + * @see #uninstallUI(javax.swing.JComponent) + */ + protected void processMouseWheelEvent(MouseWheelEvent e, JLayer l) { + } + + /** + * Processes input event occurring on the {@link JLayer} + * or any of its subcomponents. + *

+ * This method is not called unless input events are + * enabled for the {@code JLayer} objects, this {@code LayerUI} is set to. + * Input events are enabled in the overridden {@link #installUI} method + * and should be disabled in the {@link #uninstallUI} method after that. + *

+     * public void installUI(JComponent c) {
+     *    super.installUI(c);
+     *    JLayer l = (JLayer) c;
+     *    l.setLayerEventMask(AWTEvent.INPUT_METHOD_EVENT_MASK);
+     * }
+     *
+     * public void unistallUI(JComponent c) {
+     *     super.uninstallUI(c);
+     *     JLayer l = (JLayer) c;
+     *     l.setLayerEventMask(0);
+     * }
+     * 
+ * + * @param e the {@code InputMethodEvent} to be processed + * @param l the layer this {@code LayerUI} instance is set to + * + * @see JLayer#setLayerEventMask(long) + * @see #installUI(javax.swing.JComponent) + * @see #uninstallUI(javax.swing.JComponent) + */ + protected void processInputMethodEvent(InputMethodEvent e, JLayer l) { + } + + /** + * Processes hierarchy event occurring on the {@link JLayer} + * or any of its subcomponents. + *

+ * This method is not called unless hierarchy events are + * enabled for the {@code JLayer} objects, this {@code LayerUI} is set to. + * Hierarchy events are enabled in the overridden {@link #installUI} method + * and should be disabled in the {@link #uninstallUI} method after that. + *

+     * public void installUI(JComponent c) {
+     *    super.installUI(c);
+     *    JLayer l = (JLayer) c;
+     *    l.setLayerEventMask(AWTEvent.HIERARCHY_EVENT_MASK);
+     * }
+     *
+     * public void unistallUI(JComponent c) {
+     *     super.uninstallUI(c);
+     *     JLayer l = (JLayer) c;
+     *     l.setLayerEventMask(0);
+     * }
+     * 
+ * + * @param e the {@code HierarchyEvent} to be processed + * @param l the layer this {@code LayerUI} instance is set to + * + * @see JLayer#setLayerEventMask(long) + * @see #installUI(javax.swing.JComponent) + * @see #uninstallUI(javax.swing.JComponent) + */ + protected void processHierarchyEvent(HierarchyEvent e, JLayer l) { + } + + /** + * Processes hierarchy bounds event occurring on the {@link JLayer} + * or any of its subcomponents. + *

+ * This method is not called unless hierarchy bounds events are + * enabled for the {@code JLayer} objects, this {@code LayerUI} is set to. + * Hierarchy bounds events are enabled in the overridden {@link #installUI} + * method and should be disabled in the {@link #uninstallUI} method after that. + *

+     * public void installUI(JComponent c) {
+     *    super.installUI(c);
+     *    JLayer l = (JLayer) c;
+     *    l.setLayerEventMask(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK);
+     * }
+     *
+     * public void unistallUI(JComponent c) {
+     *     super.uninstallUI(c);
+     *     JLayer l = (JLayer) c;
+     *     l.setLayerEventMask(0);
+     * }
+     * 
+ * + * @param e the {@code HierarchyEvent} to be processed + * @param l the layer this {@code LayerUI} instance is set to + * + * @see JLayer#setLayerEventMask(long) + * @see #installUI(javax.swing.JComponent) + * @see #uninstallUI(javax.swing.JComponent) + */ + protected void processHierarchyBoundsEvent(HierarchyEvent e, JLayer l) { } /** @@ -250,14 +627,29 @@ public class LayerUI propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue); } + /** + * Repaints all {@code JLayer} instances this {@code LayerUI} is set to. + * Call this method when the state of this {@code LayerUI} is changed + * and the visual appearance of its {@code JLayer} objects needs to be updated. + * + * @see Component#repaint() + */ + protected void repaintLayer() { + firePropertyChange("dirty", null, null); + } + /** * Notifies the {@code LayerUI} when any of its property are changed - * and enables updating every {@code JLayer} this {@code LayerUI} instance is set to. + * and enables updating every {@code JLayer} + * this {@code LayerUI} instance is set to. * * @param evt the PropertyChangeEvent generated by this {@code LayerUI} * @param l the {@code JLayer} this LayerUI is set to */ public void applyPropertyChange(PropertyChangeEvent evt, JLayer l) { + if ("dirty".equals(evt.getPropertyName())) { + l.repaint(); + } } /** From eedc1f473a23bf70fd17efe9d5531d4a537e5dfd Mon Sep 17 00:00:00 2001 From: Alexander Potochkin Date: Fri, 6 Nov 2009 22:40:58 +0300 Subject: [PATCH 26/36] 6878399: public SwingUtilities.getParentViewport() is required Reviewed-by: peterz --- .../classes/javax/swing/JEditorPane.java | 6 +- jdk/src/share/classes/javax/swing/JList.java | 4 +- jdk/src/share/classes/javax/swing/JTable.java | 17 +++--- .../share/classes/javax/swing/JTextField.java | 2 +- jdk/src/share/classes/javax/swing/JTree.java | 4 +- .../classes/javax/swing/SwingUtilities.java | 60 +++++++++++++++++++ .../javax/swing/text/JTextComponent.java | 4 +- .../classes/sun/swing/SwingUtilities2.java | 18 ------ 8 files changed, 80 insertions(+), 35 deletions(-) diff --git a/jdk/src/share/classes/javax/swing/JEditorPane.java b/jdk/src/share/classes/javax/swing/JEditorPane.java index 4dfbf92488e..eaf61f1e60e 100644 --- a/jdk/src/share/classes/javax/swing/JEditorPane.java +++ b/jdk/src/share/classes/javax/swing/JEditorPane.java @@ -1330,7 +1330,7 @@ public class JEditorPane extends JTextComponent { */ public Dimension getPreferredSize() { Dimension d = super.getPreferredSize(); - JViewport port = SwingUtilities2.getViewport(this); + JViewport port = SwingUtilities.getParentViewport(this); if (port != null) { TextUI ui = getUI(); int prefWidth = d.width; @@ -1452,7 +1452,7 @@ public class JEditorPane extends JTextComponent { * match its own, false otherwise */ public boolean getScrollableTracksViewportWidth() { - JViewport port = SwingUtilities2.getViewport(this); + JViewport port = SwingUtilities.getParentViewport(this); if (port != null) { TextUI ui = getUI(); int w = port.getWidth(); @@ -1474,7 +1474,7 @@ public class JEditorPane extends JTextComponent { * false otherwise */ public boolean getScrollableTracksViewportHeight() { - JViewport port = SwingUtilities2.getViewport(this); + JViewport port = SwingUtilities.getParentViewport(this); if (port != null) { TextUI ui = getUI(); int h = port.getHeight(); diff --git a/jdk/src/share/classes/javax/swing/JList.java b/jdk/src/share/classes/javax/swing/JList.java index 796ac11ba6c..6c06c5ea682 100644 --- a/jdk/src/share/classes/javax/swing/JList.java +++ b/jdk/src/share/classes/javax/swing/JList.java @@ -2722,7 +2722,7 @@ public class JList extends JComponent implements Scrollable, Accessible getVisibleRowCount() <= 0) { return true; } - JViewport port = SwingUtilities2.getViewport(this); + JViewport port = SwingUtilities.getParentViewport(this); if (port != null) { return port.getWidth() > getPreferredSize().width; } @@ -2748,7 +2748,7 @@ public class JList extends JComponent implements Scrollable, Accessible getVisibleRowCount() <= 0) { return true; } - JViewport port = SwingUtilities2.getViewport(this); + JViewport port = SwingUtilities.getParentViewport(this); if (port != null) { return port.getHeight() > getPreferredSize().height; } diff --git a/jdk/src/share/classes/javax/swing/JTable.java b/jdk/src/share/classes/javax/swing/JTable.java index 28b38ce0c6a..5489c380f1a 100644 --- a/jdk/src/share/classes/javax/swing/JTable.java +++ b/jdk/src/share/classes/javax/swing/JTable.java @@ -719,7 +719,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * @see #addNotify */ protected void configureEnclosingScrollPane() { - JViewport port = SwingUtilities2.getViewport(this); + JViewport port = SwingUtilities.getParentViewport(this); if (port != null) { Container gp = port.getParent(); if (gp instanceof JScrollPane) { @@ -728,7 +728,8 @@ public class JTable extends JComponent implements TableModelListener, Scrollable // example, the rowHeaderView of the scrollPane - // an implementor of fixed columns might do this. JViewport viewport = scrollPane.getViewport(); - if (viewport == null || viewport.getView() != this) { + if (viewport == null || + SwingUtilities.getUnwrappedView(viewport) != this) { return; } scrollPane.setColumnHeaderView(getTableHeader()); @@ -751,7 +752,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * from configureEnclosingScrollPane() and updateUI() in a safe manor. */ private void configureEnclosingScrollPaneUI() { - JViewport port = SwingUtilities2.getViewport(this); + JViewport port = SwingUtilities.getParentViewport(this); if (port != null) { Container gp = port.getParent(); if (gp instanceof JScrollPane) { @@ -760,7 +761,8 @@ public class JTable extends JComponent implements TableModelListener, Scrollable // example, the rowHeaderView of the scrollPane - // an implementor of fixed columns might do this. JViewport viewport = scrollPane.getViewport(); - if (viewport == null || viewport.getView() != this) { + if (viewport == null || + SwingUtilities.getUnwrappedView(viewport) != this) { return; } // scrollPane.getViewport().setBackingStoreEnabled(true); @@ -820,7 +822,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * @since 1.3 */ protected void unconfigureEnclosingScrollPane() { - JViewport port = SwingUtilities2.getViewport(this); + JViewport port = SwingUtilities.getParentViewport(this); if (port != null) { Container gp = port.getParent(); if (gp instanceof JScrollPane) { @@ -829,7 +831,8 @@ public class JTable extends JComponent implements TableModelListener, Scrollable // example, the rowHeaderView of the scrollPane - // an implementor of fixed columns might do this. JViewport viewport = scrollPane.getViewport(); - if (viewport == null || viewport.getView() != this) { + if (viewport == null || + SwingUtilities.getUnwrappedView(viewport) != this) { return; } scrollPane.setColumnHeaderView(null); @@ -5216,7 +5219,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * @see #getFillsViewportHeight */ public boolean getScrollableTracksViewportHeight() { - JViewport port = SwingUtilities2.getViewport(this); + JViewport port = SwingUtilities.getParentViewport(this); return getFillsViewportHeight() && port != null && port.getHeight() > getPreferredSize().height; diff --git a/jdk/src/share/classes/javax/swing/JTextField.java b/jdk/src/share/classes/javax/swing/JTextField.java index de408914d22..65b80ac2674 100644 --- a/jdk/src/share/classes/javax/swing/JTextField.java +++ b/jdk/src/share/classes/javax/swing/JTextField.java @@ -290,7 +290,7 @@ public class JTextField extends JTextComponent implements SwingConstants { * @see JComponent#isValidateRoot */ public boolean isValidateRoot() { - return SwingUtilities2.getViewport(this) == null; + return SwingUtilities.getParentViewport(this) == null; } diff --git a/jdk/src/share/classes/javax/swing/JTree.java b/jdk/src/share/classes/javax/swing/JTree.java index 1b200f78591..55815b81dc2 100644 --- a/jdk/src/share/classes/javax/swing/JTree.java +++ b/jdk/src/share/classes/javax/swing/JTree.java @@ -3498,7 +3498,7 @@ public class JTree extends JComponent implements Scrollable, Accessible * @see Scrollable#getScrollableTracksViewportWidth */ public boolean getScrollableTracksViewportWidth() { - JViewport port = SwingUtilities2.getViewport(this); + JViewport port = SwingUtilities.getParentViewport(this); if (port != null) { return port.getWidth() > getPreferredSize().width; } @@ -3515,7 +3515,7 @@ public class JTree extends JComponent implements Scrollable, Accessible * @see Scrollable#getScrollableTracksViewportHeight */ public boolean getScrollableTracksViewportHeight() { - JViewport port = SwingUtilities2.getViewport(this); + JViewport port = SwingUtilities.getParentViewport(this); if (port != null) { return port.getHeight() > getPreferredSize().height; } diff --git a/jdk/src/share/classes/javax/swing/SwingUtilities.java b/jdk/src/share/classes/javax/swing/SwingUtilities.java index d7a26a0dd72..0e8a324454e 100644 --- a/jdk/src/share/classes/javax/swing/SwingUtilities.java +++ b/jdk/src/share/classes/javax/swing/SwingUtilities.java @@ -1967,4 +1967,64 @@ public class SwingUtilities implements SwingConstants SwingUtilities.updateComponentTreeUI(component); } } + + /** + * Looks for the first ancestor of the {@code component} + * which is not an instance of {@link JLayer}. + * If this ancestor is an instance of {@code JViewport}, + * this {@code JViewport} is returned, otherwise returns {@code null}. + * The following way of obtaining the parent {@code JViewport} + * is not recommended any more: + *
+     * JViewport port = null;
+     * Container parent = component.getParent();
+     * // not recommended any more
+     * if(parent instanceof JViewport) {
+     *     port = (JViewport) parent;
+     * }
+     * 
+ * Here is the way to go: + *
+     * // the correct way:
+     * JViewport port = SwingUtilities.getParentViewport(component);
+     * 
+ * @param component {@code Component} to get the parent {@code JViewport} of. + * @return the {@code JViewport} instance for the {@code component} + * or {@code null} + * @throws NullPointerException if {@code component} is {@code null} + * + * @since 1.7 + */ + public static JViewport getParentViewport(Component component) { + do { + component = component.getParent(); + if (component instanceof JViewport) { + return (JViewport) component; + } + } while(component instanceof JLayer); + return null; + } + + /** + * Returns the first {@code JViewport}'s descendant + * which is not an instance of {@code JLayer} or {@code null}. + * + * If the {@code viewport}'s view component is not a {@code JLayer}, + * this method is equal to {@link JViewport#getView()} + * otherwise {@link JLayer#getView()} will be recursively tested + * + * @return the first {@code JViewport}'s descendant + * which is not an instance of {@code JLayer} or {@code null}. + * + * @throws NullPointerException if {@code viewport} is {@code null} + * @see JViewport#getView() + * @see JLayer + */ + static Component getUnwrappedView(JViewport viewport) { + Component view = viewport.getView(); + while (view instanceof JLayer) { + view = ((JLayer)view).getView(); + } + return view; + } } diff --git a/jdk/src/share/classes/javax/swing/text/JTextComponent.java b/jdk/src/share/classes/javax/swing/text/JTextComponent.java index 371afda48b0..25ddaf9e3cc 100644 --- a/jdk/src/share/classes/javax/swing/text/JTextComponent.java +++ b/jdk/src/share/classes/javax/swing/text/JTextComponent.java @@ -2069,7 +2069,7 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A * width to match its own */ public boolean getScrollableTracksViewportWidth() { - JViewport port = SwingUtilities2.getViewport(this); + JViewport port = SwingUtilities.getParentViewport(this); if (port != null) { return port.getWidth() > getPreferredSize().width; } @@ -2090,7 +2090,7 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A * to match its own */ public boolean getScrollableTracksViewportHeight() { - JViewport port = SwingUtilities2.getViewport(this); + JViewport port = SwingUtilities.getParentViewport(this); if (port != null) { return (port.getHeight() > getPreferredSize().height); } diff --git a/jdk/src/share/classes/sun/swing/SwingUtilities2.java b/jdk/src/share/classes/sun/swing/SwingUtilities2.java index 60681d56fbc..5b835bfec54 100644 --- a/jdk/src/share/classes/sun/swing/SwingUtilities2.java +++ b/jdk/src/share/classes/sun/swing/SwingUtilities2.java @@ -1807,22 +1807,4 @@ public class SwingUtilities2 { boolean three) { return liesIn(rect, p, false, false, three); } - - /** - * Returns the {@code JViewport} instance for the {@code component} - * or {@code null}. - * - * @return the {@code JViewport} instance for the {@code component} - * or {@code null} - * @throws NullPointerException if {@code component} is {@code null} - */ - public static JViewport getViewport(Component component) { - do { - component = component.getParent(); - if (component instanceof JViewport) { - return (JViewport) component; - } - } while(component instanceof JLayer); - return null; - } } From 2fdf51d313d0cfe3873df81990a47299bc8aed3a Mon Sep 17 00:00:00 2001 From: Phil Race Date: Mon, 9 Nov 2009 14:23:49 -0800 Subject: [PATCH 27/36] 6899078: potential deadlock and performance issue in freeing strike resources with D3D pipeline Reviewed-by: tdv, igor --- jdk/src/share/classes/sun/font/Font2D.java | 15 ---- .../classes/sun/font/FontDesignMetrics.java | 2 +- .../classes/sun/font/FontStrikeDisposer.java | 4 +- .../share/classes/sun/font/StrikeCache.java | 18 ++++- .../share/classes/sun/java2d/Disposer.java | 81 +++++++++++++++++++ 5 files changed, 100 insertions(+), 20 deletions(-) diff --git a/jdk/src/share/classes/sun/font/Font2D.java b/jdk/src/share/classes/sun/font/Font2D.java index c344ebb7007..3a930d6502e 100644 --- a/jdk/src/share/classes/sun/font/Font2D.java +++ b/jdk/src/share/classes/sun/font/Font2D.java @@ -320,21 +320,6 @@ public abstract class Font2D { lastFontStrike = new SoftReference(strike); StrikeCache.refStrike(strike); return strike; - } else { - /* We have found a cleared reference that has not yet - * been removed by the disposer. - * If we make this reference unreachable by removing it - * from the map,or overwriting it with a new reference to - * a new strike, then it is possible it may never be - * enqueued for disposal. That is the implication of - * the docs for java.lang.ref. So on finding a cleared - * reference, we need to dispose the native resources, - * if they haven't already been freed. - * The reference object needs to have a reference to - * the disposer instance for this to occur. - */ - ((StrikeCache.DisposableStrike)strikeRef) - .getDisposer().dispose(); } } /* When we create a new FontStrike instance, we *must* diff --git a/jdk/src/share/classes/sun/font/FontDesignMetrics.java b/jdk/src/share/classes/sun/font/FontDesignMetrics.java index 929c0d21dd8..e81c397fdea 100644 --- a/jdk/src/share/classes/sun/font/FontDesignMetrics.java +++ b/jdk/src/share/classes/sun/font/FontDesignMetrics.java @@ -171,7 +171,7 @@ public final class FontDesignMetrics extends FontMetrics { * out we can clear the keys from the table. */ private static class KeyReference extends SoftReference - implements DisposerRecord { + implements DisposerRecord, Disposer.PollDisposable { static ReferenceQueue queue = Disposer.getQueue(); diff --git a/jdk/src/share/classes/sun/font/FontStrikeDisposer.java b/jdk/src/share/classes/sun/font/FontStrikeDisposer.java index 7245cc3736f..3ee33eccea6 100644 --- a/jdk/src/share/classes/sun/font/FontStrikeDisposer.java +++ b/jdk/src/share/classes/sun/font/FontStrikeDisposer.java @@ -25,6 +25,7 @@ package sun.font; +import sun.java2d.Disposer; import sun.java2d.DisposerRecord; /* @@ -49,7 +50,8 @@ import sun.java2d.DisposerRecord; * entries would be removed much more promptly than we need. */ -class FontStrikeDisposer implements DisposerRecord { +class FontStrikeDisposer + implements DisposerRecord, Disposer.PollDisposable { Font2D font2D; FontStrikeDesc desc; diff --git a/jdk/src/share/classes/sun/font/StrikeCache.java b/jdk/src/share/classes/sun/font/StrikeCache.java index 945b01f867e..9e5b02a8650 100644 --- a/jdk/src/share/classes/sun/font/StrikeCache.java +++ b/jdk/src/share/classes/sun/font/StrikeCache.java @@ -254,9 +254,20 @@ public final class StrikeCache { // because they may be accessed on that thread at the time of the // disposal (for example, when the accel. cache is invalidated) - // REMIND: this look a bit heavyweight, but should be ok - // because strike disposal is a relatively infrequent operation, - // more worrisome is the necessity of getting a GC here. + // Whilst this is a bit heavyweight, in most applications + // strike disposal is a relatively infrequent operation, so it + // doesn't matter. But in some tests that use vast numbers + // of strikes, the switching back and forth is measurable. + // So the "pollRemove" call is added to batch up the work. + // If we are polling we know we've already been called back + // and can directly dispose the record. + // Also worrisome is the necessity of getting a GC here. + + if (Disposer.pollingQueue) { + doDispose(disposer); + return; + } + RenderQueue rq = null; GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); @@ -277,6 +288,7 @@ public final class StrikeCache { rq.flushAndInvokeNow(new Runnable() { public void run() { doDispose(disposer); + Disposer.pollRemove(); } }); } finally { diff --git a/jdk/src/share/classes/sun/java2d/Disposer.java b/jdk/src/share/classes/sun/java2d/Disposer.java index bf9ea8ad71a..4433a278d5d 100644 --- a/jdk/src/share/classes/sun/java2d/Disposer.java +++ b/jdk/src/share/classes/sun/java2d/Disposer.java @@ -29,6 +29,7 @@ import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.PhantomReference; import java.lang.ref.WeakReference; +import java.util.ArrayList; import java.util.Hashtable; /** @@ -146,6 +147,7 @@ public class Disposer implements Runnable { rec.dispose(); obj = null; rec = null; + clearDeferredRecords(); } catch (Exception e) { System.out.println("Exception while removing reference: " + e); e.printStackTrace(); @@ -153,6 +155,85 @@ public class Disposer implements Runnable { } } + /* + * This is a marker interface that, if implemented, means it + * doesn't acquire any special locks, and is safe to + * be disposed in the poll loop on whatever thread + * which happens to be the Toolkit thread, is in use. + */ + public static interface PollDisposable { + }; + + private static ArrayList deferredRecords = null; + + private static void clearDeferredRecords() { + if (deferredRecords == null || deferredRecords.isEmpty()) { + return; + } + for (int i=0;i(5); + } + deferredRecords.add(rec); + } + } + } catch (Exception e) { + System.out.println("Exception while removing reference: " + e); + e.printStackTrace(); + } finally { + pollingQueue = false; + } + } + private static native void initIDs(); /* From a1e00ce9347549377c76b4c1ae4cb28340134f91 Mon Sep 17 00:00:00 2001 From: Yuka Kamiya Date: Wed, 11 Nov 2009 15:38:47 +0900 Subject: [PATCH 28/36] 6899397: (tz) Support tzdata2009r Reviewed-by: okutsu --- jdk/make/sun/javazic/tzdata/VERSION | 2 +- jdk/make/sun/javazic/tzdata/antarctica | 29 ++- jdk/make/sun/javazic/tzdata/asia | 225 ++++++++++++++++-- jdk/make/sun/javazic/tzdata/australasia | 48 +++- jdk/make/sun/javazic/tzdata/europe | 36 ++- jdk/make/sun/javazic/tzdata/southamerica | 66 ++++- jdk/make/sun/javazic/tzdata/zone.tab | 1 + .../sun/util/resources/TimeZoneNames.java | 9 +- .../sun/util/resources/TimeZoneNames_de.java | 7 +- .../sun/util/resources/TimeZoneNames_es.java | 8 +- .../sun/util/resources/TimeZoneNames_fr.java | 7 +- .../sun/util/resources/TimeZoneNames_it.java | 7 +- .../sun/util/resources/TimeZoneNames_ja.java | 7 +- .../sun/util/resources/TimeZoneNames_ko.java | 7 +- .../sun/util/resources/TimeZoneNames_sv.java | 7 +- .../util/resources/TimeZoneNames_zh_CN.java | 7 +- .../util/resources/TimeZoneNames_zh_TW.java | 7 +- 17 files changed, 414 insertions(+), 66 deletions(-) diff --git a/jdk/make/sun/javazic/tzdata/VERSION b/jdk/make/sun/javazic/tzdata/VERSION index 17a8a1b2984..a5146914b90 100644 --- a/jdk/make/sun/javazic/tzdata/VERSION +++ b/jdk/make/sun/javazic/tzdata/VERSION @@ -21,4 +21,4 @@ # CA 95054 USA or visit www.sun.com if you need additional information or # have any questions. # -tzdata2009l +tzdata2009r diff --git a/jdk/make/sun/javazic/tzdata/antarctica b/jdk/make/sun/javazic/tzdata/antarctica index 31a624b0e10..c77fc899cad 100644 --- a/jdk/make/sun/javazic/tzdata/antarctica +++ b/jdk/make/sun/javazic/tzdata/antarctica @@ -102,15 +102,38 @@ Rule ChileAQ 2000 max - Mar Sun>=9 3:00u 0 - # Davis, Vestfold Hills, -6835+07759, since 1957-01-13 # (except 1964-11 - 1969-02) # Mawson, Holme Bay, -6736+06253, since 1954-02-13 + +# From Steffen Thorsen (2009-03-11): +# Three Australian stations in Antarctica have changed their time zone: +# Casey moved from UTC+8 to UTC+11 +# Davis moved from UTC+7 to UTC+5 +# Mawson moved from UTC+6 to UTC+5 +# The changes occurred on 2009-10-18 at 02:00 (local times). +# +# Government source: (Australian Antarctic Division) +# +# http://www.aad.gov.au/default.asp?casid=37079 +# +# +# We have more background information here: +# +# http://www.timeanddate.com/news/time/antarctica-new-times.html +# + # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Antarctica/Casey 0 - zzz 1969 - 8:00 - WST # Western (Aus) Standard Time + 8:00 - WST 2009 Oct 18 2:00 + # Western (Aus) Standard Time + 11:00 - CAST # Casey Time Zone Antarctica/Davis 0 - zzz 1957 Jan 13 7:00 - DAVT 1964 Nov # Davis Time 0 - zzz 1969 Feb - 7:00 - DAVT + 7:00 - DAVT 2009 Oct 18 2:0 + 5:00 - DAVT Zone Antarctica/Mawson 0 - zzz 1954 Feb 13 - 6:00 - MAWT # Mawson Time + 6:00 - MAWT 2009 Oct 18 2:00 + # Mawson Time + 5:00 - MAWT # References: # # Casey Weather (1998-02-26) diff --git a/jdk/make/sun/javazic/tzdata/asia b/jdk/make/sun/javazic/tzdata/asia index 81534b919a4..139df5ee0e1 100644 --- a/jdk/make/sun/javazic/tzdata/asia +++ b/jdk/make/sun/javazic/tzdata/asia @@ -21,7 +21,6 @@ # CA 95054 USA or visit www.sun.com if you need additional information or # have any questions. # -#
 # This file is in the public domain, so clarified as of
 # 2009-05-17 by Arthur David Olson.
 
@@ -194,11 +193,30 @@ Zone	Asia/Bahrain	3:22:20 -	LMT	1920		# Al Manamah
 #
 # No DST end date has been announced yet.
 
-# From Arthur David Olson (2009-07-11):
-# Arbitrarily end DST at the end of 2009 so that a POSIX-sytle time zone string
-# can appear in the Dhaka binary file and for the benefit of old glibc
-# reimplementations of the time zone software that mishandle permanent DST.
-# A change will be required once the end date is known.
+# From Alexander Krivenyshev (2009-09-25):
+# Bangladesh won't go back to Standard Time from October 1, 2009, 
+# instead it will continue DST measure till the cabinet makes a fresh decision. 
+#
+# Following report by same newspaper-"The Daily Star Friday":
+# "DST change awaits cabinet decision-Clock won't go back by 1-hr from Oct 1"
+# 
+# http://www.thedailystar.net/newDesign/news-details.php?nid=107021
+# 
+# or
+# 
+# http://www.worldtimezone.com/dst_news/dst_news_bangladesh04.html
+# 
+
+# From Steffen Thorsen (2009-10-13):
+# IANS (Indo-Asian News Service) now reports:
+# Bangladesh has decided that the clock advanced by an hour to make 
+# maximum use of daylight hours as an energy saving measure would 
+# "continue for an indefinite period."
+#
+# One of many places where it is published:
+# 
+# http://www.thaindian.com/newsportal/business/bangladesh-to-continue-indefinitely-with-advanced-time_100259987.html
+# 
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Asia/Dhaka	6:01:40 -	LMT	1890
@@ -208,8 +226,7 @@ Zone	Asia/Dhaka	6:01:40 -	LMT	1890
 			6:30	-	BURT	1951 Sep 30
 			6:00	-	DACT	1971 Mar 26 # Dacca Time
 			6:00	-	BDT	2009 Jun 19 23:00 # Bangladesh Time
-			6:00	1:00	BDST	2010
-			6:00	-	BDT
+			6:00	1:00	BDST
 
 # Bhutan
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
@@ -373,14 +390,84 @@ Zone	Asia/Kashgar	5:03:56	-	LMT	1928 # or Kashi or Kaxgar
 			5:00	-	KAST	1980 May
 			8:00	PRC	C%sT
 
+
+# From Lee Yiu Chung (2009-10-24):
+# I found there are some mistakes for the historial DST rule for Hong
+# Kong. Accoring to the DST record from Hong Kong Observatory (actually,
+# it is not [an] observatory, but the official meteorological agency of HK,
+# and also serves as the official timing agency), there are some missing
+# and incorrect rules. Although the exact switch over time is missing, I
+# think 3:30 is correct. The official DST record for Hong Kong can be
+# obtained from
+# 
+# http://www.hko.gov.hk/gts/time/Summertime.htm
+# .
+
+# From Arthur David Olson (2009-10-28):
+# Here are the dates given at
+# 
+# http://www.hko.gov.hk/gts/time/Summertime.htm
+# 
+# as of 2009-10-28:
+# Year        Period
+# 1941        1 Apr to 30 Sep
+# 1942        Whole year 
+# 1943        Whole year
+# 1944        Whole year
+# 1945        Whole year
+# 1946        20 Apr to 1 Dec
+# 1947        13 Apr to 30 Dec
+# 1948        2 May to 31 Oct
+# 1949        3 Apr to 30 Oct
+# 1950        2 Apr to 29 Oct
+# 1951        1 Apr to 28 Oct
+# 1952        6 Apr to 25 Oct
+# 1953        5 Apr to 1 Nov
+# 1954        21 Mar to 31 Oct
+# 1955        20 Mar to 6 Nov
+# 1956        18 Mar to 4 Nov
+# 1957        24 Mar to 3 Nov
+# 1958        23 Mar to 2 Nov
+# 1959        22 Mar to 1 Nov
+# 1960        20 Mar to 6 Nov
+# 1961        19 Mar to 5 Nov
+# 1962        18 Mar to 4 Nov
+# 1963        24 Mar to 3 Nov
+# 1964        22 Mar to 1 Nov
+# 1965        18 Apr to 17 Oct
+# 1966        17 Apr to 16 Oct
+# 1967        16 Apr to 22 Oct
+# 1968        21 Apr to 20 Oct
+# 1969        20 Apr to 19 Oct
+# 1970        19 Apr to 18 Oct
+# 1971        18 Apr to 17 Oct
+# 1972        16 Apr to 22 Oct
+# 1973        22 Apr to 21 Oct
+# 1973/74     30 Dec 73 to 20 Oct 74
+# 1975        20 Apr to 19 Oct
+# 1976        18 Apr to 17 Oct
+# 1977        Nil
+# 1978        Nil
+# 1979        13 May to 21 Oct
+# 1980 to Now Nil
+# The page does not give start or end times of day.
+# The page does not give a start date for 1942.
+# The page does not givw an end date for 1945.
+# The Japanese occupation of Hong Kong began on 1941-12-25.
+# The Japanese surrender of Hong Kong was signed 1945-09-15.
+# For lack of anything better, use start of those days as the transition times.
+
 # Hong Kong (Xianggang)
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
+Rule	HK	1941	only	-	Apr	1	3:30	1:00	S
+Rule	HK	1941	only	-	Sep	30	3:30	0	-
 Rule	HK	1946	only	-	Apr	20	3:30	1:00	S
 Rule	HK	1946	only	-	Dec	1	3:30	0	-
 Rule	HK	1947	only	-	Apr	13	3:30	1:00	S
 Rule	HK	1947	only	-	Dec	30	3:30	0	-
 Rule	HK	1948	only	-	May	2	3:30	1:00	S
-Rule	HK	1948	1952	-	Oct	lastSun	3:30	0	-
+Rule	HK	1948	1951	-	Oct	lastSun	3:30	0	-
+Rule	HK	1952	only	-	Oct	25	3:30	0	-
 Rule	HK	1949	1953	-	Apr	Sun>=1	3:30	1:00	S
 Rule	HK	1953	only	-	Nov	1	3:30	0	-
 Rule	HK	1954	1964	-	Mar	Sun>=18	3:30	1:00	S
@@ -388,13 +475,15 @@ Rule	HK	1954	only	-	Oct	31	3:30	0	-
 Rule	HK	1955	1964	-	Nov	Sun>=1	3:30	0	-
 Rule	HK	1965	1977	-	Apr	Sun>=16	3:30	1:00	S
 Rule	HK	1965	1977	-	Oct	Sun>=16	3:30	0	-
-Rule	HK	1979	1980	-	May	Sun>=8	3:30	1:00	S
-Rule	HK	1979	1980	-	Oct	Sun>=16	3:30	0	-
+Rule	HK	1973	only	-	Dec	30	3:30	1:00	S
+Rule	HK	1979	only	-	May	Sun>=8	3:30	1:00	S
+Rule	HK	1979	only	-	Oct	Sun>=16	3:30	0	-
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Asia/Hong_Kong	7:36:36 -	LMT	1904 Oct 30
+			8:00	HK	HK%sT	1941 Dec 25
+			9:00	-	JST	1945 Sep 15
 			8:00	HK	HK%sT
 
-
 ###############################################################################
 
 # Taiwan
@@ -1696,16 +1785,66 @@ Zone	Asia/Muscat	3:54:20 -	LMT	1920
 # advance clocks in the country by one hour from April 15 to
 # conserve energy"
 
-# From Arthur David Olson (2009-04-10):
-# Assume for now that Pakistan will end DST in 2009 as it did in 2008.
+# From Steffen Thorsen (2009-09-17):
+# "The News International," Pakistan reports that: "The Federal
+# Government has decided to restore the previous time by moving the
+# clocks backward by one hour from October 1. A formal announcement to
+# this effect will be made after the Prime Minister grants approval in
+# this regard." 
+# 
+# http://www.thenews.com.pk/updates.asp?id=87168
+# 
+
+# From Alexander Krivenyshev (2009-09-28):
+# According to Associated Press Of Pakistan, it is confirmed that
+# Pakistan clocks across the country would be turned back by an hour from October
+# 1, 2009.
+#
+# "Clocks to go back one hour from 1 Oct"
+# 
+# http://www.app.com.pk/en_/index.php?option=com_content&task=view&id=86715&Itemid=2
+# 
+# or
+# 
+# http://www.worldtimezone.com/dst_news/dst_news_pakistan07.htm
+# 
+
+# From Steffen Thorsen (2009-09-29):
+# Alexander Krivenyshev wrote:
+# > According to Associated Press Of Pakistan, it is confirmed that
+# > Pakistan clocks across the country would be turned back by an hour from October
+# > 1, 2009.
+#
+# Now they seem to have changed their mind, November 1 is the new date:
+# 
+# http://www.thenews.com.pk/top_story_detail.asp?Id=24742
+# 
+# "The country's clocks will be reversed by one hour on November 1.
+# Officials of Federal Ministry for Interior told this to Geo News on
+# Monday."
+#
+# And more importantly, it seems that these dates will be kept every year:
+# "It has now been decided that clocks will be wound forward by one hour
+# on April 15 and reversed by an hour on November 1 every year without
+# obtaining prior approval, the officials added."
+#
+# We have confirmed this year's end date with both with the Ministry of
+# Water and Power and the Pakistan Electric Power Company:
+# 
+# http://www.timeanddate.com/news/time/pakistan-ends-dst09.html
+# 
+
+# From Christoph Goehre (2009-10-01):
+# [T]he German Consulate General in Karachi reported me today that Pakistan
+# will go back to standard time on 1st of November.
 
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
 Rule Pakistan	2002	only	-	Apr	Sun>=2	0:01	1:00	S
 Rule Pakistan	2002	only	-	Oct	Sun>=2	0:01	0	-
 Rule Pakistan	2008	only	-	Jun	1	0:00	1:00	S
 Rule Pakistan	2008	only	-	Nov	1	0:00	0	-
-Rule Pakistan	2009	only	-	Apr	15	0:00	1:00	S
-Rule Pakistan	2009	only	-	Nov	1	0:00	0	-
+Rule Pakistan	2009	max	-	Apr	15	0:00	1:00	S
+Rule Pakistan	2009	max	-	Nov	1	0:00	0	-
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Asia/Karachi	4:28:12 -	LMT	1907
 			5:30	-	IST	1942 Sep
@@ -1858,6 +1997,42 @@ Zone	Asia/Karachi	4:28:12 -	LMT	1907
 # http://www.worldtimezone.com/dst_news/dst_news_westbank01.html
 # 
 
+# From Steffen Thorsen (2009-08-31):
+# Palestine's Council of Ministers announced that they will revert back to
+# winter time on Friday, 2009-09-04.
+#
+# One news source:
+# 
+# http://www.safa.ps/ara/?action=showdetail&seid=4158
+# 
+# (Palestinian press agency, Arabic),
+# Google translate: "Decided that the Palestinian government in Ramallah
+# headed by Salam Fayyad, the start of work in time for the winter of
+# 2009, starting on Friday approved the fourth delay Sept. clock sixty
+# minutes per hour as of Friday morning."
+#
+# We are not sure if Gaza will do the same, last year they had a different
+# end date, we will keep this page updated:
+# 
+# http://www.timeanddate.com/news/time/westbank-gaza-dst-2009.html
+# 
+
+# From Alexander Krivenyshev (2009-09-02):
+# Seems that Gaza Strip will go back to Winter Time same date as West Bank.
+#
+# According to Palestinian Ministry Of Interior, West Bank and Gaza Strip plan
+# to change time back to Standard time on September 4, 2009.
+#
+# "Winter time unite the West Bank and Gaza"
+# (from Palestinian National Authority):
+# 
+# http://www.worldtimezone.com/dst_news/dst_news_gazastrip02.html
+# 
+
 # The rules for Egypt are stolen from the `africa' file.
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
 Rule EgyptAsia	1957	only	-	May	10	0:00	1:00	S
@@ -1876,7 +2051,7 @@ Rule Palestine	2006	only	-	Sep	22	0:00	0	-
 Rule Palestine	2007	only	-	Sep	Thu>=8	2:00	0	-
 Rule Palestine	2008	only	-	Aug	lastFri	2:00	0	-
 Rule Palestine	2009	max	-	Mar	lastFri	0:00	1:00	S
-Rule Palestine	2009	max	-	Sep	lastMon	2:00	0	-
+Rule Palestine	2009	max	-	Sep	Fri>=1	2:00	0	-
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Asia/Gaza	2:17:52	-	LMT	1900 Oct
@@ -2154,9 +2329,23 @@ Rule	Syria	2007	only	-	Nov	 Fri>=1	0:00	0	-
 # http://www.timeanddate.com/news/time/syria-dst-starts-march-27-2009.html
 # 
 
+# From Steffen Thorsen (2009-10-27):
+# The Syrian Arab News Network on 2009-09-29 reported that Syria will 
+# revert back to winter (standard) time on midnight between Thursday 
+# 2009-10-29 and Friday 2009-10-30:
+# 
+# http://www.sana.sy/ara/2/2009/09/29/247012.htm (Arabic)
+# 
+
+# From Arthur David Olson (2009-10-28):
+# We'll see if future DST switching times turn out to be end of the last
+# Thursday of the month or the start of the last Friday of the month or
+# something else. For now, use the start of the last Friday.
+
 Rule	Syria	2008	only	-	Apr	Fri>=1	0:00	1:00	S
-Rule	Syria	2008	max	-	Nov	1	0:00	0	-
+Rule	Syria	2008	only	-	Nov	1	0:00	0	-
 Rule	Syria	2009	max	-	Mar	lastFri	0:00	1:00	S
+Rule	Syria	2009	max	-	Oct	lastFri	0:00	0	-
 
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Asia/Damascus	2:25:12 -	LMT	1920	# Dimashq
diff --git a/jdk/make/sun/javazic/tzdata/australasia b/jdk/make/sun/javazic/tzdata/australasia
index 8e336dcea30..d9150b5ffd5 100644
--- a/jdk/make/sun/javazic/tzdata/australasia
+++ b/jdk/make/sun/javazic/tzdata/australasia
@@ -465,10 +465,56 @@ Zone Pacific/Pago_Pago	 12:37:12 -	LMT	1879 Jul  5
 # http://www.worldtimezone.com/dst_news/dst_news_samoa01.html
 # 
 
+# From Steffen Thorsen (2009-08-27):
+# Samoa's parliament passed the Daylight Saving Bill 2009, and will start 
+# daylight saving time on the first Sunday of October 2009 and end on the 
+# last Sunday of March 2010. We hope that the full text will be published 
+# soon, but we believe that the bill is only valid for 2009-2010. Samoa's 
+# Daylight Saving Act 2009 will be enforced as soon as the Head of State 
+# executes a proclamation publicizing this Act.
+#
+# Some background information here, which will be updated once we have 
+# more details:
+# 
+# http://www.timeanddate.com/news/time/samoa-dst-plan-2009.html
+# 
+
+# From Alexander Krivenyshev (2009-10-03):
+# First, my deepest condolences to people of Samoa islands and all families and
+# loved ones around the world who lost their lives in the earthquake and tsunami.
+#
+# Considering the recent devastation on Samoa by earthquake and tsunami and that
+# many government offices/ ministers are closed- not sure if "Daylight Saving
+# Bill 2009" will be implemented in next few days- on October 4, 2009.
+#
+# Here is reply from Consulate-General of Samoa in New Zealand
+# ---------------------------
+# Consul General
+# consulgeneral@samoaconsulate.org.nz
+#
+# Talofa Alexander,
+#
+# Thank you for your sympathy for our country but at this time we have not
+# been informed about the Daylight Savings Time Change.  Most Ministries in
+# Apia are closed or relocating due to weather concerns.
+#
+# When we do find out if they are still proceeding with the time change we
+# will advise you soonest.
+#
+# Kind Regards,
+# Lana
+# for: Consul General
+
+# From Steffen Thorsen (2009-10-05):
+# We have called a hotel in Samoa and asked about local time there - they 
+# are still on standard time.
+
 Zone Pacific/Apia	 12:33:04 -	LMT	1879 Jul  5
 			-11:26:56 -	LMT	1911
 			-11:30	-	SAMT	1950		# Samoa Time
-			-11:00	-	WST			# Samoa Time
+			-11:00	-	WST	2009 Oct 4
+			-11:00	1:00	WSDT	2010 Mar 28
+			-11:00	-	WST
 
 # Solomon Is
 # excludes Bougainville, for which see Papua New Guinea
diff --git a/jdk/make/sun/javazic/tzdata/europe b/jdk/make/sun/javazic/tzdata/europe
index 16dbe0ee500..d7fffc23c7e 100644
--- a/jdk/make/sun/javazic/tzdata/europe
+++ b/jdk/make/sun/javazic/tzdata/europe
@@ -2094,9 +2094,43 @@ Zone Asia/Novosibirsk	 5:31:40 -	LMT	1919 Dec 14 6:00
 			 6:00	Russia	NOV%sT	1992 Jan 19 2:00s
 			 7:00	Russia	NOV%sT	1993 May 23 # say Shanks & P.
 			 6:00	Russia	NOV%sT
+
+# From Alexander Krivenyshev (2009-10-13):
+# Kemerovo oblast' (Kemerovo region) in Russia will change current time zone on
+# March 28, 2010:
+# from current Russia Zone 6 - Krasnoyarsk Time Zone (KRA) UTC +0700
+# to Russia Zone 5 - Novosibirsk Time Zone (NOV) UTC +0600
+#
+# This is according to Government of Russia decree # 740, on September
+# 14, 2009 "Application in the territory of the Kemerovo region the Fifth
+# time zone." ("Russia Zone 5" or old "USSR Zone 5" is GMT +0600)
+#
+# Russian Government web site (Russian language)
+# 
+# http://www.government.ru/content/governmentactivity/rfgovernmentdecisions/archive/2009/09/14/991633.htm
+# 
+# or Russian-English translation by WorldTimeZone.com with reference
+# map to local region and new Russia Time Zone map after March 28, 2010
+# 
+# http://www.worldtimezone.com/dst_news/dst_news_russia03.html
+# 
+#
+# Thus, when Russia will switch to DST on the night of March 28, 2010
+# Kemerovo region (Kemerovo oblast') will not change the clock.
+#
+# As a result, Kemerovo oblast' will be in the same time zone as
+# Novosibirsk, Omsk, Tomsk, Barnaul and Altai Republic.
+
+Zone Asia/Novokuznetsk	 5:48:48 -	NMT	1920 Jan  6
+			 6:00	-	KRAT	1930 Jun 21 # Krasnoyarsk Time
+			 7:00	Russia	KRA%sT	1991 Mar 31 2:00s
+			 6:00	Russia	KRA%sT	1992 Jan 19 2:00s
+			 7:00	Russia	KRA%sT	2010 Mar 28 2:00s
+			 6:00	Russia	NOV%sT # Novosibirsk/Novokuznetsk Time
+
 #
 # From Oscar van Vlijmen (2001-08-25): [This region consists of]
-# Kemerovskaya oblast', Krasnoyarskij kraj,
+# Krasnoyarskij kraj,
 # Tajmyrskij (Dolgano-Nenetskij) avtonomnyj okrug,
 # Respublika Tuva, Respublika Khakasiya, Evenkijskij avtonomnyj okrug.
 Zone Asia/Krasnoyarsk	 6:11:20 -	LMT	1920 Jan  6
diff --git a/jdk/make/sun/javazic/tzdata/southamerica b/jdk/make/sun/javazic/tzdata/southamerica
index c886a28b126..693fec63423 100644
--- a/jdk/make/sun/javazic/tzdata/southamerica
+++ b/jdk/make/sun/javazic/tzdata/southamerica
@@ -237,9 +237,23 @@ Rule	Arg	2000	only	-	Mar	3	0:00	0	-
 # http://www.jujuy.gov.ar/index2/partes_prensa/18_10_08/235-181008.doc
 # 
 
+# From fullinet (2009-10-18):
+# As announced in
+# 
+# http://www.argentina.gob.ar/argentina/portal/paginas.dhtml?pagina=356
+# 
+# (an official .gob.ar) under title: "Sin Cambio de Hora" (english: "No hour change")
+#
+# "Por el momento, el Gobierno Nacional resolvio no modificar la hora
+# oficial, decision que estaba en estudio para su implementacion el
+# domingo 18 de octubre. Desde el Ministerio de Planificacion se anuncio
+# que la Argentina hoy, en estas condiciones meteorologicas, no necesita
+# la modificacion del huso horario, ya que 2009 nos encuentra con
+# crecimiento en la produccion y distribucion energetica."
+
 Rule	Arg	2007	only	-	Dec	30	0:00	1:00	S
-Rule	Arg	2008	max	-	Mar	Sun>=15	0:00	0	-
-Rule	Arg	2008	max	-	Oct	Sun>=15	0:00	1:00	S
+Rule	Arg	2008	2009	-	Mar	Sun>=15	0:00	0	-
+Rule	Arg	2008	only	-	Oct	Sun>=15	0:00	1:00	S
  
 # From Mariano Absatz (2004-05-21):
 # Today it was officially published that the Province of Mendoza is changing
@@ -411,15 +425,40 @@ Rule	Arg	2008	max	-	Oct	Sun>=15	0:00	1:00	S
 # during 2009, this timezone change will run from 00:00 the third Sunday
 # in March until 24:00 of the second Saturday in October.
 
-# From Arthur David Olson (2009-03-16):
-# The unofficial claim at
-# 
-# http://www.timeanddate.com/news/time/san-luis-new-time-zone.html
-# 
-# is that "The province will most likely follow the next daylight saving schedule,
-# which is planned for the second Sunday in October."
-
+# From Mariano Absatz (2009-10-16):
+# ...the Province of San Luis is a case in itself.
 #
+# The Law at
+# 
+# is ambiguous because establishes a calendar from the 2nd Sunday in
+# October at 0:00 thru the 2nd Saturday in March at 24:00 and the
+# complement of that starting on the 2nd Sunday of March at 0:00 and
+# ending on the 2nd Saturday of March at 24:00.
+#
+# This clearly breaks every time the 1st of March or October is a Sunday.
+#
+# IMHO, the "spirit of the Law" is to make the changes at 0:00 on the 2nd
+# Sunday of October and March.
+#
+# The problem is that the changes in the rest of the Provinces that did
+# change in 2007/2008, were made according to the Federal Law and Decrees
+# that did so on the 3rd Sunday of October and March.
+#
+# In fact, San Luis actually switched from UTC-4 to UTC-3 last Sunday
+# (October 11th) at 0:00.
+#
+# So I guess a new set of rules, besides "Arg", must be made and the last
+# America/Argentina/San_Luis entries should change to use these...
+#
+# I'm enclosing a patch that does what I say... regretfully, the San Luis
+# timezone must be called "WART/WARST" even when most of the time (like,
+# right now) WARST == ART... that is, since last Sunday, all the country
+# is using UTC-3, but in my patch, San Luis calls it "WARST" and the rest
+# of the country calls it "ART".
+# ...
+
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 #
 # Buenos Aires (BA), Capital Federal (CF),
@@ -552,6 +591,10 @@ Zone America/Argentina/Mendoza -4:35:16 - LMT	1894 Oct 31
 			-3:00	-	ART
 #
 # San Luis (SL)
+
+Rule	SanLuis	2008	max	-	Mar	Sun>=8	0:00	0	-
+Rule	SanLuis	2007	max	-	Oct	Sun>=8	0:00	1:00	S
+
 Zone America/Argentina/San_Luis -4:25:24 - LMT	1894 Oct 31
 			-4:16:48 -	CMT	1920 May
 			-4:00	-	ART	1930 Dec
@@ -566,8 +609,7 @@ Zone America/Argentina/San_Luis -4:25:24 - LMT	1894 Oct 31
 			-3:00	-	ART	2004 May 31
 			-4:00	-	WART	2004 Jul 25
 			-3:00	Arg	AR%sT	2008 Jan 21
-			-3:00	-	ART	2009 Mar 15
-			-4:00	Arg	WAR%sT
+			-4:00	SanLuis	WAR%sT
 #
 # Santa Cruz (SC)
 Zone America/Argentina/Rio_Gallegos -4:36:52 - LMT 1894 Oct 31
diff --git a/jdk/make/sun/javazic/tzdata/zone.tab b/jdk/make/sun/javazic/tzdata/zone.tab
index 2a323ebb90e..3e6f4657739 100644
--- a/jdk/make/sun/javazic/tzdata/zone.tab
+++ b/jdk/make/sun/javazic/tzdata/zone.tab
@@ -352,6 +352,7 @@ RU	+5312+05009	Europe/Samara	Moscow+01 - Samara, Udmurtia
 RU	+5651+06036	Asia/Yekaterinburg	Moscow+02 - Urals
 RU	+5500+07324	Asia/Omsk	Moscow+03 - west Siberia
 RU	+5502+08255	Asia/Novosibirsk	Moscow+03 - Novosibirsk
+RU	+5345+08707	Asia/Novokuznetsk	Moscow+03 - Novokuznetsk
 RU	+5601+09250	Asia/Krasnoyarsk	Moscow+04 - Yenisei River
 RU	+5216+10420	Asia/Irkutsk	Moscow+05 - Lake Baikal
 RU	+6200+12940	Asia/Yakutsk	Moscow+06 - Lena River
diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames.java
index 7f2c570ccea..ef9dfdc8c5a 100644
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames.java
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames.java
@@ -141,6 +141,8 @@ public final class TimeZoneNames extends TimeZoneNamesBundle {
                                      "Malaysia Summer Time", "MYST"};
         String NORONHA[] = new String[] {"Fernando de Noronha Time", "FNT",
                                          "Fernando de Noronha Summer Time", "FNST"};
+        String NOVT[] = new String[] {"Novosibirsk Time", "NOVT",
+                                      "Novosibirsk Summer Time", "NOVST"};
         String NPT[] = new String[] {"Nepal Time", "NPT",
                                      "Nepal Summer Time", "NPST"};
         String NST[] = new String[] {"Newfoundland Standard Time", "NST",
@@ -441,7 +443,8 @@ public final class TimeZoneNames extends TimeZoneNamesBundle {
             {"America/Winnipeg", CST},
             {"America/Yakutat", AKST},
             {"America/Yellowknife", MST},
-            {"Antarctica/Casey", WST_AUS},
+            {"Antarctica/Casey", new String[] {"Casey Time", "CAST",
+                                               "Casey Summer Time", "CAST"}},
             {"Antarctica/Davis", new String[] {"Davis Time", "DAVT",
                                                "Davis Summer Time", "DAVST"}},
             {"Antarctica/DumontDUrville", new String[] {"Dumont-d'Urville Time", "DDUT",
@@ -529,8 +532,8 @@ public final class TimeZoneNames extends TimeZoneNamesBundle {
                                           "Philippines Summer Time", "PHST"}},
             {"Asia/Muscat", GST},
             {"Asia/Nicosia", EET},
-            {"Asia/Novosibirsk", new String[] {"Novosibirsk Time", "NOVT",
-                                               "Novosibirsk Summer Time", "NOVST"}},
+            {"Asia/Novokuznetsk", NOVT},
+            {"Asia/Novosibirsk", NOVT},
             {"Asia/Oral", new String[] {"Oral Time", "ORAT",
                                         "Oral Summer Time", "ORAST"}},
             {"Asia/Omsk", new String[] {"Omsk Time", "OMST",
diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_de.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_de.java
index 7ff10f89df5..896d72a5c53 100644
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_de.java
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_de.java
@@ -141,6 +141,8 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle {
                                      "Malaysische Sommerzeit", "MYST"};
         String NORONHA[] = new String[] {"Fernando de Noronha Zeit", "FNT",
                                          "Fernando de Noronha Sommerzeit", "FNST"};
+        String NOVT[] = new String[] {"Nowosibirsker Zeit", "NOVT",
+                                      "Nowosibirsker Sommerzeit", "NOVST"};
         String NPT[] = new String[] {"Nepalesische Zeit", "NPT",
                                      "Nepalesische Sommerzeit", "NPST"};
         String NST[] = new String[] {"Neufundland Normalzeit", "NST",
@@ -441,7 +443,6 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle {
             {"America/Winnipeg", CST},
             {"America/Yakutat", AKST},
             {"America/Yellowknife", MST},
-            {"Antarctica/Casey", WST_AUS},
             {"Antarctica/Davis", new String[] {"Davis Zeit", "DAVT",
                                                "Davis Sommerzeit", "DAVST"}},
             {"Antarctica/DumontDUrville", new String[] {"Dumont-d'Urville Zeit", "DDUT",
@@ -529,8 +530,8 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle {
                                           "Philippinische Sommerzeit", "PHST"}},
             {"Asia/Muscat", GST},
             {"Asia/Nicosia", EET},
-            {"Asia/Novosibirsk", new String[] {"Nowosibirsker Zeit", "NOVT",
-                                               "Nowosibirsker Sommerzeit", "NOVST"}},
+            {"Asia/Novokuznetsk", NOVT},
+            {"Asia/Novosibirsk", NOVT},
             {"Asia/Oral", new String[] {"Oral Zeit", "ORAT",
                                         "Oral Sommerzeit", "ORAST"}},
             {"Asia/Omsk", new String[] {"Omsk Zeit", "OMST",
diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_es.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_es.java
index 9e1ffa8397c..20605d1187a 100644
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_es.java
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_es.java
@@ -141,6 +141,8 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle {
                                      "Hora de verano de Malasia", "MYST"};
         String NORONHA[] = new String[] {"Hora de Fernando de Noronha", "FNT",
                                          "Hora de verano de Fernando de Noronha", "FNST"};
+        String NOVT[] = new String[] {"Hora de Novosibirsk", "NOVT",
+                                      "Hora de verano de Novosibirsk", "NOVST"};
         String NPT[] = new String[] {"Hora de Nepal", "NPT",
                                      "Hora de verano de Nepal", "NPST"};
         String NST[] = new String[] {"Hora est\u00e1ndar de Terranova", "NST",
@@ -441,7 +443,6 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle {
             {"America/Winnipeg", CST},
             {"America/Yakutat", AKST},
             {"America/Yellowknife", MST},
-            {"Antarctica/Casey", WST_AUS},
             {"Antarctica/Davis", new String[] {"Hora de Davis", "DAVT",
                                                "Hora de verano de Davis", "DAVST"}},
             {"Antarctica/DumontDUrville", new String[] {"Hora de Dumont-d'Urville", "DDUT",
@@ -529,8 +530,9 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle {
                                           "Hora de verano de Filipinas", "PHST"}},
             {"Asia/Muscat", GST},
             {"Asia/Nicosia", EET},
-            {"Asia/Novosibirsk", new String[] {"Hora de Novosibirsk", "NOVT",
-                                               "Hora de verano de Novosibirsk", "NOVST"}},
+
+            {"Asia/Novokuznetsk", NOVT},
+            {"Asia/Novosibirsk", NOVT},
             {"Asia/Oral", new String[] {"Hora de Uralsk", "ORAT",
                                         "Hora de verano de Uralsk", "ORAST"}},
             {"Asia/Omsk", new String[] {"Hora de Omsk", "OMST",
diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_fr.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_fr.java
index 941bc4e972a..e3f8205584a 100644
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_fr.java
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_fr.java
@@ -141,6 +141,8 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle {
                                      "Heure d'\u00e9t\u00e9 de Malaisie", "MYST"};
         String NORONHA[] = new String[] {"Heure de Fernando de Noronha", "FNT",
                                          "Heure d'\u00e9t\u00e9 de Fernando de Noronha", "FNST"};
+        String NOVT[] = new String[] {"Heure de Novossibirsk", "NOVT",
+                                      "Heure d'\u00e9t\u00e9 de Novossibirsk", "NOVST"};
         String NPT[] = new String[] {"Heure du N\u00e9pal", "NPT",
                                      "Heure d'\u00e9t\u00e9 du N\u00e9pal", "NPST"};
         String NST[] = new String[] {"Heure normale de Terre-Neuve", "NST",
@@ -441,7 +443,6 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle {
             {"America/Winnipeg", CST},
             {"America/Yakutat", AKST},
             {"America/Yellowknife", MST},
-            {"Antarctica/Casey", WST_AUS},
             {"Antarctica/Davis", new String[] {"Heure de Davis", "DAVT",
                                                "Heure d'\u00e9t\u00e9 de Davis", "DAVST"}},
             {"Antarctica/DumontDUrville", new String[] {"Heure de Dumont-d'Urville", "DDUT",
@@ -529,8 +530,8 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle {
                                           "Heure d'\u00e9t\u00e9 des Philippines", "PHST"}},
             {"Asia/Muscat", GST},
             {"Asia/Nicosia", EET},
-            {"Asia/Novosibirsk", new String[] {"Heure de Novossibirsk", "NOVT",
-                                               "Heure d'\u00e9t\u00e9 de Novossibirsk", "NOVST"}},
+            {"Asia/Novokuznetsk", NOVT},
+            {"Asia/Novosibirsk", NOVT},
             {"Asia/Oral", new String[] {"Heure d'Oral", "ORAT",
                                         "Heure d'\u00e9t\u00e9 d'Oral", "ORAST"}},
             {"Asia/Omsk", new String[] {"Heure d'Omsk", "OMST",
diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_it.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_it.java
index 499f0fe2d95..e464618f2af 100644
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_it.java
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_it.java
@@ -141,6 +141,8 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle {
                                      "Ora estiva della Malaysia", "MYST"};
         String NORONHA[] = new String[] {"Ora di Fernando de Noronha", "FNT",
                                          "Ora estiva di Fernando de Noronha", "FNST"};
+        String NOVT[] = new String[] {"Ora di Novosibirsk", "NOVT",
+                                      "Ora estiva di Novosibirsk", "NOVST"};
         String NPT[] = new String[] {"Ora del Nepal", "NPT",
                                      "Ora estiva del Nepal", "NPST"};
         String NST[] = new String[] {"Ora solare di Terranova", "NST",
@@ -441,7 +443,6 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle {
             {"America/Winnipeg", CST},
             {"America/Yakutat", AKST},
             {"America/Yellowknife", MST},
-            {"Antarctica/Casey", WST_AUS},
             {"Antarctica/Davis", new String[] {"Ora di Davis", "DAVT",
                                                "Ora estiva di Davis", "DAVST"}},
             {"Antarctica/DumontDUrville", new String[] {"Ora di Dumont-d'Urville", "DDUT",
@@ -529,8 +530,8 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle {
                                           "Ora estiva delle Filippine", "PHST"}},
             {"Asia/Muscat", GST},
             {"Asia/Nicosia", EET},
-            {"Asia/Novosibirsk", new String[] {"Ora di Novosibirsk", "NOVT",
-                                               "Ora estiva di Novosibirsk", "NOVST"}},
+            {"Asia/Novokuznetsk", NOVT},
+            {"Asia/Novosibirsk", NOVT},
             {"Asia/Oral", new String[] {"Ora di Oral", "ORAT",
                                         "Ora estiva di Oral", "ORAST"}},
             {"Asia/Omsk", new String[] {"Ora di Omsk", "OMST",
diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ja.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ja.java
index 583a0a4e1c8..1292e4b8045 100644
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ja.java
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ja.java
@@ -141,6 +141,8 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle {
                                      "\u30de\u30ec\u30fc\u30b7\u30a2\u590f\u6642\u9593", "MYST"};
         String NORONHA[] = new String[] {"\u30d5\u30a7\u30eb\u30ca\u30f3\u30c9\u30fb\u30c7\u30fb\u30ce\u30ed\u30fc\u30cb\u30e3\u6642\u9593", "FNT",
                                          "\u30d5\u30a7\u30eb\u30ca\u30f3\u30c9\u30fb\u30c7\u30fb\u30ce\u30ed\u30fc\u30cb\u30e3\u590f\u6642\u9593", "FNST"};
+        String NOVT[] = new String[] {"\u30ce\u30dc\u30b7\u30d3\u30eb\u30b9\u30af\u6642\u9593", "NOVT",
+                                      "\u30ce\u30dc\u30b7\u30d3\u30eb\u30b9\u30af\u590f\u6642\u9593", "NOVST"};
         String NPT[] = new String[] {"\u30cd\u30d1\u30fc\u30eb\u6642\u9593", "NPT",
                                       "\u30cd\u30d1\u30fc\u30eb\u590f\u6642\u9593", "NPST"};
         String NST[] = new String[] {"\u30cb\u30e5\u30fc\u30d5\u30a1\u30f3\u30c9\u30e9\u30f3\u30c9\u6a19\u6e96\u6642", "NST",
@@ -441,7 +443,6 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle {
             {"America/Winnipeg", CST},
             {"America/Yakutat", AKST},
             {"America/Yellowknife", MST},
-            {"Antarctica/Casey", WST_AUS},
             {"Antarctica/Davis", new String[] {"\u30c7\u30a4\u30d3\u30b9\u6642\u9593", "DAVT",
                                                "\u30c7\u30a4\u30d3\u30b9\u590f\u6642\u9593", "DAVST"}},
             {"Antarctica/DumontDUrville", new String[] {"\u30c7\u30e5\u30e2\u30f3\u30c7\u30e5\u30eb\u30f4\u30a3\u30eb\u6642\u9593", "DDUT",
@@ -529,8 +530,8 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle {
                                           "\u30d5\u30a3\u30ea\u30d4\u30f3\u590f\u6642\u9593", "PHST"}},
             {"Asia/Muscat", GST},
             {"Asia/Nicosia", EET},
-            {"Asia/Novosibirsk", new String[] {"\u30ce\u30dc\u30b7\u30d3\u30eb\u30b9\u30af\u6642\u9593", "NOVT",
-                                               "\u30ce\u30dc\u30b7\u30d3\u30eb\u30b9\u30af\u590f\u6642\u9593", "NOVST"}},
+            {"Asia/Novokuznetsk", NOVT},
+            {"Asia/Novosibirsk", NOVT},
             {"Asia/Oral", new String[] {"\u30aa\u30e9\u30eb\u6642\u9593", "ORAT",
                                         "\u30aa\u30e9\u30eb\u590f\u6642\u9593", "ORAST"}},
             {"Asia/Omsk", new String[] {"\u30aa\u30e0\u30b9\u30af\u6642\u9593", "OMST",
diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ko.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ko.java
index 3e179dad3a8..f69e08b250e 100644
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ko.java
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ko.java
@@ -141,6 +141,8 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle {
                                      "\ub9d0\ub808\uc774\uc2dc\uc544 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "MYST"};
         String NORONHA[] = new String[] {"Fernando de Noronha \uc2dc\uac04", "FNT",
                                          "Fernando de Noronha \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "FNST"};
+        String NOVT[] = new String[] {"\ub178\ube0c\uc2dc\ube4c\uc2a4\ud06c \uc2dc\uac04", "NOVT",
+                                      "\ub178\ube0c\uc2dc\ube4c\uc2a4\ud06c \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "NOVST"};
         String NPT[] = new String[] {"\ub124\ud314 \uc2dc\uac04", "NPT",
                                       "\ub124\ud314 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "NPST"};
         String NST[] = new String[] {"\ub274\ud380\ub4e4\ub79c\ub4dc \ud45c\uc900\uc2dc", "NST",
@@ -441,7 +443,6 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle {
             {"America/Winnipeg", CST},
             {"America/Yakutat", AKST},
             {"America/Yellowknife", MST},
-            {"Antarctica/Casey", WST_AUS},
             {"Antarctica/Davis", new String[] {"Davis \uc2dc\uac04", "DAVT",
                                                "Davis \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "DAVST"}},
             {"Antarctica/DumontDUrville", new String[] {"\ub4a4\ubabd \ub4a4\ub974\ube4c \uc2dc\uac04", "DDUT",
@@ -529,8 +530,8 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle {
                                           "\ud544\ub9ac\ud540 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "PHST"}},
             {"Asia/Muscat", GST},
             {"Asia/Nicosia", EET},
-            {"Asia/Novosibirsk", new String[] {"\ub178\ube0c\uc2dc\ube4c\uc2a4\ud06c \uc2dc\uac04", "NOVT",
-                                               "\ub178\ube0c\uc2dc\ube4c\uc2a4\ud06c \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "NOVST"}},
+            {"Asia/Novokuznetsk", NOVT},
+            {"Asia/Novosibirsk", NOVT},
             {"Asia/Oral", new String[] {"Oral \ud45c\uc900\uc2dc", "ORAT",
                                         "Oral \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "ORAST"}},
             {"Asia/Omsk", new String[] {"Omsk \uc2dc\uac04", "OMST",
diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_sv.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_sv.java
index ab13cd9216b..35ce2d11c51 100644
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_sv.java
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_sv.java
@@ -141,6 +141,8 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle {
                                      "Malaysia, sommartid", "MYST"};
         String NORONHA[] = new String[] {"Fernando de Noronha, normaltid", "FNT",
                                          "Fernando de Noronha, sommartid", "FNST"};
+        String NOVT[] = new String[] {"Novosibirsk, normaltid", "NOVT",
+                                      "Novosibirsk, sommartid", "NOVST"};
         String NPT[] = new String[] {"Nepal, normaltid", "NPT",
                                      "Nepal, sommartid", "NPST"};
         String NST[] = new String[] {"Newfoundland, normaltid", "NST",
@@ -441,7 +443,6 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle {
             {"America/Winnipeg", CST},
             {"America/Yakutat", AKST},
             {"America/Yellowknife", MST},
-            {"Antarctica/Casey", WST_AUS},
             {"Antarctica/Davis", new String[] {"Davis, normaltid", "DAVT",
                                                "Davis, sommartid", "DAVST"}},
             {"Antarctica/DumontDUrville", new String[] {"Dumont-d'Urville, normaltid", "DDUT",
@@ -529,8 +530,8 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle {
                                           "Filippinerna, sommartid", "PHST"}},
             {"Asia/Muscat", GST},
             {"Asia/Nicosia", EET},
-            {"Asia/Novosibirsk", new String[] {"Novosibirsk, normaltid", "NOVT",
-                                               "Novosibirsk, sommartid", "NOVST"}},
+            {"Asia/Novokuznetsk", NOVT},
+            {"Asia/Novosibirsk", NOVT},
             {"Asia/Oral", new String[] {"Oral, normaltid", "ORAT",
                                         "Oral, sommartid", "ORAST"}},
             {"Asia/Omsk", new String[] {"Omsk, normaltid", "OMST",
diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_CN.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_CN.java
index e0dc1ec7ea3..70cdbd0a987 100644
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_CN.java
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_CN.java
@@ -141,6 +141,8 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle {
                                      "\u9a6c\u6765\u897f\u4e9a\u590f\u4ee4\u65f6", "MYST"};
         String NORONHA[] = new String[] {"\u8d39\u5c14\u5357\u591a\u5fb7\u8bfa\u7f57\u5c3c\u4e9a\u65f6\u95f4", "FNT",
                                          "\u8d39\u5c14\u5357\u591a\u5fb7\u8bfa\u7f57\u5c3c\u4e9a\u590f\u4ee4\u65f6", "FNST"};
+        String NOVT[] = new String[] {"Novosibirsk \u65f6\u95f4", "NOVT",
+                                      "Novosibirsk \u590f\u4ee4\u65f6", "NOVST"};
         String NPT[] = new String[] {"\u5c3c\u6cca\u5c14\u65f6\u95f4", "NPT",
                                      "\u5c3c\u6cca\u5c14\u590f\u4ee4\u65f6", "NPST"};
         String NST[] = new String[] {"\u7ebd\u82ac\u5170\u6807\u51c6\u65f6\u95f4", "NST",
@@ -441,7 +443,6 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle {
             {"America/Winnipeg", CST},
             {"America/Yakutat", AKST},
             {"America/Yellowknife", MST},
-            {"Antarctica/Casey", WST_AUS},
             {"Antarctica/Davis", new String[] {"\u6234\u7ef4\u65af\u65f6\u95f4", "DAVT",
                                                "\u6234\u7ef4\u65af\u590f\u4ee4\u65f6", "DAVST"}},
             {"Antarctica/DumontDUrville", new String[] {"Dumont-d'Urville \u65f6\u95f4", "DDUT",
@@ -529,8 +530,8 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle {
                                           "\u83f2\u5f8b\u5bbe\u590f\u4ee4\u65f6", "PHST"}},
             {"Asia/Muscat", GST},
             {"Asia/Nicosia", EET},
-            {"Asia/Novosibirsk", new String[] {"Novosibirsk \u65f6\u95f4", "NOVT",
-                                               "Novosibirsk \u590f\u4ee4\u65f6", "NOVST"}},
+            {"Asia/Novokuznetsk", NOVT},
+            {"Asia/Novosibirsk", NOVT},
             {"Asia/Oral", new String[] {"Oral \u65f6\u95f4", "ORAT",
                                         "Oral \u590f\u4ee4\u65f6", "ORAST"}},
             {"Asia/Omsk", new String[] {"\u9102\u6728\u65af\u514b\u65f6\u95f4", "OMST",
diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_TW.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_TW.java
index 73dd22cad1e..f5b89286ed0 100644
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_TW.java
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_TW.java
@@ -141,6 +141,8 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle {
                                      "\u99ac\u4f86\u897f\u4e9e\u590f\u4ee4\u6642\u9593", "MYST"};
         String NORONHA[] = new String[] {"\u8cbb\u723e\u5357\u591a-\u8fea\u8afe\u7f85\u5c3c\u4e9e\u6642\u9593", "FNT",
                                          "\u8cbb\u723e\u5357\u591a-\u8fea\u8afe\u7f85\u5c3c\u4e9e\u590f\u4ee4\u6642\u9593", "FNST"};
+        String NOVT[] = new String[] {"Novosibirsk \u6642\u9593", "NOVT",
+                                      "Novosibirsk \u590f\u4ee4\u6642\u9593", "NOVST"};
         String NPT[] = new String[] {"\u5c3c\u6cca\u723e\u6642\u9593", "NPT",
                                      "\u5c3c\u6cca\u723e\u590f\u4ee4\u6642\u9593", "NPST"};
         String NST[] = new String[] {"\u7d10\u82ac\u862d\u6a19\u6e96\u6642\u9593", "NST",
@@ -441,7 +443,6 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle {
             {"America/Winnipeg", CST},
             {"America/Yakutat", AKST},
             {"America/Yellowknife", MST},
-            {"Antarctica/Casey", WST_AUS},
             {"Antarctica/Davis", new String[] {"\u81fa\u7dad\u65af\u6642\u9593", "DAVT",
                                                "\u81fa\u7dad\u65af\u590f\u4ee4\u6642\u9593", "DAVST"}},
             {"Antarctica/DumontDUrville", new String[] {"Dumont-d'Urville \u6642\u9593", "DDUT",
@@ -529,8 +530,8 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle {
                                           "\u83f2\u5f8b\u8cd3\u590f\u4ee4\u6642\u9593", "PHST"}},
             {"Asia/Muscat", GST},
             {"Asia/Nicosia", EET},
-            {"Asia/Novosibirsk", new String[] {"Novosibirsk \u6642\u9593", "NOVT",
-                                               "Novosibirsk \u590f\u4ee4\u6642\u9593", "NOVST"}},
+            {"Asia/Novokuznetsk", NOVT},
+            {"Asia/Novosibirsk", NOVT},
             {"Asia/Oral", new String[] {"\u6b50\u4f5b\u6642\u9593", "ORAT",
                                         "\u6b50\u4f5b\u590f\u4ee4\u6642\u9593", "ORAST"}},
             {"Asia/Omsk", new String[] {"\u6b50\u59c6\u65af\u514b (Omsk) \u6642\u9593", "OMST",

From 1fbf7057398a125410129307e87aba43f8afd92e Mon Sep 17 00:00:00 2001
From: Dmitry Cherepanov 
Date: Wed, 11 Nov 2009 17:46:58 +0300
Subject: [PATCH 29/36] 6852111: Unhandled 'spurious wakeup' in
 java.awt.EventQueue.invokeAndWait()

Introduced InvocationEvent.isDispatched method

Reviewed-by: art, anthony
---
 .../share/classes/java/awt/EventQueue.java    |  4 +-
 .../java/awt/event/InvocationEvent.java       | 97 ++++++++++++++-----
 .../sun/awt/im/InputMethodManager.java        |  4 +-
 .../InvocationEvent/InvocationEventTest.java  | 68 +++++++++++++
 4 files changed, 149 insertions(+), 24 deletions(-)
 create mode 100644 jdk/test/java/awt/event/InvocationEvent/InvocationEventTest.java

diff --git a/jdk/src/share/classes/java/awt/EventQueue.java b/jdk/src/share/classes/java/awt/EventQueue.java
index 3e9febf79b7..b5635f4a25c 100644
--- a/jdk/src/share/classes/java/awt/EventQueue.java
+++ b/jdk/src/share/classes/java/awt/EventQueue.java
@@ -1027,7 +1027,9 @@ public class EventQueue {
 
         synchronized (lock) {
             Toolkit.getEventQueue().postEvent(event);
-            lock.wait();
+            while (!event.isDispatched()) {
+                lock.wait();
+            }
         }
 
         Throwable eventThrowable = event.getThrowable();
diff --git a/jdk/src/share/classes/java/awt/event/InvocationEvent.java b/jdk/src/share/classes/java/awt/event/InvocationEvent.java
index 0959a86cb35..e21adf352bb 100644
--- a/jdk/src/share/classes/java/awt/event/InvocationEvent.java
+++ b/jdk/src/share/classes/java/awt/event/InvocationEvent.java
@@ -78,10 +78,21 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent {
 
     /**
      * The (potentially null) Object whose notifyAll() method will be called
-     * immediately after the Runnable.run() method returns.
+     * immediately after the Runnable.run() method has returned or thrown an exception.
+     *
+     * @see #isDispatched
      */
     protected Object notifier;
 
+    /**
+     * Indicates whether the run() method of the runnable
+     * was executed or not.
+     *
+     * @see #isDispatched
+     * @since 1.7
+     */
+    private volatile boolean dispatched = false;
+
     /**
      * Set to true if dispatch() catches Throwable and stores it in the
      * exception instance variable. If false, Throwables are propagated up
@@ -144,7 +155,7 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent {
      * source which will execute the runnable's run
      * method when dispatched.  If notifier is non-null,
      * notifyAll() will be called on it
-     * immediately after run returns.
+     * immediately after run has returned or thrown an exception.
      * 

An invocation of the form InvocationEvent(source, * runnable, notifier, catchThrowables) * behaves in exactly the same way as the invocation of @@ -159,7 +170,8 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { * executed * @param notifier The {@code Object} whose notifyAll * method will be called after - * Runnable.run has returned + * Runnable.run has returned or + * thrown an exception * @param catchThrowables Specifies whether dispatch * should catch Throwable when executing * the Runnable's run @@ -180,8 +192,8 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { * Constructs an InvocationEvent with the specified * source and ID which will execute the runnable's run * method when dispatched. If notifier is non-null, - * notifyAll will be called on it - * immediately after run returns. + * notifyAll will be called on it immediately after + * run has returned or thrown an exception. *

This method throws an * IllegalArgumentException if source * is null. @@ -195,7 +207,8 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { * run method will be executed * @param notifier The Object whose notifyAll * method will be called after - * Runnable.run has returned + * Runnable.run has returned or + * thrown an exception * @param catchThrowables Specifies whether dispatch * should catch Throwable when executing the * Runnable's run @@ -217,27 +230,33 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { /** * Executes the Runnable's run() method and notifies the - * notifier (if any) when run() returns. + * notifier (if any) when run() has returned or thrown an exception. + * + * @see #isDispatched */ public void dispatch() { - if (catchExceptions) { - try { + try { + if (catchExceptions) { + try { + runnable.run(); + } + catch (Throwable t) { + if (t instanceof Exception) { + exception = (Exception) t; + } + throwable = t; + } + } + else { runnable.run(); } - catch (Throwable t) { - if (t instanceof Exception) { - exception = (Exception) t; - } - throwable = t; - } - } - else { - runnable.run(); - } + } finally { + dispatched = true; - if (notifier != null) { - synchronized (notifier) { - notifier.notifyAll(); + if (notifier != null) { + synchronized (notifier) { + notifier.notifyAll(); + } } } } @@ -277,6 +296,40 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { return when; } + /** + * Returns {@code true} if the event is dispatched or any exception is + * thrown while dispatching, {@code false} otherwise. The method should + * be called by a waiting thread that calls the {@code notifier.wait()} method. + * Since spurious wakeups are possible (as explained in {@link Object#wait()}), + * this method should be used in a waiting loop to ensure that the event + * got dispatched: + *

+     *     while (!event.isDispatched()) {
+     *         notifier.wait();
+     *     }
+     * 
+ * If the waiting thread wakes up without dispatching the event, + * the {@code isDispatched()} method returns {@code false}, and + * the {@code while} loop executes once more, thus, causing + * the awakened thread to revert to the waiting mode. + *

+ * If the {@code notifier.notifyAll()} happens before the waiting thread + * enters the {@code notifier.wait()} method, the {@code while} loop ensures + * that the waiting thread will not enter the {@code notifier.wait()} method. + * Otherwise, there is no guarantee that the waiting thread will ever be woken + * from the wait. + * + * @return {@code true} if the event has been dispatched, or any exception + * has been thrown while dispatching, {@code false} otherwise + * @see #dispatch + * @see #notifier + * @see #catchExceptions + * @since 1.7 + */ + public boolean isDispatched() { + return dispatched; + } + /** * Returns a parameter string identifying this event. * This method is useful for event-logging and for debugging. diff --git a/jdk/src/share/classes/sun/awt/im/InputMethodManager.java b/jdk/src/share/classes/sun/awt/im/InputMethodManager.java index caba8d6a152..9ee45e28e53 100644 --- a/jdk/src/share/classes/sun/awt/im/InputMethodManager.java +++ b/jdk/src/share/classes/sun/awt/im/InputMethodManager.java @@ -358,7 +358,9 @@ class ExecutableInputMethodManager extends InputMethodManager AppContext requesterAppContext = SunToolkit.targetToAppContext(requester); synchronized (lock) { SunToolkit.postEvent(requesterAppContext, event); - lock.wait(); + while (!event.isDispatched()) { + lock.wait(); + } } Throwable eventThrowable = event.getThrowable(); diff --git a/jdk/test/java/awt/event/InvocationEvent/InvocationEventTest.java b/jdk/test/java/awt/event/InvocationEvent/InvocationEventTest.java new file mode 100644 index 00000000000..5fb83d10acf --- /dev/null +++ b/jdk/test/java/awt/event/InvocationEvent/InvocationEventTest.java @@ -0,0 +1,68 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + @test + @bug 6852111 + @summary Unhandled 'spurious wakeup' in java.awt.EventQueue.invokeAndWait() + @author dmitry.cherepanov@sun.com: area=awt.event + @run main InvocationEventTest +*/ + +/** + * InvocationEventTest.java + * + * summary: Tests new isDispatched method of the InvocationEvent class + */ + +import java.awt.*; +import java.awt.event.*; + +public class InvocationEventTest +{ + public static void main(String []s) throws Exception + { + Toolkit tk = Toolkit.getDefaultToolkit(); + Runnable runnable = new Runnable() { + public void run() { + } + }; + Object lock = new Object(); + InvocationEvent event = new InvocationEvent(tk, runnable, lock, true); + + if (event.isDispatched()) { + throw new RuntimeException(" Initially, the event shouldn't be dispatched "); + } + + synchronized(lock) { + tk.getSystemEventQueue().postEvent(event); + while(!event.isDispatched()) { + lock.wait(); + } + } + + if(!event.isDispatched()) { + throw new RuntimeException(" Finally, the event should be dispatched "); + } + } +} From 67ffb33afaa55a2662d11a12ba4d62d03a7b7431 Mon Sep 17 00:00:00 2001 From: Dmitry Cherepanov Date: Wed, 11 Nov 2009 19:18:27 +0300 Subject: [PATCH 30/36] 6880694: GraphicsDevice.setFullScreenWindow(null) throws NPE if there's a fullscreen window displayed Handle "empty" refresh rates Reviewed-by: art, anthony --- jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c b/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c index 7afdf1681c6..5dfb0ff2875 100644 --- a/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c +++ b/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c @@ -1654,6 +1654,7 @@ Java_sun_awt_X11GraphicsEnvironment_getXineramaCenterPoint(JNIEnv *env, #ifndef HEADLESS #define BIT_DEPTH_MULTI java_awt_DisplayMode_BIT_DEPTH_MULTI +#define REFRESH_RATE_UNKNOWN java_awt_DisplayMode_REFRESH_RATE_UNKNOWN typedef Status (*XRRQueryVersionType) (Display *dpy, int *major_versionp, int *minor_versionp); @@ -1765,6 +1766,7 @@ X11GD_CreateDisplayMode(JNIEnv *env, jint width, jint height, { jclass displayModeClass; jmethodID cid; + jint validRefreshRate = refreshRate; displayModeClass = (*env)->FindClass(env, "java/awt/DisplayMode"); if (JNU_IsNull(env, displayModeClass)) { @@ -1780,8 +1782,13 @@ X11GD_CreateDisplayMode(JNIEnv *env, jint width, jint height, return NULL; } + // early versions of xrandr may report "empty" rates (6880694) + if (validRefreshRate <= 0) { + validRefreshRate = REFRESH_RATE_UNKNOWN; + } + return (*env)->NewObject(env, displayModeClass, cid, - width, height, bitDepth, refreshRate); + width, height, bitDepth, validRefreshRate); } static void @@ -1926,8 +1933,7 @@ Java_sun_awt_X11GraphicsDevice_getCurrentDisplayMode curRate = awt_XRRConfigCurrentRate(config); if ((sizes != NULL) && - (curSizeIndex < nsizes) && - (curRate > 0)) + (curSizeIndex < nsizes)) { XRRScreenSize curSize = sizes[curSizeIndex]; displayMode = X11GD_CreateDisplayMode(env, From 58c459c32e91b92234788048ee0def26a1a9488f Mon Sep 17 00:00:00 2001 From: Dmitry Cherepanov Date: Thu, 12 Nov 2009 12:06:46 +0300 Subject: [PATCH 31/36] 6882909: Resetting a full-screen window to normal rotates screen to normal orientation Retain rotation upon change to full screen mode Reviewed-by: art, anthony --- jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c b/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c index 5dfb0ff2875..ef4fa15afa5 100644 --- a/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c +++ b/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c @@ -1681,6 +1681,9 @@ typedef Status Rotation rotation, short rate, Time timestamp); +typedef Rotation + (*XRRConfigRotationsType)(XRRScreenConfiguration *config, + Rotation *current_rotation); static XRRQueryVersionType awt_XRRQueryVersion; static XRRGetScreenInfoType awt_XRRGetScreenInfo; @@ -1690,6 +1693,7 @@ static XRRConfigCurrentRateType awt_XRRConfigCurrentRate; static XRRConfigSizesType awt_XRRConfigSizes; static XRRConfigCurrentConfigurationType awt_XRRConfigCurrentConfiguration; static XRRSetScreenConfigAndRateType awt_XRRSetScreenConfigAndRate; +static XRRConfigRotationsType awt_XRRConfigRotations; #define LOAD_XRANDR_FUNC(f) \ do { \ @@ -1756,6 +1760,7 @@ X11GD_InitXrandrFuncs(JNIEnv *env) LOAD_XRANDR_FUNC(XRRConfigSizes); LOAD_XRANDR_FUNC(XRRConfigCurrentConfiguration); LOAD_XRANDR_FUNC(XRRSetScreenConfigAndRate); + LOAD_XRANDR_FUNC(XRRConfigRotations); return JNI_TRUE; } @@ -2010,6 +2015,7 @@ Java_sun_awt_X11GraphicsDevice_configDisplayMode jboolean success = JNI_FALSE; XRRScreenConfiguration *config; Drawable root; + Rotation currentRotation = RR_Rotate_0; AWT_LOCK(); @@ -2021,6 +2027,7 @@ Java_sun_awt_X11GraphicsDevice_configDisplayMode short chosenRate = -1; int nsizes; XRRScreenSize *sizes = awt_XRRConfigSizes(config, &nsizes); + awt_XRRConfigRotations(config, ¤tRotation); if (sizes != NULL) { int i, j; @@ -2054,7 +2061,7 @@ Java_sun_awt_X11GraphicsDevice_configDisplayMode Status status = awt_XRRSetScreenConfigAndRate(awt_display, config, root, chosenSizeIndex, - RR_Rotate_0, + currentRotation, chosenRate, CurrentTime); From 274e8c83b2faa1932a84b8ac2cfd19f758713c4f Mon Sep 17 00:00:00 2001 From: Yuka Kamiya Date: Thu, 12 Nov 2009 18:59:19 +0900 Subject: [PATCH 32/36] 6842557: NumericShaper needs to be updated for Unicode 5.1 support 6843181: NumericShaper is not thread-safe 6900137: Typo in API Doc for NumericShaper Reviewed-by: okutsu --- .../classes/java/awt/font/NumericShaper.java | 1302 +++++++++++------ .../awt/font/NumericShaper/EqualsTest.java | 65 + .../java/awt/font/NumericShaper/MTTest.java | 134 ++ .../awt/font/NumericShaper/ShapingTest.java | 105 ++ 4 files changed, 1154 insertions(+), 452 deletions(-) create mode 100644 jdk/test/java/awt/font/NumericShaper/EqualsTest.java create mode 100644 jdk/test/java/awt/font/NumericShaper/MTTest.java create mode 100644 jdk/test/java/awt/font/NumericShaper/ShapingTest.java diff --git a/jdk/src/share/classes/java/awt/font/NumericShaper.java b/jdk/src/share/classes/java/awt/font/NumericShaper.java index a1ffbf0b7c3..435b60213f0 100644 --- a/jdk/src/share/classes/java/awt/font/NumericShaper.java +++ b/jdk/src/share/classes/java/awt/font/NumericShaper.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,13 @@ package java.awt.font; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.util.Arrays; +import java.util.Comparator; +import java.util.EnumSet; +import java.util.Set; + /** * The NumericShaper class is used to convert Latin-1 (European) * digits to other Unicode decimal digits. Users of this class will @@ -64,13 +71,261 @@ package java.awt.font; * NumericShaper.getContextualShaper(NumericShaper.ARABIC | * NumericShaper.TAMIL, * NumericShaper.EUROPEAN); - * shaper.shape(text. start, count); + * shaper.shape(text, start, count); *

* + *

Bit mask- and enum-based Unicode ranges

+ * + *

This class supports two different programming interfaces to + * represent Unicode ranges for script-specific digits: bit + * mask-based ones, such as {@link #ARABIC NumericShaper.ARABIC}, and + * enum-based ones, such as {@link NumericShaper.Range#ARABIC}. + * Multiple ranges can be specified by ORing bit mask-based constants, + * such as: + *

+ * NumericShaper.ARABIC | NumericShaper.TAMIL
+ * 
+ * or creating a {@code Set} with the {@link NumericShaper.Range} + * constants, such as: + *
+ * EnumSet.of(NumericShaper.Scirpt.ARABIC, NumericShaper.Range.TAMIL)
+ * 
+ * The enum-based ranges are a super set of the bit mask-based ones. + * + *

If the two interfaces are mixed (including serialization), + * Unicode range values are mapped to their counterparts where such + * mapping is possible, such as {@code NumericShaper.Range.ARABIC} + * from/to {@code NumericShaper.ARABIC}. If any unmappable range + * values are specified, such as {@code NumericShaper.Range.BALINESE}, + * those ranges are ignored. + * * @since 1.4 */ public final class NumericShaper implements java.io.Serializable { + /** + * A {@code NumericShaper.Range} represents a Unicode range of a + * script having its own decimal digits. For example, the {@link + * NumericShaper.Range#THAI} range has the Thai digits, THAI DIGIT + * ZERO (U+0E50) to THAI DIGIT NINE (U+0E59). + * + *

The Range enum replaces the traditional bit + * mask-based values (e.g., {@link NumericShaper#ARABIC}), and + * supports more Unicode ranges than the bit mask-based ones. For + * example, the following code using the bit mask: + *

+     * NumericShaper.getContextualShaper(NumericShaper.ARABIC |
+     *                                     NumericShaper.TAMIL,
+     *                                   NumericShaper.EUROPEAN);
+     * 
+ * can be written using this enum as: + *
+     * NumericShaper.getContextualShaper(EnumSet.of(
+     *                                     NumericShaper.Range.ARABIC,
+     *                                     NumericShaper.Range.TAMIL),
+     *                                   NumericShaper.Range.EUROPEAN);
+     * 
+ * + * @since 1.7 + */ + public static enum Range { + /** + * The Latin (European) range with the Latin (ASCII) digits. + */ + EUROPEAN ('\u0030', '\u0000', '\u0300'), + /** + * The Arabic range with the Arabic-Indic digits. + */ + ARABIC ('\u0660', '\u0600', '\u0780'), + /** + * The Arabic range with the Eastern Arabic-Indic digits. + */ + EASTERN_ARABIC ('\u06f0', '\u0600', '\u0780'), + /** + * The Devanagari range with the Devanagari digits. + */ + DEVANAGARI ('\u0966', '\u0900', '\u0980'), + /** + * The Bengali range with the Bengali digits. + */ + BENGALI ('\u09e6', '\u0980', '\u0a00'), + /** + * The Gurmukhi range with the Gurmukhi digits. + */ + GURMUKHI ('\u0a66', '\u0a00', '\u0a80'), + /** + * The Gujarati range with the Gujarati digits. + */ + GUJARATI ('\u0ae6', '\u0b00', '\u0b80'), + /** + * The Oriya range with the Oriya digits. + */ + ORIYA ('\u0b66', '\u0b00', '\u0b80'), + /** + * The Tamil range with the Tamil digits. + */ + TAMIL ('\u0be6', '\u0b80', '\u0c00'), + /** + * The Telugu range with the Telugu digits. + */ + TELUGU ('\u0c66', '\u0c00', '\u0c80'), + /** + * The Kannada range with the Kannada digits. + */ + KANNADA ('\u0ce6', '\u0c80', '\u0d00'), + /** + * The Malayalam range with the Malayalam digits. + */ + MALAYALAM ('\u0d66', '\u0d00', '\u0d80'), + /** + * The Thai range with the Thai digits. + */ + THAI ('\u0e50', '\u0e00', '\u0e80'), + /** + * The Lao range with the Lao digits. + */ + LAO ('\u0ed0', '\u0e80', '\u0f00'), + /** + * The Tibetan range with the Tibetan digits. + */ + TIBETAN ('\u0f20', '\u0f00', '\u1000'), + /** + * The Myanmar range with the Myanmar digits. + */ + MYANMAR ('\u1040', '\u1000', '\u1080'), + /** + * The Ethiopic range with the Ethiopic digits. Ethiopic + * does not have a decimal digit 0 so Latin (European) 0 is + * used. + */ + ETHIOPIC ('\u1369', '\u1200', '\u1380') { + @Override + char getNumericBase() { return 1; } + }, + /** + * The Khmer range with the Khmer digits. + */ + KHMER ('\u17e0', '\u1780', '\u1800'), + /** + * The Mongolian range with the Mongolian digits. + */ + MONGOLIAN ('\u1810', '\u1800', '\u1900'), + /** + * The N'Ko range with the N'Ko digits. + */ + NKO ('\u07c0', '\u07c0', '\u0800'), + /** + * The Myanmar range with the Myanmar Shan digits. + */ + MYANMAR_SHAN ('\u1090', '\u1000', '\u10a0'), + /** + * The Limbu range with the Limbu digits. + */ + LIMBU ('\u1946', '\u1900', '\u1950'), + /** + * The New Tai Lue range with the New Tai Lue digits. + */ + NEW_TAI_LUE ('\u19d0', '\u1980', '\u19e0'), + /** + * The Balinese range with the Balinese digits. + */ + BALINESE ('\u1b50', '\u1b00', '\u1b80'), + /** + * The Sundanese range with the Sundanese digits. + */ + SUNDANESE ('\u1bb0', '\u1b80', '\u1bc0'), + /** + * The Lepcha range with the Lepcha digits. + */ + LEPCHA ('\u1c40', '\u1c00', '\u1c50'), + /** + * The Ol Chiki range with the Ol Chiki digits. + */ + OL_CHIKI ('\u1c50', '\u1c50', '\u1c80'), + /** + * The Vai range with the Vai digits. + */ + VAI ('\ua620', '\ua500', '\ua640'), + /** + * The Saurashtra range with the Saurashtra digits. + */ + SAURASHTRA ('\ua8d0', '\ua880', '\ua8e0'), + /** + * The Kayah Li range with the Kayah Li digits. + */ + KAYAH_LI ('\ua900', '\ua900', '\ua930'), + /** + * The Cham range with the Cham digits. + */ + CHAM ('\uaa50', '\uaa00', '\uaa60'); + + private static final Range[] ranges = Range.class.getEnumConstants(); + static { + // sort ranges[] by base for binary search + Arrays.sort(ranges, + new Comparator() { + public int compare(Range s1, Range s2) { + return s1.base > s2.base ? 1 : s1.base == s2.base ? 0 : -1; + } + }); + } + + private static int toRangeIndex(Range script) { + int index = script.ordinal(); + return index < NUM_KEYS ? index : -1; + } + + private static Range indexToRange(int index) { + return index < NUM_KEYS ? Range.values()[index] : null; + } + + private static int toRangeMask(Set ranges) { + int m = 0; + for (Range range : ranges) { + int index = range.ordinal(); + if (index < NUM_KEYS) { + m |= 1 << index; + } + } + return m; + } + + private static Set maskToRangeSet(int mask) { + Set set = EnumSet.noneOf(Range.class); + Range[] a = Range.values(); + for (int i = 0; i < NUM_KEYS; i++) { + if ((mask & (1 << i)) != 0) { + set.add(a[i]); + } + } + return set; + } + + // base character of range digits + private final int base; + // Unicode range + private final int start, // inclusive + end; // exclusive + + private Range(int base, int start, int end) { + this.base = base - ('0' + getNumericBase()); + this.start = start; + this.end = end; + } + + private int getDigitBase() { + return base; + } + + char getNumericBase() { + return 0; + } + + private boolean inRange(int c) { + return start <= c && c < end; + } + } + /** index of context for contextual shaping - values range from 0 to 18 */ private int key; @@ -79,6 +334,25 @@ public final class NumericShaper implements java.io.Serializable { */ private int mask; + /** + * The context {@code Range} for contextual shaping or the {@code + * Range} for non-contextual shaping. {@code null} for the bit + * mask-based API. + * + * @since 1.7 + */ + private Range shapingRange; + + /** + * {@code Set} indicating which Unicode ranges to + * shape. {@code null} for the bit mask-based API. + * + * @since 1.7 + */ + private transient Set rangeSet; + + private static final long serialVersionUID = -8022764705923730308L; + /** Identifies the Latin-1 (European) and extended range, and * Latin-1 (European) decimal base. */ @@ -105,9 +379,8 @@ public final class NumericShaper implements java.io.Serializable { /** Identifies the ORIYA range and decimal base. */ public static final int ORIYA = 1<<7; - /** Identifies the TAMIL range and decimal base. Tamil does not have a - * decimal digit 0 so Latin-1 (European) 0 is used. - */ + /** Identifies the TAMIL range and decimal base. */ + // TAMIL DIGIT ZERO was added in Unicode 4.1 public static final int TAMIL = 1<<8; /** Identifies the TELUGU range and decimal base. */ @@ -140,7 +413,12 @@ public final class NumericShaper implements java.io.Serializable { /** Identifies the MONGOLIAN range and decimal base. */ public static final int MONGOLIAN = 1<<18; - /** Identifies all ranges, for full contextual shaping. */ + /** Identifies all ranges, for full contextual shaping. + * + *

This constant specifies all of the bit mask-based + * ranges. Use {@code EmunSet.allOf(NumericShaper.Range.class)} to + * specify all of the enum-based ranges. + */ public static final int ALL_RANGES = 0x0007ffff; private static final int EUROPEAN_KEY = 0; @@ -163,42 +441,20 @@ public final class NumericShaper implements java.io.Serializable { private static final int KHMER_KEY = 17; private static final int MONGOLIAN_KEY = 18; - private static final int NUM_KEYS = 19; - - private static final String[] keyNames = { - "EUROPEAN", - "ARABIC", - "EASTERN_ARABIC", - "DEVANAGARI", - "BENGALI", - "GURMUKHI", - "GUJARATI", - "ORIYA", - "TAMIL", - "TELUGU", - "KANNADA", - "MALAYALAM", - "THAI", - "LAO", - "TIBETAN", - "MYANMAR", - "ETHIOPIC", - "KHMER", - "MONGOLIAN" - }; + private static final int NUM_KEYS = MONGOLIAN_KEY + 1; // fixed private static final int CONTEXTUAL_MASK = 1<<31; private static final char[] bases = { '\u0030' - '\u0030', // EUROPEAN - '\u0660' - '\u0030', // ARABIC - '\u06f0' - '\u0030', // EASTERN_ARABIC + '\u0660' - '\u0030', // ARABIC-INDIC + '\u06f0' - '\u0030', // EXTENDED ARABIC-INDIC (EASTERN_ARABIC) '\u0966' - '\u0030', // DEVANAGARI '\u09e6' - '\u0030', // BENGALI '\u0a66' - '\u0030', // GURMUKHI '\u0ae6' - '\u0030', // GUJARATI '\u0b66' - '\u0030', // ORIYA - '\u0be7' - '\u0030', // TAMIL - note missing zero + '\u0be6' - '\u0030', // TAMIL - zero was added in Unicode 4.1 '\u0c66' - '\u0030', // TELUGU '\u0ce6' - '\u0030', // KANNADA '\u0d66' - '\u0030', // MALAYALAM @@ -206,7 +462,7 @@ public final class NumericShaper implements java.io.Serializable { '\u0ed0' - '\u0030', // LAO '\u0f20' - '\u0030', // TIBETAN '\u1040' - '\u0030', // MYANMAR - '\u1369' - '\u0030', // ETHIOPIC + '\u1369' - '\u0031', // ETHIOPIC - no zero '\u17e0' - '\u0030', // KHMER '\u1810' - '\u0030', // MONGOLIAN }; @@ -215,14 +471,14 @@ public final class NumericShaper implements java.io.Serializable { private static final char[] contexts = { '\u0000', '\u0300', // 'EUROPEAN' (really latin-1 and extended) - '\u0600', '\u0700', // ARABIC - '\u0600', '\u0700', // EASTERN_ARABIC -- note overlap with arabic + '\u0600', '\u0780', // ARABIC + '\u0600', '\u0780', // EASTERN_ARABIC -- note overlap with arabic '\u0900', '\u0980', // DEVANAGARI '\u0980', '\u0a00', // BENGALI '\u0a00', '\u0a80', // GURMUKHI '\u0a80', '\u0b00', // GUJARATI '\u0b00', '\u0b80', // ORIYA - '\u0b80', '\u0c00', // TAMIL - note missing zero + '\u0b80', '\u0c00', // TAMIL '\u0c00', '\u0c80', // TELUGU '\u0c80', '\u0d00', // KANNADA '\u0d00', '\u0d80', // MALAYALAM @@ -230,7 +486,7 @@ public final class NumericShaper implements java.io.Serializable { '\u0e80', '\u0f00', // LAO '\u0f00', '\u1000', // TIBETAN '\u1000', '\u1080', // MYANMAR - '\u1200', '\u1380', // ETHIOPIC + '\u1200', '\u1380', // ETHIOPIC - note missing zero '\u1780', '\u1800', // KHMER '\u1800', '\u1900', // MONGOLIAN '\uffff', @@ -254,378 +510,290 @@ public final class NumericShaper implements java.io.Serializable { return (ctCache & 0x1) == 0 ? (ctCache / 2) : EUROPEAN_KEY; } + // cache for the NumericShaper.Range version + private transient volatile Range currentRange = Range.EUROPEAN; + + private Range rangeForCodePoint(int codepoint) { + Range range = currentRange; + if (range.inRange(codepoint)) { + return range; + } + + final Range[] ranges = Range.ranges; + int lo = 0; + int hi = ranges.length - 1; + while (lo <= hi) { + int mid = (lo + hi) / 2; + range = ranges[mid]; + if (codepoint < range.start) { + hi = mid - 1; + } else if (codepoint >= range.end) { + lo = mid + 1; + } else { + currentRange = range; + return range; + } + } + return Range.EUROPEAN; + } + /* * A range table of strong directional characters (types L, R, AL). * Even (left) indexes are starts of ranges of non-strong-directional (or undefined) * characters, odd (right) indexes are starts of ranges of strong directional * characters. */ - private static char[] strongTable = { - '\u0000', '\u0041', - '\u005b', '\u0061', - '\u007b', '\u00aa', - '\u00ab', '\u00b5', - '\u00b6', '\u00ba', - '\u00bb', '\u00c0', - '\u00d7', '\u00d8', - '\u00f7', '\u00f8', - '\u0220', '\u0222', - '\u0234', '\u0250', - '\u02ae', '\u02b0', - '\u02b9', '\u02bb', - '\u02c2', '\u02d0', - '\u02d2', '\u02e0', - '\u02e5', '\u02ee', - '\u02ef', '\u037a', - '\u037b', '\u0386', - '\u0387', '\u0388', - '\u038b', '\u038c', - '\u038d', '\u038e', - '\u03a2', '\u03a3', - '\u03cf', '\u03d0', - '\u03d8', '\u03da', - '\u03f4', '\u0400', - '\u0483', '\u048c', - '\u04c5', '\u04c7', - '\u04c9', '\u04cb', - '\u04cd', '\u04d0', - '\u04f6', '\u04f8', - '\u04fa', '\u0531', - '\u0557', '\u0559', - '\u0560', '\u0561', - '\u0588', '\u0589', - '\u058a', '\u05be', - '\u05bf', '\u05c0', - '\u05c1', '\u05c3', - '\u05c4', '\u05d0', - '\u05eb', '\u05f0', - '\u05f5', '\u061b', - '\u061c', '\u061f', - '\u0620', '\u0621', - '\u063b', '\u0640', - '\u064b', '\u066d', - '\u066e', '\u0671', - '\u06d6', '\u06e5', - '\u06e7', '\u06fa', - '\u06ff', '\u0700', - '\u070e', '\u0710', - '\u0711', '\u0712', - '\u072d', '\u0780', - '\u07a6', '\u0903', - '\u0904', '\u0905', - '\u093a', '\u093d', - '\u0941', '\u0949', - '\u094d', '\u0950', - '\u0951', '\u0958', - '\u0962', '\u0964', - '\u0971', '\u0982', - '\u0984', '\u0985', - '\u098d', '\u098f', - '\u0991', '\u0993', - '\u09a9', '\u09aa', - '\u09b1', '\u09b2', - '\u09b3', '\u09b6', - '\u09ba', '\u09be', - '\u09c1', '\u09c7', - '\u09c9', '\u09cb', - '\u09cd', '\u09d7', - '\u09d8', '\u09dc', - '\u09de', '\u09df', - '\u09e2', '\u09e6', - '\u09f2', '\u09f4', - '\u09fb', '\u0a05', - '\u0a0b', '\u0a0f', - '\u0a11', '\u0a13', - '\u0a29', '\u0a2a', - '\u0a31', '\u0a32', - '\u0a34', '\u0a35', - '\u0a37', '\u0a38', - '\u0a3a', '\u0a3e', - '\u0a41', '\u0a59', - '\u0a5d', '\u0a5e', - '\u0a5f', '\u0a66', - '\u0a70', '\u0a72', - '\u0a75', '\u0a83', - '\u0a84', '\u0a85', - '\u0a8c', '\u0a8d', - '\u0a8e', '\u0a8f', - '\u0a92', '\u0a93', - '\u0aa9', '\u0aaa', - '\u0ab1', '\u0ab2', - '\u0ab4', '\u0ab5', - '\u0aba', '\u0abd', - '\u0ac1', '\u0ac9', - '\u0aca', '\u0acb', - '\u0acd', '\u0ad0', - '\u0ad1', '\u0ae0', - '\u0ae1', '\u0ae6', - '\u0af0', '\u0b02', - '\u0b04', '\u0b05', - '\u0b0d', '\u0b0f', - '\u0b11', '\u0b13', - '\u0b29', '\u0b2a', - '\u0b31', '\u0b32', - '\u0b34', '\u0b36', - '\u0b3a', '\u0b3d', - '\u0b3f', '\u0b40', - '\u0b41', '\u0b47', - '\u0b49', '\u0b4b', - '\u0b4d', '\u0b57', - '\u0b58', '\u0b5c', - '\u0b5e', '\u0b5f', - '\u0b62', '\u0b66', - '\u0b71', '\u0b83', - '\u0b84', '\u0b85', - '\u0b8b', '\u0b8e', - '\u0b91', '\u0b92', - '\u0b96', '\u0b99', - '\u0b9b', '\u0b9c', - '\u0b9d', '\u0b9e', - '\u0ba0', '\u0ba3', - '\u0ba5', '\u0ba8', - '\u0bab', '\u0bae', - '\u0bb6', '\u0bb7', - '\u0bba', '\u0bbe', - '\u0bc0', '\u0bc1', - '\u0bc3', '\u0bc6', - '\u0bc9', '\u0bca', - '\u0bcd', '\u0bd7', - '\u0bd8', '\u0be7', - '\u0bf3', '\u0c01', - '\u0c04', '\u0c05', - '\u0c0d', '\u0c0e', - '\u0c11', '\u0c12', - '\u0c29', '\u0c2a', - '\u0c34', '\u0c35', - '\u0c3a', '\u0c41', - '\u0c45', '\u0c60', - '\u0c62', '\u0c66', - '\u0c70', '\u0c82', - '\u0c84', '\u0c85', - '\u0c8d', '\u0c8e', - '\u0c91', '\u0c92', - '\u0ca9', '\u0caa', - '\u0cb4', '\u0cb5', - '\u0cba', '\u0cbe', - '\u0cbf', '\u0cc0', - '\u0cc5', '\u0cc7', - '\u0cc9', '\u0cca', - '\u0ccc', '\u0cd5', - '\u0cd7', '\u0cde', - '\u0cdf', '\u0ce0', - '\u0ce2', '\u0ce6', - '\u0cf0', '\u0d02', - '\u0d04', '\u0d05', - '\u0d0d', '\u0d0e', - '\u0d11', '\u0d12', - '\u0d29', '\u0d2a', - '\u0d3a', '\u0d3e', - '\u0d41', '\u0d46', - '\u0d49', '\u0d4a', - '\u0d4d', '\u0d57', - '\u0d58', '\u0d60', - '\u0d62', '\u0d66', - '\u0d70', '\u0d82', - '\u0d84', '\u0d85', - '\u0d97', '\u0d9a', - '\u0db2', '\u0db3', - '\u0dbc', '\u0dbd', - '\u0dbe', '\u0dc0', - '\u0dc7', '\u0dcf', - '\u0dd2', '\u0dd8', - '\u0de0', '\u0df2', - '\u0df5', '\u0e01', - '\u0e31', '\u0e32', - '\u0e34', '\u0e40', - '\u0e47', '\u0e4f', - '\u0e5c', '\u0e81', - '\u0e83', '\u0e84', - '\u0e85', '\u0e87', - '\u0e89', '\u0e8a', - '\u0e8b', '\u0e8d', - '\u0e8e', '\u0e94', - '\u0e98', '\u0e99', - '\u0ea0', '\u0ea1', - '\u0ea4', '\u0ea5', - '\u0ea6', '\u0ea7', - '\u0ea8', '\u0eaa', - '\u0eac', '\u0ead', - '\u0eb1', '\u0eb2', - '\u0eb4', '\u0ebd', - '\u0ebe', '\u0ec0', - '\u0ec5', '\u0ec6', - '\u0ec7', '\u0ed0', - '\u0eda', '\u0edc', - '\u0ede', '\u0f00', - '\u0f18', '\u0f1a', - '\u0f35', '\u0f36', - '\u0f37', '\u0f38', - '\u0f39', '\u0f3e', - '\u0f48', '\u0f49', - '\u0f6b', '\u0f7f', - '\u0f80', '\u0f85', - '\u0f86', '\u0f88', - '\u0f8c', '\u0fbe', - '\u0fc6', '\u0fc7', - '\u0fcd', '\u0fcf', - '\u0fd0', '\u1000', - '\u1022', '\u1023', - '\u1028', '\u1029', - '\u102b', '\u102c', - '\u102d', '\u1031', - '\u1032', '\u1038', - '\u1039', '\u1040', - '\u1058', '\u10a0', - '\u10c6', '\u10d0', - '\u10f7', '\u10fb', - '\u10fc', '\u1100', - '\u115a', '\u115f', - '\u11a3', '\u11a8', - '\u11fa', '\u1200', - '\u1207', '\u1208', - '\u1247', '\u1248', - '\u1249', '\u124a', - '\u124e', '\u1250', - '\u1257', '\u1258', - '\u1259', '\u125a', - '\u125e', '\u1260', - '\u1287', '\u1288', - '\u1289', '\u128a', - '\u128e', '\u1290', - '\u12af', '\u12b0', - '\u12b1', '\u12b2', - '\u12b6', '\u12b8', - '\u12bf', '\u12c0', - '\u12c1', '\u12c2', - '\u12c6', '\u12c8', - '\u12cf', '\u12d0', - '\u12d7', '\u12d8', - '\u12ef', '\u12f0', - '\u130f', '\u1310', - '\u1311', '\u1312', - '\u1316', '\u1318', - '\u131f', '\u1320', - '\u1347', '\u1348', - '\u135b', '\u1361', - '\u137d', '\u13a0', - '\u13f5', '\u1401', - '\u1677', '\u1681', - '\u169b', '\u16a0', - '\u16f1', '\u1780', - '\u17b7', '\u17be', - '\u17c6', '\u17c7', - '\u17c9', '\u17d4', - '\u17db', '\u17dc', - '\u17dd', '\u17e0', - '\u17ea', '\u1810', - '\u181a', '\u1820', - '\u1878', '\u1880', - '\u18a9', '\u1e00', - '\u1e9c', '\u1ea0', - '\u1efa', '\u1f00', - '\u1f16', '\u1f18', - '\u1f1e', '\u1f20', - '\u1f46', '\u1f48', - '\u1f4e', '\u1f50', - '\u1f58', '\u1f59', - '\u1f5a', '\u1f5b', - '\u1f5c', '\u1f5d', - '\u1f5e', '\u1f5f', - '\u1f7e', '\u1f80', - '\u1fb5', '\u1fb6', - '\u1fbd', '\u1fbe', - '\u1fbf', '\u1fc2', - '\u1fc5', '\u1fc6', - '\u1fcd', '\u1fd0', - '\u1fd4', '\u1fd6', - '\u1fdc', '\u1fe0', - '\u1fed', '\u1ff2', - '\u1ff5', '\u1ff6', - '\u1ffd', '\u200e', - '\u2010', '\u207f', - '\u2080', '\u2102', - '\u2103', '\u2107', - '\u2108', '\u210a', - '\u2114', '\u2115', - '\u2116', '\u2119', - '\u211e', '\u2124', - '\u2125', '\u2126', - '\u2127', '\u2128', - '\u2129', '\u212a', - '\u212e', '\u212f', - '\u2132', '\u2133', - '\u213a', '\u2160', - '\u2184', '\u2336', - '\u237b', '\u2395', - '\u2396', '\u249c', - '\u24ea', '\u3005', - '\u3008', '\u3021', - '\u302a', '\u3031', - '\u3036', '\u3038', - '\u303b', '\u3041', - '\u3095', '\u309d', - '\u309f', '\u30a1', - '\u30fb', '\u30fc', - '\u30ff', '\u3105', - '\u312d', '\u3131', - '\u318f', '\u3190', - '\u31b8', '\u3200', - '\u321d', '\u3220', - '\u3244', '\u3260', - '\u327c', '\u327f', - '\u32b1', '\u32c0', - '\u32cc', '\u32d0', - '\u32ff', '\u3300', - '\u3377', '\u337b', - '\u33de', '\u33e0', - '\u33ff', '\u3400', - '\u4db6', '\u4e00', - '\u9fa6', '\ua000', - '\ua48d', '\uac00', - '\ud7a4', '\uf900', - '\ufa2e', '\ufb00', - '\ufb07', '\ufb13', - '\ufb18', '\ufb1d', - '\ufb1e', '\ufb1f', - '\ufb29', '\ufb2a', - '\ufb37', '\ufb38', - '\ufb3d', '\ufb3e', - '\ufb3f', '\ufb40', - '\ufb42', '\ufb43', - '\ufb45', '\ufb46', - '\ufbb2', '\ufbd3', - '\ufd3e', '\ufd50', - '\ufd90', '\ufd92', - '\ufdc8', '\ufdf0', - '\ufdfc', '\ufe70', - '\ufe73', '\ufe74', - '\ufe75', '\ufe76', - '\ufefd', '\uff21', - '\uff3b', '\uff41', - '\uff5b', '\uff66', - '\uffbf', '\uffc2', - '\uffc8', '\uffca', - '\uffd0', '\uffd2', - '\uffd8', '\uffda', - '\uffdd', '\uffff' // last entry is sentinel, actually never checked + private static int[] strongTable = { + 0x0000, 0x0041, + 0x005b, 0x0061, + 0x007b, 0x00aa, + 0x00ab, 0x00b5, + 0x00b6, 0x00ba, + 0x00bb, 0x00c0, + 0x00d7, 0x00d8, + 0x00f7, 0x00f8, + 0x02b9, 0x02bb, + 0x02c2, 0x02d0, + 0x02d2, 0x02e0, + 0x02e5, 0x02ee, + 0x02ef, 0x0370, + 0x0374, 0x0376, + 0x037e, 0x0386, + 0x0387, 0x0388, + 0x03f6, 0x03f7, + 0x0483, 0x048a, + 0x058a, 0x05be, + 0x05bf, 0x05c0, + 0x05c1, 0x05c3, + 0x05c4, 0x05c6, + 0x05c7, 0x05d0, + 0x0600, 0x0608, + 0x0609, 0x060b, + 0x060c, 0x060d, + 0x060e, 0x061b, + 0x064b, 0x066d, + 0x0670, 0x0671, + 0x06d6, 0x06e5, + 0x06e7, 0x06ee, + 0x06f0, 0x06fa, + 0x070f, 0x0710, + 0x0711, 0x0712, + 0x0730, 0x074d, + 0x07a6, 0x07b1, + 0x07eb, 0x07f4, + 0x07f6, 0x07fa, + 0x0901, 0x0903, + 0x093c, 0x093d, + 0x0941, 0x0949, + 0x094d, 0x0950, + 0x0951, 0x0958, + 0x0962, 0x0964, + 0x0981, 0x0982, + 0x09bc, 0x09bd, + 0x09c1, 0x09c7, + 0x09cd, 0x09ce, + 0x09e2, 0x09e6, + 0x09f2, 0x09f4, + 0x0a01, 0x0a03, + 0x0a3c, 0x0a3e, + 0x0a41, 0x0a59, + 0x0a70, 0x0a72, + 0x0a75, 0x0a83, + 0x0abc, 0x0abd, + 0x0ac1, 0x0ac9, + 0x0acd, 0x0ad0, + 0x0ae2, 0x0ae6, + 0x0af1, 0x0b02, + 0x0b3c, 0x0b3d, + 0x0b3f, 0x0b40, + 0x0b41, 0x0b47, + 0x0b4d, 0x0b57, + 0x0b62, 0x0b66, + 0x0b82, 0x0b83, + 0x0bc0, 0x0bc1, + 0x0bcd, 0x0bd0, + 0x0bf3, 0x0c01, + 0x0c3e, 0x0c41, + 0x0c46, 0x0c58, + 0x0c62, 0x0c66, + 0x0c78, 0x0c7f, + 0x0cbc, 0x0cbd, + 0x0ccc, 0x0cd5, + 0x0ce2, 0x0ce6, + 0x0cf1, 0x0d02, + 0x0d41, 0x0d46, + 0x0d4d, 0x0d57, + 0x0d62, 0x0d66, + 0x0dca, 0x0dcf, + 0x0dd2, 0x0dd8, + 0x0e31, 0x0e32, + 0x0e34, 0x0e40, + 0x0e47, 0x0e4f, + 0x0eb1, 0x0eb2, + 0x0eb4, 0x0ebd, + 0x0ec8, 0x0ed0, + 0x0f18, 0x0f1a, + 0x0f35, 0x0f36, + 0x0f37, 0x0f38, + 0x0f39, 0x0f3e, + 0x0f71, 0x0f7f, + 0x0f80, 0x0f85, + 0x0f86, 0x0f88, + 0x0f90, 0x0fbe, + 0x0fc6, 0x0fc7, + 0x102d, 0x1031, + 0x1032, 0x1038, + 0x1039, 0x103b, + 0x103d, 0x103f, + 0x1058, 0x105a, + 0x105e, 0x1061, + 0x1071, 0x1075, + 0x1082, 0x1083, + 0x1085, 0x1087, + 0x108d, 0x108e, + 0x135f, 0x1360, + 0x1390, 0x13a0, + 0x1680, 0x1681, + 0x169b, 0x16a0, + 0x1712, 0x1720, + 0x1732, 0x1735, + 0x1752, 0x1760, + 0x1772, 0x1780, + 0x17b7, 0x17be, + 0x17c6, 0x17c7, + 0x17c9, 0x17d4, + 0x17db, 0x17dc, + 0x17dd, 0x17e0, + 0x17f0, 0x1810, + 0x18a9, 0x18aa, + 0x1920, 0x1923, + 0x1927, 0x1929, + 0x1932, 0x1933, + 0x1939, 0x1946, + 0x19de, 0x1a00, + 0x1a17, 0x1a19, + 0x1b00, 0x1b04, + 0x1b34, 0x1b35, + 0x1b36, 0x1b3b, + 0x1b3c, 0x1b3d, + 0x1b42, 0x1b43, + 0x1b6b, 0x1b74, + 0x1b80, 0x1b82, + 0x1ba2, 0x1ba6, + 0x1ba8, 0x1baa, + 0x1c2c, 0x1c34, + 0x1c36, 0x1c3b, + 0x1dc0, 0x1e00, + 0x1fbd, 0x1fbe, + 0x1fbf, 0x1fc2, + 0x1fcd, 0x1fd0, + 0x1fdd, 0x1fe0, + 0x1fed, 0x1ff2, + 0x1ffd, 0x200e, + 0x2010, 0x2071, + 0x2074, 0x207f, + 0x2080, 0x2090, + 0x20a0, 0x2102, + 0x2103, 0x2107, + 0x2108, 0x210a, + 0x2114, 0x2115, + 0x2116, 0x2119, + 0x211e, 0x2124, + 0x2125, 0x2126, + 0x2127, 0x2128, + 0x2129, 0x212a, + 0x212e, 0x212f, + 0x213a, 0x213c, + 0x2140, 0x2145, + 0x214a, 0x214e, + 0x2153, 0x2160, + 0x2190, 0x2336, + 0x237b, 0x2395, + 0x2396, 0x249c, + 0x24ea, 0x26ac, + 0x26ad, 0x2800, + 0x2900, 0x2c00, + 0x2ce5, 0x2d00, + 0x2de0, 0x3005, + 0x3008, 0x3021, + 0x302a, 0x3031, + 0x3036, 0x3038, + 0x303d, 0x3041, + 0x3099, 0x309d, + 0x30a0, 0x30a1, + 0x30fb, 0x30fc, + 0x31c0, 0x31f0, + 0x321d, 0x3220, + 0x3250, 0x3260, + 0x327c, 0x327f, + 0x32b1, 0x32c0, + 0x32cc, 0x32d0, + 0x3377, 0x337b, + 0x33de, 0x33e0, + 0x33ff, 0x3400, + 0x4dc0, 0x4e00, + 0xa490, 0xa500, + 0xa60d, 0xa610, + 0xa66f, 0xa680, + 0xa700, 0xa722, + 0xa788, 0xa789, + 0xa802, 0xa803, + 0xa806, 0xa807, + 0xa80b, 0xa80c, + 0xa825, 0xa827, + 0xa828, 0xa840, + 0xa874, 0xa880, + 0xa8c4, 0xa8ce, + 0xa926, 0xa92e, + 0xa947, 0xa952, + 0xaa29, 0xaa2f, + 0xaa31, 0xaa33, + 0xaa35, 0xaa40, + 0xaa43, 0xaa44, + 0xaa4c, 0xaa4d, + 0xfb1e, 0xfb1f, + 0xfb29, 0xfb2a, + 0xfd3e, 0xfd50, + 0xfdfd, 0xfe70, + 0xfeff, 0xff21, + 0xff3b, 0xff41, + 0xff5b, 0xff66, + 0xffe0, 0x10000, + 0x10101, 0x10102, + 0x10140, 0x101d0, + 0x101fd, 0x10280, + 0x1091f, 0x10920, + 0x10a01, 0x10a10, + 0x10a38, 0x10a40, + 0x1d167, 0x1d16a, + 0x1d173, 0x1d183, + 0x1d185, 0x1d18c, + 0x1d1aa, 0x1d1ae, + 0x1d200, 0x1d360, + 0x1d7ce, 0x20000, + 0xe0001, 0xf0000, + 0x10fffe, 0x10ffff // sentinel }; // use a binary search with a cache - private static int stCache = 0; + private transient volatile int stCache = 0; - // warning, synchronize access to this as it modifies state - private static boolean isStrongDirectional(char c) { - if (c < strongTable[stCache]) { - stCache = search(c, strongTable, 0, stCache); - } else if (c >= strongTable[stCache + 1]) { - stCache = search(c, strongTable, stCache + 1, strongTable.length - stCache - 1); + private boolean isStrongDirectional(char c) { + int cachedIndex = stCache; + if (c < strongTable[cachedIndex]) { + cachedIndex = search(c, strongTable, 0, cachedIndex); + } else if (c >= strongTable[cachedIndex + 1]) { + cachedIndex = search(c, strongTable, cachedIndex + 1, + strongTable.length - cachedIndex - 1); } - return (stCache & 0x1) == 1; + boolean val = (cachedIndex & 0x1) == 1; + stCache = cachedIndex; + return val; } - static private int getKeyFromMask(int mask) { + private static int getKeyFromMask(int mask) { int key = 0; while (key < NUM_KEYS && ((mask & (1<The shaper assumes EUROPEAN as the starting context, that + * is, if EUROPEAN digits are encountered before any strong + * directional text in the string, the context is presumed to be + * EUROPEAN, and so the digits will not shape. + * + * @param ranges the specified Unicode ranges + * @return a contextual shaper for the specified ranges + * @throws NullPointerException if {@code ranges} is {@code null}. + * @since 1.7 + */ + public static NumericShaper getContextualShaper(Set ranges) { + NumericShaper shaper = new NumericShaper(Range.EUROPEAN, ranges); + shaper.mask = CONTEXTUAL_MASK; + return shaper; + } + /** * Returns a contextual shaper for the provided unicode range(s). * Latin-1 (EUROPEAN) digits will be converted to the decimal digits @@ -683,12 +888,37 @@ public final class NumericShaper implements java.io.Serializable { * @throws IllegalArgumentException if the specified * defaultContext is not a single valid range. */ - static public NumericShaper getContextualShaper(int ranges, int defaultContext) { + public static NumericShaper getContextualShaper(int ranges, int defaultContext) { int key = getKeyFromMask(defaultContext); ranges |= CONTEXTUAL_MASK; return new NumericShaper(key, ranges); } + /** + * Returns a contextual shaper for the provided Unicode range(s). + * The Latin-1 (EUROPEAN) digits will be converted to the decimal + * digits corresponding to the range of the preceding text, if the + * range is one of the provided ranges. The shaper uses {@code + * defaultContext} as the starting context. + * + * @param ranges the specified Unicode ranges + * @param defaultContext the starting context, such as + * {@code NumericShaper.Range.EUROPEAN} + * @return a contextual shaper for the specified Unicode ranges. + * @throws NullPointerException + * if {@code ranges} or {@code defaultContext} is {@code null} + * @since 1.7 + */ + public static NumericShaper getContextualShaper(Set ranges, + Range defaultContext) { + if (defaultContext == null) { + throw new NullPointerException(); + } + NumericShaper shaper = new NumericShaper(defaultContext, ranges); + shaper.mask = CONTEXTUAL_MASK; + return shaper; + } + /** * Private constructor. */ @@ -697,6 +927,11 @@ public final class NumericShaper implements java.io.Serializable { this.mask = mask; } + private NumericShaper(Range defaultContext, Set ranges) { + this.shapingRange = defaultContext; + this.rangeSet = EnumSet.copyOf(ranges); // throws NPE if ranges is null. + } + /** * Converts the digits in the text that occur between start and * start + count. @@ -710,19 +945,13 @@ public final class NumericShaper implements java.io.Serializable { * @throws NullPointerException if text is null */ public void shape(char[] text, int start, int count) { - if (text == null) { - throw new NullPointerException("text is null"); - } - if ((start < 0) - || (start > text.length) - || ((start + count) < 0) - || ((start + count) > text.length)) { - throw new IndexOutOfBoundsException( - "bad start or count for text of length " + text.length); - } - + checkParams(text, start, count); if (isContextual()) { - shapeContextually(text, start, count, key); + if (rangeSet == null) { + shapeContextually(text, start, count, key); + } else { + shapeContextually(text, start, count, shapingRange); + } } else { shapeNonContextually(text, start, count); } @@ -747,6 +976,60 @@ public final class NumericShaper implements java.io.Serializable { * range. */ public void shape(char[] text, int start, int count, int context) { + checkParams(text, start, count); + if (isContextual()) { + int ctxKey = getKeyFromMask(context); + if (rangeSet == null) { + shapeContextually(text, start, count, ctxKey); + } else { + shapeContextually(text, start, count, Range.values()[ctxKey]); + } + } else { + shapeNonContextually(text, start, count); + } + } + + /** + * Converts the digits in the text that occur between {@code + * start} and {@code start + count}, using the provided {@code + * context}. {@code Context} is ignored if the shaper is not a + * contextual shaper. + * + * @param text a {@code char} array + * @param start the index into {@code text} to start converting + * @param count the number of {@code char}s in {@code text} + * to convert + * @param context the context to which to convert the characters, + * such as {@code NumericShaper.Range.EUROPEAN} + * @throws IndexOutOfBoundsException + * if {@code start} or {@code start + count} is out of bounds + * @throws NullPointerException + * if {@code text} or {@code context} is null + * @since 1.7 + */ + public void shape(char[] text, int start, int count, Range context) { + checkParams(text, start, count); + if (context == null) { + throw new NullPointerException("context is null"); + } + + if (isContextual()) { + if (rangeSet != null) { + shapeContextually(text, start, count, context); + } else { + int key = Range.toRangeIndex(context); + if (key >= 0) { + shapeContextually(text, start, count, key); + } else { + shapeContextually(text, start, count, shapingRange); + } + } + } else { + shapeNonContextually(text, start, count); + } + } + + private void checkParams(char[] text, int start, int count) { if (text == null) { throw new NullPointerException("text is null"); } @@ -757,13 +1040,6 @@ public final class NumericShaper implements java.io.Serializable { throw new IndexOutOfBoundsException( "bad start or count for text of length " + text.length); } - - if (isContextual()) { - int ctxKey = getKeyFromMask(context); - shapeContextually(text, start, count, ctxKey); - } else { - shapeNonContextually(text, start, count); - } } /** @@ -785,18 +1061,45 @@ public final class NumericShaper implements java.io.Serializable { *

* if ((shaper.getRanges() & shaper.ARABIC) != 0) { ... *
+ * + *

Note that this method supports only the bit mask-based + * ranges. Call {@link #getRangeSet()} for the enum-based ranges. + * * @return the values for all the ranges to be shaped. */ public int getRanges() { return mask & ~CONTEXTUAL_MASK; } + /** + * Returns a {@code Set} representing all the Unicode ranges in + * this {@code NumericShaper} that will be shaped. + * + * @return all the Unicode ranges to be shaped. + * @since 1.7 + */ + public Set getRangeSet() { + if (rangeSet != null) { + return EnumSet.copyOf(rangeSet); + } + return Range.maskToRangeSet(mask); + } + /** * Perform non-contextual shaping. */ private void shapeNonContextually(char[] text, int start, int count) { - int base = bases[key]; - char minDigit = key == TAMIL_KEY ? '\u0031' : '\u0030'; // Tamil doesn't use decimal zero + int base; + char minDigit = '0'; + if (shapingRange != null) { + base = shapingRange.getDigitBase(); + minDigit += shapingRange.getNumericBase(); + } else { + base = bases[key]; + if (key == ETHIOPIC_KEY) { + minDigit++; // Ethiopic doesn't use decimal zero + } + } for (int i = start, e = start + count; i < e; ++i) { char c = text[i]; if (c >= minDigit && c <= '\u0039') { @@ -807,7 +1110,7 @@ public final class NumericShaper implements java.io.Serializable { /** * Perform contextual shaping. - * Synchronized to protect caches used in getContextKey and isStrongDirectional. + * Synchronized to protect caches used in getContextKey. */ private synchronized void shapeContextually(char[] text, int start, int count, int ctxKey) { @@ -818,29 +1121,64 @@ public final class NumericShaper implements java.io.Serializable { int lastkey = ctxKey; int base = bases[ctxKey]; - char minDigit = ctxKey == TAMIL_KEY ? '\u0031' : '\u0030'; // Tamil doesn't use decimal zero + char minDigit = ctxKey == ETHIOPIC_KEY ? '1' : '0'; // Ethiopic doesn't use decimal zero - for (int i = start, e = start + count; i < e; ++i) { - char c = text[i]; - if (c >= minDigit && c <= '\u0039') { - text[i] = (char)(c + base); + synchronized (NumericShaper.class) { + for (int i = start, e = start + count; i < e; ++i) { + char c = text[i]; + if (c >= minDigit && c <= '\u0039') { + text[i] = (char)(c + base); + } + + if (isStrongDirectional(c)) { + int newkey = getContextKey(c); + if (newkey != lastkey) { + lastkey = newkey; + + ctxKey = newkey; + if (((mask & EASTERN_ARABIC) != 0) && (ctxKey == ARABIC_KEY || ctxKey == EASTERN_ARABIC_KEY)) { + ctxKey = EASTERN_ARABIC_KEY; + } else if ((mask & (1<= minDigit && c <= '9') { + text[i] = (char)(c + base); + continue; + } if (isStrongDirectional(c)) { - int newkey = getContextKey(c); - if (newkey != lastkey) { - lastkey = newkey; - - ctxKey = newkey; - if (((mask & EASTERN_ARABIC) != 0) && (ctxKey == ARABIC_KEY || ctxKey == EASTERN_ARABIC_KEY)) { - ctxKey = EASTERN_ARABIC_KEY; - } else if ((mask & (1<NumericShaper and shapes identically to this one. + * Returns {@code true} if the specified object is an instance of + * NumericShaper and shapes identically to this one, + * regardless of the range representations, the bit mask or the + * enum. For example, the following code produces {@code "true"}. + *

+     * NumericShaper ns1 = NumericShaper.getShaper(NumericShaper.ARABIC);
+     * NumericShaper ns2 = NumericShaper.getShaper(NumericShaper.Range.ARABIC);
+     * System.out.println(ns1.equals(ns2));
+     * 
+ * * @param o the specified object to compare to this * NumericShaper * @return true if o is an instance @@ -869,6 +1223,22 @@ public final class NumericShaper implements java.io.Serializable { if (o != null) { try { NumericShaper rhs = (NumericShaper)o; + if (rangeSet != null) { + if (rhs.rangeSet != null) { + return isContextual() == rhs.isContextual() + && rangeSet.equals(rhs.rangeSet) + && shapingRange == rhs.shapingRange; + } + return isContextual() == rhs.isContextual() + && rangeSet.equals(Range.maskToRangeSet(rhs.mask)) + && shapingRange == Range.indexToRange(rhs.key); + } else if (rhs.rangeSet != null) { + Set rset = Range.maskToRangeSet(mask); + Range srange = Range.indexToRange(key); + return isContextual() == rhs.isContextual() + && rset.equals(rhs.rangeSet) + && srange == rhs.shapingRange; + } return rhs.mask == mask && rhs.key == key; } catch (ClassCastException e) { @@ -885,23 +1255,29 @@ public final class NumericShaper implements java.io.Serializable { public String toString() { StringBuilder buf = new StringBuilder(super.toString()); - buf.append("[contextual:" + isContextual()); + buf.append("[contextual:").append(isContextual()); + String[] keyNames = null; if (isContextual()) { - buf.append(", context:" + keyNames[key]); + buf.append(", context:"); + buf.append(shapingRange == null ? Range.values()[key] : shapingRange); } - buf.append(", range(s): "); - boolean first = true; - for (int i = 0; i < NUM_KEYS; ++i) { - if ((mask & (1 << i)) != 0) { - if (first) { - first = false; - } else { - buf.append(", "); + if (rangeSet == null) { + buf.append(", range(s): "); + boolean first = true; + for (int i = 0; i < NUM_KEYS; ++i) { + if ((mask & (1 << i)) != 0) { + if (first) { + first = false; + } else { + buf.append(", "); + } + buf.append(Range.values()[i]); } - buf.append(keyNames[i]); } + } else { + buf.append(", range set: ").append(rangeSet); } buf.append(']'); @@ -940,7 +1316,6 @@ public final class NumericShaper implements java.io.Serializable { } if (value >= 1 << 1) { - value >>= 1; bit += 1; } @@ -950,7 +1325,7 @@ public final class NumericShaper implements java.io.Serializable { /** * fast binary search over subrange of array. */ - private static int search(char value, char[] array, int start, int length) + private static int search(int value, int[] array, int start, int length) { int power = 1 << getHighBit(length); int extra = length - power; @@ -971,4 +1346,27 @@ public final class NumericShaper implements java.io.Serializable { return index; } + + /** + * Converts the {@code NumericShaper.Range} enum-based parameters, + * if any, to the bit mask-based counterparts and writes this + * object to the {@code stream}. Any enum constants that have no + * bit mask-based counterparts are ignored in the conversion. + * + * @param stream the output stream to write to + * @throws IOException if an I/O error occurs while writing to {@code stream} + * @since 1.7 + */ + private void writeObject(ObjectOutputStream stream) throws IOException { + if (shapingRange != null) { + int index = Range.toRangeIndex(shapingRange); + if (index >= 0) { + key = index; + } + } + if (rangeSet != null) { + mask |= Range.toRangeMask(rangeSet); + } + stream.defaultWriteObject(); + } } diff --git a/jdk/test/java/awt/font/NumericShaper/EqualsTest.java b/jdk/test/java/awt/font/NumericShaper/EqualsTest.java new file mode 100644 index 00000000000..b71bacf42fe --- /dev/null +++ b/jdk/test/java/awt/font/NumericShaper/EqualsTest.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6842557 + * @summary confirm that an instance which is created with new Enum ranges is + * equivalent to another instance which is created with equivalent traditional + * ranges or the same Enum ranges. + */ + +import java.awt.font.NumericShaper; +import java.util.EnumSet; +import static java.awt.font.NumericShaper.*; + +public class EqualsTest { + public static void main(String[] args) { + NumericShaper ns1 = getContextualShaper(ARABIC | TAMIL, TAMIL); + NumericShaper ns2 = getContextualShaper( + EnumSet.of(Range.ARABIC, Range.TAMIL), + Range.TAMIL); + NumericShaper ns3 = getContextualShaper( + EnumSet.of(Range.ARABIC, Range.TAMIL), + Range.TAMIL); + NumericShaper ns4 = getContextualShaper( + EnumSet.of(Range.ARABIC, Range.TAMIL), + Range.ARABIC); + + if (!ns1.equals(ns2)) { + throw new RuntimeException("ns1 != ns2: ns1=" + ns1 + ", ns2=" + ns2); + } + if (!ns2.equals(ns1)) { + throw new RuntimeException("ns2 != ns1: ns1=" + ns1 + ", ns2=" + ns2); + } + if (!ns2.equals(ns3)) { + throw new RuntimeException("ns2 != ns3: ns2=" + ns2 + ", ns3=" + ns3); + } + if (ns1.equals(ns4)) { + throw new RuntimeException("ns1 == ns4: ns1=" + ns1 + ", ns4=" + ns4); + } + if (ns2.equals(ns4)) { + throw new RuntimeException("ns2 == ns4: ns2=" + ns2 + ", ns4=" + ns4); + } + } +} diff --git a/jdk/test/java/awt/font/NumericShaper/MTTest.java b/jdk/test/java/awt/font/NumericShaper/MTTest.java new file mode 100644 index 00000000000..e2598c3c36d --- /dev/null +++ b/jdk/test/java/awt/font/NumericShaper/MTTest.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6843181 + * @summary Confirm that NumericShaper is thread-safe. + * @run main/timeout=300/othervm MTTest + */ + +import java.awt.font.NumericShaper; +import java.util.Arrays; +import java.util.EnumSet; +import static java.awt.font.NumericShaper.*; + +public class MTTest { + static volatile boolean runrun = true; + static volatile boolean err = false; + + final static String text = "-123 (English) 456.00 (Arabic) \u0641\u0642\u0643 -789 (Thai) \u0e01\u0e33 01.23"; + static char[] t1, t2; + static NumericShaper ns1, ns2, ns3, ns4; + + public static void main(String[] args) { + System.out.println(" original: " + text); + ns1 = getContextualShaper(EnumSet.of(Range.ARABIC), Range.ARABIC); + t1 = text.toCharArray(); + ns1.shape(t1, 0, t1.length); + System.out.println("expected t1: " + String.valueOf(t1)); + + ns2 = getContextualShaper(EnumSet.of(Range.THAI), Range.THAI); + t2 = text.toCharArray(); + ns2.shape(t2, 0, t2.length); + System.out.println("expected t2: " + String.valueOf(t2)); + + ns3 = getContextualShaper(ARABIC, ARABIC); + ns4 = getContextualShaper(THAI, THAI); + + Thread th1 = new Thread(new Work(ns1, t1)); + Thread th2 = new Thread(new Work(ns2, t2)); + Thread th3 = new Thread(new Work(ns1, t1)); + Thread th4 = new Thread(new Work(ns2, t2)); + Thread th5 = new Thread(new Work(ns3, t1)); + Thread th6 = new Thread(new Work(ns4, t2)); + Thread th7 = new Thread(new Work(ns3, t1)); + Thread th8 = new Thread(new Work(ns4, t2)); + + th1.start(); + th2.start(); + th3.start(); + th4.start(); + th5.start(); + th6.start(); + th7.start(); + th8.start(); + + try { + for (int i = 0; runrun && i < 180; i++) { + Thread.sleep(1000); // 1 seconds + } + runrun = false; + th1.join(); + th2.join(); + th3.join(); + th4.join(); + th5.join(); + th6.join(); + th7.join(); + th8.join(); + } + catch (InterruptedException e) { + } + + if (err) { + throw new RuntimeException("Thread-safe test failed."); + } + } + + private static class Work implements Runnable { + NumericShaper ns; + char[] expectedText; + + Work(NumericShaper ns, char[] expectedText) { + this.ns = ns; + this.expectedText = expectedText; + + } + + public void run() { + int count = 0; + while (runrun) { + char[] t = text.toCharArray(); + try { + count++; + ns.shape(t, 0, t.length); + } catch (Exception e) { + System.err.println("Error: Unexpected exception: " + e); + runrun = false; + err = true; + return; + } + if (!Arrays.equals(t, expectedText)) { + System.err.println("Error: shape() returned unexpected value: "); + System.err.println("count = " + count); + System.err.println(" expected: " + String.valueOf(expectedText)); + System.err.println(" got: " + String.valueOf(t)); + runrun = false; + err = true; + return; + } + } + } + } +} diff --git a/jdk/test/java/awt/font/NumericShaper/ShapingTest.java b/jdk/test/java/awt/font/NumericShaper/ShapingTest.java new file mode 100644 index 00000000000..047e67f12d3 --- /dev/null +++ b/jdk/test/java/awt/font/NumericShaper/ShapingTest.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6842557 + * @summary confirm that shaping works as expected. (Mainly for new characters which were added in Unicode 5) + * used where appropriate. + */ + +import java.awt.font.NumericShaper; +import java.util.EnumSet; +import static java.awt.font.NumericShaper.*; + +public class ShapingTest { + public static void main(String[] args) { + NumericShaper ns_old = getContextualShaper(ARABIC | TAMIL | ETHIOPIC, + EUROPEAN); + NumericShaper ns_new = getContextualShaper(EnumSet.of( + Range.ARABIC, Range.TAMIL, Range.ETHIOPIC), + Range.EUROPEAN); + + boolean err = false; + + String[][] data = { + // Arabic "October 10" + {"\u0623\u0643\u062a\u0648\u0628\u0631 10", + "\u0623\u0643\u062a\u0648\u0628\u0631 \u0661\u0660"}, + + // Tamil "Year 2009" + {"\u0b86\u0ba3\u0bcd\u0b9f\u0bc1 2009", + "\u0b86\u0ba3\u0bcd\u0b9f\u0bc1 \u0be8\u0be6\u0be6\u0bef"}, + // "\u0be800\u0bef is returned by pre-JDK7 because Tamil zero was not + // included in Unicode 4.0.0. + + // Ethiopic "Syllable 2009" + {"\u1200 2009", + "\u1200 \u136a00\u1371"}, + // Ethiopic zero doesn't exist even in Unicode 5.1.0. + }; + + for (int i = 0; i < data.length; i++) { + String expected = data[i][1]; + + char[] text = data[i][0].toCharArray(); + ns_old.shape(text, 0, text.length); + String got = new String(text); + + if (!expected.equals(got)) { + err = true; + System.err.println("Error with traditional range."); + System.err.println(" text = " + data[i][0]); + System.err.println(" got = " + got); + System.err.println(" expected = " + expected); + } else { + System.err.println("OK with traditional range."); + System.err.println(" text = " + data[i][0]); + System.err.println(" got = " + got); + System.err.println(" expected = " + expected); + } + + text = data[i][0].toCharArray(); + ns_new.shape(text, 0, text.length); + got = new String(text); + + if (!expected.equals(got)) { + err = true; + System.err.println("Error with new Enum range."); + System.err.println(" text = " + data[i][0]); + System.err.println(" got = " + got); + System.err.println(" expected = " + expected); + } else { + System.err.println("OK with new Enum range."); + System.err.println(" text = " + data[i][0]); + System.err.println(" got = " + got); + System.err.println(" expected = " + expected); + } + } + + if (err) { + throw new RuntimeException("shape() returned unexpected value."); + } + } + +} From 69fbaac381a92454bef364f4d4d279f9d67fc38a Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Mon, 16 Nov 2009 18:13:15 +0000 Subject: [PATCH 33/36] 6890458: Datatransfer API should not require RMI to be present Reviewed-by: uta --- .../java/awt/datatransfer/DataFlavor.java | 2 +- .../sun/awt/datatransfer/DataTransferer.java | 112 +++++++++++++++++- 2 files changed, 107 insertions(+), 7 deletions(-) diff --git a/jdk/src/share/classes/java/awt/datatransfer/DataFlavor.java b/jdk/src/share/classes/java/awt/datatransfer/DataFlavor.java index 0e559e5d359..36378882e15 100644 --- a/jdk/src/share/classes/java/awt/datatransfer/DataFlavor.java +++ b/jdk/src/share/classes/java/awt/datatransfer/DataFlavor.java @@ -1184,7 +1184,7 @@ public class DataFlavor implements Externalizable, Cloneable { */ public boolean isRepresentationClassRemote() { - return java.rmi.Remote.class.isAssignableFrom(representationClass); + return DataTransferer.isRemote(representationClass); } /** diff --git a/jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java b/jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java index 521e691024c..277d3bd9e28 100644 --- a/jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java +++ b/jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java @@ -63,8 +63,6 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.rmi.MarshalledObject; - import java.security.AccessControlContext; import java.security.AccessControlException; import java.security.AccessController; @@ -493,6 +491,13 @@ public abstract class DataTransferer { } } + /** + * Returns {@code true} if the given type is a java.rmi.Remote. + */ + public static boolean isRemote(Class type) { + return RMI.isRemote(type); + } + /** * Returns an Iterator which traverses a SortedSet of Strings which are * a total order of the standard character sets supported by the JRE. The @@ -1360,7 +1365,7 @@ search: // Source data is an RMI object } else if (flavor.isRepresentationClassRemote()) { - MarshalledObject mo = new MarshalledObject(obj); + Object mo = RMI.newMarshalledObject(obj); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(mo); oos.close(); @@ -1671,7 +1676,7 @@ search: try { byte[] ba = inputStreamToByteArray(str); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(ba)); - Object ret = ((MarshalledObject)(ois.readObject())).get(); + Object ret = RMI.getMarshalledObject(ois.readObject()); ois.close(); str.close(); return ret; @@ -2669,8 +2674,12 @@ search: Integer.valueOf(0)); nonTextRepresentationsMap.put(java.io.Serializable.class, Integer.valueOf(1)); - nonTextRepresentationsMap.put(java.rmi.Remote.class, - Integer.valueOf(2)); + + Class remoteClass = RMI.remoteClass(); + if (remoteClass != null) { + nonTextRepresentationsMap.put(remoteClass, + Integer.valueOf(2)); + } nonTextRepresentations = Collections.unmodifiableMap(nonTextRepresentationsMap); @@ -2900,4 +2909,95 @@ search: } } } + + /** + * A class that provides access to java.rmi.Remote and java.rmi.MarshalledObject + * without creating a static dependency. + */ + private static class RMI { + private static final Class remoteClass = getClass("java.rmi.Remote"); + private static final Class marshallObjectClass = + getClass("java.rmi.MarshalledObject"); + private static final Constructor marshallCtor = + getConstructor(marshallObjectClass, Object.class); + private static final Method marshallGet = + getMethod(marshallObjectClass, "get"); + + private static Class getClass(String name) { + try { + return Class.forName(name, true, null); + } catch (ClassNotFoundException e) { + return null; + } + } + + private static Constructor getConstructor(Class c, Class... types) { + try { + return (c == null) ? null : c.getDeclaredConstructor(types); + } catch (NoSuchMethodException x) { + throw new AssertionError(x); + } + } + + private static Method getMethod(Class c, String name, Class... types) { + try { + return (c == null) ? null : c.getMethod(name, types); + } catch (NoSuchMethodException e) { + throw new AssertionError(e); + } + } + + /** + * Returns {@code true} if the given class is java.rmi.Remote. + */ + static boolean isRemote(Class c) { + return (remoteClass == null) ? null : remoteClass.isAssignableFrom(c); + } + + /** + * Returns java.rmi.Remote.class if RMI is present; otherwise {@code null}. + */ + static Class remoteClass() { + return remoteClass; + } + + /** + * Returns a new MarshalledObject containing the serialized representation + * of the given object. + */ + static Object newMarshalledObject(Object obj) throws IOException { + try { + return marshallCtor.newInstance(obj); + } catch (InstantiationException x) { + throw new AssertionError(x); + } catch (IllegalAccessException x) { + throw new AssertionError(x); + } catch (InvocationTargetException x) { + Throwable cause = x.getCause(); + if (cause instanceof IOException) + throw (IOException)cause; + throw new AssertionError(x); + } + } + + /** + * Returns a new copy of the contained marshalled object. + */ + static Object getMarshalledObject(Object obj) + throws IOException, ClassNotFoundException + { + try { + return marshallGet.invoke(obj); + } catch (IllegalAccessException x) { + throw new AssertionError(x); + } catch (InvocationTargetException x) { + Throwable cause = x.getCause(); + if (cause instanceof IOException) + throw (IOException)cause; + if (cause instanceof ClassNotFoundException) + throw (ClassNotFoundException)cause; + throw new AssertionError(x); + } + } + } } From 7ab71fb443475ac07a6ee5ca7aa62109005998a1 Mon Sep 17 00:00:00 2001 From: Pavel Porvatov Date: Tue, 17 Nov 2009 16:01:09 +0300 Subject: [PATCH 34/36] 6868611: FileSystemView throws NullPointerException Reviewed-by: peterz --- .../swing/filechooser/FileSystemView.java | 166 +++++++++++------- .../JFileChooser/6868611/bug6868611.java | 93 ++++++++++ 2 files changed, 191 insertions(+), 68 deletions(-) create mode 100644 jdk/test/javax/swing/JFileChooser/6868611/bug6868611.java diff --git a/jdk/src/share/classes/javax/swing/filechooser/FileSystemView.java b/jdk/src/share/classes/javax/swing/filechooser/FileSystemView.java index 9f969796bdd..7c7ef7b6686 100644 --- a/jdk/src/share/classes/javax/swing/filechooser/FileSystemView.java +++ b/jdk/src/share/classes/javax/swing/filechooser/FileSystemView.java @@ -33,7 +33,8 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.text.MessageFormat; -import java.util.Vector; +import java.util.List; +import java.util.ArrayList; import java.lang.ref.WeakReference; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeEvent; @@ -173,22 +174,27 @@ public abstract class FileSystemView { * @since 1.4 */ public String getSystemDisplayName(File f) { - String name = null; - if (f != null) { - name = f.getName(); - if (!name.equals("..") && !name.equals(".") && - (useSystemExtensionHiding || - !isFileSystem(f) || - isFileSystemRoot(f)) && - ((f instanceof ShellFolder) || - f.exists())) { + if (f == null) { + return null; + } + String name = f.getName(); + + if (!name.equals("..") && !name.equals(".") && + (useSystemExtensionHiding || !isFileSystem(f) || isFileSystemRoot(f)) && + (f instanceof ShellFolder || f.exists())) { + + try { name = getShellFolder(f).getDisplayName(); - if (name == null || name.length() == 0) { - name = f.getPath(); // e.g. "/" - } + } catch (FileNotFoundException e) { + return null; + } + + if (name == null || name.length() == 0) { + name = f.getPath(); // e.g. "/" } } + return name; } @@ -222,17 +228,25 @@ public abstract class FileSystemView { * @since 1.4 */ public Icon getSystemIcon(File f) { - if (f != null) { - ShellFolder sf = getShellFolder(f); - Image img = sf.getIcon(false); - if (img != null) { - return new ImageIcon(img, sf.getFolderType()); - } else { - return UIManager.getIcon(f.isDirectory() ? "FileView.directoryIcon" : "FileView.fileIcon"); - } - } else { + if (f == null) { return null; } + + ShellFolder sf; + + try { + sf = getShellFolder(f); + } catch (FileNotFoundException e) { + return null; + } + + Image img = sf.getIcon(false); + + if (img != null) { + return new ImageIcon(img, sf.getFolderType()); + } else { + return UIManager.getIcon(f.isDirectory() ? "FileView.directoryIcon" : "FileView.fileIcon"); + } } /** @@ -446,24 +460,28 @@ public abstract class FileSystemView { * Gets the list of shown (i.e. not hidden) files. */ public File[] getFiles(File dir, boolean useFileHiding) { - Vector files = new Vector(); - + List files = new ArrayList(); // add all files in dir - File[] names; - if (!(dir instanceof ShellFolder)) { + if (!(dir instanceof ShellFolder)) { + try { dir = getShellFolder(dir); + } catch (FileNotFoundException e) { + return new File[0]; } + } - names = ((ShellFolder)dir).listFiles(!useFileHiding); - File f; + File[] names = ((ShellFolder) dir).listFiles(!useFileHiding); - int nameCount = (names == null) ? 0 : names.length; - for (int i = 0; i < nameCount; i++) { + if (names == null) { + return new File[0]; + } + + for (File f : names) { if (Thread.currentThread().isInterrupted()) { break; } - f = names[i]; + if (!(f instanceof ShellFolder)) { if (isFileSystemRoot(f)) { f = createFileSystemRoot(f); @@ -481,7 +499,7 @@ public abstract class FileSystemView { } } if (!useFileHiding || !isHiddenFile(f)) { - files.addElement(f); + files.add(f); } } @@ -497,42 +515,50 @@ public abstract class FileSystemView { * null if dir is null */ public File getParentDirectory(File dir) { - if (dir != null && dir.exists()) { - ShellFolder sf = getShellFolder(dir); - File psf = sf.getParentFile(); - if (psf != null) { - if (isFileSystem(psf)) { - File f = psf; - if (f != null && !f.exists()) { - // This could be a node under "Network Neighborhood". - File ppsf = psf.getParentFile(); - if (ppsf == null || !isFileSystem(ppsf)) { - // We're mostly after the exists() override for windows below. - f = createFileSystemRoot(f); - } - } - return f; - } else { - return psf; + if (dir == null || !dir.exists()) { + return null; + } + + ShellFolder sf; + + try { + sf = getShellFolder(dir); + } catch (FileNotFoundException e) { + return null; + } + + File psf = sf.getParentFile(); + + if (psf == null) { + return null; + } + + if (isFileSystem(psf)) { + File f = psf; + if (!f.exists()) { + // This could be a node under "Network Neighborhood". + File ppsf = psf.getParentFile(); + if (ppsf == null || !isFileSystem(ppsf)) { + // We're mostly after the exists() override for windows below. + f = createFileSystemRoot(f); } } + return f; + } else { + return psf; } - return null; } - ShellFolder getShellFolder(File f) { - if (!(f instanceof ShellFolder) - && !(f instanceof FileSystemRoot) - && isFileSystemRoot(f)) { - + /** + * Throws {@code FileNotFoundException} if file not found or current thread was interrupted + */ + ShellFolder getShellFolder(File f) throws FileNotFoundException { + if (!(f instanceof ShellFolder) && !(f instanceof FileSystemRoot) && isFileSystemRoot(f)) { f = createFileSystemRoot(f); } + try { return ShellFolder.getShellFolder(f); - } catch (FileNotFoundException e) { - System.err.println("FileSystemView.getShellFolder: f="+f); - e.printStackTrace(); - return null; } catch (InternalError e) { System.err.println("FileSystemView.getShellFolder: f="+f); e.printStackTrace(); @@ -596,9 +622,9 @@ class UnixFileSystemView extends FileSystemView { // Unix - using OpenWindows' default folder name. Can't find one for Motif/CDE. newFolder = createFileObject(containingDir, newFolderString); int i = 1; - while (newFolder.exists() && (i < 100)) { + while (newFolder.exists() && i < 100) { newFolder = createFileObject(containingDir, MessageFormat.format( - newFolderNextString, new Object[] { new Integer(i) })); + newFolderNextString, new Integer(i))); i++; } @@ -612,7 +638,7 @@ class UnixFileSystemView extends FileSystemView { } public boolean isFileSystemRoot(File dir) { - return (dir != null && dir.getAbsolutePath().equals("/")); + return dir != null && dir.getAbsolutePath().equals("/"); } public boolean isDrive(File dir) { @@ -654,7 +680,7 @@ class WindowsFileSystemView extends FileSystemView { public File getChild(File parent, String fileName) { if (fileName.startsWith("\\") - && !(fileName.startsWith("\\\\")) + && !fileName.startsWith("\\\\") && isFileSystem(parent)) { //Path is relative to the root of parent's drive @@ -677,9 +703,13 @@ class WindowsFileSystemView extends FileSystemView { * The Windows implementation gets information from the ShellFolder class. */ public String getSystemTypeDescription(File f) { - if (f != null) { + if (f == null) { + return null; + } + + try { return getShellFolder(f).getFolderType(); - } else { + } catch (FileNotFoundException e) { return null; } } @@ -701,9 +731,9 @@ class WindowsFileSystemView extends FileSystemView { // Using NT's default folder name File newFolder = createFileObject(containingDir, newFolderString); int i = 2; - while (newFolder.exists() && (i < 100)) { + while (newFolder.exists() && i < 100) { newFolder = createFileObject(containingDir, MessageFormat.format( - newFolderNextString, new Object[] { new Integer(i) })); + newFolderNextString, new Integer(i))); i++; } @@ -727,7 +757,7 @@ class WindowsFileSystemView extends FileSystemView { } }); - return (path != null && (path.equals("A:\\") || path.equals("B:\\"))); + return path != null && (path.equals("A:\\") || path.equals("B:\\")); } /** diff --git a/jdk/test/javax/swing/JFileChooser/6868611/bug6868611.java b/jdk/test/javax/swing/JFileChooser/6868611/bug6868611.java new file mode 100644 index 00000000000..fa555c7659b --- /dev/null +++ b/jdk/test/javax/swing/JFileChooser/6868611/bug6868611.java @@ -0,0 +1,93 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @bug 6868611 + @summary FileSystemView throws NullPointerException + @author Pavel Porvatov + @run main bug6868611 +*/ + +import javax.swing.*; +import javax.swing.filechooser.FileSystemView; +import java.io.File; + +public class bug6868611 { + private static final int COUNT = 1000; + + public static void main(String[] args) throws Exception { + String tempDirProp = System.getProperty("java.io.tmpdir"); + + final String tempDir = tempDirProp == null || !new File(tempDirProp).isDirectory() ? + System.getProperty("user.home") : tempDirProp; + + System.out.println("Temp directory: " + tempDir); + + // Create 1000 files + for (int i = 0; i < 1000; i++) { + new File(tempDir, "temp" + i).createNewFile(); + } + + // Init default FileSystemView + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + FileSystemView.getFileSystemView().getFiles(new File(tempDir), false); + } + }); + + for (int i = 0; i < COUNT; i++) { + Thread thread = new MyThread(tempDir); + + thread.start(); + + Thread.sleep((long) (Math.random() * 100)); + + thread.interrupt(); + + if (i % 100 == 0) { + System.out.print("*"); + } + } + + System.out.println(); + + // Remove 1000 files + for (int i = 0; i < 1000; i++) { + new File(tempDir, "temp" + i).delete(); + } + } + + private static class MyThread extends Thread { + private final String dir; + + private MyThread(String dir) { + this.dir = dir; + } + + public void run() { + FileSystemView fileSystemView = FileSystemView.getFileSystemView(); + + fileSystemView.getFiles(new File(dir), false); + } + } +} From 207583b21ec6991a36b1d4c4585f50ad656e99d5 Mon Sep 17 00:00:00 2001 From: Pavel Porvatov Date: Wed, 18 Nov 2009 12:58:02 +0300 Subject: [PATCH 35/36] 6520574: JFileChooser - create new folder - not editable Reviewed-by: malenkov --- .../classes/javax/swing/plaf/basic/BasicDirectoryModel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java b/jdk/src/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java index 1e5d80f8ea2..77709a94401 100644 --- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java +++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java @@ -486,7 +486,7 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh } if (remSize > 0 && addSize == 0) { fireIntervalRemoved(BasicDirectoryModel.this, remStart, remStart + remSize - 1); - } else if (addSize > 0 && remSize == 0 && fileCache.size() > addSize) { + } else if (addSize > 0 && remSize == 0 && addStart + addSize <= fileCache.size()) { fireIntervalAdded(BasicDirectoryModel.this, addStart, addStart + addSize - 1); } else { fireContentsChanged(); From 92cb82eecb1aa61ebab06105d2b694ec1708d5c3 Mon Sep 17 00:00:00 2001 From: Peter Zhelezniakov Date: Wed, 18 Nov 2009 17:36:46 +0300 Subject: [PATCH 36/36] 6882917: Nimbus and DefaultTableCellRenderer: must start with normal background Reviewed-by: rupashka --- jdk/src/share/classes/javax/swing/plaf/synth/SynthTableUI.java | 2 +- .../classes/javax/swing/table/DefaultTableCellRenderer.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/jdk/src/share/classes/javax/swing/plaf/synth/SynthTableUI.java b/jdk/src/share/classes/javax/swing/plaf/synth/SynthTableUI.java index 1b8cf989446..dcd6b6275bf 100644 --- a/jdk/src/share/classes/javax/swing/plaf/synth/SynthTableUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/synth/SynthTableUI.java @@ -638,7 +638,7 @@ class SynthTableUI extends BasicTableUI implements SynthUI, if ((b == null || b instanceof UIResource || component instanceof SynthBooleanTableCellRenderer) && !table.isCellSelected(row, column)) { - if (alternateColor != null && row % 2 == 0) { + if (alternateColor != null && row % 2 != 0) { component.setBackground(alternateColor); } } diff --git a/jdk/src/share/classes/javax/swing/table/DefaultTableCellRenderer.java b/jdk/src/share/classes/javax/swing/table/DefaultTableCellRenderer.java index 07e7265c9bf..0c2b6a97367 100644 --- a/jdk/src/share/classes/javax/swing/table/DefaultTableCellRenderer.java +++ b/jdk/src/share/classes/javax/swing/table/DefaultTableCellRenderer.java @@ -214,8 +214,9 @@ public class DefaultTableCellRenderer extends JLabel : table.getBackground(); if (background == null || background instanceof javax.swing.plaf.UIResource) { Color alternateColor = DefaultLookup.getColor(this, ui, "Table.alternateRowColor"); - if (alternateColor != null && row % 2 == 0) + if (alternateColor != null && row % 2 != 0) { background = alternateColor; + } } super.setForeground(unselectedForeground != null ? unselectedForeground