Changeset 134150 in webkit


Ignore:
Timestamp:
Nov 9, 2012 9:16:00 PM (11 years ago)
Author:
ojan@chromium.org
Message:

Should only fire a single set of mouse events and update hover state once when scrolling is done
https://bugs.webkit.org/show_bug.cgi?id=99940

Reviewed by Levi Weintraub.

Source/WebCore:

-Use a DeferrableOneShotTimer instead of a Timer. By resetting when the
timer is fired, we ensure the actual goal of not firing fake mouse events
until the scroll is completed. This is the core part of this change.
-Change our mouse event throttling to keep a running average of how long
mouse events take and adjust throttling appropriately.
Test: fast/scrolling/fake-mouse-event-throttling.html
-Maintain a minimum throttle of 100ms.

  • page/EventHandler.cpp:

(WebCore):
(WebCore::RunningAverageDurationTracker::RunningAverageDurationTracker):
(WebCore::RunningAverageDurationTracker::~RunningAverageDurationTracker):
Keep track of a running average instead of max. This lets us adjust throttling
dynamically without punishing a page for having a single mouse event handler
that takes disproportionately long.
(RunningAverageDurationTracker):
(WebCore::EventHandler::EventHandler):
(WebCore::EventHandler::clear):
(WebCore::EventHandler::mouseMoved):
(WebCore::EventHandler::handleMouseMoveEvent):
(WebCore::EventHandler::dispatchFakeMouseMoveEventSoon):
(WebCore::EventHandler::fakeMouseMoveEventTimerFired):

  • page/EventHandler.h:

(EventHandler):

  • platform/Timer.h:

(WebCore::DeferrableOneShotTimer::setDelay):
(WebCore::DeferrableOneShotTimer::delay):
Add a way of adjusting the timer delay.

LayoutTests:

Tests basic throttling. I couldn't think of a good way to test changing
the delay that wouldn't make for a test that takes minutes to run.

  • fast/scrolling/fake-mouse-event-throttling-expected.txt: Added.
  • fast/scrolling/fake-mouse-event-throttling.html: Added.
