Changeset 252205 in webkit


Ignore:
Timestamp:
Nov 7, 2019 2:18:37 PM (5 years ago)
Author:
rniwa@webkit.org
Message:

Integrate scroll event into HTML5 event loop
https://bugs.webkit.org/show_bug.cgi?id=203839
<rdar://problem/56890922>

Reviewed by Simon Fraser.

Source/WebCore:

Dispatch scroll events on each pending scroll event targets inside the update-the-rendering step
of the event loop as specified in the HTML5 and CSSOM View Module specifications:
https://html.spec.whatwg.org/multipage/webappapis.html#update-the-rendering
https://drafts.csswg.org/cssom-view/#run-the-scroll-steps

The new behavior also matches that of Chrome and Firefox.

Like resize event, the current visual viewport specification does not specify when scroll event
is dispatched on visualViewport interface: https://github.com/WICG/visual-viewport/issues/66
For now, we always dispatch upon it after dispatching on all pending scroll event targets.

Tests: fast/events/scroll-multiple-elements-in-rendering-update.html

fast/events/scroll-subframe-in-rendering-update.html
fast/visual-viewport/visual-viewport-scroll-after-resize-in-subframe.html

  • dom/Document.cpp:

(WebCore::Document::addPendingScrollEventTarget): Added.
(WebCore::Document::setNeedsVisualViewportScrollEvent): Added.
(WebCore::Document::runScrollSteps): Added. This implements run the scroll steps in CSS OM View.

  • dom/Document.h:
  • dom/DocumentEventQueue.cpp:

(WebCore::DocumentEventQueue::enqueueOrDispatchScrollEvent): Deleted.
(WebCore::DocumentEventQueue::enqueueScrollEvent): Deleted.

  • dom/DocumentEventQueue.h:
  • page/EventHandler.cpp:

(WebCore::EventHandler::sendScrollEvent):

  • page/Page.cpp:

(WebCore::Page::updateRendering): Invoke runScrollSteps on each document in the frame tree order.

  • page/VisualViewport.cpp:

(WebCore::VisualViewport::update):
(WebCore::VisualViewport::enqueueScrollEvent): Deleted.

  • page/VisualViewport.h:
  • rendering/RenderLayer.cpp:

(WebCore::RenderLayer::scrollTo):

  • rendering/RenderListBox.cpp:

(WebCore::RenderListBox::scrollTo):

LayoutTests:

Added tests to test the timing at which scroll events are fired across multiple elements and documents,
and with visualViewport, and updated the existing tests to work with the new timing.

  • editing/selection/overflow-scroll-while-selecting-text.html:
  • fast/events/scroll-multiple-elements-in-rendering-update-expected.txt: Added.
  • fast/events/scroll-multiple-elements-in-rendering-update.html: Added.
  • fast/events/scroll-subframe-in-rendering-update-expected.txt: Added.
  • fast/events/scroll-subframe-in-rendering-update.html: Added.
  • fast/scrolling/programmatic-scroll-to-negative-offset.html:
  • fast/shadow-dom/trusted-event-scoped-flags.html:
  • fast/visual-viewport/visual-viewport-scroll-after-resize-in-subframe-expected.txt: Added.
  • fast/visual-viewport/visual-viewport-scroll-after-resize-in-subframe.html: Added.
  • tiled-drawing/scrolling/fast-scroll-div-latched-mainframe.html:
