summaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
authorAnna Koskinen <Ansku@users.noreply.github.com>2020-12-18 13:16:26 +0200
committerGitHub <noreply@github.com>2020-12-18 13:16:26 +0200
commitc8e04dc5b30f8967c58df928872ca2e5e2be5c5b (patch)
tree6aae4f933e431470906b554053f21d070fe19b97 /client
parent49f70390add1655fc5eb846e7700d00cb57b5048 (diff)
downloadvaadin-framework-c8e04dc5b30f8967c58df928872ca2e5e2be5c5b.tar.gz
vaadin-framework-c8e04dc5b30f8967c58df928872ca2e5e2be5c5b.zip
Fix to LayoutManager size calculations during transform. (#12138)
* Fix to LayoutManager size calculations during transform. - ComputedStyle is slower but more reliable than using getBoundingClientRect, which does not work as expected if a transform has been applied to the element or one of its parents. This is a problem e.g. with PopupView, where getBoundingClientRect will return too small size (or even zero size) for all the popup contents while the opening animation is active. ComputedStyle ignores the transform and returns the expected value. - The presence of the element in DOM must be checked before the size is requested from ComputedStyle, if the element has disappeared from DOM without a warning and calculation is attempted anyway, the browser gets stuck. - Possibility to configure LayoutManager to use the less reliable calculations for applications where the slight performance difference is more important than layout issues within elements that have transform animations. - Manual test, problem isn't reproducible by TestBench. Fixes: #11187
Diffstat (limited to 'client')
-rw-r--r--client/src/main/java/com/vaadin/client/LayoutManager.java22
-rw-r--r--client/src/main/java/com/vaadin/client/MeasuredSize.java58
-rw-r--r--client/src/main/java/com/vaadin/client/ui/ui/UIConnector.java26
3 files changed, 93 insertions, 13 deletions
diff --git a/client/src/main/java/com/vaadin/client/LayoutManager.java b/client/src/main/java/com/vaadin/client/LayoutManager.java
index 1639004d98..3227555b54 100644
--- a/client/src/main/java/com/vaadin/client/LayoutManager.java
+++ b/client/src/main/java/com/vaadin/client/LayoutManager.java
@@ -69,6 +69,7 @@ public class LayoutManager {
}
};
private boolean everythingNeedsMeasure = false;
+ private boolean thoroughSizeCheck = true;
/**
* Sets the application connection this instance is connected to. Called
@@ -86,6 +87,24 @@ public class LayoutManager {
}
/**
+ * Set whether the measuring should use a thorough size check that evaluates
+ * the presence of the element and uses calculated size, or default to a
+ * slightly faster check that can result in incorrect size information if
+ * the check is triggered while a transform animation is ongoing. This can
+ * happen e.g. when a PopupView is opened.
+ * <p>
+ * By default, the thorough size check is enabled.
+ *
+ * @param thoroughSizeCheck
+ * {@code true} if thorough size check enabled, {@code false} if
+ * not
+ * @since
+ */
+ public void setThoroughSizeChck(boolean thoroughSizeCheck) {
+ this.thoroughSizeCheck = thoroughSizeCheck;
+ }
+
+ /**
* Returns the application connection for this layout manager.
*
* @return connection
@@ -822,7 +841,8 @@ public class LayoutManager {
private MeasureResult measuredAndUpdate(Element element,
MeasuredSize measuredSize) {
- MeasureResult measureResult = measuredSize.measure(element);
+ MeasureResult measureResult = measuredSize.measure(element,
+ thoroughSizeCheck);
if (measureResult.isChanged()) {
notifyListenersAndDepdendents(element,
measureResult.isWidthChanged(),
diff --git a/client/src/main/java/com/vaadin/client/MeasuredSize.java b/client/src/main/java/com/vaadin/client/MeasuredSize.java
index 89732dea6d..6814168bcc 100644
--- a/client/src/main/java/com/vaadin/client/MeasuredSize.java
+++ b/client/src/main/java/com/vaadin/client/MeasuredSize.java
@@ -18,6 +18,7 @@ package com.vaadin.client;
import java.util.logging.Logger;
import com.google.gwt.core.client.JsArrayString;
+import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
public class MeasuredSize {
@@ -186,7 +187,44 @@ public class MeasuredSize {
return paddings[3];
}
+ /**
+ * Measures paddings, margins, border, height, and weight of the given
+ * element and stores the results within this {@link MeasuredSize} object.
+ * The measurements are unreliable if the element or any of its parents are
+ * in the middle of a transform animation.
+ *
+ * @param element
+ * element to be measured
+ * @return data object for whether the width or height of the given element
+ * has changed since previous measure
+ * @see {@link #measure(Element, boolean)}
+ */
public MeasureResult measure(Element element) {
+ return measure(element, false);
+ }
+
+ /**
+ * Measures paddings, margins, border, height, and weight of the given
+ * element and stores the results within this {@link MeasuredSize} object.
+ *
+ * @param element
+ * element to be measured
+ * @param thoroughSizeCheck
+ * {@code true} if the measuring should use the more reliable
+ * size check that requires ensuring that the element is still
+ * present in the DOM tree, {@code false} for the slightly faster
+ * check that will give incorrect size information if this method
+ * is called while the element or any of its parents are in the
+ * middle of a transform animation.
+ * @return data object for whether the width or height of the given element
+ * has changed since previous measure
+ */
+ public MeasureResult measure(Element element, boolean thoroughSizeCheck) {
+ if (thoroughSizeCheck
+ && !Document.get().getBody().isOrHasChild(element)) {
+ return new MeasureResult(false, false);
+ }
+
Profiler.enter("MeasuredSize.measure");
boolean heightChanged = false;
boolean widthChanged = false;
@@ -239,7 +277,15 @@ public class MeasuredSize {
Profiler.leave("Measure borders");
Profiler.enter("Measure height");
- double requiredHeight = WidgetUtil.getRequiredHeightDouble(element);
+ double requiredHeight;
+ if (thoroughSizeCheck) {
+ requiredHeight = computedStyle.getHeightIncludingBorderPadding();
+ if (Double.isNaN(requiredHeight)) {
+ requiredHeight = 0;
+ }
+ } else {
+ requiredHeight = WidgetUtil.getRequiredHeightDouble(element);
+ }
double outerHeight = requiredHeight + sumHeights(margins);
double oldHeight = height;
if (setOuterHeight(outerHeight)) {
@@ -249,7 +295,15 @@ public class MeasuredSize {
Profiler.leave("Measure height");
Profiler.enter("Measure width");
- double requiredWidth = WidgetUtil.getRequiredWidthDouble(element);
+ double requiredWidth;
+ if (thoroughSizeCheck) {
+ requiredWidth = computedStyle.getWidthIncludingBorderPadding();
+ if (Double.isNaN(requiredWidth)) {
+ requiredWidth = 0;
+ }
+ } else {
+ requiredWidth = WidgetUtil.getRequiredWidthDouble(element);
+ }
double outerWidth = requiredWidth + sumWidths(margins);
double oldWidth = width;
if (setOuterWidth(outerWidth)) {
diff --git a/client/src/main/java/com/vaadin/client/ui/ui/UIConnector.java b/client/src/main/java/com/vaadin/client/ui/ui/UIConnector.java
index 5630cfab3c..afe185e769 100644
--- a/client/src/main/java/com/vaadin/client/ui/ui/UIConnector.java
+++ b/client/src/main/java/com/vaadin/client/ui/ui/UIConnector.java
@@ -15,6 +15,16 @@
*/
package com.vaadin.client.ui.ui;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
@@ -91,17 +101,8 @@ import com.vaadin.shared.ui.ui.UIServerRpc;
import com.vaadin.shared.ui.ui.UIState;
import com.vaadin.shared.util.SharedUtil;
import com.vaadin.ui.UI;
-import elemental.client.Browser;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.logging.Logger;
+import elemental.client.Browser;
@Connect(value = UI.class, loadStyle = LoadStyle.EAGER)
public class UIConnector extends AbstractSingleComponentContainerConnector
@@ -924,6 +925,11 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
getRpcProxy(DebugWindowServerRpc.class).showServerDesign(connector);
}
+ @OnStateChange("thoroughSizeCheck")
+ void onThoroughSizeChckChange() {
+ getLayoutManager().setThoroughSizeChck(getState().thoroughSizeCheck);
+ }
+
@OnStateChange("theme")
void onThemeChange() {
final String oldTheme = activeTheme;