Title: [116466] trunk/Source/WebKit2
Revision
116466
Author
[email protected]
Date
2012-05-08 16:50:52 -0700 (Tue, 08 May 2012)

Log Message

[WK2] Push wheel events if there are too many in queue
https://bugs.webkit.org/show_bug.cgi?id=85747
<rdar://problem/11390790>

Reviewed by Anders Carlsson.

It is possible that a whole bunch of messages added to the message queue, or a series
of long-running messages, cause unresponsiveness. The reason for this is that we have
a scroll event waiting for acknowledgment from the web process before it sends the next
event. And in the time between the user has scrolled, causing a large backlog of scroll
events to be held in the UI process.

We should push new scroll events if the queue accumulates too many of them.

* UIProcess/WebPageProxy.h: The vector m_currentlyProcessedWheelEvents used to hold the
series of wheel events that were coalesced and sent as a single wheel event to the web
process. When the web process acknowledges this with didReceiveEvent, the UI process
cleared that vector, then tried to coalesce the next wheel event to send. Now we might have
multiple sets of coalesced wheel events that we are sending to the web process. To keep
track of these sets, m_currentlyProcessedWheelEvents now is a queue of Vectors.
(WebPageProxy):
* UIProcess/WebPageProxy.cpp: Add new constant wheelEventQueueSizeThreshold representing
the threshold of scroll events to look for before we start pushing events.
(WebKit::canCoalesce): Move static function so that handleWheelEvent() has access. No changes.
(WebKit::coalesce): Move static function so that handleWheelEvent() has access. No changes.
(WebKit::coalescedWheelEvent): Move static function so that handleWheelEvent() has access. No changes.
(WebKit::WebPageProxy::handleWheelEvent): If we are currently waiting for acknowledgment
from the web process that a wheel event has been handled, we add it to the queue. We
check to see that the queue size is within our threshold before we return early. Otherwise
we will start pushing events in the queue. Refactor the rest of the function into
processNextQueuedWheelEvent() and sendWheelEvent(). If we are not currently waiting for
acknowledgment, nor have events in the queue, then we send the current wheel event.
(WebKit::WebPageProxy::processNextQueuedWheelEvent): Try to coalesce events based on the
wheel event at the head of the queue, and send that event to the web process.
(WebKit::WebPageProxy::sendWheelEvent): Refactored from handleWheelEvent().
(WebKit::WebPageProxy::didReceiveEvent): Instead of clearing m_currentlyProcessedWheelEvents,
which contained the set of one coalesced wheel event, we pull the head Vector, which
contains the same set of events. Refactor to use processNextQueuedWheelEvent().

Modified Paths

Diff

Modified: trunk/Source/WebKit2/ChangeLog (116465 => 116466)


