Expand test infrastructure to support scrolling tests (Part 4): Scroll Snap Support
authorbfulgham@apple.com <bfulgham@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 2 May 2015 00:39:37 +0000 (00:39 +0000)
committerbfulgham@apple.com <bfulgham@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 2 May 2015 00:39:37 +0000 (00:39 +0000)
https://bugs.webkit.org/show_bug.cgi?id=144482

Reviewed by Simon Fraser.

New tests will be landed in a second patch.

The new WheelEventTestTriggers do not work properly with scroll snap points, because some test deferral notifications
need to be triggered for state changes on the scrolling thread. This required the following changes:
1. A flag indicating that we want to know about WheelEvent state changes needed to be propagated to the scrolling thread,
   so that tests could be deferred until Scrolling thread rubberband or scroll-snap animations had completed.
2. The ScrollingNodeID needed to be used for registering and clearing deferrals.
3. The scrolling thread needed a way to dispatch messages to the main thread indicating that we should (or should not)
   defer tests due to scrolling actions.

Note that a future patch will extend this support to include the RemoteScrollingTree.

* page/WheelEventTestTrigger.cpp:
(WebCore::WheelEventTestTrigger::deferTestsForReason): Added some logging features.
(WebCore::WheelEventTestTrigger::removeTestDeferralForReason): Ditto.
(WebCore::dumpState): Helper function for logging test deferral state.
(WebCore::WheelEventTestTrigger::triggerTestTimerFired): Added some logging features.
* page/scrolling/AsyncScrollingCoordinator.cpp:
(WebCore::AsyncScrollingCoordinator::frameViewLayoutUpdated): Make sure that the scrolling thread is
told that it needs to send scrolling state back to the main thread. Only do this if we are in testing mode.
(WebCore::AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScroll): The scrollingNodeID should be
used as the identifier for this operation, not the page address.
(WebCore::AsyncScrollingCoordinator::deferTestsForReason): Added. receives messages from the scrolling thread
and notifies the testing infrastructure.
(WebCore::AsyncScrollingCoordinator::removeTestDeferralForReason): Ditto.
* page/scrolling/AsyncScrollingCoordinator.h:
* page/scrolling/ScrollingStateScrollingNode.cpp:
(WebCore::ScrollingStateScrollingNode::ScrollingStateScrollingNode): When cloning the ScrollingStateScrollingNode,
include the testing mode state.
(WebCore::ScrollingStateScrollingNode::setExpectsWheelEventTestTrigger): Added.
* page/scrolling/ScrollingStateScrollingNode.h:
(WebCore::ScrollingStateScrollingNode::expectsWheelEventTestTrigger): Added.
* page/scrolling/ScrollingTree.h:
(WebCore::ScrollingTree::deferTestsForReason): Added stub.
(WebCore::ScrollingTree::removeTestDeferralForReason): Ditto.
* page/scrolling/ThreadedScrollingTree.cpp:
(WebCore::ThreadedScrollingTree::deferTestsForReason): Added. Dispatches messages from the scrolling thread to the
main thread.
(WebCore::ThreadedScrollingTree::removeTestDeferralForReason): Ditto.
* page/scrolling/ThreadedScrollingTree.h:
* page/scrolling/mac/ScrollingTreeFrameScrollingNodeMac.h:
* page/scrolling/mac/ScrollingTreeFrameScrollingNodeMac.mm:
(WebCore::ScrollingTreeFrameScrollingNodeMac::ScrollingTreeFrameScrollingNodeMac): Initialize testing state flag.
(WebCore::ScrollingTreeFrameScrollingNodeMac::updateBeforeChildren): If the 'ExpectsWheelEventTestTrigger' flag is
set, update local state.
(WebCore::ScrollingTreeFrameScrollingNodeMac::handleWheelEvent): If we are testing, and the wheel event should be handled
asynchronously, tell the testing infrastructure we need to wait for the thread state to sync.
(WebCore::ScrollingTreeFrameScrollingNodeMac::deferTestsForReason): Added. Notifies test system we need to defer tests
until we notify them. Also used by the ScrollController during animations.
(WebCore::ScrollingTreeFrameScrollingNodeMac::removeTestDeferralForReason): Ditto.
* platform/Logging.h:
* platform/ScrollAnimator.cpp:
(WebCore::ScrollAnimator::deferTestsForReason): Added. Used by ScrollController during animation. This updates the
testing infrastructure directly, since it is running in the same process and main thread.
(WebCore::ScrollAnimator::removeTestDeferralForReason): Ditto.
* platform/ScrollAnimator.h:
* platform/cocoa/ScrollController.h:
(WebCore::ScrollControllerClient::deferTestsForReason): Change client API.
(WebCore::ScrollControllerClient::removeTestDeferralForReason): Ditto.
(WebCore::ScrollControllerClient::testTrigger): Deleted.
* platform/cocoa/ScrollController.mm:
(WebCore::ScrollController::startSnapRubberbandTimer): Use new client API.
(WebCore::ScrollController::stopSnapRubberbandTimer): Ditto.
(WebCore::ScrollController::startScrollSnapTimer): Ditto.
(WebCore::ScrollController::stopScrollSnapTimer): Ditto.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@183702 268f45cc-cd09-0410-ab3c-d52691b4dbfc

