Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(307)

Unified Diff: third_party/WebKit/Source/core/input/ScrollManager.cpp

Issue 2010133003: Add ScrollManager class (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698