6809227: poor performance on Panel.Add() method in jdk6

Reviewed-by: art, anthony
This commit is contained in:
Dmitry Cherepanov 2009-03-04 13:05:56 +03:00
parent 7a593ea895
commit 8a7cd86a28
18 changed files with 141 additions and 234 deletions

View File

@ -93,6 +93,7 @@ SUNWprivate_1.1 {
Java_sun_awt_X11_XlibWrapper_XGetWMHints; Java_sun_awt_X11_XlibWrapper_XGetWMHints;
Java_sun_awt_X11_XlibWrapper_XShapeQueryExtension; Java_sun_awt_X11_XlibWrapper_XShapeQueryExtension;
Java_sun_awt_X11_XlibWrapper_SetRectangularShape; Java_sun_awt_X11_XlibWrapper_SetRectangularShape;
Java_sun_awt_X11_XlibWrapper_SetZOrder;
Java_sun_awt_X11_XToolkit_initIDs; Java_sun_awt_X11_XToolkit_initIDs;
Java_sun_awt_X11_XWindow_getNativeColor; Java_sun_awt_X11_XWindow_getNativeColor;
Java_sun_awt_X11_XWindow_getWMInsets; Java_sun_awt_X11_XWindow_getWMInsets;

View File

@ -6656,23 +6656,7 @@ public abstract class Component implements ImageObserver, MenuContainer,
// Update stacking order // Update stacking order
if (parent != null && parent.peer != null) { peer.setZOrder(getHWPeerAboveMe());
ContainerPeer parentContPeer = (ContainerPeer) parent.peer;
// if our parent is lightweight and we are not
// we should call restack on nearest heavyweight
// container.
if (parentContPeer instanceof LightweightPeer
&& ! (peer instanceof LightweightPeer))
{
Container hwParent = getNativeContainer();
if (hwParent != null && hwParent.peer != null) {
parentContPeer = (ContainerPeer) hwParent.peer;
}
}
if (parentContPeer.isRestackSupported()) {
parentContPeer.restack();
}
}
if (!isAddNotifyComplete) { if (!isAddNotifyComplete) {
mixOnShowing(); mixOnShowing();
@ -9546,6 +9530,27 @@ public abstract class Component implements ImageObserver, MenuContainer,
return nextAbove < 0 ? -1 : nextAbove; return nextAbove < 0 ? -1 : nextAbove;
} }
final ComponentPeer getHWPeerAboveMe() {
checkTreeLock();
Container cont = getContainer();
int indexAbove = getSiblingIndexAbove();
while (cont != null) {
for (int i = indexAbove; i > -1; i--) {
Component comp = cont.getComponent(i);
if (comp != null && comp.isDisplayable() && !comp.isLightweight()) {
return comp.getPeer();
}
}
indexAbove = cont.getSiblingIndexAbove();
cont = cont.getContainer();
}
return null;
}
final int getSiblingIndexBelow() { final int getSiblingIndexBelow() {
checkTreeLock(); checkTreeLock();
Container parent = getContainer(); Container parent = getContainer();

View File

@ -649,10 +649,7 @@ public class Container extends Component {
// each HW descendant independently. // each HW descendant independently.
return !comp.peer.isReparentSupported(); return !comp.peer.isReparentSupported();
} else { } else {
// if container didn't change we still might need to recreate component's window as return false;
// changes to zorder should be reflected in native window stacking order and it might
// not be supported by the platform. This is important only for heavyweight child
return !((ContainerPeer)(newNativeContainer.peer)).isRestackSupported();
} }
} }
@ -809,11 +806,6 @@ public class Container extends Component {
if (peer != null) { if (peer != null) {
if (comp.peer == null) { // Remove notify was called or it didn't have peer - create new one if (comp.peer == null) { // Remove notify was called or it didn't have peer - create new one
comp.addNotify(); comp.addNotify();
// New created peer creates component on top of the stacking order
Container newNativeContainer = getHeavyweightContainer();
if (((ContainerPeer)newNativeContainer.getPeer()).isRestackSupported()) {
((ContainerPeer)newNativeContainer.getPeer()).restack();
}
} else { // Both container and child have peers, it means child peer should be reparented. } else { // Both container and child have peers, it means child peer should be reparented.
// In both cases we need to reparent native widgets. // In both cases we need to reparent native widgets.
Container newNativeContainer = getHeavyweightContainer(); Container newNativeContainer = getHeavyweightContainer();
@ -822,13 +814,8 @@ public class Container extends Component {
// Native container changed - need to reparent native widgets // Native container changed - need to reparent native widgets
newNativeContainer.reparentChild(comp); newNativeContainer.reparentChild(comp);
} }
// If component still has a peer and it is either container or heavyweight comp.peer.setZOrder(comp.getHWPeerAboveMe());
// and restack is supported we have to restack native windows since order might have changed
if ((!comp.isLightweight() || (comp instanceof Container))
&& ((ContainerPeer)newNativeContainer.getPeer()).isRestackSupported())
{
((ContainerPeer)newNativeContainer.getPeer()).restack();
}
if (!comp.isLightweight() && isLightweight()) { if (!comp.isLightweight() && isLightweight()) {
// If component is heavyweight and one of the containers is lightweight // If component is heavyweight and one of the containers is lightweight
// the location of the component should be fixed. // the location of the component should be fixed.
@ -2607,13 +2594,6 @@ public class Container extends Component {
for (int i = 0; i < component.size(); i++) { for (int i = 0; i < component.size(); i++) {
component.get(i).addNotify(); component.get(i).addNotify();
} }
// Update stacking order if native platform allows
ContainerPeer cpeer = (ContainerPeer)peer;
if (cpeer.isRestackSupported()) {
cpeer.restack();
}
} }
} }

View File

@ -539,6 +539,12 @@ public interface ComponentPeer {
*/ */
void applyShape(Region shape); void applyShape(Region shape);
/**
* Lowers this component at the bottom of the above HW peer. If the above parameter
* is null then the method places this component at the top of the Z-order.
*/
void setZOrder(ComponentPeer above);
/** /**
* Updates internal data structures related to the component's GC. * Updates internal data structures related to the component's GC.
* *

View File

@ -76,21 +76,4 @@ public interface ContainerPeer extends ComponentPeer {
* @see Container#validateTree() * @see Container#validateTree()
*/ */
void endLayout(); void endLayout();
/**
* Restacks native windows - children of this native window - according to
* Java container order.
*
* @since 1.5
*/
void restack();
/**
* Indicates availability of restacking operation in this container.
*
* @return Returns true if restack is supported, false otherwise
*
* @since 1.5
*/
boolean isRestackSupported();
} }

View File

@ -278,19 +278,6 @@ public class NullComponentPeer implements LightweightPeer,
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
/**
* @see java.awt.peer.ContainerPeer#restack
*/
public void restack() {
throw new UnsupportedOperationException();
}
/**
* @see java.awt.peer.ContainerPeer#isRestackSupported
*/
public boolean isRestackSupported() {
return false;
}
public void layout() { public void layout() {
} }
@ -306,6 +293,13 @@ public class NullComponentPeer implements LightweightPeer,
public void applyShape(Region shape) { public void applyShape(Region shape) {
} }
/**
* Lowers this component at the bottom of the above HW peer. If the above parameter
* is null then the method places this component at the top of the Z-order.
*/
public void setZOrder(ComponentPeer above) {
}
public void updateGraphicsData(GraphicsConfiguration gc) {} public void updateGraphicsData(GraphicsConfiguration gc) {}
public GraphicsConfiguration getAppropriateGraphicsConfiguration( public GraphicsConfiguration getAppropriateGraphicsConfiguration(

View File

@ -1415,59 +1415,21 @@ public class XComponentPeer extends XWindow implements ComponentPeer, DropTarget
} }
} }
public void restack() { /**
synchronized(target.getTreeLock()) { * Lowers this component at the bottom of the above HW peer. If the above parameter
// Build the list of X windows in the window corresponding to this container * is null then the method places this component at the top of the Z-order.
// This list is already in correct Java stacking order */
Container cont = (Container)target; public void setZOrder(ComponentPeer above) {
Vector order = new Vector(cont.getComponentCount()); long aboveWindow = (above != null) ? ((XComponentPeer)above).getWindow() : 0;
HashSet set = new HashSet();
addTree(order, set, cont); XToolkit.awtLock();
try{
XToolkit.awtLock(); XlibWrapper.SetZOrder(XToolkit.getDisplay(), getWindow(), aboveWindow);
try { }finally{
// Get the current list of X window in X window. Some of the windows XToolkit.awtUnlock();
// might be only native
XQueryTree qt = new XQueryTree(getContentWindow());
try {
if (qt.execute() != 0) {
if (qt.get_nchildren() != 0) {
long pchildren = qt.get_children();
int j = 0; // index to insert
for (int i = 0; i < qt.get_nchildren(); i++) {
Long w = Long.valueOf(Native.getLong(pchildren, i));
if (!set.contains(w)) {
set.add(w);
order.add(j++, w);
}
}
}
}
if (order.size() != 0) {
// Create native array of the windows
long windows = Native.allocateLongArray(order.size());
Native.putLong(windows, order);
// Restack native window according to the new order
XlibWrapper.XRestackWindows(XToolkit.getDisplay(), windows, order.size());
XlibWrapper.unsafe.freeMemory(windows);
}
} finally {
qt.dispose();
}
} finally {
XToolkit.awtUnlock();
}
} }
} }
public boolean isRestackSupported() {
return true;
}
private void addTree(Collection order, Set set, Container cont) { private void addTree(Collection order, Set set, Container cont) {
for (int i = 0; i < cont.getComponentCount(); i++) { for (int i = 0; i < cont.getComponentCount(); i++) {
Component comp = cont.getComponent(i); Component comp = cont.getComponent(i);

View File

@ -380,5 +380,8 @@ public class XEmbedChildProxyPeer implements ComponentPeer, XEventDispatcher{
public void applyShape(Region shape) { public void applyShape(Region shape) {
} }
public void setZOrder(ComponentPeer above) {
}
public void updateGraphicsData(GraphicsConfiguration gc) {} public void updateGraphicsData(GraphicsConfiguration gc) {}
} }

View File

@ -533,6 +533,7 @@ static native String XSetLocaleModifiers(String modifier_list);
static native void SetRectangularShape(long display, long window, static native void SetRectangularShape(long display, long window,
int lox, int loy, int hix, int hiy, int lox, int loy, int hix, int hiy,
sun.java2d.pipe.Region region); sun.java2d.pipe.Region region);
static native void SetZOrder(long display, long window, long above);
/* Global memory area used for X lib parameter passing */ /* Global memory area used for X lib parameter passing */

View File

@ -1945,3 +1945,31 @@ Java_sun_awt_X11_XlibWrapper_SetRectangularShape
ShapeBounding, 0, 0, None, ShapeSet); ShapeBounding, 0, 0, None, ShapeSet);
} }
} }
/*
* Class: XlibWrapper
* Method: SetZOrder
*/
JNIEXPORT void JNICALL
Java_sun_awt_X11_XlibWrapper_SetZOrder
(JNIEnv *env, jclass clazz, jlong display, jlong window, jlong above)
{
AWT_CHECK_HAVE_LOCK();
XWindowChanges wc;
wc.sibling = (Window)jlong_to_ptr(above);
unsigned int value_mask = CWStackMode;
if (above == 0) {
wc.stack_mode = Above;
} else {
wc.stack_mode = Below;
value_mask |= CWSibling;
}
XConfigureWindow((Display *)jlong_to_ptr(display),
(Window)jlong_to_ptr(window),
value_mask, &wc );
}