16 files changed:
Source/WebCore/ChangeLog
Source/WebCore/page/WheelEventTestTrigger.cpp
Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp
Source/WebCore/page/scrolling/AsyncScrollingCoordinator.h
Source/WebCore/page/scrolling/ScrollingStateScrollingNode.cpp
Source/WebCore/page/scrolling/ScrollingStateScrollingNode.h
Source/WebCore/page/scrolling/ScrollingTree.h
Source/WebCore/page/scrolling/ThreadedScrollingTree.cpp
Source/WebCore/page/scrolling/ThreadedScrollingTree.h
Source/WebCore/page/scrolling/mac/ScrollingTreeFrameScrollingNodeMac.h
Source/WebCore/page/scrolling/mac/ScrollingTreeFrameScrollingNodeMac.mm
Source/WebCore/platform/Logging.h
Source/WebCore/platform/ScrollAnimator.cpp
Source/WebCore/platform/ScrollAnimator.h
Source/WebCore/platform/cocoa/ScrollController.h
Source/WebCore/platform/cocoa/ScrollController.mm

index 5e1611d..b4c53d8 100644 (file)
@@ -1,3 +1,76 @@
+2015-05-01  Brent Fulgham  <bfulgham@apple.com>
+
+        Expand test infrastructure to support scrolling tests (Part 4): Scroll Snap Support
+        https://bugs.webkit.org/show_bug.cgi?id=144482
+
+        Reviewed by Simon Fraser.
+
+        New tests will be landed in a second patch.
+
+        The new WheelEventTestTriggers do not work properly with scroll snap points, because some test deferral notifications
+        need to be triggered for state changes on the scrolling thread. This required the following changes:
+        1. A flag indicating that we want to know about WheelEvent state changes needed to be propagated to the scrolling thread,
+           so that tests could be deferred until Scrolling thread rubberband or scroll-snap animations had completed.
+        2. The ScrollingNodeID needed to be used for registering and clearing deferrals.
+        3. The scrolling thread needed a way to dispatch messages to the main thread indicating that we should (or should not)
+           defer tests due to scrolling actions.
+
+        Note that a future patch will extend this support to include the RemoteScrollingTree.
+
+        * page/WheelEventTestTrigger.cpp:
+        (WebCore::WheelEventTestTrigger::deferTestsForReason): Added some logging features.
+        (WebCore::WheelEventTestTrigger::removeTestDeferralForReason): Ditto.
+        (WebCore::dumpState): Helper function for logging test deferral state.
+        (WebCore::WheelEventTestTrigger::triggerTestTimerFired): Added some logging features.
+        * page/scrolling/AsyncScrollingCoordinator.cpp:
+        (WebCore::AsyncScrollingCoordinator::frameViewLayoutUpdated): Make sure that the scrolling thread is
+        told that it needs to send scrolling state back to the main thread. Only do this if we are in testing mode.
+        (WebCore::AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScroll): The scrollingNodeID should be
+        used as the identifier for this operation, not the page address.
+        (WebCore::AsyncScrollingCoordinator::deferTestsForReason): Added. receives messages from the scrolling thread
+        and notifies the testing infrastructure.
+        (WebCore::AsyncScrollingCoordinator::removeTestDeferralForReason): Ditto.
+        * page/scrolling/AsyncScrollingCoordinator.h:
+        * page/scrolling/ScrollingStateScrollingNode.cpp:
+        (WebCore::ScrollingStateScrollingNode::ScrollingStateScrollingNode): When cloning the ScrollingStateScrollingNode,
+        include the testing mode state.
+        (WebCore::ScrollingStateScrollingNode::setExpectsWheelEventTestTrigger): Added.
+        * page/scrolling/ScrollingStateScrollingNode.h:
+        (WebCore::ScrollingStateScrollingNode::expectsWheelEventTestTrigger): Added.
+        * page/scrolling/ScrollingTree.h:
+        (WebCore::ScrollingTree::deferTestsForReason): Added stub.
+        (WebCore::ScrollingTree::removeTestDeferralForReason): Ditto.
+        * page/scrolling/ThreadedScrollingTree.cpp:
+        (WebCore::ThreadedScrollingTree::deferTestsForReason): Added. Dispatches messages from the scrolling thread to the
+        main thread.
+        (WebCore::ThreadedScrollingTree::removeTestDeferralForReason): Ditto.
+        * page/scrolling/ThreadedScrollingTree.h:
+        * page/scrolling/mac/ScrollingTreeFrameScrollingNodeMac.h:
+        * page/scrolling/mac/ScrollingTreeFrameScrollingNodeMac.mm:
+        (WebCore::ScrollingTreeFrameScrollingNodeMac::ScrollingTreeFrameScrollingNodeMac): Initialize testing state flag.
+        (WebCore::ScrollingTreeFrameScrollingNodeMac::updateBeforeChildren): If the 'ExpectsWheelEventTestTrigger' flag is
+        set, update local state.
+        (WebCore::ScrollingTreeFrameScrollingNodeMac::handleWheelEvent): If we are testing, and the wheel event should be handled
+        asynchronously, tell the testing infrastructure we need to wait for the thread state to sync.
+        (WebCore::ScrollingTreeFrameScrollingNodeMac::deferTestsForReason): Added. Notifies test system we need to defer tests
+        until we notify them. Also used by the ScrollController during animations.
+        (WebCore::ScrollingTreeFrameScrollingNodeMac::removeTestDeferralForReason): Ditto.
+        * platform/Logging.h:
+        * platform/ScrollAnimator.cpp:
+        (WebCore::ScrollAnimator::deferTestsForReason): Added. Used by ScrollController during animation. This updates the
+        testing infrastructure directly, since it is running in the same process and main thread.
+        (WebCore::ScrollAnimator::removeTestDeferralForReason): Ditto.
+        * platform/ScrollAnimator.h:
+        * platform/cocoa/ScrollController.h:
+        (WebCore::ScrollControllerClient::deferTestsForReason): Change client API.
+        (WebCore::ScrollControllerClient::removeTestDeferralForReason): Ditto.
+        (WebCore::ScrollControllerClient::testTrigger): Deleted.
+        * platform/cocoa/ScrollController.mm:
+        (WebCore::ScrollController::startSnapRubberbandTimer): Use new client API.
+        (WebCore::ScrollController::stopSnapRubberbandTimer): Ditto.
+        (WebCore::ScrollController::startScrollSnapTimer): Ditto.
+        (WebCore::ScrollController::stopScrollSnapTimer): Ditto.
+
 2015-05-01  Joseph Pecoraro  <pecoraro@apple.com>
 
         Inline some small methods instead of them being EXPORT'd and out of line
