From 4267567f5366b237c763d1b93cd09501a483a070 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen <allan.jensen@qt.io> Date: Tue, 24 Oct 2017 16:30:31 +0200 Subject: [PATCH] Coalesce wheel events when possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Combine wheel events if we are getting more than Chromium can handle. This improves latency and perceived performance when scrolling with touchpads or fine-grained mouse, on a slow machine or with a debug build. Change-Id: Id847c8e7782e155c28067b6051ce92896b68ca7a Reviewed-by: Michael Brüning <michael.bruning@qt.io> --- src/core/render_widget_host_view_qt.cpp | 24 ++++++++++++- src/core/render_widget_host_view_qt.h | 4 +++ src/core/web_event_factory.cpp | 48 +++++++++++++++++-------- src/core/web_event_factory.h | 1 + 4 files changed, 61 insertions(+), 16 deletions(-) diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index d1fc7d171..a45383946 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -282,6 +282,7 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost* widget , m_cursorPositionWithinSelection(-1) , m_cursorPosition(0) , m_emptyPreviousSelection(true) + , m_wheelAckPending(false) { m_host->SetView(this); #ifndef QT_NO_ACCESSIBILITY @@ -1350,7 +1351,28 @@ void RenderWidgetHostViewQt::accessibilityActiveChanged(bool active) void RenderWidgetHostViewQt::handleWheelEvent(QWheelEvent *ev) { - m_host->ForwardWheelEvent(WebEventFactory::toWebWheelEvent(ev, dpiScale())); + if (!m_wheelAckPending) { + Q_ASSERT(m_pendingWheelEvents.isEmpty()); + m_wheelAckPending = true; + m_host->ForwardWheelEvent(WebEventFactory::toWebWheelEvent(ev, dpiScale())); + return; + } + if (!m_pendingWheelEvents.isEmpty()) { + // Try to combine with this wheel event with the last pending one. + if (WebEventFactory::coalesceWebWheelEvent(m_pendingWheelEvents.last(), ev, dpiScale())) + return; + } + m_pendingWheelEvents.append(WebEventFactory::toWebWheelEvent(ev, dpiScale())); +} + +void RenderWidgetHostViewQt::WheelEventAck(const blink::WebMouseWheelEvent &/*event*/, content::InputEventAckState /*ack_result*/) +{ + m_wheelAckPending = false; + if (!m_pendingWheelEvents.isEmpty()) { + m_wheelAckPending = true; + m_host->ForwardWheelEvent(m_pendingWheelEvents.takeFirst()); + } + // TODO: We could forward unhandled wheelevents to our parent. } void RenderWidgetHostViewQt::clearPreviousTouchMotionState() diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h index 59e21b853..4b7f9094e 100644 --- a/src/core/render_widget_host_view_qt.h +++ b/src/core/render_widget_host_view_qt.h @@ -152,6 +152,7 @@ public: bool HasAcceleratedSurface(const gfx::Size&) override; void DidCreateNewRendererCompositorFrameSink(cc::mojom::CompositorFrameSinkClient* renderer_compositor_frame_sink) override; void SubmitCompositorFrame(const viz::LocalSurfaceId&, cc::CompositorFrame) override; + void WheelEventAck(const blink::WebMouseWheelEvent &event, content::InputEventAckState ack_result) override; void GetScreenInfo(content::ScreenInfo* results); gfx::Rect GetBoundsInRootWindow() override; @@ -270,6 +271,9 @@ private: QString m_surroundingText; bool m_imeHasHiddenTextCapability; + + bool m_wheelAckPending; + QList<blink::WebMouseWheelEvent> m_pendingWheelEvents; }; } // namespace QtWebEngineCore diff --git a/src/core/web_event_factory.cpp b/src/core/web_event_factory.cpp index 18f8d393f..c31de19a2 100644 --- a/src/core/web_event_factory.cpp +++ b/src/core/web_event_factory.cpp @@ -1247,38 +1247,56 @@ WebGestureEvent WebEventFactory::toWebGestureEvent(QNativeGestureEvent *ev, doub } #endif -blink::WebMouseWheelEvent WebEventFactory::toWebWheelEvent(QWheelEvent *ev, double dpiScale) +static void setBlinkWheelEventDelta(blink::WebMouseWheelEvent &webEvent) { - WebMouseWheelEvent webEvent; - webEvent.delta_x = 0; - webEvent.delta_y = 0; - webEvent.wheel_ticks_x = 0; - webEvent.wheel_ticks_y = 0; - webEvent.SetType(webEventTypeForEvent(ev)); - webEvent.SetModifiers(modifiersForEvent(ev)); - webEvent.SetTimeStampSeconds(currentTimeForEvent(ev)); - - webEvent.wheel_ticks_x = static_cast<float>(ev->angleDelta().x()) / QWheelEvent::DefaultDeltasPerStep; - webEvent.wheel_ticks_y = static_cast<float>(ev->angleDelta().y()) / QWheelEvent::DefaultDeltasPerStep; - // We can't use the device specific QWheelEvent::pixelDelta(), so we calculate // a pixel delta based on ticks and scroll per line. static const float cDefaultQtScrollStep = 20.f; #if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)) - const int wheelScrollLines = QGuiApplication::styleHints()->wheelScrollLines(); + static const int wheelScrollLines = QGuiApplication::styleHints()->wheelScrollLines(); #else - const int wheelScrollLines = 3; + static const int wheelScrollLines = 3; #endif webEvent.delta_x = webEvent.wheel_ticks_x * wheelScrollLines * cDefaultQtScrollStep; webEvent.delta_y = webEvent.wheel_ticks_y * wheelScrollLines * cDefaultQtScrollStep; +} + +blink::WebMouseWheelEvent WebEventFactory::toWebWheelEvent(QWheelEvent *ev, double dpiScale) +{ + WebMouseWheelEvent webEvent; + webEvent.SetType(webEventTypeForEvent(ev)); + webEvent.SetModifiers(modifiersForEvent(ev)); + webEvent.SetTimeStampSeconds(currentTimeForEvent(ev)); webEvent.SetPositionInWidget(ev->x() / dpiScale, ev->y() / dpiScale); webEvent.SetPositionInScreen(ev->globalX(), ev->globalY()); + webEvent.wheel_ticks_x = static_cast<float>(ev->angleDelta().x()) / QWheelEvent::DefaultDeltasPerStep; + webEvent.wheel_ticks_y = static_cast<float>(ev->angleDelta().y()) / QWheelEvent::DefaultDeltasPerStep; + setBlinkWheelEventDelta(webEvent); + return webEvent; } +bool WebEventFactory::coalesceWebWheelEvent(blink::WebMouseWheelEvent &webEvent, QWheelEvent *ev, double dpiScale) +{ + if (webEventTypeForEvent(ev) != webEvent.GetType()) + return false; + if (modifiersForEvent(ev) != webEvent.GetModifiers()) + return false; + + webEvent.SetTimeStampSeconds(currentTimeForEvent(ev)); + webEvent.SetPositionInWidget(ev->x() / dpiScale, ev->y() / dpiScale); + webEvent.SetPositionInScreen(ev->globalX(), ev->globalY()); + + webEvent.wheel_ticks_x += static_cast<float>(ev->angleDelta().x()) / QWheelEvent::DefaultDeltasPerStep; + webEvent.wheel_ticks_y += static_cast<float>(ev->angleDelta().y()) / QWheelEvent::DefaultDeltasPerStep; + setBlinkWheelEventDelta(webEvent); + + return true; +} + content::NativeWebKeyboardEvent WebEventFactory::toWebKeyboardEvent(QKeyEvent *ev) { content::NativeWebKeyboardEvent webKitEvent(reinterpret_cast<gfx::NativeEvent>(ev)); diff --git a/src/core/web_event_factory.h b/src/core/web_event_factory.h index 259795c1f..5758af848 100644 --- a/src/core/web_event_factory.h +++ b/src/core/web_event_factory.h @@ -68,6 +68,7 @@ public: static blink::WebGestureEvent toWebGestureEvent(QNativeGestureEvent *, double dpiScale); #endif static blink::WebMouseWheelEvent toWebWheelEvent(QWheelEvent*, double dpiScale); + static bool coalesceWebWheelEvent(blink::WebMouseWheelEvent &, QWheelEvent*, double dpiScale); static content::NativeWebKeyboardEvent toWebKeyboardEvent(QKeyEvent*); }; -- GitLab