Index: third_party/WebKit/Source/core/input/ScrollManager.cpp |
diff --git a/third_party/WebKit/Source/core/input/ScrollManager.cpp b/third_party/WebKit/Source/core/input/ScrollManager.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c6971393ecdca49667bbfb91f0cc808454d91103 |
--- /dev/null |
+++ b/third_party/WebKit/Source/core/input/ScrollManager.cpp |
@@ -0,0 +1,657 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "core/input/ScrollManager.h" |
+ |
+#include "core/dom/DOMNodeIds.h" |
+#include "core/events/GestureEvent.h" |
+#include "core/frame/FrameHost.h" |
+#include "core/frame/FrameView.h" |
+#include "core/frame/TopControls.h" |
+#include "core/html/HTMLFrameOwnerElement.h" |
+#include "core/input/EventHandler.h" |
+#include "core/layout/LayoutPart.h" |
+#include "core/loader/DocumentLoader.h" |
+#include "core/page/AutoscrollController.h" |
+#include "core/page/Page.h" |
+#include "core/page/scrolling/OverscrollController.h" |
+#include "core/page/scrolling/RootScroller.h" |
+#include "core/page/scrolling/ScrollState.h" |
+#include "core/paint/PaintLayer.h" |
+#include "platform/PlatformGestureEvent.h" |
+ |
+ |
+namespace blink { |
+ |
+namespace { |
+ |
+// 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(); |
+ |
+ DCHECK(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(); |
+ |
+ DCHECK(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 |
+ |
+ScrollManager::ScrollManager(LocalFrame* frame) |
+: m_frame(frame) |
+{ |
+ clear(); |
+} |
+ |
+ScrollManager::~ScrollManager() |
+{ |
+} |
+ |
+void ScrollManager::clear() |
+{ |
+ m_lastGestureScrollOverWidget = false; |
+ m_scrollbarHandlingScrollGesture = nullptr; |
+ m_resizeScrollableArea = nullptr; |
+ m_offsetFromResizeCorner = LayoutSize(); |
+ clearGestureScrollState(); |
+} |
+ |
+void ScrollManager::clearGestureScrollState() |
+{ |
+ m_scrollGestureHandlingNode = nullptr; |
+ m_previousGestureScrolledNode = nullptr; |
+ m_deltaConsumedForScrollSequence = false; |
+ m_currentScrollChain.clear(); |
+ |
+ if (FrameHost* host = frameHost()) { |
+ bool resetX = true; |
+ bool resetY = true; |
+ host->overscrollController().resetAccumulated(resetX, resetY); |
+ } |
+} |
+ |
+void ScrollManager::stopAutoscroll() |
+{ |
+ if (AutoscrollController* controller = autoscrollController()) |
+ controller->stopAutoscroll(); |
+} |
+ |
+bool ScrollManager::panScrollInProgress() const |
+{ |
+ return autoscrollController() && autoscrollController()->panScrollInProgress(); |
+} |
+ |
+AutoscrollController* ScrollManager::autoscrollController() const |
+{ |
+ if (Page* page = m_frame->page()) |
+ return &page->autoscrollController(); |
+ return nullptr; |
+} |
+ |
+ScrollResult ScrollManager::physicalScroll(ScrollGranularity granularity, |
+ const FloatSize& delta, const FloatPoint& position, |
+ const FloatSize& velocity, Node* startNode, Node** stopNode, bool* consumed) |
+{ |
+ if (consumed) |
+ *consumed = false; |
+ if (delta.isZero()) |
+ return ScrollResult(); |
+ |
+ Node* node = startNode; |
+ DCHECK(node && node->layoutObject()); |
+ |
+ m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets(); |
+ |
+ ScrollResult result; |
+ |
+ LayoutBox* curBox = node->layoutObject()->enclosingBox(); |
+ while (curBox) { |
+ // If we're at the stopNode, we should try to scroll it but we shouldn't |
+ // chain past it. |
+ bool shouldStopChaining = |
+ stopNode && *stopNode && curBox->node() == *stopNode; |
+ bool wasRootScroller = false; |
+ |
+ result = scrollBox( |
+ curBox, |
+ granularity, |
+ delta, |
+ position, |
+ velocity, |
+ &wasRootScroller); |
+ |
+ if (result.didScroll() && stopNode) |
+ *stopNode = curBox->node(); |
+ |
+ if (result.didScroll() || shouldStopChaining) { |
+ setFrameWasScrolledByUser(); |
+ if (consumed) |
+ *consumed = true; |
+ return result; |
+ } |
+ if (wasRootScroller) { |
+ // Don't try to chain past the root scroller, even if there's |
+ // eligible ancestors. |
+ break; |
+ } |
+ |
+ curBox = curBox->containingBlock(); |
+ } |
+ |
+ return result; |
+} |
+ |
+bool ScrollManager::logicalScroll(ScrollDirection direction, ScrollGranularity granularity, Node* startNode, Node* mousePressNode) |
+{ |
+ Node* node = startNode; |
+ |
+ if (!node) |
+ node = m_frame->document()->focusedElement(); |
+ |
+ if (!node) |
+ node = mousePressNode; |
+ |
+ if ((!node || !node->layoutObject()) && m_frame->view() && !m_frame->view()->layoutViewItem().isNull()) |
+ node = m_frame->view()->layoutViewItem().node(); |
+ |
+ if (!node) |
+ return false; |
+ |
+ m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets(); |
+ |
+ LayoutBox* curBox = node->layoutObject()->enclosingBox(); |
+ while (curBox) { |
+ ScrollDirectionPhysical physicalDirection = toPhysicalDirection( |
+ direction, curBox->isHorizontalWritingMode(), curBox->style()->isFlippedBlocksWritingMode()); |
+ |
+ ScrollResult result = curBox->scroll(granularity, toScrollDelta(physicalDirection, 1)); |
+ |
+ if (result.didScroll()) { |
+ setFrameWasScrolledByUser(); |
+ return true; |
+ } |
+ |
+ curBox = curBox->containingBlock(); |
+ } |
+ |
+ return false; |
+} |
+ |
+// TODO(bokan): This should be merged with logicalScroll assuming |
+// defaultSpaceEventHandler's chaining scroll can be done crossing frames. |
+bool ScrollManager::bubblingScroll(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode, Node* mousePressNode) |
+{ |
+ // 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()->updateStyleAndLayoutIgnorePendingStylesheets(); |
+ // FIXME: enable scroll customization in this case. See crbug.com/410974. |
+ if (logicalScroll(direction, granularity, startingNode, mousePressNode)) |
+ return true; |
+ |
+ Frame* parentFrame = m_frame->tree().parent(); |
+ if (!parentFrame || !parentFrame->isLocalFrame()) |
+ return false; |
+ // FIXME: Broken for OOPI. |
+ return toLocalFrame(parentFrame)->eventHandler().bubblingScroll(direction, granularity, m_frame->deprecatedLocalOwner()); |
+} |
+ |
+ScrollResult ScrollManager::scrollBox(LayoutBox* box, |
+ ScrollGranularity granularity, const FloatSize& delta, |
+ const FloatPoint& position, const FloatSize& velocity, |
+ bool* wasRootScroller) |
+{ |
+ DCHECK(box); |
+ Node* node = box->node(); |
+ |
+ // 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()) { |
+ *wasRootScroller = false; |
+ return box->scroll(granularity, delta); |
+ } |
+ |
+ // Viewport actions should only happen when scrolling an element in the |
+ // main frame. |
+ DCHECK(m_frame->isMainFrame()); |
+ |
+ // 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(std::move(scrollStateData)); |
+ |
+ customizedScroll(*node, *scrollState); |
+ |
+ ScrollResult result( |
+ scrollState->deltaX() != delta.width(), |
+ scrollState->deltaY() != delta.height(), |
+ scrollState->deltaX(), |
+ scrollState->deltaY()); |
+ |
+ *wasRootScroller = true; |
+ m_currentScrollChain.clear(); |
+ |
+ return result; |
+} |
+ |
+void ScrollManager::setFrameWasScrolledByUser() |
+{ |
+ if (DocumentLoader* documentLoader = m_frame->loader().documentLoader()) |
+ documentLoader->initialScrollState().wasScrolledByUser = true; |
+} |
+ |
+void ScrollManager::customizedScroll(const Node& startNode, ScrollState& scrollState) |
+{ |
+ if (scrollState.fullyConsumed()) |
+ return; |
+ |
+ if (scrollState.deltaX() || scrollState.deltaY()) |
+ m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets(); |
+ |
+ if (m_currentScrollChain.empty()) |
+ recomputeScrollChain(*m_frame, startNode, m_currentScrollChain); |
+ scrollState.setScrollChain(m_currentScrollChain); |
+ |
+ scrollState.distributeToScrollChainDescendant(); |
+} |
+ |
+WebInputEventResult ScrollManager::handleGestureScrollBegin(const PlatformGestureEvent& gestureEvent) |
bokan
2016/05/31 19:39:13
To me, this and (related methods) seems like it be
mustaq
2016/05/31 20:20:10
Again, may be a TODO in the class-level comment in
Navid Zolghadr
2016/06/01 17:36:43
I was on the fence on whether to put the scroll ge
|
+{ |
+ Document* document = m_frame->document(); |
+ if (document->layoutViewItem().isNull()) |
+ return WebInputEventResult::NotHandled; |
+ |
+ FrameView* view = m_frame->view(); |
+ if (!view) |
+ return WebInputEventResult::NotHandled; |
+ |
+ // If there's no layoutObject on the node, send the event to the nearest ancestor with a layoutObject. |
+ // Needed for <option> and <optgroup> elements so we can touch scroll <select>s |
+ while (m_scrollGestureHandlingNode && !m_scrollGestureHandlingNode->layoutObject()) |
+ m_scrollGestureHandlingNode = m_scrollGestureHandlingNode->parentOrShadowHostNode(); |
+ |
+ if (!m_scrollGestureHandlingNode) { |
+ if (RuntimeEnabledFeatures::scrollCustomizationEnabled()) |
+ m_scrollGestureHandlingNode = m_frame->document()->documentElement(); |
+ else |
+ return WebInputEventResult::NotHandled; |
+ } |
+ DCHECK(m_scrollGestureHandlingNode); |
+ |
+ passScrollGestureEventToWidget(gestureEvent, m_scrollGestureHandlingNode->layoutObject()); |
+ if (RuntimeEnabledFeatures::scrollCustomizationEnabled()) { |
+ m_currentScrollChain.clear(); |
+ OwnPtr<ScrollStateData> scrollStateData = adoptPtr(new ScrollStateData()); |
+ scrollStateData->position_x = gestureEvent.position().x(); |
+ scrollStateData->position_y = gestureEvent.position().y(); |
+ scrollStateData->is_beginning = true; |
+ scrollStateData->from_user_input = true; |
+ scrollStateData->delta_consumed_for_scroll_sequence = m_deltaConsumedForScrollSequence; |
+ ScrollState* scrollState = ScrollState::create(std::move(scrollStateData)); |
+ customizedScroll(*m_scrollGestureHandlingNode.get(), *scrollState); |
+ } else { |
+ if (m_frame->isMainFrame()) |
+ m_frame->host()->topControls().scrollBegin(); |
+ } |
+ return WebInputEventResult::HandledSystem; |
+} |
+ |
+WebInputEventResult ScrollManager::handleGestureScrollUpdate(const PlatformGestureEvent& gestureEvent) |
+{ |
+ DCHECK_EQ(gestureEvent.type(), PlatformEvent::GestureScrollUpdate); |
+ |
+ // Negate the deltas since the gesture event stores finger movement and |
+ // scrolling occurs in the direction opposite the finger's movement |
+ // direction. e.g. Finger moving up has negative event delta but causes the |
+ // page to scroll down causing positive scroll delta. |
+ FloatSize delta(-gestureEvent.deltaX(), -gestureEvent.deltaY()); |
+ FloatSize velocity(-gestureEvent.velocityX(), -gestureEvent.velocityY()); |
+ if (delta.isZero()) |
+ return WebInputEventResult::NotHandled; |
+ |
+ ScrollGranularity granularity = gestureEvent.deltaUnits(); |
+ Node* node = m_scrollGestureHandlingNode.get(); |
+ |
+ // Scroll customization is only available for touch. |
+ bool handleScrollCustomization = RuntimeEnabledFeatures::scrollCustomizationEnabled() && gestureEvent.source() == PlatformGestureSourceTouchscreen; |
+ if (node) { |
+ LayoutObject* layoutObject = node->layoutObject(); |
+ if (!layoutObject) |
+ return WebInputEventResult::NotHandled; |
+ |
+ // Try to send the event to the correct view. |
+ WebInputEventResult result = passScrollGestureEventToWidget(gestureEvent, layoutObject); |
+ if (result != WebInputEventResult::NotHandled) { |
+ if (gestureEvent.preventPropagation() |
+ && !RuntimeEnabledFeatures::scrollCustomizationEnabled()) { |
+ // This is an optimization which doesn't apply with |
+ // scroll customization enabled. |
+ m_previousGestureScrolledNode = m_scrollGestureHandlingNode; |
+ } |
+ // FIXME: we should allow simultaneous scrolling of nested |
+ // iframes along perpendicular axes. See crbug.com/466991. |
+ m_deltaConsumedForScrollSequence = true; |
+ return result; |
+ } |
+ |
+ if (handleScrollCustomization) { |
+ 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(); |
+ scrollStateData->is_in_inertial_phase = gestureEvent.inertialPhase() == ScrollInertialPhaseMomentum; |
+ scrollStateData->from_user_input = true; |
+ scrollStateData->delta_consumed_for_scroll_sequence = m_deltaConsumedForScrollSequence; |
+ ScrollState* scrollState = ScrollState::create(std::move(scrollStateData)); |
+ if (m_previousGestureScrolledNode) { |
+ // The ScrollState needs to know what the current |
+ // native scrolling element is, so that for an |
+ // inertial scroll that shouldn't propagate, only the |
+ // currently scrolling element responds. |
+ DCHECK(m_previousGestureScrolledNode->isElementNode()); |
+ scrollState->setCurrentNativeScrollingElement(toElement(m_previousGestureScrolledNode.get())); |
+ } |
+ customizedScroll(*node, *scrollState); |
+ m_previousGestureScrolledNode = scrollState->currentNativeScrollingElement(); |
+ m_deltaConsumedForScrollSequence = scrollState->deltaConsumedForScrollSequence(); |
+ if (scrollState->deltaX() != delta.width() |
+ || scrollState->deltaY() != delta.height()) { |
+ setFrameWasScrolledByUser(); |
+ return WebInputEventResult::HandledSystem; |
+ } |
+ } else { |
+ Node* stopNode = nullptr; |
+ if (gestureEvent.preventPropagation()) |
+ stopNode = m_previousGestureScrolledNode.get(); |
+ |
+ bool consumed = false; |
+ ScrollResult result = physicalScroll( |
+ granularity, |
+ delta, |
+ FloatPoint(gestureEvent.position()), |
+ velocity, |
+ node, |
+ &stopNode, |
+ &consumed); |
+ |
+ if (gestureEvent.preventPropagation()) |
+ m_previousGestureScrolledNode = stopNode; |
+ |
+ if ((!stopNode || !isRootScroller(*stopNode)) && frameHost()) { |
+ frameHost()->overscrollController().resetAccumulated( |
+ result.didScrollX, result.didScrollY); |
+ } |
+ |
+ if (consumed) |
+ return WebInputEventResult::HandledSystem; |
+ } |
+ } |
+ |
+ return WebInputEventResult::NotHandled; |
+} |
+ |
+WebInputEventResult ScrollManager::handleGestureScrollEnd(const PlatformGestureEvent& gestureEvent) |
+{ |
+ Node* node = m_scrollGestureHandlingNode; |
+ |
+ if (node) { |
+ passScrollGestureEventToWidget(gestureEvent, node->layoutObject()); |
+ if (RuntimeEnabledFeatures::scrollCustomizationEnabled()) { |
+ OwnPtr<ScrollStateData> scrollStateData = adoptPtr(new ScrollStateData()); |
+ scrollStateData->is_ending = true; |
+ scrollStateData->is_in_inertial_phase = gestureEvent.inertialPhase() == ScrollInertialPhaseMomentum; |
+ scrollStateData->from_user_input = true; |
+ scrollStateData->is_direct_manipulation = true; |
+ scrollStateData->delta_consumed_for_scroll_sequence = m_deltaConsumedForScrollSequence; |
+ ScrollState* scrollState = ScrollState::create(std::move(scrollStateData)); |
+ customizedScroll(*node, *scrollState); |
+ } |
+ } |
+ |
+ clearGestureScrollState(); |
+ return WebInputEventResult::NotHandled; |
+} |
+ |
+FrameHost* ScrollManager::frameHost() const |
+{ |
+ if (!m_frame->page()) |
+ return nullptr; |
+ |
+ return &m_frame->page()->frameHost(); |
+} |
+ |
+WebInputEventResult ScrollManager::passScrollGestureEventToWidget(const PlatformGestureEvent& gestureEvent, LayoutObject* layoutObject) |
+{ |
+ DCHECK(gestureEvent.isScrollEvent()); |
+ |
+ if (!m_lastGestureScrollOverWidget || !layoutObject || !layoutObject->isLayoutPart()) |
+ return WebInputEventResult::NotHandled; |
+ |
+ Widget* widget = toLayoutPart(layoutObject)->widget(); |
+ |
+ if (!widget || !widget->isFrameView()) |
+ return WebInputEventResult::NotHandled; |
+ |
+ return toFrameView(widget)->frame().eventHandler().handleGestureScrollEvent(gestureEvent); |
+} |
+ |
+bool ScrollManager::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 (!frameHost() || !frameHost()->rootScroller()) |
+ return false; |
+ |
+ return frameHost()->rootScroller()->get() == &node; |
+} |
+ |
+ |
+WebInputEventResult ScrollManager::handleGestureScrollEvent(const PlatformGestureEvent& gestureEvent) |
+{ |
+ Node* eventTarget = nullptr; |
+ Scrollbar* scrollbar = nullptr; |
+ if (gestureEvent.type() != PlatformEvent::GestureScrollBegin) { |
+ scrollbar = m_scrollbarHandlingScrollGesture.get(); |
+ eventTarget = m_scrollGestureHandlingNode.get(); |
+ } |
+ |
+ if (!eventTarget) { |
+ Document* document = m_frame->document(); |
+ if (document->layoutViewItem().isNull()) |
+ return WebInputEventResult::NotHandled; |
+ |
+ FrameView* view = m_frame->view(); |
+ LayoutPoint viewPoint = view->rootFrameToContents(gestureEvent.position()); |
+ HitTestRequest request(HitTestRequest::ReadOnly); |
+ HitTestResult result(request, viewPoint); |
+ document->layoutViewItem().hitTest(result); |
+ |
+ eventTarget = result.innerNode(); |
+ |
+ m_lastGestureScrollOverWidget = result.isOverWidget(); |
+ m_scrollGestureHandlingNode = eventTarget; |
+ m_previousGestureScrolledNode = nullptr; |
+ |
+ if (!scrollbar) |
+ scrollbar = result.scrollbar(); |
+ } |
+ |
+ if (scrollbar) { |
+ bool shouldUpdateCapture = false; |
+ if (scrollbar->gestureEvent(gestureEvent, &shouldUpdateCapture)) { |
+ if (shouldUpdateCapture) |
+ m_scrollbarHandlingScrollGesture = scrollbar; |
+ return WebInputEventResult::HandledSuppressed; |
+ } |
+ m_scrollbarHandlingScrollGesture = nullptr; |
+ } |
+ |
+ if (eventTarget) { |
+ if (handleScrollGestureOnResizer(eventTarget, gestureEvent)) |
+ return WebInputEventResult::HandledSuppressed; |
+ |
+ GestureEvent* gestureDomEvent = GestureEvent::create(eventTarget->document().domWindow(), gestureEvent); |
+ if (gestureDomEvent) { |
+ DispatchEventResult gestureDomEventResult = eventTarget->dispatchEvent(gestureDomEvent); |
+ if (gestureDomEventResult != DispatchEventResult::NotCanceled) { |
+ DCHECK(gestureDomEventResult != DispatchEventResult::CanceledByEventHandler); |
+ return EventHandler::toWebInputEventResult(gestureDomEventResult); |
+ } |
+ } |
+ } |
+ |
+ switch (gestureEvent.type()) { |
+ case PlatformEvent::GestureScrollBegin: |
+ return handleGestureScrollBegin(gestureEvent); |
+ case PlatformEvent::GestureScrollUpdate: |
+ return handleGestureScrollUpdate(gestureEvent); |
+ case PlatformEvent::GestureScrollEnd: |
+ return handleGestureScrollEnd(gestureEvent); |
+ case PlatformEvent::GestureFlingStart: |
+ case PlatformEvent::GesturePinchBegin: |
+ case PlatformEvent::GesturePinchEnd: |
+ case PlatformEvent::GesturePinchUpdate: |
+ return WebInputEventResult::NotHandled; |
+ default: |
+ NOTREACHED(); |
+ return WebInputEventResult::NotHandled; |
+ } |
+} |
+ |
+bool ScrollManager::isScrollbarHandlingGestures() const |
+{ |
+ return m_scrollbarHandlingScrollGesture.get(); |
+} |
+ |
+bool ScrollManager::handleScrollGestureOnResizer(Node* eventTarget, const PlatformGestureEvent& gestureEvent) |
+{ |
+ if (gestureEvent.type() == PlatformEvent::GestureScrollBegin) { |
+ PaintLayer* layer = eventTarget->layoutObject() ? eventTarget->layoutObject()->enclosingLayer() : nullptr; |
+ IntPoint p = m_frame->view()->rootFrameToContents(gestureEvent.position()); |
+ if (layer && layer->getScrollableArea() && layer->getScrollableArea()->isPointInResizeControl(p, ResizerForTouch)) { |
+ m_resizeScrollableArea = layer->getScrollableArea(); |
+ m_resizeScrollableArea->setInResizeMode(true); |
+ m_offsetFromResizeCorner = LayoutSize(m_resizeScrollableArea->offsetFromResizeCorner(p)); |
+ return true; |
+ } |
+ } else if (gestureEvent.type() == PlatformEvent::GestureScrollUpdate) { |
+ if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode()) { |
+ m_resizeScrollableArea->resize(gestureEvent, m_offsetFromResizeCorner); |
+ return true; |
+ } |
+ } else if (gestureEvent.type() == PlatformEvent::GestureScrollEnd) { |
+ if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode()) { |
+ m_resizeScrollableArea->setInResizeMode(false); |
+ m_resizeScrollableArea = nullptr; |
+ return false; |
+ } |
+ } |
+ |
+ return false; |
+} |
+ |
+bool ScrollManager::inResizeMode() const |
+{ |
+ return m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode(); |
+} |
+ |
+void ScrollManager::resize(const PlatformEvent& evt) |
+{ |
+ m_resizeScrollableArea->resize(evt, m_offsetFromResizeCorner); |
+} |
+ |
+void ScrollManager::clearResizeScrollableArea(bool shouldNotBeNull) |
+{ |
+ if (shouldNotBeNull) |
+ DCHECK(m_resizeScrollableArea); |
+ |
+ if (m_resizeScrollableArea) |
+ m_resizeScrollableArea->setInResizeMode(false); |
+ m_resizeScrollableArea = nullptr; |
+} |
+ |
+void ScrollManager::setResizeScrollableArea(PaintLayer* layer, IntPoint p) |
+{ |
+ m_resizeScrollableArea = layer->getScrollableArea(); |
+ m_resizeScrollableArea->setInResizeMode(true); |
+ m_offsetFromResizeCorner = LayoutSize(m_resizeScrollableArea->offsetFromResizeCorner(p)); |
+} |
+ |
+bool ScrollManager::canHandleGestureEvent(const GestureEventWithHitTestResults& targetedEvent) |
+{ |
+ Scrollbar* scrollbar = targetedEvent.hitTestResult().scrollbar(); |
+ |
+ if (scrollbar) { |
+ bool shouldUpdateCapture = false; |
+ if (scrollbar->gestureEvent(targetedEvent.event(), &shouldUpdateCapture)) { |
+ if (shouldUpdateCapture) |
+ m_scrollbarHandlingScrollGesture = scrollbar; |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
+DEFINE_TRACE(ScrollManager) |
+{ |
+ visitor->trace(m_frame); |
+ visitor->trace(m_scrollGestureHandlingNode); |
+ visitor->trace(m_previousGestureScrolledNode); |
+ visitor->trace(m_scrollbarHandlingScrollGesture); |
+ visitor->trace(m_resizeScrollableArea); |
+} |
+ |
+} // namespace blink |