Location:
trunk
Files:
2 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r134149 r134150  
     12012-11-09  Ojan Vafai  <ojan@chromium.org>
     2
     3        Should only fire a single set of mouse events and update hover state once when scrolling is done
     4        https://bugs.webkit.org/show_bug.cgi?id=99940
     5
     6        Reviewed by Levi Weintraub.
     7
     8        Tests basic throttling. I couldn't think of a good way to test changing
     9        the delay that wouldn't make for a test that takes minutes to run.
     10
     11        * fast/scrolling/fake-mouse-event-throttling-expected.txt: Added.
     12        * fast/scrolling/fake-mouse-event-throttling.html: Added.
     13
    1142012-11-09  Rick Byers  <rbyers@chromium.org>
    215
  • trunk/LayoutTests/platform/mac/TestExpectations

    r133884 r134150  
    11661166platform/mac/tiled-drawing/ [ Skip ]
    11671167
     1168# DRT is not firing fake mouse events. Safari fires them fine. Looks like a bug with Apple's Mac DRT.
     1169webkit.org/b/101808 fast/scrolling/fake-mouse-event-throttling.html [ Skip ]
     1170
    11681171webkit.org/b/100846 inspector-protocol/debugger-pause-dedicated-worker.html [ Skip ]
    11691172webkit.org/b/100846 inspector-protocol/debugger-terminate-dedicated-worker-while-paused.html [ Skip ]
  • trunk/Source/WebCore/ChangeLog

    r134149 r134150  
     12012-11-09  Ojan Vafai  <ojan@chromium.org>
     2
     3        Should only fire a single set of mouse events and update hover state once when scrolling is done
     4        https://bugs.webkit.org/show_bug.cgi?id=99940
     5
     6        Reviewed by Levi Weintraub.
     7
     8        -Use a DeferrableOneShotTimer instead of a Timer. By resetting when the
     9        timer is fired, we ensure the actual goal of not firing fake mouse events
     10        until the scroll is completed. This is the core part of this change.
     11        -Change our mouse event throttling to keep a running average of how long
     12        mouse events take and adjust throttling appropriately.
     13        Test: fast/scrolling/fake-mouse-event-throttling.html
     14        -Maintain a minimum throttle of 100ms.
     15
     16        * page/EventHandler.cpp:
     17        (WebCore):
     18        (WebCore::RunningAverageDurationTracker::RunningAverageDurationTracker):
     19        (WebCore::RunningAverageDurationTracker::~RunningAverageDurationTracker):
     20        Keep track of a running average instead of max. This lets us adjust throttling
     21        dynamically without punishing a page for having a single mouse event handler
     22        that takes disproportionately long.
     23        (RunningAverageDurationTracker):
     24        (WebCore::EventHandler::EventHandler):
     25        (WebCore::EventHandler::clear):
     26        (WebCore::EventHandler::mouseMoved):
     27        (WebCore::EventHandler::handleMouseMoveEvent):
     28        (WebCore::EventHandler::dispatchFakeMouseMoveEventSoon):
     29        (WebCore::EventHandler::fakeMouseMoveEventTimerFired):
     30        * page/EventHandler.h:
     31        (EventHandler):
     32        * platform/Timer.h:
     33        (WebCore::DeferrableOneShotTimer::setDelay):
     34        (WebCore::DeferrableOneShotTimer::delay):
     35        Add a way of adjusting the timer delay.
     36
    1372012-11-09  Rick Byers  <rbyers@chromium.org>
    238
  • trunk/Source/WebCore/page/EventHandler.cpp

    r134144 r134150  
    137137const double autoscrollInterval = 0.05;
    138138
    139 // The amount of time to wait before sending a fake mouse event, triggered
    140 // during a scroll. The short interval is used if the content responds to the mouse events quickly enough,
    141 // otherwise the long interval is used.
    142 const double fakeMouseMoveShortInterval = 0.1;
    143 const double fakeMouseMoveLongInterval = 0.250;
     139// The amount of time to wait before sending a fake mouse event, triggered during a scroll.
     140const double fakeMouseMoveMinimumInterval = 0.1;
     141// Amount to increase the fake mouse event throttling when the running average exceeds the delay.
     142// Picked fairly arbitrarily.
     143const double fakeMouseMoveIntervalIncrease = 0.05;
     144const double fakeMouseMoveRunningAverageCount = 10;
     145// Decrease the fakeMouseMoveInterval when the current delay is >2x the running average,
     146// but only decrease to 3/4 the current delay to avoid too much thrashing.
     147// Not sure this distinction really matters in practice.
     148const double fakeMouseMoveIntervalReductionLimit = 0.5;
     149const double fakeMouseMoveIntervalReductionFraction = 0.75;
    144150
    145151enum NoCursorChangeType { NoCursorChange };
     
    158164};
    159165
    160 class MaximumDurationTracker {
     166class RunningAverageDurationTracker {
    161167public:
    162     explicit MaximumDurationTracker(double *maxDuration)
    163         : m_maxDuration(maxDuration)
     168    RunningAverageDurationTracker(double* average, unsigned numberOfRunsToTrack)
     169        : m_average(average)
     170        , m_numberOfRunsToTrack(numberOfRunsToTrack)
    164171        , m_start(monotonicallyIncreasingTime())
    165172    {
    166173    }
    167174
    168     ~MaximumDurationTracker()
     175    ~RunningAverageDurationTracker()
    169176    {
    170         *m_maxDuration = max(*m_maxDuration, monotonicallyIncreasingTime() - m_start);
     177        double duration = monotonicallyIncreasingTime() - m_start;
     178        if (!*m_average) {
     179            *m_average = duration;
     180            return;
     181        }
     182        *m_average = (*m_average * (m_numberOfRunsToTrack - 1) + (duration)) / m_numberOfRunsToTrack;
    171183    }
    172184
    173185private:
    174     double* m_maxDuration;
     186    double* m_average;
     187    unsigned m_numberOfRunsToTrack;
    175188    double m_start;
    176189};
     
    317330    , m_mouseDownMayStartAutoscroll(false)
    318331    , m_mouseDownWasInSubframe(false)
    319     , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFired)
     332    , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFired, fakeMouseMoveMinimumInterval)
    320333#if ENABLE(SVG)
    321334    , m_svgPan(false)
     
    334347    , m_touchPressed(false)
    335348#endif
    336     , m_maxMouseMovedDuration(0)
     349    , m_mouseMovedDurationRunningAverage(0)
    337350    , m_baseEventType(PlatformEvent::NoType)
    338351{
     
    386399    m_scrollGestureHandlingNode = 0;
    387400#endif
    388     m_maxMouseMovedDuration = 0;
     401    m_mouseMovedDurationRunningAverage = 0;
    389402    m_baseEventType = PlatformEvent::NoType;
    390403}
     
    17331746{
    17341747    RefPtr<FrameView> protector(m_frame->view());
    1735     MaximumDurationTracker maxDurationTracker(&m_maxMouseMovedDuration);
     1748    RunningAverageDurationTracker durationTracker(&m_mouseMovedDurationRunningAverage, fakeMouseMoveRunningAverageCount);
    17361749
    17371750
     
    28642877        return;
    28652878
    2866     // If the content has ever taken longer than fakeMouseMoveShortInterval we
    2867     // reschedule the timer and use a longer time. This will cause the content
    2868     // to receive these moves only after the user is done scrolling, reducing
    2869     // pauses during the scroll.
    2870     if (m_maxMouseMovedDuration > fakeMouseMoveShortInterval) {
    2871         if (m_fakeMouseMoveEventTimer.isActive())
    2872             m_fakeMouseMoveEventTimer.stop();
    2873         m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveLongInterval);
    2874     } else {
    2875         if (!m_fakeMouseMoveEventTimer.isActive())
    2876             m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveShortInterval);
    2877     }
     2879    // Adjust the mouse move throttling so that it's roughly around our running average of the duration of mousemove events.
     2880    // This will cause the content to receive these moves only after the user is done scrolling, reducing pauses during the scroll.
     2881    // This will only measure the duration of the mousemove event though (not for example layouts),
     2882    // so maintain at least a minimum interval.
     2883    if (m_mouseMovedDurationRunningAverage > m_fakeMouseMoveEventTimer.delay())
     2884        m_fakeMouseMoveEventTimer.setDelay(m_mouseMovedDurationRunningAverage + fakeMouseMoveIntervalIncrease);
     2885    else if (m_mouseMovedDurationRunningAverage < fakeMouseMoveIntervalReductionLimit * m_fakeMouseMoveEventTimer.delay())
     2886        m_fakeMouseMoveEventTimer.setDelay(max(fakeMouseMoveMinimumInterval, fakeMouseMoveIntervalReductionFraction * m_fakeMouseMoveEventTimer.delay()));
     2887    m_fakeMouseMoveEventTimer.restart();
    28782888}
    28792889
     
    28952905}
    28962906
    2897 void EventHandler::fakeMouseMoveEventTimerFired(Timer<EventHandler>* timer)
     2907void EventHandler::fakeMouseMoveEventTimerFired(DeferrableOneShotTimer<EventHandler>* timer)
    28982908{
    28992909    ASSERT_UNUSED(timer, timer == &m_fakeMouseMoveEventTimer);
  • trunk/Source/WebCore/page/EventHandler.h

    r134144 r134150  
    283283    static bool eventInvertsTabsToLinksClientCallResult(KeyboardEvent*);
    284284
    285     void fakeMouseMoveEventTimerFired(Timer<EventHandler>*);
     285    void fakeMouseMoveEventTimerFired(DeferrableOneShotTimer<EventHandler>*);
    286286    void cancelFakeMouseMoveEvent();
    287287
     
    406406    bool m_mouseDownWasInSubframe;
    407407
    408     Timer<EventHandler> m_fakeMouseMoveEventTimer;
     408    DeferrableOneShotTimer<EventHandler> m_fakeMouseMoveEventTimer;
    409409
    410410#if ENABLE(SVG)
     
    463463#endif
    464464
    465     double m_maxMouseMovedDuration;
     465    double m_mouseMovedDurationRunningAverage;
    466466    PlatformEvent::Type m_baseEventType;
    467467};
  • trunk/Source/WebCore/platform/Timer.h

    r130720 r134150  
    141141    }
    142142
     143    void setDelay(double delay)
     144    {
     145        m_delay = delay;
     146        if (isActive()) {
     147            stop();
     148            restart();
     149        }
     150    }
     151
     152    double delay() const { return m_delay; }
     153
    143154    using TimerBase::stop;
    144155    using TimerBase::isActive;
Note: See TracChangeset for help on using the changeset viewer.