From be23b014866160cb4bc3af8ed808c6f749270dce Mon Sep 17 00:00:00 2001 From: Anna Koskinen Date: Fri, 5 Feb 2021 14:55:00 +0200 Subject: [PATCH] Re-use ComputedStyles in Escalator when possible. (#12186) --- .../com/vaadin/client/widgets/Escalator.java | 39 ++++- .../java/com/vaadin/client/widgets/Grid.java | 8 +- .../performance/BasicPerformanceTest.java | 140 ++++++++++++++++-- .../client/PerformanceExtensionClientRpc.java | 9 ++ .../client/PerformanceExtensionConnector.java | 45 ++++++ .../server/PerformanceExtension.java | 39 +++++ 6 files changed, 261 insertions(+), 19 deletions(-) create mode 100644 uitest/src/main/java/com/vaadin/tests/widgetset/client/PerformanceExtensionClientRpc.java create mode 100644 uitest/src/main/java/com/vaadin/tests/widgetset/client/PerformanceExtensionConnector.java create mode 100644 uitest/src/main/java/com/vaadin/tests/widgetset/server/PerformanceExtension.java diff --git a/client/src/main/java/com/vaadin/client/widgets/Escalator.java b/client/src/main/java/com/vaadin/client/widgets/Escalator.java index a5046ce970..a9f8e0862c 100644 --- a/client/src/main/java/com/vaadin/client/widgets/Escalator.java +++ b/client/src/main/java/com/vaadin/client/widgets/Escalator.java @@ -7160,6 +7160,8 @@ public class Escalator extends Widget private final ElementPositionBookkeeper positions = new ElementPositionBookkeeper(); + private Map 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! + *

+ * 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 diff --git a/client/src/main/java/com/vaadin/client/widgets/Grid.java b/client/src/main/java/com/vaadin/client/widgets/Grid.java index d4c93751ea..99a4a269bd 100755 --- a/client/src/main/java/com/vaadin/client/widgets/Grid.java +++ b/client/src/main/java/com/vaadin/client/widgets/Grid.java @@ -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 extends ResizeComposite implements HasSelectionHandlers, // 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 extends ResizeComposite implements HasSelectionHandlers, }); } - private double getEscalatorInnerHeight() { - return new ComputedStyle(getEscalator().getTableWrapper()) - .getHeightIncludingBorderPadding(); - } - /** * Grid does not support adding Widgets this way. *

diff --git a/uitest/src/main/java/com/vaadin/tests/performance/BasicPerformanceTest.java b/uitest/src/main/java/com/vaadin/tests/performance/BasicPerformanceTest.java index 0e3dd73615..d15090d73a 100644 --- a/uitest/src/main/java/com/vaadin/tests/performance/BasicPerformanceTest.java +++ b/uitest/src/main/java/com/vaadin/tests/performance/BasicPerformanceTest.java @@ -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 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 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("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("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 createGrid() { + Grid 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 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 index 0000000000..25d25ddd6c --- /dev/null +++ b/uitest/src/main/java/com/vaadin/tests/widgetset/client/PerformanceExtensionClientRpc.java @@ -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 index 0000000000..744d6f92b0 --- /dev/null +++ b/uitest/src/main/java/com/vaadin/tests/widgetset/client/PerformanceExtensionConnector.java @@ -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 index 0000000000..b13d418cfd --- /dev/null +++ b/uitest/src/main/java/com/vaadin/tests/widgetset/server/PerformanceExtension.java @@ -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(); + } +} -- 2.39.5