Changeset 75555 in webkit


Ignore:
Timestamp:
Jan 11, 2011 2:47:10 PM (13 years ago)
Author:
mihaip@chromium.org
Message:

2011-01-11 Mihai Parparita <mihaip@chromium.org>

Reviewed by Darin Fisher.

Scroll event should be fired asynchronously
https://bugs.webkit.org/show_bug.cgi?id=45631

Update existing tests that assumed that scroll events fired
synchronously.

  • editing/input/page-up-down-scrolls-expected.txt:
  • editing/input/page-up-down-scrolls.html:
  • fast/events/fire-scroll-event-element-expected.txt: Copied from LayoutTests/fast/events/fire-scroll-event-expected.txt.
  • fast/events/fire-scroll-event-element.html: Added. Does the same

tests as fire-scroll-event.html, but on an individual element instead
of the whole document.

  • fast/events/fire-scroll-event-expected.txt:
  • fast/events/fire-scroll-event.html: Now explicitly tests for

synchronous behavior when scrolling the document, and that we don't
fire the event more than once.

  • fast/events/remove-child-onscroll.html:
  • fast/events/scroll-during-zoom-change.html:
  • fast/events/scroll-event-does-not-bubble.html:
  • fast/events/scroll-event-phase-expected.txt: Added.
  • fast/events/scroll-event-phase.html: Added. Checks that we can listen

for scroll events in both the capture and bubble phase.

  • fast/layers/removed-by-scroll-handler.html:
  • fast/overflow/onscroll-layer-self-destruct.html:
  • fast/repaint/repaint-during-scroll.html:

2011-01-11 Mihai Parparita <mihaip@chromium.org>

Reviewed by Darin Fisher.

Scroll event should be fired asynchronously
https://bugs.webkit.org/show_bug.cgi?id=45631

Tests: fast/events/fire-scroll-event.html

fast/events/fire-scroll-event-element.html
fast/events/scroll-event-phase.html

Makes scroll events fire asynchronously to be in compliance with the
CSSOM View Module and consistent with Gecko, Opera and (to some degree)
IE.

Implemented via the EventQueue class added by r74062 (EventQueue now
has a convenience enqueueScrollEvent method).

  • dom/EventQueue.cpp: (WebCore::EventQueue::enqueueScrollEvent): (WebCore::EventQueue::pendingEventTimerFired):
  • dom/EventQueue.h:
  • page/EventHandler.cpp: (WebCore::EventHandler::sendScrollEvent):
  • rendering/RenderLayer.cpp: (WebCore::RenderLayer::scrollToOffset):
  • rendering/RenderListBox.cpp: (WebCore::RenderListBox::valueChanged):