--- trunk/Source/WebKit2/ChangeLog	2012-05-08 23:24:04 UTC (rev 116465)
+++ trunk/Source/WebKit2/ChangeLog	2012-05-08 23:50:52 UTC (rev 116466)
@@ -1,3 +1,44 @@
+2012-05-06  Jon Lee  <[email protected]>
+
+        [WK2] Push wheel events if there are too many in queue
+        https://bugs.webkit.org/show_bug.cgi?id=85747
+        <rdar://problem/11390790>
+
+        Reviewed by Anders Carlsson.
+
+        It is possible that a whole bunch of messages added to the message queue, or a series
+        of long-running messages, cause unresponsiveness. The reason for this is that we have
+        a scroll event waiting for acknowledgment from the web process before it sends the next
+        event. And in the time between the user has scrolled, causing a large backlog of scroll
+        events to be held in the UI process.
+
+        We should push new scroll events if the queue accumulates too many of them.
+
+        * UIProcess/WebPageProxy.h: The vector m_currentlyProcessedWheelEvents used to hold the
+        series of wheel events that were coalesced and sent as a single wheel event to the web
+        process. When the web process acknowledges this with didReceiveEvent, the UI process
+        cleared that vector, then tried to coalesce the next wheel event to send. Now we might have
+        multiple sets of coalesced wheel events that we are sending to the web process. To keep
+        track of these sets, m_currentlyProcessedWheelEvents now is a queue of Vectors.
+        (WebPageProxy):
+        * UIProcess/WebPageProxy.cpp: Add new constant wheelEventQueueSizeThreshold representing
+        the threshold of scroll events to look for before we start pushing events.
+        (WebKit::canCoalesce): Move static function so that handleWheelEvent() has access. No changes.
+        (WebKit::coalesce): Move static function so that handleWheelEvent() has access. No changes.
+        (WebKit::coalescedWheelEvent): Move static function so that handleWheelEvent() has access. No changes.
+        (WebKit::WebPageProxy::handleWheelEvent): If we are currently waiting for acknowledgment
+        from the web process that a wheel event has been handled, we add it to the queue. We
+        check to see that the queue size is within our threshold before we return early. Otherwise
+        we will start pushing events in the queue. Refactor the rest of the function into
+        processNextQueuedWheelEvent() and sendWheelEvent(). If we are not currently waiting for
+        acknowledgment, nor have events in the queue, then we send the current wheel event.
+        (WebKit::WebPageProxy::processNextQueuedWheelEvent): Try to coalesce events based on the
+        wheel event at the head of the queue, and send that event to the web process.
+        (WebKit::WebPageProxy::sendWheelEvent): Refactored from handleWheelEvent().
+        (WebKit::WebPageProxy::didReceiveEvent): Instead of clearing m_currentlyProcessedWheelEvents,
+        which contained the set of one coalesced wheel event, we pull the head Vector, which
+        contains the same set of events. Refactor to use processNextQueuedWheelEvent().
+
 2012-05-08  Timothy Hatcher  <[email protected]>
 
         Fix the SOFT_LINK_STAGED_FRAMEWORK_OPTIONAL macro so it passes the full path to dlopen.

Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp (116465 => 116466)


--- trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp	2012-05-08 23:24:04 UTC (rev 116465)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp	2012-05-08 23:50:52 UTC (rev 116466)
@@ -109,6 +109,9 @@
 
 using namespace WebCore;
 
+// Represents the number of wheel events we can hold in the queue before we start pushing them preemptively.
+static const unsigned wheelEventQueueSizeThreshold = 10;
+
 namespace WebKit {
 
 WKPageDebugPaintFlags WebPageProxy::s_debugPaintFlags = 0;
@@ -985,6 +988,68 @@
         process()->send(Messages::WebPage::MouseEvent(event), m_pageID);
 }
 
+#if MERGE_WHEEL_EVENTS
+static bool canCoalesce(const WebWheelEvent& a, const WebWheelEvent& b)
+{
+    if (a.position() != b.position())
+        return false;
+    if (a.globalPosition() != b.globalPosition())
+        return false;
+    if (a.modifiers() != b.modifiers())
+        return false;
+    if (a.granularity() != b.granularity())
+        return false;
+#if PLATFORM(MAC)
+    if (a.phase() != b.phase())
+        return false;
+    if (a.momentumPhase() != b.momentumPhase())
+        return false;
+    if (a.hasPreciseScrollingDeltas() != b.hasPreciseScrollingDeltas())
+        return false;
+#endif
+
+    return true;
+}
+
+static WebWheelEvent coalesce(const WebWheelEvent& a, const WebWheelEvent& b)
+{
+    ASSERT(canCoalesce(a, b));
+
+    FloatSize mergedDelta = a.delta() + b.delta();
+    FloatSize mergedWheelTicks = a.wheelTicks() + b.wheelTicks();
+
+#if PLATFORM(MAC)
+    return WebWheelEvent(WebEvent::Wheel, b.position(), b.globalPosition(), mergedDelta, mergedWheelTicks, b.granularity(), b.phase(), b.momentumPhase(), b.hasPreciseScrollingDeltas(), b.modifiers(), b.timestamp(), b.directionInvertedFromDevice());
+#else
+    return WebWheelEvent(WebEvent::Wheel, b.position(), b.globalPosition(), mergedDelta, mergedWheelTicks, b.granularity(), b.modifiers(), b.timestamp());
+#endif
+}
+#endif // MERGE_WHEEL_EVENTS
+
+static WebWheelEvent coalescedWheelEvent(Deque<NativeWebWheelEvent>& queue, Vector<NativeWebWheelEvent>& coalescedEvents)
+{
+    ASSERT(!queue.isEmpty());
+    ASSERT(coalescedEvents.isEmpty());
+
+#if MERGE_WHEEL_EVENTS
+    NativeWebWheelEvent firstEvent = queue.takeFirst();
+    coalescedEvents.append(firstEvent);
+
+    WebWheelEvent event = firstEvent;
+    while (!queue.isEmpty() && canCoalesce(event, queue.first())) {
+        NativeWebWheelEvent firstEvent = queue.takeFirst();
+        coalescedEvents.append(firstEvent);
+        event = coalesce(event, firstEvent);
+    }
+
+    return event;
+#else
+    while (!queue.isEmpty())
+        coalescedEvents.append(queue.takeFirst());
+    return coalescedEvents.last();
+#endif
+}
+
 void WebPageProxy::handleWheelEvent(const NativeWebWheelEvent& event)
 {
     if (!isValid())
@@ -992,19 +1057,42 @@
 
     if (!m_currentlyProcessedWheelEvents.isEmpty()) {
         m_wheelEventQueue.append(event);
+        if (m_wheelEventQueue.size() < wheelEventQueueSizeThreshold)
+            return;
+        // The queue has too many wheel events, so push a new event.
+    }
+
+    if (!m_wheelEventQueue.isEmpty()) {
+        processNextQueuedWheelEvent();
         return;
     }
 
-    m_currentlyProcessedWheelEvents.append(event);
+    OwnPtr<Vector<NativeWebWheelEvent> > coalescedWheelEvent = adoptPtr(new Vector<NativeWebWheelEvent>);
+    coalescedWheelEvent->append(event);
+    m_currentlyProcessedWheelEvents.append(coalescedWheelEvent.release());
+    sendWheelEvent(event);
+}
 
