From 2f7d9810e53401c48d4a5972de726c1e5d9a8e46 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Leif=20=C3=85strand?= Date: Wed, 11 Apr 2012 22:18:59 +0300 Subject: [PATCH] Run scrollbar fix for the next ancestor where it might be needed (#8615) The previous behavior of only running it for the direct parent if applicable didn't catch all situations where the fix was needed. Also postpone layout fix until no interfering changes are expected. --- .../terminal/gwt/client/LayoutManager.java | 75 +++++++++++-------- .../ui/layout/LayoutDependencyTree.java | 41 +++++++++- 2 files changed, 81 insertions(+), 35 deletions(-) diff --git a/src/com/vaadin/terminal/gwt/client/LayoutManager.java b/src/com/vaadin/terminal/gwt/client/LayoutManager.java index 4ec5523156..db57b11c9e 100644 --- a/src/com/vaadin/terminal/gwt/client/LayoutManager.java +++ b/src/com/vaadin/terminal/gwt/client/LayoutManager.java @@ -23,7 +23,6 @@ import com.vaadin.terminal.gwt.client.ui.VNotification; import com.vaadin.terminal.gwt.client.ui.layout.ElementResizeEvent; import com.vaadin.terminal.gwt.client.ui.layout.ElementResizeListener; import com.vaadin.terminal.gwt.client.ui.layout.LayoutDependencyTree; -import com.vaadin.terminal.gwt.client.ui.layout.MayScrollChildren; public class LayoutManager { private static final String LOOP_ABORT_MESSAGE = "Aborting layout after 100 passes. This would probably be an infinite loop."; @@ -41,7 +40,7 @@ public class LayoutManager { private final Collection needsMeasure = new HashSet(); - private final Collection pendingOverflowFixes = new HashSet(); + private Collection pendingOverflowFixes = new HashSet(); private final Map> elementResizeListeners = new HashMap>(); private final Set listenersToFire = new HashSet(); @@ -207,6 +206,10 @@ public class LayoutManager { int measuredConnectorCount = measureConnectors( currentDependencyTree, everythingNeedsMeasure); everythingNeedsMeasure = false; + if (measuredConnectorCount == 0) { + VConsole.log("No more changes in pass " + passes); + break; + } int measureTime = passDuration.elapsedMillis(); VConsole.log(" Measured " + measuredConnectorCount @@ -233,11 +236,9 @@ public class LayoutManager { } FastStringSet updatedSet = FastStringSet.create(); - boolean changed = false; while (currentDependencyTree.hasHorizontalConnectorToLayout() || currentDependencyTree.hasVerticaConnectorToLayout()) { - changed = true; for (ManagedLayout layout : currentDependencyTree .getHorizontalLayoutTargets()) { if (layout instanceof DirectionalManagedLayout) { @@ -308,11 +309,6 @@ public class LayoutManager { VConsole.log(b.toString()); } - if (!changed) { - VConsole.log("No more changes in pass " + passes); - break; - } - VConsole.log("Pass " + passes + " completed in " + passDuration.elapsedMillis() + " ms"); @@ -352,9 +348,30 @@ public class LayoutManager { HashMap originalOverflows = new HashMap(); + HashSet delayedOverflowFixes = new HashSet(); + // First set overflow to hidden (and save previous value so it can // be restored later) for (ComponentConnector componentConnector : pendingOverflowFixes) { + // Delay the overflow fix if the involved connectors might still + // change + if (!currentDependencyTree + .noMoreChangesExpected(componentConnector) + || !currentDependencyTree + .noMoreChangesExpected(componentConnector + .getParent())) { + delayedOverflowFixes.add(componentConnector); + continue; + } + + if (debugLogging) { + VConsole.log("Doing overflow fix for " + + Util.getConnectorString(componentConnector) + + " in " + + Util.getConnectorString(componentConnector + .getParent())); + } + Element parentElement = componentConnector.getWidget() .getElement().getParentElement(); Style style = parentElement.getStyle(); @@ -370,6 +387,8 @@ public class LayoutManager { style.setOverflow(Overflow.HIDDEN); } + pendingOverflowFixes.removeAll(delayedOverflowFixes); + // Then ensure all scrolling elements are reflowed by measuring for (ComponentConnector componentConnector : pendingOverflowFixes) { componentConnector.getWidget().getElement().getParentElement() @@ -384,20 +403,13 @@ public class LayoutManager { originalOverflows.get(parentElement)); layoutDependencyTree.setNeedsMeasure(componentConnector, true); - - ComponentContainerConnector parent = componentConnector - .getParent(); - if (parent instanceof ManagedLayout) { - ManagedLayout managedParent = (ManagedLayout) parent; - layoutDependencyTree.setNeedsHorizontalLayout( - managedParent, true); - layoutDependencyTree.setNeedsVerticalLayout(managedParent, - true); - } } - VConsole.log("Did overflow fix for " + pendingOverflowFixes.size() - + " elements in " + duration.elapsedMillis() + " ms"); - pendingOverflowFixes.clear(); + if (!pendingOverflowFixes.isEmpty()) { + VConsole.log("Did overflow fix for " + + pendingOverflowFixes.size() + " elements in " + + duration.elapsedMillis() + " ms"); + } + pendingOverflowFixes = delayedOverflowFixes; } int measureCount = 0; @@ -440,7 +452,7 @@ public class LayoutManager { private void onConnectorChange(ComponentConnector connector, boolean widthChanged, boolean heightChanged) { - doOverflowAutoFix(connector); + setNeedsOverflowFix(connector); if (heightChanged) { currentDependencyTree.markHeightAsChanged(connector); } @@ -449,14 +461,15 @@ public class LayoutManager { } } - private void doOverflowAutoFix(ComponentConnector connector) { - // IE9 doesn't need the original fix, but for some reason it needs one - if (connector.getParent() instanceof MayScrollChildren - && (BrowserInfo.get().requiresOverflowAutoFix() || BrowserInfo - .get().isIE9()) - && !"absolute".equals(connector.getWidget().getElement() - .getStyle().getPosition())) { - pendingOverflowFixes.add(connector); + private void setNeedsOverflowFix(ComponentConnector connector) { + // IE9 doesn't need the original fix, but for some reason it needs this + if (BrowserInfo.get().requiresOverflowAutoFix() + || BrowserInfo.get().isIE9()) { + ComponentConnector scrollingBoundary = currentDependencyTree + .getScrollingBoundary(connector); + if (scrollingBoundary != null) { + pendingOverflowFixes.add(scrollingBoundary); + } } } diff --git a/src/com/vaadin/terminal/gwt/client/ui/layout/LayoutDependencyTree.java b/src/com/vaadin/terminal/gwt/client/ui/layout/LayoutDependencyTree.java index 52b530823a..1ca8933ff2 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/layout/LayoutDependencyTree.java +++ b/src/com/vaadin/terminal/gwt/client/ui/layout/LayoutDependencyTree.java @@ -25,6 +25,9 @@ public class LayoutDependencyTree { private boolean needsLayout = false; private boolean needsMeasure = false; + private boolean scrollingParentCached = false; + private ComponentConnector scrollingBoundary = null; + private Set measureBlockers = new HashSet(); private Set layoutBlockers = new HashSet(); @@ -104,7 +107,8 @@ public class LayoutDependencyTree { public void setNeedsLayout(boolean needsLayout) { if (!(connector instanceof ManagedLayout)) { throw new IllegalStateException( - "Only managed layouts can need layout"); + "Only managed layouts can need layout, layout attempted for " + + Util.getConnectorString(connector)); } if (needsLayout && !this.needsLayout) { // If enabling needsLayout @@ -224,9 +228,10 @@ public class LayoutDependencyTree { // Should also go through the hierarchy to discover appeared or // disappeared scrollbars - LayoutDependency potentiallyChangedScrollbar = findPotentiallyChangedScrollbar(); - if (potentiallyChangedScrollbar != null) { - potentiallyChangedScrollbar.setNeedsMeasure(true); + ComponentConnector scrollingBoundary = getScrollingBoundary(connector); + if (scrollingBoundary != null) { + getDependency(scrollingBoundary, getOppositeDirection()) + .setNeedsMeasure(true); } } @@ -316,6 +321,11 @@ public class LayoutDependencyTree { return s; } + public boolean noMoreChangesExpected() { + return !needsLayout && !needsMeasure && layoutBlockers.isEmpty() + && measureBlockers.isEmpty(); + } + } private static final int HORIZONTAL = 0; @@ -485,4 +495,27 @@ public class LayoutDependencyTree { VConsole.log(getDependency(connector, HORIZONTAL).toString()); VConsole.log(getDependency(connector, VERTICAL).toString()); } + + public boolean noMoreChangesExpected(ComponentConnector connector) { + return getDependency(connector, HORIZONTAL).noMoreChangesExpected() + && getDependency(connector, VERTICAL).noMoreChangesExpected(); + } + + public ComponentConnector getScrollingBoundary(ComponentConnector connector) { + LayoutDependency dependency = getDependency(connector, HORIZONTAL); + if (!dependency.scrollingParentCached) { + ComponentContainerConnector parent = dependency.connector + .getParent(); + if (parent instanceof MayScrollChildren) { + dependency.scrollingBoundary = connector; + } else if (parent != null) { + dependency.scrollingBoundary = getScrollingBoundary(parent); + } else { + // No scrolling parent + } + + dependency.scrollingParentCached = true; + } + return dependency.scrollingBoundary; + } } -- 2.39.5