Modified: branches/safari-536-branch/Source/WebKit2/ChangeLog (117118 => 117119)
--- branches/safari-536-branch/Source/WebKit2/ChangeLog 2012-05-15 19:43:24 UTC (rev 117118)
+++ branches/safari-536-branch/Source/WebKit2/ChangeLog 2012-05-15 19:45:07 UTC (rev 117119)
@@ -1,5 +1,50 @@
2012-05-15 Lucas Forschler <[email protected]>
+ Merge 116466
+
+ 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-15 Lucas Forschler <[email protected]>
+
Merge 116449
2012-05-08 Timothy Hatcher <[email protected]>
Modified: branches/safari-536-branch/Source/WebKit2/UIProcess/WebPageProxy.cpp (117118 => 117119)
--- branches/safari-536-branch/Source/WebKit2/UIProcess/WebPageProxy.cpp 2012-05-15 19:43:24 UTC (rev 117118)
+++ branches/safari-536-branch/Source/WebKit2/UIProcess/WebPageProxy.cpp 2012-05-15 19:45:07 UTC (rev 117119)
@@ -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;
}