+void WebPageProxy::processNextQueuedWheelEvent()
+{
+    OwnPtr<Vector<NativeWebWheelEvent> > nextCoalescedEvent = adoptPtr(new Vector<NativeWebWheelEvent>);
+    WebWheelEvent nextWheelEvent = coalescedWheelEvent(m_wheelEventQueue, *nextCoalescedEvent.get());
+    m_currentlyProcessedWheelEvents.append(nextCoalescedEvent.release());
+    sendWheelEvent(nextWheelEvent);
+}
+
+void WebPageProxy::sendWheelEvent(const WebWheelEvent& event)
+{
     process()->responsivenessTimer()->start();
 
     if (m_shouldSendEventsSynchronously) {
         bool handled = false;
         process()->sendSync(Messages::WebPage::WheelEventSyncForTesting(event), Messages::WebPage::WheelEventSyncForTesting::Reply(handled), m_pageID);
         didReceiveEvent(event.type(), handled);
-    } else
-        process()->send(Messages::EventDispatcher::WheelEvent(m_pageID, event, canGoBack(), canGoForward()), 0);
+        return;
+    }
+
+    process()->send(Messages::EventDispatcher::WheelEvent(m_pageID, event, canGoBack(), canGoForward()), 0);
 }
 
 void WebPageProxy::handleKeyboardEvent(const NativeWebKeyboardEvent& event)
@@ -2967,68 +3055,6 @@
     m_pageClient->setCursorHiddenUntilMouseMoves(hiddenUntilMouseMoves);
 }
 