index cf1eee3..1d09330 100644 (file)
 #include "config.h"
 #include "WheelEventTestTrigger.h"
 
+#include "Logging.h"
+
+#if !LOG_DISABLED
+#include <wtf/text/CString.h>
+#include <wtf/text/StringBuilder.h>
+#endif
+
 namespace WebCore {
 
 WheelEventTestTrigger::WheelEventTestTrigger()
@@ -42,6 +49,7 @@ void WheelEventTestTrigger::clearAllTestDeferrals()
     m_deferTestTriggerReasons.clear();
     m_testNotificationCallback = std::function<void()>();
     m_testTriggerTimer.stop();
+    LOG(WheelEventTestTriggers, "      (=) WheelEventTestTrigger::clearAllTestDeferrals: cleared all test state.");
 }
 
 void WheelEventTestTrigger::setTestCallbackAndStartNotificationTimer(std::function<void()> functionCallback)
@@ -62,6 +70,7 @@ void WheelEventTestTrigger::deferTestsForReason(ScrollableAreaIdentifier identif
     if (it == m_deferTestTriggerReasons.end())
         it = m_deferTestTriggerReasons.add(identifier, std::set<DeferTestTriggerReason>()).iterator;
     
+    LOG(WheelEventTestTriggers, "      (=) WheelEventTestTrigger::deferTestsForReason: id=%p, reason=%d", identifier, reason);
     it->value.insert(reason);
 }
 
@@ -72,20 +81,43 @@ void WheelEventTestTrigger::removeTestDeferralForReason(ScrollableAreaIdentifier
     if (it == m_deferTestTriggerReasons.end())
         return;
 
+    LOG(WheelEventTestTriggers, "      (=) WheelEventTestTrigger::removeTestDeferralForReason: id=%p, reason=%d", identifier, reason);
     it->value.erase(reason);
     
     if (it->value.empty())
         m_deferTestTriggerReasons.remove(it);
 }
 