Location:
trunk
Files:
4 added
17 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r75552 r75555  
     12011-01-11  Mihai Parparita  <mihaip@chromium.org>
     2
     3        Reviewed by Darin Fisher.
     4
     5        Scroll event should be fired asynchronously
     6        https://bugs.webkit.org/show_bug.cgi?id=45631
     7       
     8        Update existing tests that assumed that scroll events fired
     9        synchronously.
     10
     11        * editing/input/page-up-down-scrolls-expected.txt:
     12        * editing/input/page-up-down-scrolls.html:
     13        * fast/events/fire-scroll-event-element-expected.txt: Copied from LayoutTests/fast/events/fire-scroll-event-expected.txt.
     14        * fast/events/fire-scroll-event-element.html: Added. Does the same
     15            tests as fire-scroll-event.html, but on an individual element instead
     16            of the whole document.
     17        * fast/events/fire-scroll-event-expected.txt:
     18        * fast/events/fire-scroll-event.html: Now explicitly tests for
     19            synchronous behavior when scrolling the document, and that we don't
     20            fire the event more than once.
     21        * fast/events/remove-child-onscroll.html:
     22        * fast/events/scroll-during-zoom-change.html:
     23        * fast/events/scroll-event-does-not-bubble.html:
     24        * fast/events/scroll-event-phase-expected.txt: Added.
     25        * fast/events/scroll-event-phase.html: Added. Checks that we can listen
     26            for scroll events in both the capture and bubble phase.
     27        * fast/layers/removed-by-scroll-handler.html:
     28        * fast/overflow/onscroll-layer-self-destruct.html:
     29        * fast/repaint/repaint-during-scroll.html:
     30
    1312011-01-11  Mihai Parparita  <mihaip@chromium.org>
    232
  • trunk/LayoutTests/editing/input/page-up-down-scrolls-expected.txt

    r60591 r75555  
    11xx
    2 This test simulates hitting page up and page down once each. Both keypresses should generate exactly one scroll event. This test requires DRT to pass.
     2This test simulates hitting page up and page down once each. Both keypresses should generate exactly one scroll event. If running manually, press the keys now.
    33PASS
    44(just here to force scrollbars)
  • trunk/LayoutTests/editing/input/page-up-down-scrolls.html

    r60591 r75555  
    33<head>
    44<script>
    5 if (window.layoutTestController)
     5if (window.layoutTestController) {
    66    layoutTestController.dumpAsText();
     7    layoutTestController.waitUntilDone();
     8}
    79
    8 function scr()
    9 {
     10var step = 0;
     11
     12onscroll = function() {
    1013    document.getElementById('log').innerText += 'x';
     14
     15    switch (step) {
     16    case 0:
     17        if (window.eventSender)
     18            eventSender.keyDown('pageUp');
     19            break;
     20    case 1:
     21        document.getElementById('results').innerText = 'PASS';
     22        if (window.layoutTestController)
     23            layoutTestController.notifyDone();
     24        break;
     25    }
     26   
     27    step++;
    1128}
    1229
    1330function runTest()
    1431{
    15     if (!window.eventSender)
    16         return;
    17 
    18     window.addEventListener('scroll', scr, false);
    19 
    20     eventSender.keyDown("pageDown");
    21     var text = document.getElementById('log').innerText;
    22     if (text != "x")
    23         throw "log should contain x, not " + text;
    24 
    25     eventSender.keyDown("pageUp");
    26     var text = document.getElementById('log').innerText;
    27     if (text != "xx")
    28         throw "log should contain xx, not " + text;
    29 
    30     document.getElementById("results").innerText = "PASS";
     32    if (window.eventSender)
     33        eventSender.keyDown('pageDown');
    3134}
    3235</script>
     
    3437<body onload="runTest()">
    3538<span id="log" style="position:fixed"></span>
    36 <div>This test simulates hitting page up and page down once each. Both keypresses should generate exactly one scroll event. This test requires DRT to pass.</div>
     39<div>This test simulates hitting page up and page down once each. Both keypresses should generate exactly one scroll event. If running manually, press the keys now.</div>
    3740<div id="results">FAIL</div>
    3841<div style="height:50000px">(just here to force scrollbars)</div>
  • trunk/LayoutTests/fast/events/fire-scroll-event-expected.txt

    r20982 r75555  
    1 PASSED
     1Checks that the scroll event fires on the document asychronously and only once.
    22
    3 If the word 'PASSED' does not appear above, then the test has failed. If the test fails, it means that a scroll event did not fire.
     3On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
    44
    5 a
    6 a
    7 a
    8 a
    9 a
    10 a
    11 a
    12 a
    13 a
    14 a
    15 a
    16 a
    17 a
    18 a
    19 a
    20 a
    21 a
    22 a
    23 a
    24 a
    25 a
    26 a
    27 a
    28 a
    29 a
    30 a
    31 a
    32 a
    33 a
    34 a
    35 a
    36 a
    37 a
    38 a
    39 a
    40 a
    41 a
    42 a
    43 a
    44 a
    45 a
    46 a
    47 a
    48 a
    49 a
    50 a
    51 a
    52 a
    53 a
    54 a
    55 a
    56 a
    57 a
    58 a
    595
     6Scroll event bubbles: true
     7PASS Scroll position: (200, 200)
     8PASS successfullyParsed is true
     9
     10TEST COMPLETE
     11
  • trunk/LayoutTests/fast/events/fire-scroll-event.html

    r20982 r75555  
    11<html>
     2<link rel="stylesheet" href="../js/resources/js-test-style.css">
     3<script src="../js/resources/js-test-pre.js"></script>
     4<body style="min-width: 5000px; min-height: 5000px">
     5<p id="description"></p>
     6<div id="console"></div>
    27<script>
    3 var eventFired = false;
     8description('Checks that the scroll event fires on the document asychronously and only once.');
    49
    5 function scroller() {
    6     if (!eventFired) {
    7         eventFired = true;
    8         document.getElementById("passed").innerHTML = "<p style='color:red'>PASSED</p>";
     10var eventCount = 0;
     11var doneTimeout;
     12
     13onscroll = function(event)
     14{
     15    eventCount++;
     16    if (eventCount == 1) {
     17        debug('Scroll event bubbles: ' + event.bubbles);
     18        var scrollX = document.body.scrollLeft;
     19        var scrollY = document.body.scrollTop;
     20        testPassed('Scroll position: (' + scrollX + ', ' + scrollY + ')');
     21        // Don't call notifyDone straight away, in case there's another scroll event coming.
     22        doneTimeout = setTimeout(finishJSTest, 100);
     23    } else {
     24        clearTimeout(doneTimeout);
     25        testFailed('Scroll handler was invoked ' + eventCount + ' times');
     26        finishJSTest();
    927    }
    1028}
    1129
    12 window.onload = function() {
    13     window.addEventListener('scroll', scroller, false);
    14     window.scrollTo(500, 500);
    15     if (window.layoutTestController) {
    16         layoutTestController.dumpAsText();
     30onload = function()
     31{
     32    window.scrollTo(100, 100);
     33    if (eventCount > 0) {
     34        testFailed('Scroll event fired synchronously');
     35        finishJSTest();
    1736    }
     37    window.scrollTo(200, 200);
    1838}
    1939
     40var successfullyParsed = true;
     41var jsTestIsAsync = true;
    2042</script>
    21 <body>
    22 <div id="passed"></div>
    23 
    24 <p>If the word 'PASSED' does not appear above, then the test has failed. If the test fails, it means that a scroll event did not fire.</p>
    25 
    26 a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>
    27 a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>
    28 a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>
     43<script src="../js/resources/js-test-post.js"></script>
    2944</body>
    3045</html>
  • trunk/LayoutTests/fast/events/remove-child-onscroll.html

    r55737 r75555  
    1010            {
    1111                if (window.eventSender && window.layoutTestController) {
     12                    layoutTestController.waitUntilDone();
    1213                    eventSender.mouseMoveTo(100, 100);
    1314                    eventSender.mouseScrollBy(0, -1);
    14                     eventSender.mouseScrollBy(-1, -1);
    15                     layoutTestController.notifyDone();
     15                    var scrollCount = 0;
     16                    document.getElementById('dv').addEventListener(
     17                        'scroll',
     18                        function(event) {
     19                            this.removeChild(this.firstChild);
     20                            scrollCount++;
     21                            if (scrollCount == 1)
     22                                eventSender.mouseScrollBy(-1, -1);
     23                            else
     24                                layoutTestController.notifyDone();
     25                        },
     26                        false);
    1627                }
    1728            }
     
    2031    <body onload="setTimeout('dispatchScrollEvents();', 1);">
    2132        This test verifies that children can be removed by their parent element's onscroll event handler.  The test succeeds if this is the only text remaining after the two scroll events are dispatched.  The test fails if the inner div remains in the output or if WebKit crashes.<br><br>
    22         <div id="dv" style="overflow: auto; width: 200px; height: 200px; whitespace: nowrap;" onscroll="this.removeChild(this.firstChild)">
     33        <div id="dv" style="overflow: auto; width: 200px; height: 200px; whitespace: nowrap;">
    2334        <div style="width:300px; height:300px">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum
    2435        </div>
  • trunk/LayoutTests/fast/events/scroll-during-zoom-change.html

    r41338 r75555  
    1717    {
    1818        event.target.parentNode.removeChild(event.target);
     19        if (window.layoutTestController) {
     20            layoutTestController.notifyDone();
     21        }
    1922    }
    2023
     
    2831    }
    2932
    30     if (window.layoutTestController)
     33    if (window.layoutTestController) {
    3134        layoutTestController.dumpAsText();
     35        layoutTestController.waitUntilDone();
     36    }
    3237    test();
    3338</script>
  • trunk/LayoutTests/fast/events/scroll-event-does-not-bubble.html

    r35168 r75555  
    11<html>
    22<script>
     3var windowWasScrolled = false;
     4var doneTimeout;
     5
    36function windowScrolled() {
     7    windowWasScrolled = true;
    48    document.getElementById('result').innerHTML = 'FAILURE: window.onscroll was called.';
     9    clearTimeout(doneTimeout);   
    510}
    611
    712function divScrolled() {
    8     document.getElementById('result').innerHTML = 'SUCCESS: div.onscroll was called, but window.onscroll was not.';
     13    if (!windowWasScrolled)
     14        document.getElementById('result').innerHTML = 'SUCCESS: div.onscroll was called, but window.onscroll was not.';
     15    // Don't call notifyDone straight away, in case there's another scroll event coming/bubbling.
     16    doneTimeout = setTimeout(function() {
     17        if (window.layoutTestController)
     18            layoutTestController.notifyDone();
     19        }, 100);   
    920}
    1021
     
    2536    // Don't pollute the test result with nonsense.
    2637    div.innerHTML = '';
    27    
    28     if (window.layoutTestController)
    29         layoutTestController.notifyDone();
    30    
    3138}
    3239
  • trunk/LayoutTests/fast/layers/removed-by-scroll-handler.html

    r19204 r75555  
    1212    Result: <span id="result">test did not complete.</span>
    1313</p>
    14 <div id="t" style="overflow: auto; width: 200px; height: 100px;" onscroll="if (overflowRemove) this.parentNode.removeChild(this);">
     14<div id="t" style="overflow: auto; width: 200px; height: 100px;" onscroll="this.parentNode.removeChild(this);handleScroll(0);">
    1515    <div style="height: 200px;"></div>
    1616</div>
    1717
    18 <div style="overflow: auto; width: 200px; height: 100px;" onscroll="if (secondOverflowRemove) this.parentNode.removeChild(this);">
     18<div style="overflow: auto; width: 200px; height: 100px;" onscroll="this.parentNode.removeChild(this);handleScroll(1);">
    1919    <div style="height: 200px;"></div>
    2020    <div id="d"></div>
     
    2222
    2323<script>
    24     var overflowRemove = false;
    25     var secondOverflowRemove = false;
     24    var scrolledFirstContainer = false;
     25    var scrolledSecondContainer = false;
    2626
    2727    document.body.offsetTop; t.scrollTop = 20;
    2828
    29     overflowRemove = true;
    30     document.getElementById('t').innerHTML = '';
    31 
    32     secondOverflowRemove = true;
    3329    document.getElementById('d').scrollIntoView();
    3430   
    35     document.getElementById('result').innerText = "SUCCESS";
    36 
    37     if (window.layoutTestController)
    38         layoutTestController.notifyDone();
     31    function handleScroll(index)
     32    {
     33        if (index == 0) scrolledFirstContainer = true;
     34        else if (index == 1) scrolledSecondContainer = true;
     35       
     36        if (scrolledFirstContainer && scrolledSecondContainer) {
     37            document.getElementById('result').innerText = "SUCCESS";
     38       
     39            if (window.layoutTestController)
     40                layoutTestController.notifyDone();
     41        }
     42    }
    3943</script>
  • trunk/LayoutTests/fast/overflow/onscroll-layer-self-destruct.html

    r12581 r75555  
    22<script>
    33function test() {
    4     if (window.layoutTestController)
     4    if (window.layoutTestController) {
    55        layoutTestController.dumpAsText();
     6        layoutTestController.waitUntilDone();
     7    }
    68    document.getElementById("it").scrollTop = 100;
    79}
     
    911<body onload="test()">
    1012<p>This test involves a layer that self-destructs when scrolled. If there's no crash, then the test succeeded.</p>
    11 <div id="it" style="height: 100%; overflow: auto;" onscroll="style.display = 'none'">
     13<div id="it" style="height: 100%; overflow: auto;" onscroll="style.display = 'none';if (window.layoutTestController) layoutTestController.notifyDone();">
    1214<div style="height: 2000px;"></div>
    1315</div>
  • trunk/LayoutTests/fast/repaint/repaint-during-scroll.html

    r55159 r75555  
    44        function repaintTest()
    55        {
     6            if (window.layoutTestController)
     7                layoutTestController.waitUntilDone();
    68            var target = document.getElementById("target");
    79            scrollBy(0, 100);
     
    1214            var target = document.getElementById("target");
    1315            target.style.backgroundColor = "green";
     16            if (window.layoutTestController)
     17                layoutTestController.notifyDone();
    1418        }
    1519    </script>
  • trunk/Source/WebCore/ChangeLog

    r75549 r75555  
     12011-01-11  Mihai Parparita  <mihaip@chromium.org>
     2
     3        Reviewed by Darin Fisher.
     4
     5        Scroll event should be fired asynchronously
     6        https://bugs.webkit.org/show_bug.cgi?id=45631
     7
     8        Tests: fast/events/fire-scroll-event.html
     9               fast/events/fire-scroll-event-element.html
     10               fast/events/scroll-event-phase.html
     11
     12        Makes scroll events fire asynchronously to be in compliance with the
     13        CSSOM View Module and consistent with Gecko, Opera and (to some degree)
     14        IE.
     15       
     16        Implemented via the EventQueue class added by r74062 (EventQueue now
     17        has a convenience enqueueScrollEvent method).
     18
     19        * dom/EventQueue.cpp:
     20        (WebCore::EventQueue::enqueueScrollEvent):
     21        (WebCore::EventQueue::pendingEventTimerFired):
     22        * dom/EventQueue.h:
     23        * page/EventHandler.cpp:
     24        (WebCore::EventHandler::sendScrollEvent):
     25        * rendering/RenderLayer.cpp:
     26        (WebCore::RenderLayer::scrollToOffset):
     27        * rendering/RenderListBox.cpp:
     28        (WebCore::RenderListBox::valueChanged):
     29
    1302011-01-11  Patrick Gansterer  <paroga@webkit.org>
    231
  • trunk/Source/WebCore/dom/EventQueue.cpp

    r74062 r75555  
    4949}
    5050
     51void EventQueue::enqueueScrollEvent(PassRefPtr<Node> target, ScrollEventTargetType targetType)
     52{
     53    if (!m_nodesWithQueuedScrollEvents.add(target.get()).second)
     54        return;
     55
     56    // Per the W3C CSSOM View Module, scroll events fired at the document should bubble, others should not.
     57    bool canBubble = targetType == ScrollEventDocumentTarget;
     58    RefPtr<Event> scrollEvent = Event::create(eventNames().scrollEvent, canBubble, false /* non cancelleable */);
     59    scrollEvent->setTarget(target);
     60    enqueueEvent(scrollEvent.release());
     61}
     62
    5163void EventQueue::pendingEventTimerFired(Timer<EventQueue>*)
    5264{
     
    5567    Vector<RefPtr<Event> > queuedEvents;
    5668    queuedEvents.swap(m_queuedEvents);
     69   
     70    m_nodesWithQueuedScrollEvents.clear();
    5771
    5872    for (size_t i = 0; i < queuedEvents.size(); i++)
  • trunk/Source/WebCore/dom/EventQueue.h

    r74062 r75555  
    2929
    3030#include "Timer.h"
     31#include <wtf/HashSet.h>
    3132#include <wtf/Noncopyable.h>
    3233#include <wtf/RefPtr.h>
     
    4243
    4344public:
     45    enum ScrollEventTargetType {
     46        ScrollEventDocumentTarget,
     47        ScrollEventElementTarget
     48    };
     49
    4450    EventQueue();
    4551
    4652    void enqueueEvent(PassRefPtr<Event>);
     53    void enqueueScrollEvent(PassRefPtr<Node>, ScrollEventTargetType);
    4754
    4855private:
     
    5259    Timer<EventQueue> m_pendingEventTimer;
    5360    Vector<RefPtr<Event> > m_queuedEvents;
     61    HashSet<Node*> m_nodesWithQueuedScrollEvents;
    5462};
    5563
  • trunk/Source/WebCore/page/EventHandler.cpp

    r75287 r75555  
    3737#include "Editor.h"
    3838#include "EventNames.h"
     39#include "EventQueue.h"
    3940#include "FloatPoint.h"
    4041#include "FloatRect.h"
     
    27992800    setFrameWasScrolledByUser();
    28002801    if (m_frame->view() && m_frame->document())
    2801         m_frame->document()->dispatchEvent(Event::create(eventNames().scrollEvent, true, false));
     2802        m_frame->document()->eventQueue()->enqueueScrollEvent(m_frame->document(), EventQueue::ScrollEventDocumentTarget);
    28022803}
    28032804
  • trunk/Source/WebCore/rendering/RenderLayer.cpp

    r75472 r75555  
    5252#include "Document.h"
    5353#include "EventHandler.h"
    54 #include "EventNames.h"
     54#include "EventQueue.h"
    5555#include "FloatPoint3D.h"
    5656#include "FloatRect.h"
     
    13981398
    13991399    // Schedule the scroll DOM event.
    1400     if (view) {
    1401         if (FrameView* frameView = view->frameView())
    1402             frameView->scheduleEvent(Event::create(eventNames().scrollEvent, false, false), renderer()->node());
    1403     }
     1400    renderer()->node()->document()->eventQueue()->enqueueScrollEvent(renderer()->node(), EventQueue::ScrollEventElementTarget);
    14041401}
    14051402
  • trunk/Source/WebCore/rendering/RenderListBox.cpp

    r75537 r75555  
    3737#include "Document.h"
    3838#include "EventHandler.h"
    39 #include "EventNames.h"
     39#include "EventQueue.h"
    4040#include "FocusController.h"
    4141#include "Frame.h"
     
    540540        m_indexOffset = newOffset;
    541541        repaint();
    542         node()->dispatchEvent(Event::create(eventNames().scrollEvent, false, false));
     542        node()->document()->eventQueue()->enqueueScrollEvent(node(), EventQueue::ScrollEventElementTarget);
    543543    }
    544544}
Note: See TracChangeset for help on using the changeset viewer.