Index: third_party/WebKit/Source/core/input/EventHandler.cpp |
diff --git a/third_party/WebKit/Source/core/input/EventHandler.cpp b/third_party/WebKit/Source/core/input/EventHandler.cpp |
index e142c70191dd7dc5ba452ec9985e361c8e69b634..c84317bf5523ee4dc4d7943e64cb1513f5f44cf7 100644 |
--- a/third_party/WebKit/Source/core/input/EventHandler.cpp |
+++ b/third_party/WebKit/Source/core/input/EventHandler.cpp |
@@ -164,6 +164,47 @@ bool shouldRefetchEventTarget(const MouseEventWithHitTestResults& mev) |
return targetNode->isShadowRoot() && isHTMLInputElement(*toShadowRoot(targetNode)->host()); |
} |
+// TODO(bokan): This method can go away once all scrolls happen through the |
+// scroll customization path. |
+void computeScrollChainForSingleNode(Node& node, std::deque<int>& scrollChain) |
+{ |
+ scrollChain.clear(); |
+ |
+ ASSERT(node.layoutObject()); |
+ Element* element = toElement(&node); |
+ |
+ scrollChain.push_front(DOMNodeIds::idForNode(element)); |
+} |
+ |
+void recomputeScrollChain(const LocalFrame& frame, const Node& startNode, |
+ std::deque<int>& scrollChain) |
+{ |
+ scrollChain.clear(); |
+ |
+ ASSERT(startNode.layoutObject()); |
+ LayoutBox* curBox = startNode.layoutObject()->enclosingBox(); |
+ |
+ // Scrolling propagates along the containing block chain. |
+ while (curBox && !curBox->isLayoutView()) { |
+ Node* curNode = curBox->node(); |
+ // FIXME: this should reject more elements, as part of crbug.com/410974. |
+ if (curNode && curNode->isElementNode()) { |
+ Element* curElement = toElement(curNode); |
+ if (curElement == frame.document()->scrollingElement()) |
+ break; |
+ scrollChain.push_front(DOMNodeIds::idForNode(curElement)); |
+ } |
+ curBox = curBox->containingBlock(); |
+ } |
+ // TODO(tdresser): this should sometimes be excluded, as part of crbug.com/410974. |
+ // We need to ensure that the scrollingElement is always part of |
+ // the scroll chain. In quirks mode, when the scrollingElement is |
+ // the body, some elements may use the documentElement as their |
+ // containingBlock, so we ensure the scrollingElement is added |
+ // here. |
+ scrollChain.push_front(DOMNodeIds::idForNode(frame.document()->scrollingElement())); |
+} |
+ |
} // namespace |
using namespace HTMLNames; |
@@ -222,35 +263,6 @@ private: |
Cursor m_cursor; |
}; |
-void recomputeScrollChain(const LocalFrame& frame, const Node& startNode, |
- std::deque<int>& scrollChain) |
-{ |
- scrollChain.clear(); |
- |
- ASSERT(startNode.layoutObject()); |
- LayoutBox* curBox = startNode.layoutObject()->enclosingBox(); |
- |
- // Scrolling propagates along the containing block chain. |
- while (curBox && !curBox->isLayoutView()) { |
- Node* curNode = curBox->node(); |
- // FIXME: this should reject more elements, as part of crbug.com/410974. |
- if (curNode && curNode->isElementNode()) { |
- Element* curElement = toElement(curNode); |
- if (curElement == frame.document()->scrollingElement()) |
- break; |
- scrollChain.push_front(DOMNodeIds::idForNode(curElement)); |
- } |
- curBox = curBox->containingBlock(); |
- } |
- // TODO(tdresser): this should sometimes be excluded, as part of crbug.com/410974. |
- // We need to ensure that the scrollingElement is always part of |
- // the scroll chain. In quirks mode, when the scrollingElement is |
- // the body, some elements may use the documentElement as their |
- // containingBlock, so we ensure the scrollingElement is added |
- // here. |
- scrollChain.push_front(DOMNodeIds::idForNode(frame.document()->scrollingElement())); |
-} |
- |
EventHandler::EventHandler(LocalFrame* frame) |
: m_frame(frame) |
, m_mousePressed(false) |
@@ -611,7 +623,83 @@ void EventHandler::stopAutoscroll() |
controller->stopAutoscroll(); |
} |
-ScrollResult EventHandler::physicalScroll(ScrollGranularity granularity, const FloatSize& delta, Node* startNode, Node** stopNode, bool* consumed) |
+ScrollResult EventHandler::scrollBox(LayoutBox* box, |
+ ScrollGranularity granularity, const FloatSize& delta, |
+ const FloatPoint& position, const FloatSize& velocity, |
+ bool* wasRootScroller) |
+{ |
+ ASSERT(box); |
+ Node* node = box->node(); |
+ Document* document = m_frame->document(); |
+ Element* scrollingElement = document->scrollingElement(); |
+ |
+ bool isRootFrame = !document->ownerElement(); |
+ |
+ // TODO(bokan): If the ViewportScrollCallback is installed on the body, we |
+ // can still hit the HTML element for scrolling in which case it'll bubble |
+ // up to the document node and try to scroll the LayoutView directly. Make |
+ // sure we never scroll the LayoutView like this by manually resetting the |
+ // scroll to happen on the scrolling element. This can also happen in |
+ // QuirksMode when the body is scrollable and scrollingElement == nullptr. |
+ if (node && node->isDocumentNode() && isRootFrame) { |
+ node = scrollingElement |
+ ? scrollingElement |
+ : document->documentElement(); |
+ } |
+ |
+ // If there's no ApplyScroll callback on the element, scroll as usuall in |
+ // the non-scroll-customization case. |
+ if (!node || !node->isElementNode() || !toElement(node)->getApplyScroll()) { |
+ ASSERT(!isRootFrame |
+ || node != scrollingElement |
+ || (!scrollingElement && node != document->documentElement())); |
+ *wasRootScroller = false; |
+ return box->scroll(granularity, delta); |
+ } |
+ |
+ ASSERT(isRootFrame); |
+ |
+ // If there is an ApplyScroll callback, its because we placed one on the |
+ // root scroller to control top controls and overscroll. Invoke a scroll |
+ // using parts of the scroll customization framework on just this element. |
+ computeScrollChainForSingleNode(*node, m_currentScrollChain); |
+ |
+ OwnPtr<ScrollStateData> scrollStateData = adoptPtr(new ScrollStateData()); |
+ scrollStateData->delta_x = delta.width(); |
+ scrollStateData->delta_y = delta.height(); |
+ scrollStateData->position_x = position.x(); |
+ scrollStateData->position_y = position.y(); |
+ // TODO(bokan): delta_granularity is meant to be the number of pixels per |
+ // unit of delta but we can't determine that until we get to the area we'll |
+ // scroll. This is a hack, we stuff the enum into the double value for |
+ // now. |
+ scrollStateData->delta_granularity = static_cast<double>(granularity); |
+ scrollStateData->velocity_x = velocity.width(); |
+ scrollStateData->velocity_y = velocity.height(); |
+ scrollStateData->should_propagate = false; |
+ scrollStateData->is_in_inertial_phase = false; |
+ scrollStateData->from_user_input = true; |
+ scrollStateData->delta_consumed_for_scroll_sequence = false; |
+ ScrollState* scrollState = |
+ ScrollState::create(scrollStateData.release()); |
+ |
+ customizedScroll(*node, *scrollState); |
+ |
+ ScrollResult result( |
+ scrollState->deltaX() != delta.width(), |
+ scrollState->deltaY() != delta.height(), |
+ scrollState->deltaX(), |
+ scrollState->deltaY()); |
+ |
+ *wasRootScroller = true; |
+ m_currentScrollChain.clear(); |
+ |
+ return result; |
+} |
+ |
+ScrollResult EventHandler::physicalScroll(ScrollGranularity granularity, |
+ const FloatSize& delta, const FloatPoint& position, |
+ const FloatSize& velocity, Node* startNode, Node** stopNode, bool* consumed) |
{ |
if (consumed) |
*consumed = false; |
@@ -631,7 +719,15 @@ ScrollResult EventHandler::physicalScroll(ScrollGranularity granularity, const F |
// chain past it. |
bool shouldStopChaining = |
stopNode && *stopNode && curBox->node() == *stopNode; |
- result = curBox->scroll(granularity, delta); |
+ bool wasRootScroller = false; |
+ |
+ result = scrollBox( |
+ curBox, |
+ granularity, |
+ delta, |
+ position, |
+ velocity, |
+ &wasRootScroller); |
if (result.didScroll() && stopNode) |
*stopNode = curBox->node(); |
@@ -641,6 +737,10 @@ ScrollResult EventHandler::physicalScroll(ScrollGranularity granularity, const F |
if (consumed) |
*consumed = true; |
return result; |
+ } else if (wasRootScroller) { |
+ // Don't try to chain past the root scroller, even if there's |
+ // eligible ancestors. |
+ break; |
} |
curBox = curBox->containingBlock(); |
@@ -1894,13 +1994,18 @@ void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEv |
// FIXME: enable scroll customization in this case. See crbug.com/410974. |
bool consumed = false; |
- ScrollResult result = physicalScroll(granularity, delta, startNode, &node, &consumed); |
+ |
+ physicalScroll( |
+ granularity, |
+ delta, |
+ FloatPoint(), |
+ FloatSize(), |
+ startNode, |
+ &node, |
+ &consumed); |
if (consumed) |
wheelEvent->setDefaultHandled(); |
- |
- if (m_frame->isMainFrame()) |
- handleOverscroll(result); |
} |
WebInputEventResult EventHandler::handleGestureShowPress() |
@@ -2393,6 +2498,20 @@ void EventHandler::handleOverscroll(const ScrollResult& scrollResult, const Floa |
} |
} |
+bool EventHandler::isRootScroller(const Node& node) const |
+{ |
+ // The root scroller is the one Element on the page designated to perform |
+ // "viewport actions" like top controls movement and overscroll glow. |
+ |
+ if (!node.isElementNode() || node.document().ownerElement()) |
+ return false; |
+ |
+ Element* scrollingElement = node.document().scrollingElement(); |
+ return scrollingElement |
+ ? toElement(&node) == node.document().scrollingElement() |
+ : toElement(&node) == node.document().documentElement(); |
+} |
+ |
WebInputEventResult EventHandler::handleGestureScrollUpdate(const PlatformGestureEvent& gestureEvent) |
{ |
ASSERT(gestureEvent.type() == PlatformEvent::GestureScrollUpdate); |
@@ -2435,6 +2554,7 @@ WebInputEventResult EventHandler::handleGestureScrollUpdate(const PlatformGestur |
OwnPtr<ScrollStateData> scrollStateData = adoptPtr(new ScrollStateData()); |
scrollStateData->delta_x = delta.width(); |
scrollStateData->delta_y = delta.height(); |
+ scrollStateData->delta_granularity = ScrollByPrecisePixel; |
scrollStateData->velocity_x = velocity.width(); |
scrollStateData->velocity_y = velocity.height(); |
scrollStateData->should_propagate = !gestureEvent.preventPropagation(); |
@@ -2464,17 +2584,20 @@ WebInputEventResult EventHandler::handleGestureScrollUpdate(const PlatformGestur |
stopNode = m_previousGestureScrolledNode.get(); |
bool consumed = false; |
- ScrollResult result = physicalScroll(granularity, delta, node, &stopNode, &consumed); |
+ ScrollResult result = physicalScroll( |
+ granularity, |
+ delta, |
+ FloatPoint(gestureEvent.position()), |
+ velocity, |
+ node, |
+ &stopNode, |
+ &consumed); |
if (gestureEvent.preventPropagation()) |
m_previousGestureScrolledNode = stopNode; |
- if (m_frame->isMainFrame() && (!stopNode || stopNode->layoutObject() == m_frame->view()->layoutView())) { |
- FloatPoint positionInRootFrame = FloatPoint(gestureEvent.position().x(), gestureEvent.position().y()); |
- handleOverscroll(result, positionInRootFrame, velocity); |
- } else { |
+ if (!stopNode || !isRootScroller(*stopNode)) |
resetOverscroll(result.didScrollX, result.didScrollY); |
- } |
if (consumed) |
return WebInputEventResult::HandledSystem; |