Index: Source/core/page/EventHandler.cpp |
diff --git a/Source/core/page/EventHandler.cpp b/Source/core/page/EventHandler.cpp |
index b8548bb6582db3a974f41d39422710f492c3ee7f..cd2f34027eed7121f923fb6735bf71868437409f 100644 |
--- a/Source/core/page/EventHandler.cpp |
+++ b/Source/core/page/EventHandler.cpp |
@@ -80,6 +80,7 @@ |
#include "core/page/Page.h" |
#include "core/page/SpatialNavigation.h" |
#include "core/page/TouchAdjustment.h" |
+#include "core/page/scrolling/ScrollState.h" |
#include "core/svg/SVGDocumentExtensions.h" |
#include "platform/PlatformGestureEvent.h" |
#include "platform/PlatformKeyboardEvent.h" |
@@ -195,6 +196,32 @@ static inline bool shouldRefetchEventTarget(const MouseEventWithHitTestResults& |
return targetNode->isShadowRoot() && isHTMLInputElement(*toShadowRoot(targetNode)->host()); |
} |
+void recomputeScrollChain(LocalFrame* const frame, Node* scrollGestureHandlingNode, WillBeHeapVector<RefPtrWillBeMember<Element>>& scrollChain) |
+{ |
+ ASSERT(frame); |
+ ASSERT(scrollGestureHandlingNode); |
+ scrollChain.clear(); |
+ bool rootLayerScrolls = frame->settings() && frame->settings()->rootLayerScrolls(); |
+ LayoutBox* curBox = scrollGestureHandlingNode->renderer()->enclosingBox(); |
+ |
+ bool includesDocument = false; |
+ while (curBox && (rootLayerScrolls || !curBox->isLayoutView())) { |
+ Node* curNode = curBox->node(); |
+ curBox = curBox->containingBlock(); |
+ |
+ includesDocument = includesDocument || curNode == frame->document()->documentElement(); |
+ |
+ // FIXME: this should reject more elements. |
+ if (!curNode || !curNode->isElementNode()) |
+ continue; |
+ ASSERT(curNode->isElementNode()); |
+ scrollChain.prepend(toElement(curNode)); |
+ } |
+ |
+ if (!includesDocument) |
+ scrollChain.prepend(frame->document()->documentElement()); |
+} |
+ |
EventHandler::EventHandler(LocalFrame* frame) |
: m_frame(frame) |
, m_mousePressed(false) |
@@ -222,6 +249,7 @@ EventHandler::EventHandler(LocalFrame* frame) |
, m_longTapShouldInvokeContextMenu(false) |
, m_activeIntervalTimer(this, &EventHandler::activeIntervalTimerFired) |
, m_lastShowPressTimestamp(0) |
+ , m_scrollLockedToElement(false) |
{ |
} |
@@ -250,6 +278,8 @@ DEFINE_TRACE(EventHandler) |
visitor->trace(m_scrollGestureHandlingNode); |
visitor->trace(m_previousGestureScrolledNode); |
visitor->trace(m_lastDeferredTapElement); |
+ visitor->trace(m_currentNativeScrollingElement); |
+ visitor->trace(m_currentScrollChain); |
#endif |
} |
@@ -943,11 +973,44 @@ bool EventHandler::scroll(ScrollDirection direction, ScrollGranularity granulari |
return false; |
} |
+// FIXME: handle flipped direction (toPhysicalDirection) and granularity. |
+bool EventHandler::customizedScroll(ScrollState* scrollState, Node* startNode) |
+{ |
+ Node* node = startNode; |
+ |
+ if (!node) |
+ node = m_frame->document()->focusedElement(); |
+ |
+ if (!node) |
+ node = m_mousePressNode.get(); |
+ |
+ if (!node || !node->renderer()) |
+ return false; |
+ |
+ if (!m_currentScrollChain.size() && m_scrollGestureHandlingNode.get()) |
+ recomputeScrollChain(m_frame, m_scrollGestureHandlingNode.get(), m_currentScrollChain); |
+ scrollState->setScrollChain(m_currentScrollChain); |
+ |
+ double deltaX = scrollState->deltaX(); |
+ double deltaY = scrollState->deltaY(); |
+ scrollState->distributeToScrollChainDescendant(); |
+ bool didScroll = deltaX != scrollState->deltaX() || deltaY != scrollState->deltaY(); |
+ |
+ if (didScroll) { |
+ if (scrollState->fromUserInput()) |
+ setFrameWasScrolledByUser(); |
+ return true; |
+ } |
+ |
+ return false; |
+} |
+ |
bool EventHandler::bubblingScroll(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode) |
{ |
// The layout needs to be up to date to determine if we can scroll. We may be |
// here because of an onLoad event, in which case the final layout hasn't been performed yet. |
m_frame->document()->updateLayoutIgnorePendingStylesheets(); |
+ // FIXME: enable scroll customization in this case. |
if (scroll(direction, granularity, startingNode)) |
return true; |
LocalFrame* frame = m_frame; |
@@ -2062,6 +2125,8 @@ void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEv |
// Break up into two scrolls if we need to. Diagonal movement on |
// a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set). |
+ |
+ // FIXME: enable scroll customization in this case. |
if (scroll(ScrollRight, granularity, startNode, &stopNode, wheelEvent->deltaX(), roundedIntPoint(wheelEvent->absoluteLocation()))) |
wheelEvent->setDefaultHandled(); |
@@ -2454,9 +2519,19 @@ bool EventHandler::handleGestureScrollEnd(const PlatformGestureEvent& gestureEve |
RefPtrWillBeRawPtr<Node> node = m_scrollGestureHandlingNode; |
clearGestureScrollNodes(); |
- if (node) |
- passScrollGestureEventToWidget(gestureEvent, node->renderer()); |
+ if (node) { |
+ if (passScrollGestureEventToWidget(gestureEvent, node->renderer())) |
+ return false; |
+ if (RuntimeEnabledFeatures::scrollCustomizationEnabled()) { |
+ ScrollState* scrollState = ScrollState::create(gestureEvent.deltaX(), gestureEvent.deltaY(), |
+ 0, gestureEvent.velocityX(), gestureEvent.velocityY(), gestureEvent.inertial(), true, true); |
+ customizedScroll(scrollState, node.get()); |
+ } |
+ } |
+ m_currentNativeScrollingElement = nullptr; |
+ m_scrollLockedToElement = false; |
+ m_currentScrollChain.clear(); |
return false; |
} |
@@ -2475,22 +2550,26 @@ bool EventHandler::handleGestureScrollBegin(const PlatformGestureEvent& gestureE |
while (m_scrollGestureHandlingNode && !m_scrollGestureHandlingNode->renderer()) |
m_scrollGestureHandlingNode = m_scrollGestureHandlingNode->parentOrShadowHostNode(); |
- if (!m_scrollGestureHandlingNode) |
- return false; |
+ if (!m_scrollGestureHandlingNode) { |
+ if (RuntimeEnabledFeatures::scrollCustomizationEnabled()) |
+ m_scrollGestureHandlingNode = m_frame->document()->documentElement(); |
+ else |
+ return false; |
+ } |
passScrollGestureEventToWidget(gestureEvent, m_scrollGestureHandlingNode->renderer()); |
if (m_frame->isMainFrame()) |
m_frame->host()->topControls().scrollBegin(); |
- return true; |
-} |
+ if (!RuntimeEnabledFeatures::scrollCustomizationEnabled()) |
+ return true; |
-static bool scrollAreaOnBothAxes(const FloatSize& delta, ScrollableArea& view) |
-{ |
- bool scrolledHorizontal = view.scroll(ScrollLeft, ScrollByPrecisePixel, delta.width()); |
- bool scrolledVertical = view.scroll(ScrollUp, ScrollByPrecisePixel, delta.height()); |
- return scrolledHorizontal || scrolledVertical; |
+ m_currentNativeScrollingElement = nullptr; |
+ m_scrollLockedToElement = false; |
+ |
+ recomputeScrollChain(m_frame, m_scrollGestureHandlingNode.get(), m_currentScrollChain); |
+ return true; |
} |
bool EventHandler::handleGestureScrollUpdate(const PlatformGestureEvent& gestureEvent) |
@@ -2515,28 +2594,43 @@ bool EventHandler::handleGestureScrollUpdate(const PlatformGestureEvent& gesture |
if (passScrollGestureEventToWidget(gestureEvent, renderer)) { |
if (gestureEvent.preventPropagation()) |
m_previousGestureScrolledNode = m_scrollGestureHandlingNode; |
- |
+ m_scrollLockedToElement = true; |
return true; |
} |
- |
if (gestureEvent.preventPropagation()) |
stopNode = m_previousGestureScrolledNode.get(); |
- // First try to scroll the closest scrollable LayoutBox ancestor of |node|. |
- ScrollGranularity granularity = ScrollByPixel; |
- bool horizontalScroll = scroll(ScrollLeft, granularity, node, &stopNode, delta.width()); |
- bool verticalScroll = scroll(ScrollUp, granularity, node, &stopNode, delta.height()); |
+ bool scrolled = false; |
+ if (RuntimeEnabledFeatures::scrollCustomizationEnabled()) { |
+ ScrollState* scrollState = ScrollState::create(gestureEvent.deltaX(), gestureEvent.deltaY(), |
+ 0, gestureEvent.velocityX(), gestureEvent.velocityY(), gestureEvent.inertial(), false, true, |
+ !gestureEvent.preventPropagation()); |
+ scrollState->setCurrentNativeScrollingElement(m_currentNativeScrollingElement.get()); |
+ scrollState->setScrollLockedToElement(m_scrollLockedToElement); |
+ scrolled = customizedScroll(scrollState, node); |
+ m_currentNativeScrollingElement = scrollState->currentNativeScrollingElement(); |
+ m_scrollLockedToElement = scrollState->scrollLockedToElement(); |
+ } else { |
+ // First try to scroll the closest scrollable LayoutBox ancestor of |node|. |
+ ScrollGranularity granularity = ScrollByPixel; |
+ scrolled = scroll(ScrollLeft, granularity, node, &stopNode, delta.width()) |
+ | scroll(ScrollUp, granularity, node, &stopNode, delta.height()); |
+ } |
if (gestureEvent.preventPropagation()) |
m_previousGestureScrolledNode = stopNode; |
- if (horizontalScroll || verticalScroll) { |
+ if (scrolled) { |
setFrameWasScrolledByUser(); |
return true; |
} |
} |
+ |
+ if (RuntimeEnabledFeatures::scrollCustomizationEnabled()) |
+ return false; |
+ |
// If this is main frame, allow top controls to scroll first and update |
// delta accordingly |
bool consumed = false; |
@@ -2554,16 +2648,7 @@ bool EventHandler::handleGestureScrollUpdate(const PlatformGestureEvent& gesture |
if (!view) |
return consumed; |
- if (scrollAreaOnBothAxes(delta, *view)) { |
- setFrameWasScrolledByUser(); |
- return true; |
- } |
- |
- // If this is the main frame and it didn't scroll, propagate up to the pinch viewport. |
- if (!m_frame->settings()->pinchVirtualViewportEnabled() || !m_frame->isMainFrame()) |
- return consumed; |
- |
- if (scrollAreaOnBothAxes(delta, m_frame->host()->pinchViewport())) { |
+ if (m_frame->scrollByDelta(delta)) { |
setFrameWasScrolledByUser(); |
return true; |
} |
@@ -3404,6 +3489,7 @@ void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event) |
return; |
ScrollDirection direction = event->shiftKey() ? ScrollBlockDirectionBackward : ScrollBlockDirectionForward; |
+ // FIXME: enable scroll customization in this case. |
if (scroll(direction, ScrollByPage)) { |
event->setDefaultHandled(); |
return; |