+#if !LOG_DISABLED
+static void dumpState(WTF::HashMap<WheelEventTestTrigger::ScrollableAreaIdentifier, std::set<WheelEventTestTrigger::DeferTestTriggerReason>> reasons)
+{
+    LOG(WheelEventTestTriggers, "   WheelEventTestTrigger::dumpState:");
+    for (const auto& scrollRegion : reasons) {
+        LOG(WheelEventTestTriggers, "   For scroll region %p", scrollRegion.key);
+        StringBuilder reasons;
+        for (const auto& reason : scrollRegion.value) {
+            if (!reasons.isEmpty())
+                reasons.append(", ");
+            reasons.append(String::number(reason));
+        }
+        LOG(WheelEventTestTriggers, "     Reasons: %s", reasons.toString().utf8().data());
+    }
+}
+#endif
+    
 void WheelEventTestTrigger::triggerTestTimerFired()
 {
     std::function<void()> functionCallback;
 
     {
         std::lock_guard<std::mutex> lock(m_testTriggerMutex);
-        if (!m_deferTestTriggerReasons.isEmpty())
+        if (!m_deferTestTriggerReasons.isEmpty()) {
+#if !LOG_DISABLED
+            if (isLogChannelEnabled("WheelEventTestTrigger"))
+                dumpState(m_deferTestTriggerReasons);
+#endif
             return;
+        }
 
         functionCallback = WTF::move(m_testNotificationCallback);
         m_testNotificationCallback = std::function<void()>();
@@ -93,6 +125,7 @@ void WheelEventTestTrigger::triggerTestTimerFired()
 
     m_testTriggerTimer.stop();
 
+    LOG(WheelEventTestTriggers, "  WheelEventTestTrigger::triggerTestTimerFired: FIRING TEST");
     if (functionCallback)
         functionCallback();
 }
index 59411e7..eccf413 100644 (file)
@@ -32,6 +32,7 @@
 #include "Frame.h"
 #include "FrameView.h"
 #include "GraphicsLayer.h"
+#include "Logging.h"
 #include "MainFrame.h"
 #include "Page.h"
 #include "ScrollAnimator.h"
@@ -147,6 +148,14 @@ void AsyncScrollingCoordinator::frameViewLayoutUpdated(FrameView& frameView)
         setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Vertical, *verticalSnapOffsets, m_page->deviceScaleFactor());
 #endif
 
+#if PLATFORM(COCOA)
+    Page* page = frameView.frame().page();
+    if (page && page->expectsWheelEventTriggers()) {
+        LOG(WheelEventTestTriggers, "    AsyncScrollingCoordinator::frameViewLayoutUpdated: Expects wheel event test trigger=%d", page->expectsWheelEventTriggers());
+        node->setExpectsWheelEventTestTrigger(page->expectsWheelEventTriggers());
+    }
+#endif
+
     ScrollableAreaParameters scrollParameters;
     scrollParameters.horizontalScrollElasticity = frameView.horizontalScrollElasticity();
     scrollParameters.verticalScrollElasticity = frameView.verticalScrollElasticity();
@@ -361,7 +370,7 @@ void AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScroll(ScrollingNo
         if (m_page->expectsWheelEventTriggers()) {
             frameView.scrollAnimator().setWheelEventTestTrigger(m_page->testTrigger());
             if (const auto& trigger = m_page->testTrigger())
-                trigger->removeTestDeferralForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(m_page), WheelEventTestTrigger::ScrollingThreadSyncNeeded);
+                trigger->removeTestDeferralForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(scrollingNodeID), WheelEventTestTrigger::ScrollingThreadSyncNeeded);
         }
 #endif
         
@@ -380,7 +389,7 @@ void AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScroll(ScrollingNo
         if (m_page->expectsWheelEventTriggers()) {
             frameView.scrollAnimator().setWheelEventTestTrigger(m_page->testTrigger());
             if (const auto& trigger = m_page->testTrigger())
-                trigger->removeTestDeferralForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(m_page), WheelEventTestTrigger::ScrollingThreadSyncNeeded);
+                trigger->removeTestDeferralForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(scrollingNodeID), WheelEventTestTrigger::ScrollingThreadSyncNeeded);
         }
 #endif
     }
@@ -552,6 +561,30 @@ String AsyncScrollingCoordinator::scrollingStateTreeAsText() const
     return String();
 }
 
+#if PLATFORM(COCOA)
+void AsyncScrollingCoordinator::deferTestsForReason(WheelEventTestTrigger::ScrollableAreaIdentifier identifier, WheelEventTestTrigger::DeferTestTriggerReason reason) const
+{
+    if (!m_page || !m_page->expectsWheelEventTriggers())
+        return;
+
+    if (const auto& trigger = m_page->testTrigger()) {
+        LOG(WheelEventTestTriggers, "    (!) AsyncScrollingCoordinator::deferTestsForReason: Deferring %p for reason %d.", identifier, reason);
+        trigger->deferTestsForReason(identifier, reason);
+    }
+}
+
+void AsyncScrollingCoordinator::removeTestDeferralForReason(WheelEventTestTrigger::ScrollableAreaIdentifier identifier, WheelEventTestTrigger::DeferTestTriggerReason reason) const
+{
+    if (!m_page || !m_page->expectsWheelEventTriggers())
+        return;
+
+    if (const auto& trigger = m_page->testTrigger()) {
+        LOG(WheelEventTestTriggers, "    (!) AsyncScrollingCoordinator::removeTestDeferralForReason: Deferring %p for reason %d.", identifier, reason);
+        trigger->removeTestDeferralForReason(identifier, reason);
+    }
+}
+#endif
+
 } // namespace WebCore
 
 #endif // ENABLE(ASYNC_SCROLLING)
index d9a4c53..e26cd03 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -56,6 +56,11 @@ public:
 
     WEBCORE_EXPORT void scheduleUpdateScrollPositionAfterAsyncScroll(ScrollingNodeID, const FloatPoint&, bool programmaticScroll, SetOrSyncScrollingLayerPosition);
 