-#if MERGE_WHEEL_EVENTS
-static bool canCoalesce(const WebWheelEvent& a, const WebWheelEvent& b)
-{
-    if (a.position() != b.position())
-        return false;
-    if (a.globalPosition() != b.globalPosition())
-        return false;
-    if (a.modifiers() != b.modifiers())
-        return false;
-    if (a.granularity() != b.granularity())
-        return false;
-#if PLATFORM(MAC)
-    if (a.phase() != b.phase())
-        return false;
-    if (a.momentumPhase() != b.momentumPhase())
-        return false;
-    if (a.hasPreciseScrollingDeltas() != b.hasPreciseScrollingDeltas())
-        return false;
-#endif
-
-    return true;
-}
-
-static WebWheelEvent coalesce(const WebWheelEvent& a, const WebWheelEvent& b)
-{
-    ASSERT(canCoalesce(a, b));
-
-    FloatSize mergedDelta = a.delta() + b.delta();
-    FloatSize mergedWheelTicks = a.wheelTicks() + b.wheelTicks();
-
-#if PLATFORM(MAC)
-    return WebWheelEvent(WebEvent::Wheel, b.position(), b.globalPosition(), mergedDelta, mergedWheelTicks, b.granularity(), b.phase(), b.momentumPhase(), b.hasPreciseScrollingDeltas(), b.modifiers(), b.timestamp(), b.directionInvertedFromDevice());
-#else
-    return WebWheelEvent(WebEvent::Wheel, b.position(), b.globalPosition(), mergedDelta, mergedWheelTicks, b.granularity(), b.modifiers(), b.timestamp());
-#endif
-}
-#endif
-
-static WebWheelEvent coalescedWheelEvent(Deque<NativeWebWheelEvent>& queue, Vector<NativeWebWheelEvent>& coalescedEvents)
-{
-    ASSERT(!queue.isEmpty());
-    ASSERT(coalescedEvents.isEmpty());
-
-#if MERGE_WHEEL_EVENTS
-    NativeWebWheelEvent firstEvent = queue.takeFirst();
-    coalescedEvents.append(firstEvent);
-
-    WebWheelEvent event = firstEvent;
-    while (!queue.isEmpty() && canCoalesce(event, queue.first())) {
-        NativeWebWheelEvent firstEvent = queue.takeFirst();
-        coalescedEvents.append(firstEvent);
-        event = coalesce(event, firstEvent);
-    }
-
-    return event;
-#else
-    while (!queue.isEmpty())
-        coalescedEvents.append(queue.takeFirst());
-    return coalescedEvents.last();
-#endif
-}
-
 void WebPageProxy::didReceiveEvent(uint32_t opaqueType, bool handled)
 {
     WebEvent::Type type = static_cast<WebEvent::Type>(opaqueType);
@@ -3091,19 +3117,14 @@
     case WebEvent::Wheel: {
         ASSERT(!m_currentlyProcessedWheelEvents.isEmpty());
 
+        OwnPtr<Vector<NativeWebWheelEvent> > oldestCoalescedEvent = m_currentlyProcessedWheelEvents.takeFirst();
+
         // FIXME: Dispatch additional events to the didNotHandleWheelEvent client function.
         if (!handled && m_uiClient.implementsDidNotHandleWheelEvent())
-            m_uiClient.didNotHandleWheelEvent(this, m_currentlyProcessedWheelEvents.last());
+            m_uiClient.didNotHandleWheelEvent(this, oldestCoalescedEvent->last());
 
-        m_currentlyProcessedWheelEvents.clear();
-
-        if (!m_wheelEventQueue.isEmpty()) {
-            WebWheelEvent newWheelEvent = coalescedWheelEvent(m_wheelEventQueue, m_currentlyProcessedWheelEvents);
-
-            process()->responsivenessTimer()->start();
-            process()->send(Messages::EventDispatcher::WheelEvent(m_pageID, newWheelEvent, canGoBack(), canGoForward()), 0);
-        }
-
+        if (!m_wheelEventQueue.isEmpty())
+            processNextQueuedWheelEvent();
         break;
     }
 

Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.h (116465 => 116466)


--- trunk/Source/WebKit2/UIProcess/WebPageProxy.h	2012-05-08 23:24:04 UTC (rev 116465)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.h	2012-05-08 23:50:52 UTC (rev 116466)
@@ -903,6 +903,9 @@
     void windowedPluginGeometryDidChange(const WebCore::IntRect& frameRect, const WebCore::IntRect& clipRect, uint64_t windowID);
 #endif
 
+    void processNextQueuedWheelEvent();
+    void sendWheelEvent(const WebWheelEvent&);
+
     PageClient* m_pageClient;
     WebLoaderClient m_loaderClient;
     WebPolicyClient m_policyClient;
@@ -1024,7 +1027,7 @@
 #endif
     Deque<NativeWebKeyboardEvent> m_keyEventQueue;
     Deque<NativeWebWheelEvent> m_wheelEventQueue;
-    Vector<NativeWebWheelEvent> m_currentlyProcessedWheelEvents;
+    Deque<OwnPtr<Vector<NativeWebWheelEvent> > > m_currentlyProcessedWheelEvents;
 
     bool m_processingMouseMoveEvent;
     OwnPtr<NativeWebMouseEvent> m_nextMouseMoveEvent;
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to