From a3799e5890a4bef23bcc02aa7c79a5807d7eb673 Mon Sep 17 00:00:00 2001 From: serb Date: Fri, 22 May 2015 19:27:33 +0300 Subject: [PATCH] 8071306: GUI perfomance are very slow compared java 1.6.0_45 Reviewed-by: azvegint, ant --- src/share/classes/java/awt/Component.java | 23 +++- src/share/classes/java/awt/Container.java | 103 +++++++++--------- .../SetEnabledPerformance.java | 72 ++++++++++++ 3 files changed, 144 insertions(+), 54 deletions(-) create mode 100644 test/java/awt/Component/SetEnabledPerformance/SetEnabledPerformance.java diff --git a/src/share/classes/java/awt/Component.java b/src/share/classes/java/awt/Component.java index c77c5f2ef..e82678731 100644 --- a/src/share/classes/java/awt/Component.java +++ b/src/share/classes/java/awt/Component.java @@ -1301,6 +1301,25 @@ public abstract class Component implements ImageObserver, MenuContainer, return visible && (parent == null || parent.isRecursivelyVisible()); } + /** + * Determines the bounds of a visible part of the component relative to its + * parent. + * + * @return the visible part of bounds + */ + private Rectangle getRecursivelyVisibleBounds() { + final Component container = getContainer(); + final Rectangle bounds = getBounds(); + if (container == null) { + // we are top level window or haven't a container, return our bounds + return bounds; + } + // translate the container's bounds to our coordinate space + final Rectangle parentsBounds = container.getRecursivelyVisibleBounds(); + parentsBounds.setLocation(0, 0); + return parentsBounds.intersection(bounds); + } + /** * Translates absolute coordinates into coordinates in the coordinate * space of this component. @@ -1473,7 +1492,7 @@ public abstract class Component implements ImageObserver, MenuContainer, ComponentPeer peer = this.peer; if (peer != null) { peer.setEnabled(true); - if (visible) { + if (visible && !getRecursivelyVisibleBounds().isEmpty()) { updateCursorImmediately(); } } @@ -1522,7 +1541,7 @@ public abstract class Component implements ImageObserver, MenuContainer, ComponentPeer peer = this.peer; if (peer != null) { peer.setEnabled(false); - if (visible) { + if (visible && !getRecursivelyVisibleBounds().isEmpty()) { updateCursorImmediately(); } } diff --git a/src/share/classes/java/awt/Container.java b/src/share/classes/java/awt/Container.java index ee8ba9114..a270051d8 100644 --- a/src/share/classes/java/awt/Container.java +++ b/src/share/classes/java/awt/Container.java @@ -44,6 +44,7 @@ import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.security.AccessController; +import java.util.ArrayList; import java.util.EventListener; import java.util.HashSet; import java.util.Set; @@ -100,7 +101,7 @@ public class Container extends Component { * @see #add * @see #getComponents */ - private java.util.List component = new java.util.ArrayList(); + private java.util.List component = new ArrayList<>(); /** * Layout manager for this container. @@ -2545,28 +2546,24 @@ public class Container extends Component { if (!contains(x, y)) { return null; } + Component lightweight = null; synchronized (getTreeLock()) { - // Two passes: see comment in sun.awt.SunGraphicsCallback - for (int i = 0; i < component.size(); i++) { - Component comp = component.get(i); - if (comp != null && - !(comp.peer instanceof LightweightPeer)) { - if (comp.contains(x - comp.x, y - comp.y)) { + // Optimized version of two passes: + // see comment in sun.awt.SunGraphicsCallback + for (final Component comp : component) { + if (comp.contains(x - comp.x, y - comp.y)) { + if (!comp.isLightweight()) { + // return heavyweight component as soon as possible return comp; } - } - } - for (int i = 0; i < component.size(); i++) { - Component comp = component.get(i); - if (comp != null && - comp.peer instanceof LightweightPeer) { - if (comp.contains(x - comp.x, y - comp.y)) { - return comp; + if (lightweight == null) { + // save and return later the first lightweight component + lightweight = comp; } } } } - return this; + return lightweight != null ? lightweight : this; } /** @@ -2670,52 +2667,54 @@ public class Container extends Component { return null; } - final Component findComponentAtImpl(int x, int y, boolean ignoreEnabled){ - checkTreeLock(); + final Component findComponentAtImpl(int x, int y, boolean ignoreEnabled) { + // checkTreeLock(); commented for a performance reason if (!(contains(x, y) && visible && (ignoreEnabled || enabled))) { return null; } - - // Two passes: see comment in sun.awt.SunGraphicsCallback - for (int i = 0; i < component.size(); i++) { - Component comp = component.get(i); - if (comp != null && - !(comp.peer instanceof LightweightPeer)) { - if (comp instanceof Container) { - comp = ((Container)comp).findComponentAtImpl(x - comp.x, - y - comp.y, - ignoreEnabled); - } else { - comp = comp.getComponentAt(x - comp.x, y - comp.y); - } - if (comp != null && comp.visible && - (ignoreEnabled || comp.enabled)) - { - return comp; - } + Component lightweight = null; + // Optimized version of two passes: + // see comment in sun.awt.SunGraphicsCallback + for (final Component comp : component) { + final int x1 = x - comp.x; + final int y1 = y - comp.y; + if (!comp.contains(x1, y1)) { + continue; // fast path } - } - for (int i = 0; i < component.size(); i++) { - Component comp = component.get(i); - if (comp != null && - comp.peer instanceof LightweightPeer) { - if (comp instanceof Container) { - comp = ((Container)comp).findComponentAtImpl(x - comp.x, - y - comp.y, - ignoreEnabled); - } else { - comp = comp.getComponentAt(x - comp.x, y - comp.y); + if (!comp.isLightweight()) { + final Component child = getChildAt(comp, x1, y1, ignoreEnabled); + if (child != null) { + // return heavyweight component as soon as possible + return child; } - if (comp != null && comp.visible && - (ignoreEnabled || comp.enabled)) - { - return comp; + } else { + if (lightweight == null) { + // save and return later the first lightweight component + lightweight = getChildAt(comp, x1, y1, ignoreEnabled); } } } + return lightweight != null ? lightweight : this; + } - return this; + /** + * Helper method for findComponentAtImpl. Finds a child component using + * findComponentAtImpl for Container and getComponentAt for Component. + */ + private static Component getChildAt(Component comp, int x, int y, + boolean ignoreEnabled) { + if (comp instanceof Container) { + comp = ((Container) comp).findComponentAtImpl(x, y, + ignoreEnabled); + } else { + comp = comp.getComponentAt(x, y); + } + if (comp != null && comp.visible && + (ignoreEnabled || comp.enabled)) { + return comp; + } + return null; } /** diff --git a/test/java/awt/Component/SetEnabledPerformance/SetEnabledPerformance.java b/test/java/awt/Component/SetEnabledPerformance/SetEnabledPerformance.java new file mode 100644 index 000000000..c898ef7ef --- /dev/null +++ b/test/java/awt/Component/SetEnabledPerformance/SetEnabledPerformance.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Component; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Robot; + +import javax.swing.JButton; +import javax.swing.SwingUtilities; + +/** + * @test + * @bug 8071306 + * @author Sergey Bylokhov + */ +public final class SetEnabledPerformance { + + private static Frame frame; + + private static void createAndShowGUI() { + frame = new Frame(); + frame.setLayout(new FlowLayout(FlowLayout.CENTER, 25, 0)); + frame.setSize(600, 600); + frame.setLocationRelativeTo(null); + for (int i = 1; i < 10001; ++i) { + frame.add(new JButton("Button " + i)); + } + frame.setVisible(true); + } + + public static void main(final String[] args) throws Exception { + SwingUtilities.invokeAndWait(() -> createAndShowGUI()); + final Robot robot = new Robot(); + robot.waitForIdle(); + robot.mouseMove(frame.getX() + 15, frame.getY() + 300); + robot.waitForIdle(); + SwingUtilities.invokeAndWait(() -> { + long m = System.currentTimeMillis(); + for (final Component comp : frame.getComponents()) { + comp.setEnabled(false); + } + m = System.currentTimeMillis() - m; + System.err.println("Disabled in " + m + " ms"); + frame.dispose(); + // we should be much faster, but leaves 1000 for the slow systems + if (m > 1000) { + throw new RuntimeException("Too slow"); + } + }); + } +} \ No newline at end of file -- GitLab