diff options
author | Artur Signell <artur@vaadin.com> | 2013-02-06 13:22:28 +0000 |
---|---|---|
committer | Vaadin Code Review <review@vaadin.com> | 2013-02-06 13:22:28 +0000 |
commit | 216e557e11dae53ba352dfed59b510b840db8d5b (patch) | |
tree | b991790b675375ae043fccff98b56914edd2a755 | |
parent | 4ce2129ab4982a08471b90cf4495d72c2c1391cf (diff) | |
parent | 9014f45134b4ba5b34c386aafc4a6dbd66118be6 (diff) | |
download | vaadin-framework-216e557e11dae53ba352dfed59b510b840db8d5b.tar.gz vaadin-framework-216e557e11dae53ba352dfed59b510b840db8d5b.zip |
Merge "Use faster collections in LayoutManager and related classes (#10937)" into 7.0
-rw-r--r-- | client/src/com/vaadin/client/LayoutManager.java | 183 | ||||
-rw-r--r-- | client/src/com/vaadin/client/ui/layout/LayoutDependencyTree.java | 366 |
2 files changed, 377 insertions, 172 deletions
diff --git a/client/src/com/vaadin/client/LayoutManager.java b/client/src/com/vaadin/client/LayoutManager.java index d83811d8c5..d3366e86f3 100644 --- a/client/src/com/vaadin/client/LayoutManager.java +++ b/client/src/com/vaadin/client/LayoutManager.java @@ -15,7 +15,6 @@ */ package com.vaadin.client; -import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -48,12 +47,12 @@ public class LayoutManager { private LayoutDependencyTree currentDependencyTree; - private final Collection<ManagedLayout> needsHorizontalLayout = new HashSet<ManagedLayout>(); - private final Collection<ManagedLayout> needsVerticalLayout = new HashSet<ManagedLayout>(); + private FastStringSet needsHorizontalLayout = FastStringSet.create(); + private FastStringSet needsVerticalLayout = FastStringSet.create(); - private final Collection<ComponentConnector> needsMeasure = new HashSet<ComponentConnector>(); + private FastStringSet needsMeasure = FastStringSet.create(); - private Collection<ComponentConnector> pendingOverflowFixes = new HashSet<ComponentConnector>(); + private FastStringSet pendingOverflowFixes = FastStringSet.create(); private final Map<Element, Collection<ElementResizeListener>> elementResizeListeners = new HashMap<Element, Collection<ElementResizeListener>>(); private final Set<Element> listenersToFire = new HashSet<Element>(); @@ -212,15 +211,15 @@ public class LayoutManager { return currentDependencyTree != null; } - private void countLayout(Map<ManagedLayout, Integer> layoutCounts, + private void countLayout(FastStringMap<Integer> layoutCounts, ManagedLayout layout) { - Integer count = layoutCounts.get(layout); + Integer count = layoutCounts.get(layout.getConnectorId()); if (count == null) { count = Integer.valueOf(0); } else { count = Integer.valueOf(count.intValue() + 1); } - layoutCounts.put(layout, count); + layoutCounts.put(layout.getConnectorId(), count); if (count.intValue() > 2) { VConsole.error(Util.getConnectorString(layout) + " has been layouted " + count.intValue() + " times"); @@ -242,7 +241,7 @@ public class LayoutManager { layoutPending = false; layoutTimer.cancel(); try { - currentDependencyTree = new LayoutDependencyTree(); + currentDependencyTree = new LayoutDependencyTree(connection); doLayout(); } finally { currentDependencyTree = null; @@ -261,24 +260,36 @@ public class LayoutManager { private void doLayout() { VConsole.log("Starting layout phase"); - Map<ManagedLayout, Integer> layoutCounts = new HashMap<ManagedLayout, Integer>(); + FastStringMap<Integer> layoutCounts = FastStringMap.create(); int passes = 0; Duration totalDuration = new Duration(); - for (ManagedLayout layout : needsHorizontalLayout) { - currentDependencyTree.setNeedsHorizontalLayout(layout, true); - } - for (ManagedLayout layout : needsVerticalLayout) { - currentDependencyTree.setNeedsVerticalLayout(layout, true); + ConnectorMap connectorMap = ConnectorMap.get(connection); + + JsArrayString dump = needsHorizontalLayout.dump(); + int dumpLength = dump.length(); + for (int i = 0; i < dumpLength; i++) { + String layoutId = dump.get(i); + currentDependencyTree.setNeedsHorizontalLayout(layoutId, true); } - needsHorizontalLayout.clear(); - needsVerticalLayout.clear(); - for (ComponentConnector connector : needsMeasure) { - currentDependencyTree.setNeedsMeasure(connector, true); + dump = needsVerticalLayout.dump(); + dumpLength = dump.length(); + for (int i = 0; i < dumpLength; i++) { + String layoutId = dump.get(i); + currentDependencyTree.setNeedsVerticalLayout(layoutId, true); } - needsMeasure.clear(); + needsHorizontalLayout = FastStringSet.create(); + needsVerticalLayout = FastStringSet.create(); + + dump = needsMeasure.dump(); + dumpLength = dump.length(); + for (int i = 0; i < dumpLength; i++) { + String layoutId = dump.get(i); + currentDependencyTree.setNeedsMeasure(layoutId, true); + } + needsMeasure = FastStringSet.create(); measureNonConnectors(); @@ -333,8 +344,13 @@ public class LayoutManager { while (currentDependencyTree.hasHorizontalConnectorToLayout() || currentDependencyTree.hasVerticaConnectorToLayout()) { - for (ManagedLayout layout : currentDependencyTree - .getHorizontalLayoutTargets()) { + + JsArrayString layoutTargets = currentDependencyTree + .getHorizontalLayoutTargetsJsArray(); + int length = layoutTargets.length(); + for (int i = 0; i < length; i++) { + ManagedLayout layout = (ManagedLayout) connectorMap + .getConnector(layoutTargets.get(i)); if (layout instanceof DirectionalManagedLayout) { currentDependencyTree .markAsHorizontallyLayouted(layout); @@ -362,8 +378,12 @@ public class LayoutManager { } } - for (ManagedLayout layout : currentDependencyTree - .getVerticalLayoutTargets()) { + layoutTargets = currentDependencyTree + .getVerticalLayoutTargetsJsArray(); + length = layoutTargets.length(); + for (int i = 0; i < length; i++) { + ManagedLayout layout = (ManagedLayout) connectorMap + .getConnector(layoutTargets.get(i)); if (layout instanceof DirectionalManagedLayout) { currentDependencyTree.markAsVerticallyLayouted(layout); DirectionalManagedLayout cl = (DirectionalManagedLayout) layout; @@ -436,19 +456,22 @@ public class LayoutManager { } int postLayoutStart = totalDuration.elapsedMillis(); - for (ComponentConnector connector : connection.getConnectorMap() - .getComponentConnectors()) { + JsArrayObject<ComponentConnector> componentConnectors = connectorMap + .getComponentConnectorsAsJsArray(); + int size = componentConnectors.size(); + for (int i = 0; i < size; i++) { + ComponentConnector connector = componentConnectors.get(i); if (connector instanceof PostLayoutListener) { ((PostLayoutListener) connector).postLayout(); } } - int postLayoutDone = (totalDuration.elapsedMillis() - postLayoutStart); - VConsole.log("Invoke post layout listeners in " + postLayoutDone - + " ms"); + int postLayoutDone = totalDuration.elapsedMillis(); + VConsole.log("Invoke post layout listeners in " + + (postLayoutDone - postLayoutStart) + " ms"); cleanMeasuredSizes(); - int cleaningDone = (totalDuration.elapsedMillis() - postLayoutDone); - VConsole.log("Cleaned old measured sizes in " + cleaningDone + "ms"); + int cleaningTime = (totalDuration.elapsedMillis() - postLayoutDone); + VConsole.log("Cleaned old measured sizes in " + cleaningTime + "ms"); VConsole.log("Total layout phase time: " + totalDuration.elapsedMillis() + "ms"); @@ -462,16 +485,24 @@ public class LayoutManager { private int measureConnectors(LayoutDependencyTree layoutDependencyTree, boolean measureAll) { - if (!pendingOverflowFixes.isEmpty()) { + JsArrayString pendingOverflowConnectorsIds = pendingOverflowFixes + .dump(); + int pendingOverflowCount = pendingOverflowConnectorsIds.length(); + ConnectorMap connectorMap = ConnectorMap.get(connection); + if (pendingOverflowCount > 0) { Duration duration = new Duration(); HashMap<Element, String> originalOverflows = new HashMap<Element, String>(); - HashSet<ComponentConnector> delayedOverflowFixes = new HashSet<ComponentConnector>(); + FastStringSet delayedOverflowFixes = FastStringSet.create(); // First set overflow to hidden (and save previous value so it can // be restored later) - for (ComponentConnector componentConnector : pendingOverflowFixes) { + for (int i = 0; i < pendingOverflowCount; i++) { + String connectorId = pendingOverflowConnectorsIds.get(i); + ComponentConnector componentConnector = (ComponentConnector) connectorMap + .getConnector(connectorId); + // Delay the overflow fix if the involved connectors might still // change boolean connectorChangesExpected = !currentDependencyTree @@ -481,7 +512,7 @@ public class LayoutManager { .noMoreChangesExpected((ComponentConnector) componentConnector .getParent()); if (connectorChangesExpected || parentChangesExcpected) { - delayedOverflowFixes.add(componentConnector); + delayedOverflowFixes.add(connectorId); continue; } @@ -510,60 +541,76 @@ public class LayoutManager { pendingOverflowFixes.removeAll(delayedOverflowFixes); + JsArrayString remainingOverflowFixIds = pendingOverflowFixes.dump(); + int remainingCount = remainingOverflowFixIds.length(); + // Then ensure all scrolling elements are reflowed by measuring - for (ComponentConnector componentConnector : pendingOverflowFixes) { + for (int i = 0; i < remainingCount; i++) { + ComponentConnector componentConnector = (ComponentConnector) connectorMap + .getConnector(remainingOverflowFixIds.get(i)); componentConnector.getWidget().getElement().getParentElement() .getOffsetHeight(); } // Finally restore old overflow value and update bookkeeping - for (ComponentConnector componentConnector : pendingOverflowFixes) { + for (int i = 0; i < remainingCount; i++) { + String connectorId = remainingOverflowFixIds.get(i); + ComponentConnector componentConnector = (ComponentConnector) connectorMap + .getConnector(connectorId); Element parentElement = componentConnector.getWidget() .getElement().getParentElement(); parentElement.getStyle().setProperty("overflow", originalOverflows.get(parentElement)); - layoutDependencyTree.setNeedsMeasure(componentConnector, true); + layoutDependencyTree.setNeedsMeasure(connectorId, true); } if (!pendingOverflowFixes.isEmpty()) { - VConsole.log("Did overflow fix for " - + pendingOverflowFixes.size() + " elements in " - + duration.elapsedMillis() + " ms"); + VConsole.log("Did overflow fix for " + remainingCount + + " elements in " + duration.elapsedMillis() + " ms"); } pendingOverflowFixes = delayedOverflowFixes; } int measureCount = 0; if (measureAll) { - ComponentConnector[] allConnectors = ConnectorMap.get(connection) - .getComponentConnectors(); + JsArrayObject<ComponentConnector> allConnectors = connectorMap + .getComponentConnectorsAsJsArray(); + int size = allConnectors.size(); // Find connectors that should actually be measured - ArrayList<ComponentConnector> connectors = new ArrayList<ComponentConnector>(); - for (ComponentConnector candidate : allConnectors) { + JsArrayObject<ComponentConnector> connectors = JsArrayObject + .createArray().cast(); + for (int i = 0; i < size; i++) { + ComponentConnector candidate = allConnectors.get(i); if (needsMeasure(candidate.getWidget().getElement())) { connectors.add(candidate); } } - for (ComponentConnector connector : connectors) { - measureConnector(connector); + int connectorCount = connectors.size(); + for (int i = 0; i < connectorCount; i++) { + measureConnector(connectors.get(i)); } - for (ComponentConnector connector : connectors) { - layoutDependencyTree.setNeedsMeasure(connector, false); + for (int i = 0; i < connectorCount; i++) { + layoutDependencyTree.setNeedsMeasure(connectors.get(i) + .getConnectorId(), false); } - measureCount += connectors.size(); + measureCount += connectorCount; } while (layoutDependencyTree.hasConnectorsToMeasure()) { - Collection<ComponentConnector> measureTargets = layoutDependencyTree - .getMeasureTargets(); - for (ComponentConnector connector : measureTargets) { + JsArrayString measureTargets = layoutDependencyTree + .getMeasureTargetsJsArray(); + int length = measureTargets.length(); + for (int i = 0; i < length; i++) { + ComponentConnector connector = (ComponentConnector) connectorMap + .getConnector(measureTargets.get(i)); measureConnector(connector); measureCount++; } - for (ComponentConnector connector : measureTargets) { - layoutDependencyTree.setNeedsMeasure(connector, false); + for (int i = 0; i < length; i++) { + String connectorId = measureTargets.get(i); + layoutDependencyTree.setNeedsMeasure(connectorId, false); } } return measureCount; @@ -598,7 +645,7 @@ public class LayoutManager { ComponentConnector scrollingBoundary = currentDependencyTree .getScrollingBoundary(connector); if (scrollingBoundary != null) { - pendingOverflowFixes.add(scrollingBoundary); + pendingOverflowFixes.add(scrollingBoundary.getConnectorId()); } } } @@ -630,16 +677,12 @@ public class LayoutManager { JsArrayString dependents = measuredSize.getDependents(); for (int i = 0; i < dependents.length(); i++) { String pid = dependents.get(i); - ManagedLayout dependent = (ManagedLayout) connection - .getConnectorMap().getConnector(pid); - if (dependent != null) { + if (pid != null) { if (heightChanged) { - currentDependencyTree.setNeedsVerticalLayout(dependent, - true); + currentDependencyTree.setNeedsVerticalLayout(pid, true); } if (widthChanged) { - currentDependencyTree.setNeedsHorizontalLayout(dependent, - true); + currentDependencyTree.setNeedsHorizontalLayout(pid, true); } } } @@ -654,9 +697,11 @@ public class LayoutManager { public void forceLayout() { ConnectorMap connectorMap = connection.getConnectorMap(); - ComponentConnector[] componentConnectors = connectorMap - .getComponentConnectors(); - for (ComponentConnector connector : componentConnectors) { + JsArrayObject<ComponentConnector> componentConnectors = connectorMap + .getComponentConnectorsAsJsArray(); + int size = componentConnectors.size(); + for (int i = 0; i < size; i++) { + ComponentConnector connector = componentConnectors.get(i); if (connector instanceof ManagedLayout) { setNeedsLayout((ManagedLayout) connector); } @@ -689,7 +734,7 @@ public class LayoutManager { * the managed layout that should be layouted */ public final void setNeedsHorizontalLayout(ManagedLayout layout) { - needsHorizontalLayout.add(layout); + needsHorizontalLayout.add(layout.getConnectorId()); } /** @@ -704,7 +749,7 @@ public class LayoutManager { * the managed layout that should be layouted */ public final void setNeedsVerticalLayout(ManagedLayout layout) { - needsVerticalLayout.add(layout); + needsVerticalLayout.add(layout.getConnectorId()); } /** @@ -1311,7 +1356,7 @@ public class LayoutManager { if (isLayoutRunning()) { currentDependencyTree.setNeedsMeasure(component, true); } else { - needsMeasure.add(component); + needsMeasure.add(component.getConnectorId()); layoutLater(); } } diff --git a/client/src/com/vaadin/client/ui/layout/LayoutDependencyTree.java b/client/src/com/vaadin/client/ui/layout/LayoutDependencyTree.java index 343791fb72..4c46846d14 100644 --- a/client/src/com/vaadin/client/ui/layout/LayoutDependencyTree.java +++ b/client/src/com/vaadin/client/ui/layout/LayoutDependencyTree.java @@ -17,19 +17,28 @@ package com.vaadin.client.ui.layout; import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import com.google.gwt.core.client.JsArrayString; +import com.vaadin.client.ApplicationConnection; import com.vaadin.client.ComponentConnector; +import com.vaadin.client.ConnectorMap; +import com.vaadin.client.FastStringMap; +import com.vaadin.client.FastStringSet; import com.vaadin.client.HasComponentsConnector; +import com.vaadin.client.JsArrayObject; import com.vaadin.client.ServerConnector; import com.vaadin.client.Util; import com.vaadin.client.VConsole; import com.vaadin.client.ui.ManagedLayout; import com.vaadin.shared.AbstractComponentState; +/** + * Internal class used to keep track of layout dependencies during one layout + * run. This class is not intended to be used directly by applications. + * + * @author Vaadin Ltd + * @since 7.0.0 + */ public class LayoutDependencyTree { private class LayoutDependency { private final ComponentConnector connector; @@ -41,8 +50,8 @@ public class LayoutDependencyTree { private boolean scrollingParentCached = false; private ComponentConnector scrollingBoundary = null; - private Set<ComponentConnector> measureBlockers = new HashSet<ComponentConnector>(); - private Set<ComponentConnector> layoutBlockers = new HashSet<ComponentConnector>(); + private FastStringSet measureBlockers = FastStringSet.create(); + private FastStringSet layoutBlockers = FastStringSet.create(); public LayoutDependency(ComponentConnector connector, int direction) { this.connector = connector; @@ -50,33 +59,49 @@ public class LayoutDependencyTree { } private void addLayoutBlocker(ComponentConnector blocker) { - boolean blockerAdded = layoutBlockers.add(blocker); - if (blockerAdded && layoutBlockers.size() == 1) { - if (needsLayout) { - getLayoutQueue(direction).remove(connector); - } else { - // Propagation already done if needsLayout is set - propagatePotentialLayout(); + String blockerId = blocker.getConnectorId(); + if (!layoutBlockers.contains(blockerId)) { + boolean wasEmpty = layoutBlockers.isEmpty(); + layoutBlockers.add(blockerId); + if (wasEmpty) { + if (needsLayout) { + getLayoutQueue(direction).remove( + connector.getConnectorId()); + } else { + // Propagation already done if needsLayout is set + propagatePotentialLayout(); + } } } } private void removeLayoutBlocker(ComponentConnector blocker) { - boolean removed = layoutBlockers.remove(blocker); - if (removed && layoutBlockers.isEmpty()) { - if (needsLayout) { - getLayoutQueue(direction).add((ManagedLayout) connector); - } else { - propagateNoUpcomingLayout(); + String blockerId = blocker.getConnectorId(); + if (layoutBlockers.contains(blockerId)) { + layoutBlockers.remove(blockerId); + if (layoutBlockers.isEmpty()) { + if (needsLayout) { + getLayoutQueue(direction).add( + connector.getConnectorId()); + } else { + propagateNoUpcomingLayout(); + } } } } private void addMeasureBlocker(ComponentConnector blocker) { - boolean blockerAdded = measureBlockers.add(blocker); - if (blockerAdded && measureBlockers.size() == 1) { + String blockerId = blocker.getConnectorId(); + boolean alreadyAdded = measureBlockers.contains(blockerId); + if (alreadyAdded) { + return; + } + boolean wasEmpty = measureBlockers.isEmpty(); + measureBlockers.add(blockerId); + if (wasEmpty) { if (needsMeasure) { - getMeasureQueue(direction).remove(connector); + getMeasureQueue(direction).remove( + connector.getConnectorId()); } else { propagatePotentialResize(); } @@ -84,10 +109,15 @@ public class LayoutDependencyTree { } private void removeMeasureBlocker(ComponentConnector blocker) { - boolean removed = measureBlockers.remove(blocker); - if (removed && measureBlockers.isEmpty()) { + String blockerId = blocker.getConnectorId(); + boolean alreadyRemoved = !measureBlockers.contains(blockerId); + if (alreadyRemoved) { + return; + } + measureBlockers.remove(blockerId); + if (measureBlockers.isEmpty()) { if (needsMeasure) { - getMeasureQueue(direction).add(connector); + getMeasureQueue(direction).add(connector.getConnectorId()); } else { propagateNoUpcomingResize(); } @@ -101,7 +131,7 @@ public class LayoutDependencyTree { if (measureBlockers.isEmpty()) { // Add to queue if there are no blockers - getMeasureQueue(direction).add(connector); + getMeasureQueue(direction).add(connector.getConnectorId()); // Only need to propagate if not already propagated when // setting blockers propagatePotentialResize(); @@ -112,7 +142,7 @@ public class LayoutDependencyTree { // in both directions even if there is a blocker in one // direction) this.needsMeasure = needsMeasure; - getMeasureQueue(direction).remove(connector); + getMeasureQueue(direction).remove(connector.getConnectorId()); propagateNoUpcomingResize(); } } @@ -129,7 +159,7 @@ public class LayoutDependencyTree { if (layoutBlockers.isEmpty()) { // Add to queue if there are no blockers - getLayoutQueue(direction).add((ManagedLayout) connector); + getLayoutQueue(direction).add(connector.getConnectorId()); // Only need to propagate if not already propagated when // setting blockers propagatePotentialLayout(); @@ -140,20 +170,23 @@ public class LayoutDependencyTree { // (SimpleManagedLayout gets layouted in both directions // even if there is a blocker in one direction) this.needsLayout = needsLayout; - getLayoutQueue(direction).remove(connector); + getLayoutQueue(direction).remove(connector.getConnectorId()); propagateNoUpcomingLayout(); } } private void propagatePotentialResize() { - for (ComponentConnector needsSize : getNeedsSizeForLayout()) { - LayoutDependency layoutDependency = getDependency(needsSize, + JsArrayString needsSizeForLayout = getNeedsSizeForLayout(); + int length = needsSizeForLayout.length(); + for (int i = 0; i < length; i++) { + String needsSizeId = needsSizeForLayout.get(i); + LayoutDependency layoutDependency = getDependency(needsSizeId, direction); layoutDependency.addLayoutBlocker(connector); } } - private Collection<ComponentConnector> getNeedsSizeForLayout() { + private JsArrayString getNeedsSizeForLayout() { // Find all connectors that need the size of this connector for // layouting @@ -161,15 +194,15 @@ public class LayoutDependencyTree { // Connector itself needs size if it isn't undefined? // Children doesn't care? - ArrayList<ComponentConnector> needsSize = new ArrayList<ComponentConnector>(); + JsArrayString needsSize = JsArrayObject.createArray().cast(); if (!isUndefinedInDirection(connector, direction)) { - needsSize.add(connector); + needsSize.push(connector.getConnectorId()); } if (!isRelativeInDirection(connector, direction)) { ServerConnector parent = connector.getParent(); if (parent instanceof ComponentConnector) { - needsSize.add((ComponentConnector) parent); + needsSize.push(parent.getConnectorId()); } } @@ -177,38 +210,44 @@ public class LayoutDependencyTree { } private void propagateNoUpcomingResize() { - for (ComponentConnector mightNeedLayout : getNeedsSizeForLayout()) { + JsArrayString needsSizeForLayout = getNeedsSizeForLayout(); + int length = needsSizeForLayout.length(); + for (int i = 0; i < length; i++) { + String mightNeedLayoutId = needsSizeForLayout.get(i); LayoutDependency layoutDependency = getDependency( - mightNeedLayout, direction); + mightNeedLayoutId, direction); layoutDependency.removeLayoutBlocker(connector); } } private void propagatePotentialLayout() { - for (ComponentConnector sizeMightChange : getResizedByLayout()) { + JsArrayString resizedByLayout = getResizedByLayout(); + int length = resizedByLayout.length(); + for (int i = 0; i < length; i++) { + String sizeMightChangeId = resizedByLayout.get(i); LayoutDependency layoutDependency = getDependency( - sizeMightChange, direction); + sizeMightChangeId, direction); layoutDependency.addMeasureBlocker(connector); } } - private Collection<ComponentConnector> getResizedByLayout() { + private JsArrayString getResizedByLayout() { // Components that might get resized by a layout of this component // Parent never resized // Connector itself resized if undefined // Children resized if relative - ArrayList<ComponentConnector> resized = new ArrayList<ComponentConnector>(); + JsArrayString resized = JsArrayObject.createArray().cast(); if (isUndefinedInDirection(connector, direction)) { - resized.add(connector); + resized.push(connector.getConnectorId()); } if (connector instanceof HasComponentsConnector) { HasComponentsConnector container = (HasComponentsConnector) connector; for (ComponentConnector child : container.getChildComponents()) { if (isRelativeInDirection(child, direction)) { - resized.add(child); + resized.push(child.getConnectorId()); } } } @@ -217,9 +256,12 @@ public class LayoutDependencyTree { } private void propagateNoUpcomingLayout() { - for (ComponentConnector sizeMightChange : getResizedByLayout()) { + JsArrayString resizedByLayout = getResizedByLayout(); + int length = resizedByLayout.length(); + for (int i = 0; i < length; i++) { + String sizeMightChangeId = resizedByLayout.get(i); LayoutDependency layoutDependency = getDependency( - sizeMightChange, direction); + sizeMightChangeId, direction); layoutDependency.removeMeasureBlocker(connector); } } @@ -227,10 +269,13 @@ public class LayoutDependencyTree { public void markSizeAsChanged() { // When the size has changed, all that use that size should be // layouted - for (ComponentConnector connector : getNeedsSizeForLayout()) { - LayoutDependency layoutDependency = getDependency(connector, + JsArrayString needsSizeForLayout = getNeedsSizeForLayout(); + int length = needsSizeForLayout.length(); + for (int i = 0; i < length; i++) { + String connectorId = needsSizeForLayout.get(i); + LayoutDependency layoutDependency = getDependency(connectorId, direction); - if (connector instanceof ManagedLayout) { + if (layoutDependency.connector instanceof ManagedLayout) { layoutDependency.setNeedsLayout(true); } else { // Should simulate setNeedsLayout(true) + markAsLayouted -> @@ -243,8 +288,8 @@ public class LayoutDependencyTree { // disappeared scrollbars ComponentConnector scrollingBoundary = getScrollingBoundary(connector); if (scrollingBoundary != null) { - getDependency(scrollingBoundary, getOppositeDirection()) - .setNeedsMeasure(true); + getDependency(scrollingBoundary.getConnectorId(), + getOppositeDirection()).setNeedsMeasure(true); } } @@ -264,7 +309,7 @@ public class LayoutDependencyTree { return null; } if (parent instanceof MayScrollChildren) { - return getDependency(currentConnector, + return getDependency(currentConnector.getConnectorId(), getOppositeDirection()); } currentConnector = (ComponentConnector) parent; @@ -287,8 +332,11 @@ public class LayoutDependencyTree { } private void propagatePostLayoutMeasure() { - for (ComponentConnector resized : getResizedByLayout()) { - LayoutDependency layoutDependency = getDependency(resized, + JsArrayString resizedByLayout = getResizedByLayout(); + int length = resizedByLayout.length(); + for (int i = 0; i < length; i++) { + String resizedId = resizedByLayout.get(i); + LayoutDependency layoutDependency = getDependency(resizedId, direction); layoutDependency.setNeedsMeasure(true); } @@ -296,7 +344,8 @@ public class LayoutDependencyTree { // Special case for e.g. wrapping texts if (direction == HORIZONTAL && !connector.isUndefinedWidth() && connector.isUndefinedHeight()) { - LayoutDependency dependency = getDependency(connector, VERTICAL); + LayoutDependency dependency = getDependency( + connector.getConnectorId(), VERTICAL); dependency.setNeedsMeasure(true); } } @@ -317,7 +366,7 @@ public class LayoutDependencyTree { if (needsLayout) { s += "Needs layout\n"; } - if (getLayoutQueue(direction).contains(connector)) { + if (getLayoutQueue(direction).contains(connector.getConnectorId())) { s += "In layout queue\n"; } s += "Layout blockers: " + blockersToString(layoutBlockers) + "\n"; @@ -325,7 +374,7 @@ public class LayoutDependencyTree { if (needsMeasure) { s += "Needs measure\n"; } - if (getMeasureQueue(direction).contains(connector)) { + if (getMeasureQueue(direction).contains(connector.getConnectorId())) { s += "In measure queue\n"; } s += "Measure blockers: " + blockersToString(measureBlockers); @@ -343,86 +392,131 @@ public class LayoutDependencyTree { private static final int HORIZONTAL = 0; private static final int VERTICAL = 1; - private final Map<?, ?>[] dependenciesInDirection = new Map<?, ?>[] { - new HashMap<ComponentConnector, LayoutDependency>(), - new HashMap<ComponentConnector, LayoutDependency>() }; + @SuppressWarnings("unchecked") + private final FastStringMap<LayoutDependency>[] dependenciesInDirection = new FastStringMap[] { + FastStringMap.create(), FastStringMap.create() }; + + private final FastStringSet[] measureQueueInDirection = new FastStringSet[] { + FastStringSet.create(), FastStringSet.create() }; + + private final FastStringSet[] layoutQueueInDirection = new FastStringSet[] { + FastStringSet.create(), FastStringSet.create() }; - private final Collection<?>[] measureQueueInDirection = new HashSet<?>[] { - new HashSet<ComponentConnector>(), - new HashSet<ComponentConnector>() }; + private final ApplicationConnection connection; - private final Collection<?>[] layoutQueueInDirection = new HashSet<?>[] { - new HashSet<ComponentConnector>(), - new HashSet<ComponentConnector>() }; + public LayoutDependencyTree(ApplicationConnection connection) { + this.connection = connection; + } public void setNeedsMeasure(ComponentConnector connector, boolean needsMeasure) { - setNeedsHorizontalMeasure(connector, needsMeasure); - setNeedsVerticalMeasure(connector, needsMeasure); + setNeedsMeasure(connector.getConnectorId(), needsMeasure); + } + + public void setNeedsMeasure(String connectorId, boolean needsMeasure) { + setNeedsHorizontalMeasure(connectorId, needsMeasure); + setNeedsVerticalMeasure(connectorId, needsMeasure); } public void setNeedsHorizontalMeasure(ComponentConnector connector, boolean needsMeasure) { - LayoutDependency dependency = getDependency(connector, HORIZONTAL); + setNeedsHorizontalMeasure(connector.getConnectorId(), needsMeasure); + } + + public void setNeedsHorizontalMeasure(String connectorId, + boolean needsMeasure) { + LayoutDependency dependency = getDependency(connectorId, HORIZONTAL); dependency.setNeedsMeasure(needsMeasure); } public void setNeedsVerticalMeasure(ComponentConnector connector, boolean needsMeasure) { - LayoutDependency dependency = getDependency(connector, VERTICAL); + setNeedsVerticalMeasure(connector.getConnectorId(), needsMeasure); + } + + public void setNeedsVerticalMeasure(String connectorId, boolean needsMeasure) { + LayoutDependency dependency = getDependency(connectorId, VERTICAL); dependency.setNeedsMeasure(needsMeasure); } - private LayoutDependency getDependency(ComponentConnector connector, - int direction) { - @SuppressWarnings("unchecked") - Map<ComponentConnector, LayoutDependency> dependencies = (Map<ComponentConnector, LayoutDependency>) dependenciesInDirection[direction]; - LayoutDependency dependency = dependencies.get(connector); + private LayoutDependency getDependency(String connectorId, int direction) { + FastStringMap<LayoutDependency> dependencies = dependenciesInDirection[direction]; + LayoutDependency dependency = dependencies.get(connectorId); if (dependency == null) { + ComponentConnector connector = (ComponentConnector) ConnectorMap + .get(connection).getConnector(connectorId); dependency = new LayoutDependency(connector, direction); - dependencies.put(connector, dependency); + dependencies.put(connectorId, dependency); } return dependency; } - @SuppressWarnings("unchecked") - private Collection<ManagedLayout> getLayoutQueue(int direction) { - return (Collection<ManagedLayout>) layoutQueueInDirection[direction]; + private FastStringSet getLayoutQueue(int direction) { + return layoutQueueInDirection[direction]; } - @SuppressWarnings("unchecked") - private Collection<ComponentConnector> getMeasureQueue(int direction) { - return (Collection<ComponentConnector>) measureQueueInDirection[direction]; + private FastStringSet getMeasureQueue(int direction) { + return measureQueueInDirection[direction]; } + /** + * @param layout + * @param needsLayout + * + * @deprecated As of 7.0.1, use + * {@link #setNeedsHorizontalLayout(String, boolean)} for + * improved performance. + */ + @Deprecated public void setNeedsHorizontalLayout(ManagedLayout layout, boolean needsLayout) { - LayoutDependency dependency = getDependency(layout, HORIZONTAL); + setNeedsHorizontalLayout(layout.getConnectorId(), needsLayout); + } + + public void setNeedsHorizontalLayout(String connectorId, boolean needsLayout) { + LayoutDependency dependency = getDependency(connectorId, HORIZONTAL); dependency.setNeedsLayout(needsLayout); } + /** + * @param layout + * @param needsLayout + * + * @deprecated As of 7.0.1, use + * {@link #setNeedsVerticalLayout(String, boolean)} for improved + * performance. + */ + @Deprecated public void setNeedsVerticalLayout(ManagedLayout layout, boolean needsLayout) { - LayoutDependency dependency = getDependency(layout, VERTICAL); + setNeedsVerticalLayout(layout.getConnectorId(), needsLayout); + } + + public void setNeedsVerticalLayout(String connectorId, boolean needsLayout) { + LayoutDependency dependency = getDependency(connectorId, VERTICAL); dependency.setNeedsLayout(needsLayout); } public void markAsHorizontallyLayouted(ManagedLayout layout) { - LayoutDependency dependency = getDependency(layout, HORIZONTAL); + LayoutDependency dependency = getDependency(layout.getConnectorId(), + HORIZONTAL); dependency.markAsLayouted(); } public void markAsVerticallyLayouted(ManagedLayout layout) { - LayoutDependency dependency = getDependency(layout, VERTICAL); + LayoutDependency dependency = getDependency(layout.getConnectorId(), + VERTICAL); dependency.markAsLayouted(); } public void markHeightAsChanged(ComponentConnector connector) { - LayoutDependency dependency = getDependency(connector, VERTICAL); + LayoutDependency dependency = getDependency(connector.getConnectorId(), + VERTICAL); dependency.markSizeAsChanged(); } public void markWidthAsChanged(ComponentConnector connector) { - LayoutDependency dependency = getDependency(connector, HORIZONTAL); + LayoutDependency dependency = getDependency(connector.getConnectorId(), + HORIZONTAL); dependency.markSizeAsChanged(); } @@ -444,7 +538,7 @@ public class LayoutDependencyTree { } } - private static String getCompactConnectorString(ComponentConnector connector) { + private static String getCompactConnectorString(ServerConnector connector) { return Util.getSimpleName(connector) + " (" + connector.getConnectorId() + ")"; } @@ -459,10 +553,14 @@ public class LayoutDependencyTree { } } - private static String blockersToString( - Collection<ComponentConnector> blockers) { + private String blockersToString(FastStringSet blockers) { StringBuilder b = new StringBuilder("["); - for (ComponentConnector blocker : blockers) { + + ConnectorMap connectorMap = ConnectorMap.get(connection); + JsArrayString blockersDump = blockers.dump(); + for (int i = 0; i < blockersDump.length(); i++) { + ServerConnector blocker = connectorMap.getConnector(blockersDump + .get(i)); if (b.length() != 1) { b.append(", "); } @@ -485,36 +583,98 @@ public class LayoutDependencyTree { return !getLayoutQueue(VERTICAL).isEmpty(); } + /** + * @return + * @deprecated As of 7.0.1, use {@link #getHorizontalLayoutTargetsJsArray()} + * for improved performance. + */ + @Deprecated public ManagedLayout[] getHorizontalLayoutTargets() { - Collection<ManagedLayout> queue = getLayoutQueue(HORIZONTAL); - return queue.toArray(new ManagedLayout[queue.size()]); + return asManagedLayoutArray(getHorizontalLayoutTargetsJsArray()); } + /** + * @return + * @deprecated As of 7.0.1, use {@link #getVerticalLayoutTargetsJsArray()} + * for improved performance. + */ + @Deprecated public ManagedLayout[] getVerticalLayoutTargets() { - Collection<ManagedLayout> queue = getLayoutQueue(VERTICAL); - return queue.toArray(new ManagedLayout[queue.size()]); + return asManagedLayoutArray(getVerticalLayoutTargetsJsArray()); + } + + private ManagedLayout[] asManagedLayoutArray(JsArrayString connectorIdArray) { + int length = connectorIdArray.length(); + ConnectorMap connectorMap = ConnectorMap.get(connection); + ManagedLayout[] result = new ManagedLayout[length]; + for (int i = 0; i < length; i++) { + result[i] = (ManagedLayout) connectorMap + .getConnector(connectorIdArray.get(i)); + } + return result; } + public JsArrayString getHorizontalLayoutTargetsJsArray() { + return getLayoutQueue(HORIZONTAL).dump(); + } + + public JsArrayString getVerticalLayoutTargetsJsArray() { + return getLayoutQueue(VERTICAL).dump(); + } + + /** + * @return + * @deprecated As of 7.0.1, use {@link #getMeasureTargetsJsArray()} for + * improved performance. + */ + @Deprecated public Collection<ComponentConnector> getMeasureTargets() { - Collection<ComponentConnector> measureTargets = new HashSet<ComponentConnector>( - getMeasureQueue(HORIZONTAL)); - measureTargets.addAll(getMeasureQueue(VERTICAL)); + JsArrayString targetIds = getMeasureTargetsJsArray(); + int length = targetIds.length(); + ArrayList<ComponentConnector> targets = new ArrayList<ComponentConnector>( + length); + ConnectorMap connectorMap = ConnectorMap.get(connection); + + for (int i = 0; i < length; i++) { + targets.add((ComponentConnector) connectorMap + .getConnector(targetIds.get(i))); + } + return targets; + } + + public JsArrayString getMeasureTargetsJsArray() { + FastStringSet horizontalQueue = getMeasureQueue(HORIZONTAL); + JsArrayString measureTargets = horizontalQueue.dump(); + + JsArrayString verticalDump = getMeasureQueue(VERTICAL).dump(); + int length = verticalDump.length(); + for (int i = 0; i < length; i++) { + String connectorId = verticalDump.get(i); + if (!horizontalQueue.contains(connectorId)) { + measureTargets.push(connectorId); + } + } + return measureTargets; } public void logDependencyStatus(ComponentConnector connector) { VConsole.log("===="); - VConsole.log(getDependency(connector, HORIZONTAL).toString()); - VConsole.log(getDependency(connector, VERTICAL).toString()); + String connectorId = connector.getConnectorId(); + VConsole.log(getDependency(connectorId, HORIZONTAL).toString()); + VConsole.log(getDependency(connectorId, VERTICAL).toString()); } public boolean noMoreChangesExpected(ComponentConnector connector) { - return getDependency(connector, HORIZONTAL).noMoreChangesExpected() - && getDependency(connector, VERTICAL).noMoreChangesExpected(); + return getDependency(connector.getConnectorId(), HORIZONTAL) + .noMoreChangesExpected() + && getDependency(connector.getConnectorId(), VERTICAL) + .noMoreChangesExpected(); } public ComponentConnector getScrollingBoundary(ComponentConnector connector) { - LayoutDependency dependency = getDependency(connector, HORIZONTAL); + LayoutDependency dependency = getDependency(connector.getConnectorId(), + HORIZONTAL); if (!dependency.scrollingParentCached) { ServerConnector parent = dependency.connector.getParent(); if (parent instanceof MayScrollChildren) { |