View File

@ -941,4 +941,15 @@ public abstract class WComponentPeer extends WObjectPeer
} }
} }
/**
* Lowers this component at the bottom of the above component. If the above parameter
* is null then the method places this component at the top of the Z-order.
*/
public void setZOrder(ComponentPeer above) {
long aboveHWND = (above != null) ? ((WComponentPeer)above).getHWnd() : 0;
setZOrder(aboveHWND);
}
private native void setZOrder(long above);
} }

View File

@ -231,20 +231,6 @@ public class WFileDialogPeer extends WWindowPeer implements FileDialogPeer {
*/ */
private static native void initIDs(); private static native void initIDs();
/**
* WFileDialogPeer doesn't have native pData so we don't do restack on it
* @see java.awt.peer.ContainerPeer#restack
*/
public void restack() {
}
/**
* @see java.awt.peer.ContainerPeer#isRestackSupported
*/
public boolean isRestackSupported() {
return false;
}
// The effects are not supported for system dialogs. // The effects are not supported for system dialogs.
public void applyShape(sun.java2d.pipe.Region shape) {} public void applyShape(sun.java2d.pipe.Region shape) {}
public void setOpacity(float opacity) {} public void setOpacity(float opacity) {}

View File

@ -143,20 +143,6 @@ public class WPrintDialogPeer extends WWindowPeer implements DialogPeer {
*/ */
private static native void initIDs(); private static native void initIDs();
/**
* WPrintDialogPeer doesn't have native pData so we don't do restack on it
* @see java.awt.peer.ContainerPeer#restack
*/
public void restack() {
}
/**
* @see java.awt.peer.ContainerPeer#isRestackSupported
*/
public boolean isRestackSupported() {
return false;
}
// The effects are not supported for system dialogs. // The effects are not supported for system dialogs.
public void applyShape(sun.java2d.pipe.Region shape) {} public void applyShape(sun.java2d.pipe.Region shape) {}
public void setOpacity(float opacity) {} public void setOpacity(float opacity) {}

View File

@ -269,10 +269,4 @@ class WScrollPanePeer extends WPanelPeer implements ScrollPanePeer {
} }
} }
/**
* @see java.awt.peer.ContainerPeer#restack
*/
public void restack() {
// Since ScrollPane can only have one child its restacking does nothing.
}
} }