+#if PLATFORM(COCOA)
+    void deferTestsForReason(WheelEventTestTrigger::ScrollableAreaIdentifier, WheelEventTestTrigger::DeferTestTriggerReason) const;
+    void removeTestDeferralForReason(WheelEventTestTrigger::ScrollableAreaIdentifier, WheelEventTestTrigger::DeferTestTriggerReason) const;
+#endif
+
 protected:
     WEBCORE_EXPORT AsyncScrollingCoordinator(Page*);
 
index 2410bc4..fd7319a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -35,7 +35,6 @@ namespace WebCore {
 
 ScrollingStateScrollingNode::ScrollingStateScrollingNode(ScrollingStateTree& stateTree, ScrollingNodeType nodeType, ScrollingNodeID nodeID)
     : ScrollingStateNode(nodeType, stateTree, nodeID)
-    , m_requestedScrollPositionRepresentsProgrammaticScroll(false)
 {
 }
 
@@ -53,6 +52,7 @@ ScrollingStateScrollingNode::ScrollingStateScrollingNode(const ScrollingStateScr
 #endif
     , m_scrollableAreaParameters(stateNode.scrollableAreaParameters())
     , m_requestedScrollPositionRepresentsProgrammaticScroll(stateNode.requestedScrollPositionRepresentsProgrammaticScroll())
+    , m_expectsWheelEventTestTrigger(stateNode.expectsWheelEventTestTrigger())
 {
 }
 
@@ -141,6 +141,15 @@ void ScrollingStateScrollingNode::setRequestedScrollPosition(const FloatPoint& r
     setPropertyChanged(RequestedScrollPosition);
 }
 
+void ScrollingStateScrollingNode::setExpectsWheelEventTestTrigger(bool expectsTestTrigger)
+{
+    if (expectsTestTrigger == m_expectsWheelEventTestTrigger)
+        return;
+
+    m_expectsWheelEventTestTrigger = expectsTestTrigger;
+    setPropertyChanged(ExpectsWheelEventTestTrigger);
+}
+
 void ScrollingStateScrollingNode::dumpProperties(TextStream& ts, int indent) const
 {
     if (m_scrollPosition != FloatPoint()) {
index 70a5aaa..0fd0307 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2014-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -51,6 +51,7 @@ public:
         HorizontalSnapOffsets,
         VerticalSnapOffsets,
 #endif
+        ExpectsWheelEventTestTrigger,
     };
 
     const FloatSize& scrollableAreaSize() const { return m_scrollableAreaSize; }
@@ -82,7 +83,10 @@ public:
     const FloatPoint& requestedScrollPosition() const { return m_requestedScrollPosition; }
     bool requestedScrollPositionRepresentsProgrammaticScroll() const { return m_requestedScrollPositionRepresentsProgrammaticScroll; }
     WEBCORE_EXPORT void setRequestedScrollPosition(const FloatPoint&, bool representsProgrammaticScroll);
-    
+
+    bool expectsWheelEventTestTrigger() const { return m_expectsWheelEventTestTrigger; }
+    WEBCORE_EXPORT void setExpectsWheelEventTestTrigger(bool);
+
     virtual void dumpProperties(TextStream&, int indent) const override;
     
 protected:
@@ -101,7 +105,8 @@ private:
     Vector<float> m_verticalSnapOffsets;
 #endif
     ScrollableAreaParameters m_scrollableAreaParameters;
-    bool m_requestedScrollPositionRepresentsProgrammaticScroll;
+    bool m_requestedScrollPositionRepresentsProgrammaticScroll { false };
+    bool m_expectsWheelEventTestTrigger { false };
 };
 
 } // namespace WebCore
index 578caf0..56bc596 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -31,6 +31,7 @@
 #include "PlatformWheelEvent.h"
 #include "Region.h"
 #include "ScrollingCoordinator.h"
+#include "WheelEventTestTrigger.h"
 #include <wtf/Functional.h>
 #include <wtf/HashMap.h>
 #include <wtf/ThreadSafeRefCounted.h>
@@ -100,6 +101,8 @@ public:
     
 #if PLATFORM(MAC)
     virtual void handleWheelEventPhase(PlatformWheelEventPhase) = 0;
+    virtual void deferTestsForReason(WheelEventTestTrigger::ScrollableAreaIdentifier, WheelEventTestTrigger::DeferTestTriggerReason) { }
+    virtual void removeTestDeferralForReason(WheelEventTestTrigger::ScrollableAreaIdentifier, WheelEventTestTrigger::DeferTestTriggerReason) { }
 #endif
 
     // Can be called from any thread. Will update what edges allow rubber-banding.
index d619c32..0eacdba 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -122,6 +122,29 @@ void ThreadedScrollingTree::handleWheelEventPhase(PlatformWheelEventPhase phase)
         scrollingCoordinator->handleWheelEventPhase(phase);
     });
 }
