]> source.dussan.org Git - vaadin-framework.git/commitdiff
Re-use ComputedStyles in Escalator when possible. (#12186)
authorAnna Koskinen <Ansku@users.noreply.github.com>
Fri, 5 Feb 2021 12:55:00 +0000 (14:55 +0200)
committerGitHub <noreply@github.com>
Fri, 5 Feb 2021 12:55:00 +0000 (14:55 +0200)
client/src/main/java/com/vaadin/client/widgets/Escalator.java
client/src/main/java/com/vaadin/client/widgets/Grid.java
uitest/src/main/java/com/vaadin/tests/performance/BasicPerformanceTest.java
uitest/src/main/java/com/vaadin/tests/widgetset/client/PerformanceExtensionClientRpc.java [new file with mode: 0644]
uitest/src/main/java/com/vaadin/tests/widgetset/client/PerformanceExtensionConnector.java [new file with mode: 0644]
uitest/src/main/java/com/vaadin/tests/widgetset/server/PerformanceExtension.java [new file with mode: 0644]

index a5046ce970d0bb107e0031d357513cb29b5545b8..a9f8e0862cb74855de8b6178dc82c9f4e12d0133 100644 (file)
@@ -7160,6 +7160,8 @@ public class Escalator extends Widget
 
     private final ElementPositionBookkeeper positions = new ElementPositionBookkeeper();
 
+    private Map<Element, ComputedStyle> computedStyleMap = new HashMap<>();
+
     /**
      * Creates a new Escalator widget instance.
      */
@@ -7249,14 +7251,28 @@ public class Escalator extends Widget
     private double getBoundingWidth(Element element) {
         // Gets the current width, including border and padding, for the element
         // while ignoring any transforms applied to the element (e.g. scale)
-        return new ComputedStyle(element).getWidthIncludingBorderPadding();
+        if (!computedStyleMap.containsKey(element)) {
+            if (computedStyleMap.isEmpty()) {
+                // ensure the next event loop calculates the sizes anew
+                Scheduler.get().scheduleDeferred(() -> clearComputedStyles());
+            }
+            computedStyleMap.put(element, new ComputedStyle(element));
+        }
+        return computedStyleMap.get(element).getWidthIncludingBorderPadding();
     }
 
     private double getBoundingHeight(Element element) {
         // Gets the current height, including border and padding, for the
         // element while ignoring any transforms applied to the element (e.g.
         // scale)
-        return new ComputedStyle(element).getHeightIncludingBorderPadding();
+        if (!computedStyleMap.containsKey(element)) {
+            if (computedStyleMap.isEmpty()) {
+                // ensure the next event loop calculates the sizes anew
+                Scheduler.get().scheduleDeferred(() -> clearComputedStyles());
+            }
+            computedStyleMap.put(element, new ComputedStyle(element));
+        }
+        return computedStyleMap.get(element).getHeightIncludingBorderPadding();
     }
 
     private int getBodyRowCount() {
@@ -8305,6 +8321,25 @@ public class Escalator extends Widget
         return getBoundingWidth(tableWrapper);
     }
 
+    /**
+     * Gets the escalator's inner height. This is the entire height in pixels,
+     * without the horizontal scrollbar.
+     *
+     * @return escalator's inner height
+     */
+    public double getInnerHeight() {
+        return getBoundingHeight(tableWrapper);
+    }
+
+    /**
+     * FOR INTERNAL USE ONLY, MAY GET REMOVED OR MODIFIED AT ANY TIME!
+     * <p>
+     * Clears the computed styles.
+     */
+    void clearComputedStyles() {
+        computedStyleMap.clear();
+    }
+
     /**
      * Resets all cached pixel sizes and reads new values from the DOM. This
      * methods should be used e.g. when styles affecting the dimensions of
index d4c93751ea7222a84ec2f40c69245d69fcff4f64..99a4a269bd3f062ca0e4ae485fa58f87b8cd6291 100755 (executable)
@@ -77,7 +77,6 @@ import com.google.gwt.user.client.ui.PopupPanel;
 import com.google.gwt.user.client.ui.ResizeComposite;
 import com.google.gwt.user.client.ui.Widget;
 import com.vaadin.client.BrowserInfo;
-import com.vaadin.client.ComputedStyle;
 import com.vaadin.client.DeferredWorker;
 import com.vaadin.client.Focusable;
 import com.vaadin.client.WidgetUtil;
@@ -3456,7 +3455,7 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
 
             // Update latest width to prevent recalculate on height change.
             lastCalculatedInnerWidth = escalator.getInnerWidth();
-            lastCalculatedInnerHeight = getEscalatorInnerHeight();
+            lastCalculatedInnerHeight = escalator.getInnerHeight();
         }
 
         private boolean columnsAreGuaranteedToBeWiderThanGrid() {
@@ -9404,11 +9403,6 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
         });
     }
 
-    private double getEscalatorInnerHeight() {
-        return new ComputedStyle(getEscalator().getTableWrapper())
-                .getHeightIncludingBorderPadding();
-    }
-
     /**
      * Grid does not support adding Widgets this way.
      * <p>
index 0e3dd736157e06c6b0839e790ec20946635a365e..d15090d73a13bed167d1c1d25c560a74a5265188 100644 (file)
@@ -1,21 +1,40 @@
 package com.vaadin.tests.performance;
 
+import java.math.BigDecimal;
+import java.util.Date;
 import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+import java.util.Random;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
+import com.vaadin.annotations.Widgetset;
 import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.data.bean.Address;
+import com.vaadin.tests.data.bean.Country;
+import com.vaadin.tests.data.bean.Person;
+import com.vaadin.tests.data.bean.Sex;
 import com.vaadin.tests.util.TestUtils;
+import com.vaadin.tests.widgetset.TestingWidgetSet;
+import com.vaadin.tests.widgetset.server.PerformanceExtension;
 import com.vaadin.ui.AbstractOrderedLayout;
 import com.vaadin.ui.Button;
+import com.vaadin.ui.ComboBox;
 import com.vaadin.ui.Component;
 import com.vaadin.ui.ComponentContainer;
+import com.vaadin.ui.DateField;
+import com.vaadin.ui.Grid;
 import com.vaadin.ui.HorizontalLayout;
 import com.vaadin.ui.Label;
 import com.vaadin.ui.Panel;
+import com.vaadin.ui.TextField;
 import com.vaadin.ui.UI;
 import com.vaadin.ui.VerticalLayout;
 import com.vaadin.v7.ui.TextArea;
 import com.vaadin.v7.ui.themes.Reindeer;
 
+@Widgetset(TestingWidgetSet.NAME)
 public class BasicPerformanceTest extends UI {
 
     private int updateOneCount = 0;
@@ -24,6 +43,7 @@ public class BasicPerformanceTest extends UI {
 
     private int clientLimit;
     private int serverLimit;
+    private PerformanceExtension performanceExtension;
     private boolean reportBootstap = true;
     private String performanceTopic;
     private final Button reportPerformanceButton = new Button(
@@ -31,6 +51,7 @@ public class BasicPerformanceTest extends UI {
                 TestUtils.reportPerformance(performanceTopic, serverLimit,
                         clientLimit, reportBootstap);
                 event.getButton().setEnabled(false);
+                performanceExtension.stop();
             });
 
     @Override
@@ -62,24 +83,49 @@ public class BasicPerformanceTest extends UI {
         performanceReportArea.setWidth("200px");
         TestUtils.installPerformanceReporting(performanceReportArea);
 
+        Label performanceLabel = new Label();
+        performanceLabel.setId("performanceLabel");
+        performanceExtension = PerformanceExtension.wrap(performanceLabel);
+
         VerticalLayout leftBar = new VerticalLayout();
         leftBar.setWidth("250px");
         leftBar.addComponent(new Label("This is the left bar"));
         leftBar.addComponent(performanceReportArea);
+        leftBar.addComponent(performanceLabel);
         leftBar.addComponent(reportPerformanceButton);
 
         leftBar.addComponent(new Button("Set 20 panels as content", event -> {
-            popupateContent(contentLayout, 20, true);
+            populateContent(contentLayout, 20, true);
             updatePerformanceReporting("20 panels", 100, 100);
         }));
         leftBar.addComponent(new Button("Set 40 panels as content", event -> {
-            popupateContent(contentLayout, 40, true);
+            populateContent(contentLayout, 40, true);
             updatePerformanceReporting("40 panels", 100, 100);
         }));
         leftBar.addComponent(new Button("Set 40 layouts as content", event -> {
-            popupateContent(contentLayout, 40, false);
+            populateContent(contentLayout, 40, false);
             updatePerformanceReporting("40 layouts", 100, 100);
         }));
+        leftBar.addComponent(
+                new Button("Set 40 field panels as content", event -> {
+                    populateContent(contentLayout, 40, true, true);
+                    updatePerformanceReporting("40 field panels", 100, 100);
+                }));
+        leftBar.addComponent(
+                new Button("Set 20 small grids as content", event -> {
+                    populateWithGrids(1, 20);
+                    updatePerformanceReporting("small grids", 100, 100);
+                }));
+        leftBar.addComponent(
+                new Button("Set 10 medium grids as content", event -> {
+                    populateWithGrids(1000, 10);
+                    updatePerformanceReporting("medium grids", 100, 100);
+                }));
+        leftBar.addComponent(
+                new Button("Set 5 large grids as content", event -> {
+                    populateWithGrids(100000, 5);
+                    updatePerformanceReporting("large grids", 100, 100);
+                }));
 
         leftBar.addComponent(new Button("Update all labels", event -> {
             Iterator<Component> componentIterator = contentLayout
@@ -146,19 +192,47 @@ public class BasicPerformanceTest extends UI {
         return mainLayout;
     }
 
-    private void popupateContent(VerticalLayout contentLayout, int childCount,
+    private void populateWithGrids(int itemCount, int gridCount) {
+        performanceExtension.start();
+        contentLayout.removeAllComponents();
+        for (int i = 0; i < gridCount; i++) {
+            Grid<Person> grid = createGrid();
+            grid.setItems(createBeans(itemCount));
+            contentLayout.addComponent(grid);
+        }
+    }
+
+    private void populateContent(VerticalLayout contentLayout, int childCount,
             boolean wrapInPanel) {
+        populateContent(contentLayout, childCount, wrapInPanel, false);
+    }
+
+    private void populateContent(VerticalLayout contentLayout, int childCount,
+            boolean wrapInPanel, boolean useFields) {
+        performanceExtension.start();
         contentLayout.removeAllComponents();
         for (int i = 0; i < childCount; i++) {
             VerticalLayout left = new VerticalLayout();
-            left.addComponent(new Label("Label 1"));
-            left.addComponent(new Label("Label 2"));
-            left.addComponent(new Label("Label 3"));
+            if (useFields) {
+                left.addComponent(new TextField("Field 1"));
+                left.addComponent(new ComboBox<String>("Field 2"));
+                left.addComponent(new DateField("Field 3"));
+            } else {
+                left.addComponent(new Label("Label 1"));
+                left.addComponent(new Label("Label 2"));
+                left.addComponent(new Label("Label 3"));
+            }
 
             VerticalLayout right = new VerticalLayout();
-            right.addComponent(new Label("Label 4"));
-            right.addComponent(new Label("Label 5"));
-            right.addComponent(new Label("Label 6"));
+            if (useFields) {
+                right.addComponent(new TextField("Field 4"));
+                right.addComponent(new ComboBox<String>("Field 5"));
+                right.addComponent(new DateField("Field 6"));
+            } else {
+                right.addComponent(new Label("Label 4"));
+                right.addComponent(new Label("Label 5"));
+                right.addComponent(new Label("Label 6"));
+            }
 
             HorizontalLayout columns = new HorizontalLayout();
             columns.addComponent(left);
@@ -177,4 +251,50 @@ public class BasicPerformanceTest extends UI {
             }
         }
     }
+
+    protected Grid<Person> createGrid() {
+        Grid<Person> grid = new Grid<>();
+        grid.addColumn(Person::getFirstName).setCaption("First Name");
+        grid.addColumn(Person::getLastName).setCaption("Last Name");
+        grid.addColumn(person -> Optional.ofNullable(person.getAddress())
+                .map(Address::getStreetAddress).orElse(null))
+                .setCaption("Street");
+        grid.addColumn(person -> Optional.ofNullable(person.getAddress())
+                .map(Address::getPostalCode).map(Object::toString).orElse(""))
+                .setCaption("Zip");
+        grid.addColumn(person -> Optional.ofNullable(person.getAddress())
+                .map(Address::getCity).orElse(null)).setCaption("City");
+        return grid;
+    }
+
+    private Random random = new Random();
+
+    protected List<Person> createBeans(int size) {
+        return IntStream.range(0, size).mapToObj(this::createPerson)
+                .collect(Collectors.toList());
+    }
+
+    protected Person createPerson(int index) {
+        random.setSeed(index);
+        Person person = new Person();
+        person.setFirstName("First Name " + random.nextInt());
+        person.setLastName("Last Name " + random.nextInt());
+        person.setAge(random.nextInt());
+        person.setBirthDate(new Date(random.nextLong()));
+        person.setDeceased(random.nextBoolean());
+        person.setEmail(random.nextInt() + "user@example.com");
+        person.setRent(new BigDecimal(random.nextLong()));
+        person.setSalary(random.nextInt());
+        person.setSalaryDouble(random.nextDouble());
+        person.setSex(Sex.values()[random.nextInt(Sex.values().length)]);
+
+        Address address = new Address();
+        person.setAddress(address);
+        address.setCity("city " + random.nextInt());
+        address.setPostalCode(random.nextInt());
+        address.setStreetAddress("street address " + random.nextInt());
+        address.setCountry(
+                Country.values()[random.nextInt(Country.values().length)]);
+        return person;
+    }
 }
diff --git a/uitest/src/main/java/com/vaadin/tests/widgetset/client/PerformanceExtensionClientRpc.java b/uitest/src/main/java/com/vaadin/tests/widgetset/client/PerformanceExtensionClientRpc.java
new file mode 100644 (file)
index 0000000..25d25dd
--- /dev/null
@@ -0,0 +1,9 @@
+package com.vaadin.tests.widgetset.client;
+
+import com.vaadin.shared.communication.ClientRpc;
+
+public interface PerformanceExtensionClientRpc extends ClientRpc {
+    public void start();
+
+    public void stop();
+}
\ No newline at end of file
diff --git a/uitest/src/main/java/com/vaadin/tests/widgetset/client/PerformanceExtensionConnector.java b/uitest/src/main/java/com/vaadin/tests/widgetset/client/PerformanceExtensionConnector.java
new file mode 100644 (file)
index 0000000..744d6f9
--- /dev/null
@@ -0,0 +1,45 @@
+package com.vaadin.tests.widgetset.client;
+
+import com.vaadin.client.ServerConnector;
+import com.vaadin.client.communication.MessageHandler;
+import com.vaadin.client.extensions.AbstractExtensionConnector;
+import com.vaadin.shared.communication.ServerRpc;
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.tests.widgetset.server.PerformanceExtension;
+
+@Connect(PerformanceExtension.class)
+public class PerformanceExtensionConnector extends AbstractExtensionConnector {
+    private MessageHandler messageHandler;
+    private int startProcessingTime = 0;
+
+    @Override
+    protected void extend(ServerConnector target) {
+        messageHandler = getConnection().getMessageHandler();
+        registerRpc(PerformanceExtensionClientRpc.class,
+                new PerformanceExtensionClientRpc() {
+
+                    @Override
+                    public void start() {
+                        startProcessingTime = getTotalProcessingTime(
+                                messageHandler);
+                    }
+
+                    @Override
+                    public void stop() {
+                        getRpcProxy(PerformanceExtensionServerRpc.class)
+                                .total(getTotalProcessingTime(messageHandler)
+                                        - startProcessingTime);
+                        startProcessingTime = 0;
+                    }
+                });
+    }
+
+    private native int getTotalProcessingTime(MessageHandler handler)
+    /*-{
+    return handler.@com.vaadin.client.communication.MessageHandler::totalProcessingTime;
+    }-*/;
+
+    public interface PerformanceExtensionServerRpc extends ServerRpc {
+        public void total(int total);
+    }
+}
diff --git a/uitest/src/main/java/com/vaadin/tests/widgetset/server/PerformanceExtension.java b/uitest/src/main/java/com/vaadin/tests/widgetset/server/PerformanceExtension.java
new file mode 100644 (file)
index 0000000..b13d418
--- /dev/null
@@ -0,0 +1,39 @@
+package com.vaadin.tests.widgetset.server;
+
+import com.vaadin.server.AbstractExtension;
+import com.vaadin.tests.widgetset.client.PerformanceExtensionClientRpc;
+import com.vaadin.tests.widgetset.client.PerformanceExtensionConnector;
+import com.vaadin.ui.Label;
+
+public class PerformanceExtension extends AbstractExtension {
+    private Label label;
+
+    private PerformanceExtension() {
+        registerRpc(
+                new PerformanceExtensionConnector.PerformanceExtensionServerRpc() {
+                    @Override
+                    public void total(int total) {
+                        label.setValue("Total: " + total);
+                    }
+                });
+    }
+
+    public static PerformanceExtension wrap(Label label) {
+        PerformanceExtension extension = new PerformanceExtension();
+        extension.label = label;
+        extension.extend(label);
+        return extension;
+    }
+
+    public void start() {
+        getRpcProxy(
+                PerformanceExtensionClientRpc.class)
+                        .start();
+    }
+
+    public void stop() {
+        getRpcProxy(
+                PerformanceExtensionClientRpc.class)
+                        .stop();
+    }
+}