View File

@ -149,6 +149,11 @@ struct GetInsetsStruct {
jobject window; jobject window;
RECT *insets; RECT *insets;
}; };
// Struct for _SetZOrder function
struct SetZOrderStruct {
jobject component;
jlong above;
};
/************************************************************************/ /************************************************************************/
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -6170,6 +6175,33 @@ ret:
delete data; delete data;
} }
void AwtComponent::_SetZOrder(void *param) {
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
SetZOrderStruct *data = (SetZOrderStruct *)param;
jobject self = data->component;
HWND above = HWND_TOP;
if (data->above != 0) {
above = reinterpret_cast<HWND>(data->above);
}
AwtComponent *c = NULL;
PDATA pData;
JNI_CHECK_PEER_GOTO(self, ret);
c = (AwtComponent *)pData;
if (::IsWindow(c->GetHWnd())) {
::SetWindowPos(c->GetHWnd(), above, 0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_DEFERERASE | SWP_ASYNCWINDOWPOS);
}
ret:
env->DeleteGlobalRef(self);
delete data;
}
void AwtComponent::PostUngrabEvent() { void AwtComponent::PostUngrabEvent() {
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
jobject target = GetTarget(env); jobject target = GetTarget(env);
@ -6896,6 +6928,21 @@ Java_sun_awt_windows_WComponentPeer_setRectangularShape(JNIEnv* env, jobject sel
CATCH_BAD_ALLOC; CATCH_BAD_ALLOC;
} }
JNIEXPORT void JNICALL
Java_sun_awt_windows_WComponentPeer_setZOrder(JNIEnv* env, jobject self, jlong above)
{
TRY;
SetZOrderStruct * data = new SetZOrderStruct;
data->component = env->NewGlobalRef(self);
data->above = above;
AwtToolkit::GetInstance().SyncCall(AwtComponent::_SetZOrder, data);
// global refs and data are deleted in _SetLower
CATCH_BAD_ALLOC;
}
} /* extern "C" */ } /* extern "C" */