+
+void ThreadedScrollingTree::deferTestsForReason(WheelEventTestTrigger::ScrollableAreaIdentifier identifier, WheelEventTestTrigger::DeferTestTriggerReason reason)
+{
+    if (!m_scrollingCoordinator)
+        return;
+
+    RefPtr<AsyncScrollingCoordinator> scrollingCoordinator = m_scrollingCoordinator;
+    RunLoop::main().dispatch([scrollingCoordinator, identifier, reason] {
+        scrollingCoordinator->deferTestsForReason(identifier, reason);
+    });
+}
+
+void ThreadedScrollingTree::removeTestDeferralForReason(WheelEventTestTrigger::ScrollableAreaIdentifier identifier, WheelEventTestTrigger::DeferTestTriggerReason reason)
+{
+    if (!m_scrollingCoordinator)
+        return;
+    
+    RefPtr<AsyncScrollingCoordinator> scrollingCoordinator = m_scrollingCoordinator;
+    RunLoop::main().dispatch([scrollingCoordinator, identifier, reason] {
+        scrollingCoordinator->removeTestDeferralForReason(identifier, reason);
+    });
+}
+
 #endif
 
 } // namespace WebCore
index 5733823..a7413ef 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -61,7 +61,9 @@ protected:
 
     virtual void scrollingTreeNodeDidScroll(ScrollingNodeID, const FloatPoint& scrollPosition, SetOrSyncScrollingLayerPosition = SyncScrollingLayerPosition) override;
 #if PLATFORM(MAC)
-    virtual void handleWheelEventPhase(PlatformWheelEventPhase) override;
+    void handleWheelEventPhase(PlatformWheelEventPhase) override;
+    void deferTestsForReason(WheelEventTestTrigger::ScrollableAreaIdentifier, WheelEventTestTrigger::DeferTestTriggerReason) override;
+    void removeTestDeferralForReason(WheelEventTestTrigger::ScrollableAreaIdentifier, WheelEventTestTrigger::DeferTestTriggerReason) override;
 #endif
 
 private:
index 49e7de8..1a1ba52 100644 (file)
@@ -79,6 +79,9 @@ private:
 
     bool isAlreadyPinnedInDirectionOfGesture(const PlatformWheelEvent&, ScrollEventAxis);
 
+    void deferTestsForReason(WheelEventTestTrigger::ScrollableAreaIdentifier, WheelEventTestTrigger::DeferTestTriggerReason) const override;
+    void removeTestDeferralForReason(WheelEventTestTrigger::ScrollableAreaIdentifier, WheelEventTestTrigger::DeferTestTriggerReason) const override;
+
 #if ENABLE(CSS_SCROLL_SNAP) && PLATFORM(MAC)
     LayoutUnit scrollOffsetOnAxis(ScrollEventAxis) const override;
     void immediateScrollOnAxis(ScrollEventAxis, float delta) override;
@@ -99,8 +102,9 @@ private:
     RetainPtr<ScrollbarPainter> m_verticalScrollbarPainter;
     RetainPtr<ScrollbarPainter> m_horizontalScrollbarPainter;
     FloatPoint m_probableMainThreadScrollPosition;
-    bool m_lastScrollHadUnfilledPixels;
-    bool m_hadFirstUpdate;
+    bool m_lastScrollHadUnfilledPixels { false };
+    bool m_hadFirstUpdate { false };
+    bool m_expectsWheelEventTestTrigger { false };
 };
 
 } // namespace WebCore
index a545518..7f64dc5 100644 (file)
@@ -29,6 +29,7 @@
 #if ENABLE(ASYNC_SCROLLING) && PLATFORM(MAC)
 
 #import "FrameView.h"
+#import "Logging.h"
 #import "NSScrollerImpDetails.h"
 #import "PlatformWheelEvent.h"
 #import "ScrollingCoordinator.h"
@@ -56,10 +57,8 @@ PassRefPtr<ScrollingTreeFrameScrollingNode> ScrollingTreeFrameScrollingNodeMac::
 ScrollingTreeFrameScrollingNodeMac::ScrollingTreeFrameScrollingNodeMac(ScrollingTree& scrollingTree, ScrollingNodeID nodeID)
     : ScrollingTreeFrameScrollingNode(scrollingTree, nodeID)
     , m_scrollController(*this)
-    , m_verticalScrollbarPainter(0)
-    , m_horizontalScrollbarPainter(0)
-    , m_lastScrollHadUnfilledPixels(false)
-    , m_hadFirstUpdate(false)
+    , m_verticalScrollbarPainter(nullptr)
+    , m_horizontalScrollbarPainter(nullptr)
 {
 }
 
@@ -139,6 +138,9 @@ void ScrollingTreeFrameScrollingNodeMac::updateBeforeChildren(const ScrollingSta
         m_scrollController.updateScrollSnapPoints(ScrollEventAxis::Vertical, convertToLayoutUnits(scrollingStateNode.verticalSnapOffsets()));
 #endif
 
+    if (scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::ExpectsWheelEventTestTrigger))
+        m_expectsWheelEventTestTrigger = scrollingStateNode.expectsWheelEventTestTrigger();
+
     m_hadFirstUpdate = true;
 }
 
