From a2d6e4fb4b1fd13e9a1b88f2ab1b78d14d8b64a9 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Sun, 18 Sep 2016 23:00:58 +0300 Subject: [PATCH] Use requestAnimationFrame when scrolling in Grid (#20294) Chrome no longer (since version 5x) always fire deferred commands immediately during scrolling but can delay them with several hundred milliseconds, making grid really unresponsive. So far, nobody has been able to provide a reliable test case. Change-Id: Ide80aef2d661c9e27b67c8e62e85734af7a38cab --- .../widget/escalator/ScrollbarBundle.java | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/client/src/main/java/com/vaadin/client/widget/escalator/ScrollbarBundle.java b/client/src/main/java/com/vaadin/client/widget/escalator/ScrollbarBundle.java index 7443b5d315..c8bc8462e9 100644 --- a/client/src/main/java/com/vaadin/client/widget/escalator/ScrollbarBundle.java +++ b/client/src/main/java/com/vaadin/client/widget/escalator/ScrollbarBundle.java @@ -16,6 +16,9 @@ package com.vaadin.client.widget.escalator; +import com.google.gwt.animation.client.AnimationScheduler; +import com.google.gwt.animation.client.AnimationScheduler.AnimationCallback; +import com.google.gwt.animation.client.AnimationScheduler.AnimationSupportDetector; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.dom.client.Element; @@ -47,12 +50,14 @@ import com.vaadin.client.widget.grid.events.ScrollHandler; * @see HorizontalScrollbarBundle */ public abstract class ScrollbarBundle implements DeferredWorker { + private static final boolean supportsRequestAnimationFrame = new AnimationSupportDetector() + .isNativelySupported(); private class ScrollEventFirer { + private final ScheduledCommand fireEventCommand = new ScheduledCommand() { @Override public void execute() { - /* * Some kind of native-scroll-event related asynchronous problem * occurs here (at least on desktops) where the internal @@ -92,7 +97,23 @@ public abstract class ScrollbarBundle implements DeferredWorker { * We'll gather all the scroll events, and only fire once, once * everything has calmed down. */ - Scheduler.get().scheduleDeferred(fireEventCommand); + if (supportsRequestAnimationFrame) { + // Chrome MUST use this as deferred commands will sometimes + // be run with a 300+ ms delay when scrolling. + AnimationScheduler.get() + .requestAnimationFrame(new AnimationCallback() { + @Override + public void execute(double timestamp) { + fireEventCommand.execute(); + + } + }); + } else { + // Does not support requestAnimationFrame and the fallback + // uses a delay of 16ms, we stick to the old deferred + // command which uses a delay of 0ms + Scheduler.get().scheduleDeferred(fireEventCommand); + } isBeingFired = true; } } @@ -894,7 +915,10 @@ public abstract class ScrollbarBundle implements DeferredWorker { @Override public boolean isWorkPending() { + // Need to include scrollEventFirer.isBeingFired as it might use + // requestAnimationFrame - which is not automatically checked return scrollSizeTemporaryScrollHandler != null - || offsetSizeTemporaryScrollHandler != null; + || offsetSizeTemporaryScrollHandler != null + || scrollEventFirer.isBeingFired; } } -- 2.39.5