View File

@ -680,6 +680,7 @@ public:
static jintArray _CreatePrintedPixels(void *param); static jintArray _CreatePrintedPixels(void *param);
static jboolean _NativeHandlesWheelScrolling(void *param); static jboolean _NativeHandlesWheelScrolling(void *param);
static void _SetRectangularShape(void *param); static void _SetRectangularShape(void *param);
static void _SetZOrder(void *param);
static HWND sm_focusOwner; static HWND sm_focusOwner;
static HWND sm_focusedWindow; static HWND sm_focusedWindow;

View File

@ -34,70 +34,6 @@
jfieldID AwtPanel::insets_ID; jfieldID AwtPanel::insets_ID;
static char* AWTPANEL_RESTACK_MSG_1 = "Peers array is null";
static char* AWTPANEL_RESTACK_MSG_2 = "Peer null in JNI";
static char* AWTPANEL_RESTACK_MSG_3 = "Native resources unavailable";
static char* AWTPANEL_RESTACK_MSG_4 = "Child peer is null";
void* AwtPanel::Restack(void * param) {
TRY;
JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
jobjectArray peers = (jobjectArray)param;
int peerCount = env->GetArrayLength(peers);
if (peerCount < 1) {
env->DeleteGlobalRef(peers);
return AWTPANEL_RESTACK_MSG_1;
}
jobject self = env->GetObjectArrayElement(peers, 0);
// It's entirely possible that our native resources have been destroyed
// before our java peer - if we're dispose()d, for instance.
// Alert caller w/ IllegalComponentStateException.
if (self == NULL) {
env->DeleteGlobalRef(peers);
return AWTPANEL_RESTACK_MSG_2;
}
PDATA pData = JNI_GET_PDATA(self);
if (pData == NULL) {
env->DeleteGlobalRef(peers);
env->DeleteLocalRef(self);
return AWTPANEL_RESTACK_MSG_3;
}
AwtPanel* panel = (AwtPanel*)pData;
HWND prevWindow = 0;
for (int i = 1; i < peerCount; i++) {
jobject peer = env->GetObjectArrayElement(peers, i);
if (peer == NULL) {
// Nonsense
env->DeleteGlobalRef(peers);
env->DeleteLocalRef(self);
return AWTPANEL_RESTACK_MSG_4;
}
PDATA child_pData = JNI_GET_PDATA(peer);
if (child_pData == NULL) {
env->DeleteLocalRef(peer);
env->DeleteGlobalRef(peers);
env->DeleteLocalRef(self);
return AWTPANEL_RESTACK_MSG_3;
}
AwtComponent* child_comp = (AwtComponent*)child_pData;
::SetWindowPos(child_comp->GetHWnd(), prevWindow, 0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_DEFERERASE | SWP_ASYNCWINDOWPOS);
prevWindow = child_comp->GetHWnd();
env->DeleteLocalRef(peer);
}
env->DeleteGlobalRef(peers);
env->DeleteLocalRef(self);
CATCH_BAD_ALLOC_RET("Allocation error");
return NULL;
}
/************************************************************************ /************************************************************************
* AwtPanel native methods * AwtPanel native methods
*/ */
@ -116,18 +52,4 @@ Java_sun_awt_windows_WPanelPeer_initIDs(JNIEnv *env, jclass cls) {
CATCH_BAD_ALLOC; CATCH_BAD_ALLOC;
} }
JNIEXPORT void JNICALL
Java_sun_awt_windows_WPanelPeer_pRestack(JNIEnv *env, jobject self, jobjectArray peers) {
TRY;
const char * error = (const char*)AwtToolkit::GetInstance().InvokeFunction(AwtPanel::Restack, env->NewGlobalRef(peers));
if (error != NULL) {
JNU_ThrowByName(env, "java/awt/IllegalComponentStateException", error);
}
CATCH_BAD_ALLOC;
}
} /* extern "C" */ } /* extern "C" */

View File

@ -35,11 +35,8 @@
class AwtPanel { class AwtPanel {
public: public:
static void* Restack(void * param);
/* java.awt.Panel field ids */ /* java.awt.Panel field ids */
static jfieldID insets_ID; static jfieldID insets_ID;
}; };
#endif // AWT_PANEL_H #endif // AWT_PANEL_H