@@ -172,6 +174,15 @@ void ScrollingTreeFrameScrollingNodeMac::handleWheelEvent(const PlatformWheelEve
         [m_horizontalScrollbarPainter setUsePresentationValue:NO];
     }
 
+#if ENABLE(CSS_SCROLL_SNAP) || ENABLE(RUBBER_BANDING)
+    if (m_expectsWheelEventTestTrigger) {
+        if (scrollingTree().shouldHandleWheelEventSynchronously(wheelEvent))
+            removeTestDeferralForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(scrollingNodeID()), WheelEventTestTrigger::ScrollingThreadSyncNeeded);
+        else
+            deferTestsForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(scrollingNodeID()), WheelEventTestTrigger::ScrollingThreadSyncNeeded);
+    }
+#endif
+
     m_scrollController.handleWheelEvent(wheelEvent);
     scrollingTree().setOrClearLatchedNode(wheelEvent, scrollingNodeID());
     scrollingTree().handleWheelEventPhase(wheelEvent.phase());
@@ -561,6 +572,24 @@ float ScrollingTreeFrameScrollingNodeMac::pageScaleFactor() const
 }
 #endif
 
+void ScrollingTreeFrameScrollingNodeMac::deferTestsForReason(WheelEventTestTrigger::ScrollableAreaIdentifier identifier, WheelEventTestTrigger::DeferTestTriggerReason reason) const
+{
+    if (!m_expectsWheelEventTestTrigger)
+        return;
+
+    LOG(WheelEventTestTriggers, "  ScrollingTreeFrameScrollingNodeMac::deferTestsForReason: STARTING deferral for %p because of %d", identifier, reason);
+    scrollingTree().deferTestsForReason(identifier, reason);
+}
+    
+void ScrollingTreeFrameScrollingNodeMac::removeTestDeferralForReason(WheelEventTestTrigger::ScrollableAreaIdentifier identifier, WheelEventTestTrigger::DeferTestTriggerReason reason) const
+{
+    if (!m_expectsWheelEventTestTrigger)
+        return;
+    
+    LOG(WheelEventTestTriggers, "   ScrollingTreeFrameScrollingNodeMac::deferTestsForReason: ENDING deferral for %p because of %d", identifier, reason);
+    scrollingTree().removeTestDeferralForReason(identifier, reason);
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(ASYNC_SCROLLING) && PLATFORM(MAC)
index 50884e9..228bc95 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003, 2006, 2013 Apple Inc.  All rights reserved.
+ * Copyright (C) 2003, 2006, 2013, 2015 Apple Inc.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -76,6 +76,7 @@ namespace WebCore {
     M(WebAudio) \
     M(WebGL) \
     M(WebReplay) \
+    M(WheelEventTestTriggers) \
 
 #define DECLARE_LOG_CHANNEL(name) \
     WEBCORE_EXPORT extern WTFLogChannel JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX, name);
index f75cf6e..08339b1 100644 (file)
@@ -192,4 +192,22 @@ void ScrollAnimator::immediateScrollOnAxis(ScrollEventAxis axis, float delta)
 }
 #endif
 
+#if (ENABLE(CSS_SCROLL_SNAP) || ENABLE(RUBBER_BANDING)) && PLATFORM(MAC)
+void ScrollAnimator::deferTestsForReason(WheelEventTestTrigger::ScrollableAreaIdentifier identifier, WheelEventTestTrigger::DeferTestTriggerReason reason) const
+{
+    if (!m_wheelEventTestTrigger)
+        return;
+
+    m_wheelEventTestTrigger->deferTestsForReason(identifier, reason);
+}
+
+void ScrollAnimator::removeTestDeferralForReason(WheelEventTestTrigger::ScrollableAreaIdentifier identifier, WheelEventTestTrigger::DeferTestTriggerReason reason) const
+{
+    if (!m_wheelEventTestTrigger)
+        return;
+    
+    m_wheelEventTestTrigger->removeTestDeferralForReason(identifier, reason);
+}
+#endif
+
 } // namespace WebCore
index 60374d0..b97cc24 100644 (file)
@@ -121,7 +121,8 @@ public:
 
     void setWheelEventTestTrigger(RefPtr<WheelEventTestTrigger>&& testTrigger) { m_wheelEventTestTrigger = testTrigger; }
 #if (ENABLE(CSS_SCROLL_SNAP) || ENABLE(RUBBER_BANDING)) && PLATFORM(MAC)
-    WheelEventTestTrigger* testTrigger() const override { return m_wheelEventTestTrigger.get(); }
+    void deferTestsForReason(WheelEventTestTrigger::ScrollableAreaIdentifier, WheelEventTestTrigger::DeferTestTriggerReason) const override;
+    void removeTestDeferralForReason(WheelEventTestTrigger::ScrollableAreaIdentifier, WheelEventTestTrigger::DeferTestTriggerReason) const override;
 #endif
     
 #if ENABLE(CSS_SCROLL_SNAP) && PLATFORM(MAC)