Location:
trunk
Files:
4 added
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r252204 r252205  
     12019-11-06  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        Integrate scroll event into HTML5 event loop
     4        https://bugs.webkit.org/show_bug.cgi?id=203839
     5        <rdar://problem/56890922>
     6
     7        Reviewed by Simon Fraser.
     8
     9        Added tests to test the timing at which scroll events are fired across multiple elements and documents,
     10        and with visualViewport, and updated the existing tests to work with the new timing.
     11
     12        * editing/selection/overflow-scroll-while-selecting-text.html:
     13        * fast/events/scroll-multiple-elements-in-rendering-update-expected.txt: Added.
     14        * fast/events/scroll-multiple-elements-in-rendering-update.html: Added.
     15        * fast/events/scroll-subframe-in-rendering-update-expected.txt: Added.
     16        * fast/events/scroll-subframe-in-rendering-update.html: Added.
     17        * fast/scrolling/programmatic-scroll-to-negative-offset.html:
     18        * fast/shadow-dom/trusted-event-scoped-flags.html:
     19        * fast/visual-viewport/visual-viewport-scroll-after-resize-in-subframe-expected.txt: Added.
     20        * fast/visual-viewport/visual-viewport-scroll-after-resize-in-subframe.html: Added.
     21        * tiled-drawing/scrolling/fast-scroll-div-latched-mainframe.html:
     22
    1232019-11-07  Justin Fan  <justin_fan@apple.com>
    224
  • trunk/LayoutTests/editing/selection/overflow-scroll-while-selecting-text.html

    r244388 r252205  
    3131const text = document.getElementById("text");
    3232text.scrollTo(0, 1000);
    33 addEventListener("load", () => text.scrollTo(0, 500));
    34 text.addEventListener("scroll", () => {
    35     text.textContent = "";
    36     testPassed("Successfully removed the text.");
    37     finishJSTest();
     33addEventListener("load", () => {
     34    text.addEventListener("scroll", () => {
     35        text.textContent = "";
     36        testPassed("Successfully removed the text.");
     37        finishJSTest();
     38    });
     39    text.scrollTo(0, 500);
    3840});
    3941</script>
  • trunk/LayoutTests/fast/scrolling/programmatic-scroll-to-negative-offset.html

    r245742 r252205  
    2626                        scroller.scrollLeft = 50;
    2727
    28                         scroller.addEventListener('scroll', (event) => {
    29                                 shouldBe("scroller.scrollLeft", "0");
    30                                 shouldBe("scroller.scrollLeft", "0");
    31                                 finishJSTest();
    32                         }, false);
     28                        setTimeout(() => {
     29                        scroller.addEventListener('scroll', (event) => {
     30                                shouldBe("scroller.scrollLeft", "0");
     31                                shouldBe("scroller.scrollLeft", "0");
     32                                finishJSTest();
     33                        }, false);
    3334
    34                         setTimeout(() => {
    3535                                scroller.scrollLeft = -200;
    3636                                scroller.scrollTop = -100;
  • trunk/LayoutTests/fast/shadow-dom/trusted-event-scoped-flags.html

    r251867 r252205  
    9797    setTimeout(function () {
    9898        window.scrollTo(0, 1000);
    99         setTimeout(function () {
    100             checkFlags('', {eventType: 'scroll', composed: false});
    101             window.scrollTo(0, 0);
    102             testResizeEvent();
    103         }, 0);
     99        requestAnimationFrame(() => {
     100            setTimeout(function () {
     101                checkFlags('', {eventType: 'scroll', composed: false});
     102                window.scrollTo(0, 0);
     103                testResizeEvent();
     104            }, 0);
     105        });
    104106    }, 0);
    105107}
  • trunk/LayoutTests/tiled-drawing/scrolling/fast-scroll-div-latched-mainframe.html

    r235806 r252205  
    4848}
    4949
     50let didCheck = false;
    5051function checkForScroll()
    5152{
     53    if (didCheck)
     54        return;
     55    didCheck = true;
     56
    5257    // The div should not have scrolled at all.
    5358    var pageScrollPositionAfter = document.scrollingElement.scrollTop;
     
    97102
    98103        eventSender.monitorWheelEvents();
    99         setTimeout(scrollTest, 0);
     104        requestIdleCallback(() => {
     105            setTimeout(scrollTest, 0);
     106        });
    100107    } else {
    101108        var messageLocation = document.getElementById('parent');
  • trunk/Source/WebCore/ChangeLog

    r252189 r252205  
     12019-11-06  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        Integrate scroll event into HTML5 event loop
     4        https://bugs.webkit.org/show_bug.cgi?id=203839
     5        <rdar://problem/56890922>
     6
     7        Reviewed by Simon Fraser.
     8
     9        Dispatch scroll events on each pending scroll event targets inside the update-the-rendering step
     10        of the event loop as specified in the HTML5 and CSSOM View Module specifications:
     11        https://html.spec.whatwg.org/multipage/webappapis.html#update-the-rendering
     12        https://drafts.csswg.org/cssom-view/#run-the-scroll-steps
     13
     14        The new behavior also matches that of Chrome and Firefox.
     15
     16        Like resize event, the current visual viewport specification does not specify when scroll event
     17        is dispatched on visualViewport interface: https://github.com/WICG/visual-viewport/issues/66
     18        For now, we always dispatch upon it after dispatching on all pending scroll event targets.
     19
     20        Tests: fast/events/scroll-multiple-elements-in-rendering-update.html
     21               fast/events/scroll-subframe-in-rendering-update.html
     22               fast/visual-viewport/visual-viewport-scroll-after-resize-in-subframe.html
     23
     24        * dom/Document.cpp:
     25        (WebCore::Document::addPendingScrollEventTarget): Added.
     26        (WebCore::Document::setNeedsVisualViewportScrollEvent): Added.
     27        (WebCore::Document::runScrollSteps): Added. This implements run the scroll steps in CSS OM View.
     28        * dom/Document.h:
     29        * dom/DocumentEventQueue.cpp:
     30        (WebCore::DocumentEventQueue::enqueueOrDispatchScrollEvent): Deleted.
     31        (WebCore::DocumentEventQueue::enqueueScrollEvent): Deleted.
     32        * dom/DocumentEventQueue.h:
     33        * page/EventHandler.cpp:
     34        (WebCore::EventHandler::sendScrollEvent):
     35        * page/Page.cpp:
     36        (WebCore::Page::updateRendering): Invoke runScrollSteps on each document in the frame tree order.
     37        * page/VisualViewport.cpp:
     38        (WebCore::VisualViewport::update):
     39        (WebCore::VisualViewport::enqueueScrollEvent): Deleted.
     40        * page/VisualViewport.h:
     41        * rendering/RenderLayer.cpp:
     42        (WebCore::RenderLayer::scrollTo):
     43        * rendering/RenderListBox.cpp:
     44        (WebCore::RenderListBox::scrollTo):
     45
    1462019-11-07  Zalan Bujtas  <zalan@apple.com>
    247
  • trunk/Source/WebCore/dom/Document.cpp

    r252060 r252205  
    40024002}
    40034003
     4004void Document::addPendingScrollEventTarget(ContainerNode& target)
     4005{
     4006    if (m_pendingScrollEventTargets.contains(&target))
     4007        return;
     4008
     4009    if (m_pendingScrollEventTargets.isEmpty())
     4010        scheduleTimedRenderingUpdate();
     4011
     4012    m_pendingScrollEventTargets.append(makeWeakPtr(target));
     4013}
     4014
     4015void Document::setNeedsVisualViewportScrollEvent()
     4016{
     4017    if (!m_needsVisualViewportScrollEvent)
     4018        scheduleTimedRenderingUpdate();
     4019    m_needsVisualViewportScrollEvent = true;
     4020}
     4021
     4022// https://drafts.csswg.org/cssom-view/#run-the-scroll-steps
     4023void Document::runScrollSteps()
     4024{
     4025    // FIXME: The order of dispatching is not specified: https://github.com/WICG/visual-viewport/issues/66.
     4026    if (!m_pendingScrollEventTargets.isEmpty()) {
     4027        LOG_WITH_STREAM(Events, stream << "Document" << this << "sending scroll events to pending scroll event targets");
     4028        auto currentTargets = WTFMove(m_pendingScrollEventTargets);
     4029        for (auto target : currentTargets) {
     4030            auto protectedTarget = makeRefPtr(target.get());
     4031            ASSERT(protectedTarget);
     4032            if (!protectedTarget)
     4033                continue;
     4034            auto bubbles = protectedTarget->isDocumentNode() ? Event::CanBubble::Yes : Event::CanBubble::No;
     4035            protectedTarget->dispatchEvent(Event::create(eventNames().scrollEvent, bubbles, Event::IsCancelable::No));
     4036        }
     4037    }
     4038    if (m_needsVisualViewportScrollEvent) {
     4039        LOG_WITH_STREAM(Events, stream << "Document" << this << "sending scroll events to visualViewport");
     4040        m_needsVisualViewportResizeEvent = false;
     4041        if (auto* window = domWindow())
     4042            window->visualViewport().dispatchEvent(Event::create(eventNames().scrollEvent, Event::CanBubble::No, Event::IsCancelable::No));
     4043    }
     4044}
     4045
    40044046void Document::addAudioProducer(MediaProducer& audioProducer)
    40054047{
  • trunk/Source/WebCore/dom/Document.h

    r251930 r252205  
    13651365    void runResizeSteps();
    13661366
     1367    void addPendingScrollEventTarget(ContainerNode&);
     1368    void setNeedsVisualViewportScrollEvent();
     1369    void runScrollSteps();
     1370
    13671371    WEBCORE_EXPORT void addAudioProducer(MediaProducer&);
    13681372    WEBCORE_EXPORT void removeAudioProducer(MediaProducer&);
     
    20202024    bool m_needsDOMWindowResizeEvent { false };
    20212025    bool m_needsVisualViewportResizeEvent { false };
     2026    bool m_needsVisualViewportScrollEvent { false };
    20222027    bool m_isTimerThrottlingEnabled { false };
    20232028    bool m_isSuspended { false };
     
    20352040    bool m_isTelephoneNumberParsingAllowed { true };
    20362041#endif
     2042
     2043    Vector<WeakPtr<ContainerNode>> m_pendingScrollEventTargets;
    20372044
    20382045#if ENABLE(MEDIA_STREAM)
  • trunk/Source/WebCore/dom/DocumentEventQueue.cpp

    r252122 r252205  
    8282}
    8383
    84 void DocumentEventQueue::enqueueOrDispatchScrollEvent(Node& target)
    85 {
    86     ASSERT(&target.document() == &m_document);
    87 
    88     // Per the W3C CSSOM View Module, scroll events fired at the document should bubble, others should not.
    89     enqueueScrollEvent(target, target.isDocumentNode() ? Event::CanBubble::Yes : Event::CanBubble::No, Event::IsCancelable::No);
    90 }
    91 
    92 void DocumentEventQueue::enqueueScrollEvent(EventTarget& target, Event::CanBubble canBubble, Event::IsCancelable cancelable)
    93 {
    94     if (m_isClosed)
    95         return;
    96 
    97     if (!m_document.hasListenerType(Document::SCROLL_LISTENER))
    98         return;
    99 
    100     if (!m_targetsWithQueuedScrollEvents.add(&target).isNewEntry)
    101         return;
    102 
    103     Ref<Event> scrollEvent = Event::create(eventNames().scrollEvent, canBubble, cancelable);
    104     scrollEvent->setTarget(&target);
    105     enqueueEvent(WTFMove(scrollEvent));
    106 }
    107 
    10884bool DocumentEventQueue::cancelEvent(Event& event)
    10985{
  • trunk/Source/WebCore/dom/DocumentEventQueue.h

    r252122 r252205  
    4848    void close() override;
    4949
    50     void enqueueOrDispatchScrollEvent(Node&);
    51     void enqueueScrollEvent(EventTarget&, Event::CanBubble, Event::IsCancelable);
    5250
    5351private:
  • trunk/Source/WebCore/page/EventHandler.cpp

    r251517 r252205  
    40304030    Ref<Frame> protectedFrame(m_frame);
    40314031    setFrameWasScrolledByUser();
    4032     if (m_frame.view() && m_frame.document())
    4033         m_frame.document()->eventQueue().enqueueOrDispatchScrollEvent(*m_frame.document());
     4032    if (!m_frame.view())
     4033        return;
     4034    auto document = makeRefPtr(m_frame.document());
     4035    if (!document)
     4036        return;
     4037    document->addPendingScrollEventTarget(*document);
    40344038}
    40354039
  • trunk/Source/WebCore/page/Page.cpp

    r252013 r252205  
    12911291    layoutIfNeeded();
    12921292
     1293    // Flush autofocus candidates
     1294
    12931295    forEachDocument([&](Document& document) {
    12941296        document.runResizeSteps();
    12951297    });
    12961298
    1297     // FIXME: Run the scroll steps
     1299    forEachDocument([&](Document& document) {
     1300        document.runScrollSteps();
     1301    });
    12981302
    12991303    forEachDocument([&](Document& document) {
     
    13191323        document->updateResizeObservations(*this);
    13201324#endif
    1321 
    1322     // FIXME: Flush autofocus candidates
    1323     // https://github.com/whatwg/html/issues/4992
    13241325
    13251326    layoutIfNeeded();
  • trunk/Source/WebCore/page/VisualViewport.cpp

    r252122 r252205  
    169169    }
    170170
     171    RefPtr<Document> document = frame ? frame->document() : nullptr;
    171172    if (m_offsetLeft != offsetLeft || m_offsetTop != offsetTop) {
    172         enqueueScrollEvent();
     173        if (document)
     174            document->setNeedsVisualViewportScrollEvent();
    173175        m_offsetLeft = offsetLeft;
    174176        m_offsetTop = offsetTop;
    175177    }
    176178    if (m_width != width || m_height != height || m_scale != scale) {
    177         if (auto* frame = this->frame())
    178             frame->document()->setNeedsVisualViewportResize();
     179        if (document)
     180            document->setNeedsVisualViewportResize();
    179181        m_width = width;
    180182        m_height = height;
     
    183185}
    184186
    185 void VisualViewport::enqueueScrollEvent()
    186 {
    187     auto* frame = this->frame();
    188     if (!frame)
    189         return;
    190 
    191     frame->document()->eventQueue().enqueueScrollEvent(*this, Event::CanBubble::No, Event::IsCancelable::No);
    192 }
    193 
    194187} // namespace WebCore
  • trunk/Source/WebCore/page/VisualViewport.h

    r246490 r252205  
    6161    void derefEventTarget() final { deref(); }
    6262
    63     void enqueueResizeEvent();
    64     void enqueueScrollEvent();
    65 
    6663    void updateFrameLayout() const;
    6764
  • trunk/Source/WebCore/rendering/RenderLayer.cpp

    r251369 r252205  
    26742674    // Schedule the scroll and scroll-related DOM events.
    26752675    if (Element* element = renderer().element())
    2676         element->document().eventQueue().enqueueOrDispatchScrollEvent(*element);
     2676        element->document().addPendingScrollEventTarget(*element);
    26772677
    26782678    if (scrollsOverflow())
  • trunk/Source/WebCore/rendering/RenderListBox.cpp

    r250946 r252205  
    714714
    715715    repaint();
    716     document().eventQueue().enqueueOrDispatchScrollEvent(selectElement());
     716    document().addPendingScrollEventTarget(selectElement());
    717717}
    718718
Note: See TracChangeset for help on using the changeset viewer.