Changeset 116466 in webkit


Ignore:
Timestamp:
May 8, 2012 4:50:52 PM (12 years ago)
Author:
jonlee@apple.com
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().

Location:
trunk/Source/WebKit2
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebKit2/ChangeLog

    r116449 r116466  
     12012-05-06  Jon Lee  <jonlee@apple.com>
     2
     3        [WK2] Push wheel events if there are too many in queue
     4        https://bugs.webkit.org/show_bug.cgi?id=85747
     5        <rdar://problem/11390790>
     6
     7        Reviewed by Anders Carlsson.
     8
     9        It is possible that a whole bunch of messages added to the message queue, or a series
     10        of long-running messages, cause unresponsiveness. The reason for this is that we have
     11        a scroll event waiting for acknowledgment from the web process before it sends the next
     12        event. And in the time between the user has scrolled, causing a large backlog of scroll
     13        events to be held in the UI process.
     14
     15        We should push new scroll events if the queue accumulates too many of them.
     16
     17        * UIProcess/WebPageProxy.h: The vector m_currentlyProcessedWheelEvents used to hold the
     18        series of wheel events that were coalesced and sent as a single wheel event to the web
     19        process. When the web process acknowledges this with didReceiveEvent, the UI process
     20        cleared that vector, then tried to coalesce the next wheel event to send. Now we might have
     21        multiple sets of coalesced wheel events that we are sending to the web process. To keep
     22        track of these sets, m_currentlyProcessedWheelEvents now is a queue of Vectors.
     23        (WebPageProxy):
     24        * UIProcess/WebPageProxy.cpp: Add new constant wheelEventQueueSizeThreshold representing
     25        the threshold of scroll events to look for before we start pushing events.
     26        (WebKit::canCoalesce): Move static function so that handleWheelEvent() has access. No changes.
     27        (WebKit::coalesce): Move static function so that handleWheelEvent() has access. No changes.
     28        (WebKit::coalescedWheelEvent): Move static function so that handleWheelEvent() has access. No changes.
     29        (WebKit::WebPageProxy::handleWheelEvent): If we are currently waiting for acknowledgment
     30        from the web process that a wheel event has been handled, we add it to the queue. We
     31        check to see that the queue size is within our threshold before we return early. Otherwise
     32        we will start pushing events in the queue. Refactor the rest of the function into
     33        processNextQueuedWheelEvent() and sendWheelEvent(). If we are not currently waiting for
     34        acknowledgment, nor have events in the queue, then we send the current wheel event.
     35        (WebKit::WebPageProxy::processNextQueuedWheelEvent): Try to coalesce events based on the
     36        wheel event at the head of the queue, and send that event to the web process.
     37        (WebKit::WebPageProxy::sendWheelEvent): Refactored from handleWheelEvent().
     38        (WebKit::WebPageProxy::didReceiveEvent): Instead of clearing m_currentlyProcessedWheelEvents,
     39        which contained the set of one coalesced wheel event, we pull the head Vector, which
     40        contains the same set of events. Refactor to use processNextQueuedWheelEvent().
     41
    1422012-05-08  Timothy Hatcher  <timothy@apple.com>
    243
  • trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp

    r116178 r116466  
    110110using namespace WebCore;
    111111
     112// Represents the number of wheel events we can hold in the queue before we start pushing them preemptively.
     113static const unsigned wheelEventQueueSizeThreshold = 10;
     114
    112115namespace WebKit {
    113116
     
    986989}
    987990
     991#if MERGE_WHEEL_EVENTS
     992static bool canCoalesce(const WebWheelEvent& a, const WebWheelEvent& b)
     993{
     994    if (a.position() != b.position())
     995        return false;
     996    if (a.globalPosition() != b.globalPosition())
     997        return false;
     998    if (a.modifiers() != b.modifiers())
     999        return false;
     1000    if (a.granularity() != b.granularity())
     1001        return false;
     1002#if PLATFORM(MAC)
     1003    if (a.phase() != b.phase())
     1004        return false;
     1005    if (a.momentumPhase() != b.momentumPhase())
     1006        return false;
     1007    if (a.hasPreciseScrollingDeltas() != b.hasPreciseScrollingDeltas())
     1008        return false;
     1009#endif
     1010
     1011    return true;
     1012}
     1013
     1014static WebWheelEvent coalesce(const WebWheelEvent& a, const WebWheelEvent& b)
     1015{
     1016    ASSERT(canCoalesce(a, b));
     1017
     1018    FloatSize mergedDelta = a.delta() + b.delta();
     1019    FloatSize mergedWheelTicks = a.wheelTicks() + b.wheelTicks();
     1020
     1021#if PLATFORM(MAC)
     1022    return WebWheelEvent(WebEvent::Wheel, b.position(), b.globalPosition(), mergedDelta, mergedWheelTicks, b.granularity(), b.phase(), b.momentumPhase(), b.hasPreciseScrollingDeltas(), b.modifiers(), b.timestamp(), b.directionInvertedFromDevice());
     1023#else
     1024    return WebWheelEvent(WebEvent::Wheel, b.position(), b.globalPosition(), mergedDelta, mergedWheelTicks, b.granularity(), b.modifiers(), b.timestamp());
     1025#endif
     1026}
     1027#endif // MERGE_WHEEL_EVENTS
     1028
     1029static WebWheelEvent coalescedWheelEvent(Deque<NativeWebWheelEvent>& queue, Vector<NativeWebWheelEvent>& coalescedEvents)
     1030{
     1031    ASSERT(!queue.isEmpty());
     1032    ASSERT(coalescedEvents.isEmpty());
     1033
     1034#if MERGE_WHEEL_EVENTS
     1035    NativeWebWheelEvent firstEvent = queue.takeFirst();
     1036    coalescedEvents.append(firstEvent);
     1037
     1038    WebWheelEvent event = firstEvent;
     1039    while (!queue.isEmpty() && canCoalesce(event, queue.first())) {
     1040        NativeWebWheelEvent firstEvent = queue.takeFirst();
     1041        coalescedEvents.append(firstEvent);
     1042        event = coalesce(event, firstEvent);
     1043    }
     1044
     1045    return event;
     1046#else
     1047    while (!queue.isEmpty())
     1048        coalescedEvents.append(queue.takeFirst());
     1049    return coalescedEvents.last();
     1050#endif
     1051}
     1052
    9881053void WebPageProxy::handleWheelEvent(const NativeWebWheelEvent& event)
    9891054{
     
    9931058    if (!m_currentlyProcessedWheelEvents.isEmpty()) {
    9941059        m_wheelEventQueue.append(event);
    995         return;
    996     }
    997 
    998     m_currentlyProcessedWheelEvents.append(event);
    999 
     1060        if (m_wheelEventQueue.size() < wheelEventQueueSizeThreshold)
     1061            return;
     1062        // The queue has too many wheel events, so push a new event.
     1063    }
     1064
     1065    if (!m_wheelEventQueue.isEmpty()) {
     1066        processNextQueuedWheelEvent();
     1067        return;
     1068    }
     1069
     1070    OwnPtr<Vector<NativeWebWheelEvent> > coalescedWheelEvent = adoptPtr(new Vector<NativeWebWheelEvent>);
     1071    coalescedWheelEvent->append(event);
     1072    m_currentlyProcessedWheelEvents.append(coalescedWheelEvent.release());
     1073    sendWheelEvent(event);
     1074}
     1075
     1076void WebPageProxy::processNextQueuedWheelEvent()
     1077{
     1078    OwnPtr<Vector<NativeWebWheelEvent> > nextCoalescedEvent = adoptPtr(new Vector<NativeWebWheelEvent>);
     1079    WebWheelEvent nextWheelEvent = coalescedWheelEvent(m_wheelEventQueue, *nextCoalescedEvent.get());
     1080    m_currentlyProcessedWheelEvents.append(nextCoalescedEvent.release());
     1081    sendWheelEvent(nextWheelEvent);
     1082}
     1083
     1084void WebPageProxy::sendWheelEvent(const WebWheelEvent& event)
     1085{
    10001086    process()->responsivenessTimer()->start();
    10011087
     
    10041090        process()->sendSync(Messages::WebPage::WheelEventSyncForTesting(event), Messages::WebPage::WheelEventSyncForTesting::Reply(handled), m_pageID);
    10051091        didReceiveEvent(event.type(), handled);
    1006     } else
    1007         process()->send(Messages::EventDispatcher::WheelEvent(m_pageID, event, canGoBack(), canGoForward()), 0);
     1092        return;
     1093    }
     1094
     1095    process()->send(Messages::EventDispatcher::WheelEvent(m_pageID, event, canGoBack(), canGoForward()), 0);
    10081096}
    10091097
     
    29683056}
    29693057
    2970 #if MERGE_WHEEL_EVENTS
    2971 static bool canCoalesce(const WebWheelEvent& a, const WebWheelEvent& b)
    2972 {
    2973     if (a.position() != b.position())
    2974         return false;
    2975     if (a.globalPosition() != b.globalPosition())
    2976         return false;
    2977     if (a.modifiers() != b.modifiers())
    2978         return false;
    2979     if (a.granularity() != b.granularity())
    2980         return false;
    2981 #if PLATFORM(MAC)
    2982     if (a.phase() != b.phase())
    2983         return false;
    2984     if (a.momentumPhase() != b.momentumPhase())
    2985         return false;
    2986     if (a.hasPreciseScrollingDeltas() != b.hasPreciseScrollingDeltas())
    2987         return false;
    2988 #endif
    2989 
    2990     return true;
    2991 }
    2992 
    2993 static WebWheelEvent coalesce(const WebWheelEvent& a, const WebWheelEvent& b)
    2994 {
    2995     ASSERT(canCoalesce(a, b));
    2996 
    2997     FloatSize mergedDelta = a.delta() + b.delta();
    2998     FloatSize mergedWheelTicks = a.wheelTicks() + b.wheelTicks();
    2999 
    3000 #if PLATFORM(MAC)
    3001     return WebWheelEvent(WebEvent::Wheel, b.position(), b.globalPosition(), mergedDelta, mergedWheelTicks, b.granularity(), b.phase(), b.momentumPhase(), b.hasPreciseScrollingDeltas(), b.modifiers(), b.timestamp(), b.directionInvertedFromDevice());
    3002 #else
    3003     return WebWheelEvent(WebEvent::Wheel, b.position(), b.globalPosition(), mergedDelta, mergedWheelTicks, b.granularity(), b.modifiers(), b.timestamp());
    3004 #endif
    3005 }
    3006 #endif
    3007 
    3008 static WebWheelEvent coalescedWheelEvent(Deque<NativeWebWheelEvent>& queue, Vector<NativeWebWheelEvent>& coalescedEvents)
    3009 {
    3010     ASSERT(!queue.isEmpty());
    3011     ASSERT(coalescedEvents.isEmpty());
    3012 
    3013 #if MERGE_WHEEL_EVENTS
    3014     NativeWebWheelEvent firstEvent = queue.takeFirst();
    3015     coalescedEvents.append(firstEvent);
    3016 
    3017     WebWheelEvent event = firstEvent;
    3018     while (!queue.isEmpty() && canCoalesce(event, queue.first())) {
    3019         NativeWebWheelEvent firstEvent = queue.takeFirst();
    3020         coalescedEvents.append(firstEvent);
    3021         event = coalesce(event, firstEvent);
    3022     }
    3023 
    3024     return event;
    3025 #else
    3026     while (!queue.isEmpty())
    3027         coalescedEvents.append(queue.takeFirst());
    3028     return coalescedEvents.last();
    3029 #endif
    3030 }
    3031 
    30323058void WebPageProxy::didReceiveEvent(uint32_t opaqueType, bool handled)
    30333059{
     
    30923118        ASSERT(!m_currentlyProcessedWheelEvents.isEmpty());
    30933119
     3120        OwnPtr<Vector<NativeWebWheelEvent> > oldestCoalescedEvent = m_currentlyProcessedWheelEvents.takeFirst();
     3121
    30943122        // FIXME: Dispatch additional events to the didNotHandleWheelEvent client function.
    30953123        if (!handled && m_uiClient.implementsDidNotHandleWheelEvent())
    3096             m_uiClient.didNotHandleWheelEvent(this, m_currentlyProcessedWheelEvents.last());
    3097 
    3098         m_currentlyProcessedWheelEvents.clear();
    3099 
    3100         if (!m_wheelEventQueue.isEmpty()) {
    3101             WebWheelEvent newWheelEvent = coalescedWheelEvent(m_wheelEventQueue, m_currentlyProcessedWheelEvents);
    3102 
    3103             process()->responsivenessTimer()->start();
    3104             process()->send(Messages::EventDispatcher::WheelEvent(m_pageID, newWheelEvent, canGoBack(), canGoForward()), 0);
    3105         }
    3106 
     3124            m_uiClient.didNotHandleWheelEvent(this, oldestCoalescedEvent->last());
     3125
     3126        if (!m_wheelEventQueue.isEmpty())
     3127            processNextQueuedWheelEvent();
    31073128        break;
    31083129    }
  • trunk/Source/WebKit2/UIProcess/WebPageProxy.h

    r115650 r116466  
    904904#endif
    905905
     906    void processNextQueuedWheelEvent();
     907    void sendWheelEvent(const WebWheelEvent&);
     908
    906909    PageClient* m_pageClient;
    907910    WebLoaderClient m_loaderClient;
     
    10251028    Deque<NativeWebKeyboardEvent> m_keyEventQueue;
    10261029    Deque<NativeWebWheelEvent> m_wheelEventQueue;
    1027     Vector<NativeWebWheelEvent> m_currentlyProcessedWheelEvents;
     1030    Deque<OwnPtr<Vector<NativeWebWheelEvent> > > m_currentlyProcessedWheelEvents;
    10281031
    10291032    bool m_processingMouseMoveEvent;
Note: See TracChangeset for help on using the changeset viewer.