index 7c1e15e..2eae9c1 100644 (file)
@@ -31,6 +31,7 @@
 #include "FloatPoint.h"
 #include "FloatSize.h"
 #include "ScrollTypes.h"
+#include "WheelEventTestTrigger.h"
 #include <wtf/Noncopyable.h>
 #include <wtf/RunLoop.h>
 
@@ -76,7 +77,8 @@ public:
     // the page to scroll to the nearest boundary point.
     virtual void adjustScrollPositionToBoundsIfNecessary() = 0;
 
-    virtual WheelEventTestTrigger* testTrigger() const { return nullptr; }
+    virtual void deferTestsForReason(WheelEventTestTrigger::ScrollableAreaIdentifier, WheelEventTestTrigger::DeferTestTriggerReason) const { /* Do nothing */ }
+    virtual void removeTestDeferralForReason(WheelEventTestTrigger::ScrollableAreaIdentifier, WheelEventTestTrigger::DeferTestTriggerReason) const { /* Do nothing */ }
 
 #if ENABLE(CSS_SCROLL_SNAP) && PLATFORM(MAC)
     virtual LayoutUnit scrollOffsetOnAxis(ScrollEventAxis) const = 0;
@@ -166,12 +168,12 @@ private:
     RunLoop::Timer<ScrollController> m_verticalScrollSnapTimer;
 #endif
 
-    bool m_inScrollGesture;
-    bool m_momentumScrollInProgress;
-    bool m_ignoreMomentumScrolls;
-    bool m_snapRubberbandTimerIsActive;
+    bool m_inScrollGesture { false };
+    bool m_momentumScrollInProgress { false };
+    bool m_ignoreMomentumScrolls { false };
+    bool m_snapRubberbandTimerIsActive { false };
 };
-
+    
 } // namespace WebCore
 
 #endif // ENABLE(RUBBER_BANDING)
index 43cc37c..f579c00 100644 (file)
@@ -130,10 +130,6 @@ ScrollController::ScrollController(ScrollControllerClient& client)
     , m_horizontalScrollSnapTimer(RunLoop::current(), this, &ScrollController::horizontalScrollSnapTimerFired)
     , m_verticalScrollSnapTimer(RunLoop::current(), this, &ScrollController::verticalScrollSnapTimerFired)
 #endif
-    , m_inScrollGesture(false)
-    , m_momentumScrollInProgress(false)
-    , m_ignoreMomentumScrolls(false)
-    , m_snapRubberbandTimerIsActive(false)
 {
 }
 
@@ -413,8 +409,7 @@ void ScrollController::startSnapRubberbandTimer()
     m_client.startSnapRubberbandTimer();
     m_snapRubberbandTimer.startRepeating(1.0 / 60.0);
 
-    if (auto* trigger = m_client.testTrigger())
-        trigger->deferTestsForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(this), WheelEventTestTrigger::RubberbandInProgress);
+    m_client.deferTestsForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(this), WheelEventTestTrigger::RubberbandInProgress);
 }
 
 void ScrollController::stopSnapRubberbandTimer()
@@ -423,8 +418,7 @@ void ScrollController::stopSnapRubberbandTimer()
     m_snapRubberbandTimer.stop();
     m_snapRubberbandTimerIsActive = false;
     
-    if (auto* trigger = m_client.testTrigger())
-        trigger->removeTestDeferralForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(this), WheelEventTestTrigger::RubberbandInProgress);
+    m_client.removeTestDeferralForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(this), WheelEventTestTrigger::RubberbandInProgress);
 }
 
 void ScrollController::snapRubberBand()
@@ -624,8 +618,7 @@ void ScrollController::startScrollSnapTimer(ScrollEventAxis axis)
     if (!m_horizontalScrollSnapTimer.isActive() && !m_verticalScrollSnapTimer.isActive())
         return;
 
-    if (auto* trigger = m_client.testTrigger())
-        trigger->deferTestsForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(this), WheelEventTestTrigger::ScrollSnapInProgress);
+    m_client.deferTestsForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(this), WheelEventTestTrigger::ScrollSnapInProgress);
 }
 
 void ScrollController::stopScrollSnapTimer(ScrollEventAxis axis)
@@ -637,8 +630,7 @@ void ScrollController::stopScrollSnapTimer(ScrollEventAxis axis)
     if (m_horizontalScrollSnapTimer.isActive() || m_verticalScrollSnapTimer.isActive())
         return;
 
-    if (auto* trigger = m_client.testTrigger())
-        trigger->removeTestDeferralForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(this), WheelEventTestTrigger::ScrollSnapInProgress);
+    m_client.removeTestDeferralForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(this), WheelEventTestTrigger::ScrollSnapInProgress);
 }
 
 void ScrollController::horizontalScrollSnapTimerFired()