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

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

Issue 2137113002: Create GestureManager class and move related logic (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Make GestureManager friend of EventHandler Created 4 years, 5 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/GestureManager.cpp
diff --git a/third_party/WebKit/Source/core/input/GestureManager.cpp b/third_party/WebKit/Source/core/input/GestureManager.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6ea4e40daedfc66c5c96ff6b065128a7785bb149
--- /dev/null
+++ b/third_party/WebKit/Source/core/input/GestureManager.cpp
@@ -0,0 +1,318 @@
+// 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/GestureManager.h"
+
+#include "core/dom/Document.h"
+#include "core/editing/SelectionController.h"
+#include "core/events/GestureEvent.h"
+#include "core/frame/FrameHost.h"
+#include "core/frame/FrameView.h"
+#include "core/frame/Settings.h"
+#include "core/frame/VisualViewport.h"
+#include "core/input/EventHandler.h"
+#include "core/page/ChromeClient.h"
+#include "core/page/Page.h"
+
+namespace blink {
+
+GestureManager::GestureManager(LocalFrame* frame, ScrollManager* scrollManager,
+ PointerEventManager* pointerEventManager,
+ SelectionController* selectionController)
+: m_frame(frame)
+, m_scrollManager(scrollManager)
dtapuska 2016/07/13 12:19:28 This looks like a wacky indent. Is this what git c
Navid Zolghadr 2016/07/13 16:28:14 Done.
+, m_pointerEventManager(pointerEventManager)
+, m_selectionController(selectionController)
+{
+ clear();
+}
+
+GestureManager::~GestureManager()
+{
+}
+
+void GestureManager::clear()
+{
+ m_suppressMouseEventsFromGestures = false;
+ m_longTapShouldInvokeContextMenu = false;
+ m_lastShowPressTimestamp = 0;
+}
+
+DEFINE_TRACE(GestureManager)
+{
+ visitor->trace(m_frame);
+ visitor->trace(m_selectionController);
+}
+
+HitTestRequest::HitTestRequestType GestureManager::getHitTypeForGestureType(PlatformEvent::EventType type)
+{
+ HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEvent;
+ switch (type) {
+ case PlatformEvent::GestureShowPress:
+ case PlatformEvent::GestureTapUnconfirmed:
+ return hitType | HitTestRequest::Active;
+ case PlatformEvent::GestureTapDownCancel:
+ // A TapDownCancel received when no element is active shouldn't really be changing hover state.
+ if (!m_frame->document()->activeHoverElement())
+ hitType |= HitTestRequest::ReadOnly;
+ return hitType | HitTestRequest::Release;
+ case PlatformEvent::GestureTap:
+ return hitType | HitTestRequest::Release;
+ case PlatformEvent::GestureTapDown:
+ case PlatformEvent::GestureLongPress:
+ case PlatformEvent::GestureLongTap:
+ case PlatformEvent::GestureTwoFingerTap:
+ // FIXME: Shouldn't LongTap and TwoFingerTap clear the Active state?
+ return hitType | HitTestRequest::Active | HitTestRequest::ReadOnly;
+ default:
+ NOTREACHED();
+ return hitType | HitTestRequest::Active | HitTestRequest::ReadOnly;
+ }
+}
+
+WebInputEventResult GestureManager::handleGestureEventInFrame(const GestureEventWithHitTestResults& targetedEvent)
+{
+ DCHECK(!targetedEvent.event().isScrollEvent());
+
+ Node* eventTarget = targetedEvent.hitTestResult().innerNode();
+ const PlatformGestureEvent& gestureEvent = targetedEvent.event();
+
+ if (m_scrollManager->canHandleGestureEvent(targetedEvent))
+ return WebInputEventResult::HandledSuppressed;
+
+ if (eventTarget) {
+ 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::GestureTapDown:
+ return handleGestureTapDown(targetedEvent);
+ case PlatformEvent::GestureTap:
+ return handleGestureTap(targetedEvent);
+ case PlatformEvent::GestureShowPress:
+ return handleGestureShowPress();
+ case PlatformEvent::GestureLongPress:
+ return handleGestureLongPress(targetedEvent);
+ case PlatformEvent::GestureLongTap:
+ return handleGestureLongTap(targetedEvent);
+ case PlatformEvent::GestureTwoFingerTap:
+ return m_frame->eventHandler().sendContextMenuEventForGesture(targetedEvent);
+ case PlatformEvent::GesturePinchBegin:
+ case PlatformEvent::GesturePinchEnd:
+ case PlatformEvent::GesturePinchUpdate:
+ case PlatformEvent::GestureTapDownCancel:
+ case PlatformEvent::GestureTapUnconfirmed:
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ return WebInputEventResult::NotHandled;
+}
+
+WebInputEventResult GestureManager::handleGestureTapDown(const GestureEventWithHitTestResults& targetedEvent)
+{
+ m_suppressMouseEventsFromGestures =
+ m_pointerEventManager->primaryPointerdownCanceled(targetedEvent.event().uniqueTouchEventId());
+ return WebInputEventResult::NotHandled;
+}
+
+WebInputEventResult GestureManager::handleGestureTap(const GestureEventWithHitTestResults& targetedEvent)
+{
+ FrameView* frameView(m_frame->view());
+ const PlatformGestureEvent& gestureEvent = targetedEvent.event();
+ HitTestRequest::HitTestRequestType hitType = getHitTypeForGestureType(gestureEvent.type());
+ uint64_t preDispatchDomTreeVersion = m_frame->document()->domTreeVersion();
+ uint64_t preDispatchStyleVersion = m_frame->document()->styleVersion();
+
+ UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
+
+ HitTestResult currentHitTest = targetedEvent.hitTestResult();
+
+ // We use the adjusted position so the application isn't surprised to see a event with
+ // co-ordinates outside the target's bounds.
+ IntPoint adjustedPoint = frameView->rootFrameToContents(gestureEvent.position());
+
+ const unsigned modifiers = gestureEvent.getModifiers();
+
+ if (!m_suppressMouseEventsFromGestures) {
+ PlatformMouseEvent fakeMouseMove(gestureEvent.position(), gestureEvent.globalPosition(),
+ NoButton, PlatformEvent::MouseMoved, /* clickCount */ 0,
+ static_cast<PlatformEvent::Modifiers>(modifiers),
+ PlatformMouseEvent::FromTouch, gestureEvent.timestamp(), WebPointerProperties::PointerType::Mouse);
+ m_frame->eventHandler().dispatchMouseEvent(EventTypeNames::mousemove, currentHitTest.innerNode(), 0, fakeMouseMove);
+ }
+
+ // Do a new hit-test in case the mousemove event changed the DOM.
+ // Note that if the original hit test wasn't over an element (eg. was over a scrollbar) we
+ // don't want to re-hit-test because it may be in the wrong frame (and there's no way the page
+ // could have seen the event anyway).
+ // Also note that the position of the frame may have changed, so we need to recompute the content
+ // co-ordinates (updating layout/style as hitTestResultAtPoint normally would).
+ // FIXME: Use a hit-test cache to avoid unnecessary hit tests. http://crbug.com/398920
+ if (currentHitTest.innerNode()) {
+ LocalFrame* mainFrame = m_frame->localFrameRoot();
+ if (mainFrame && mainFrame->view())
+ mainFrame->view()->updateLifecycleToCompositingCleanPlusScrolling();
+ adjustedPoint = frameView->rootFrameToContents(gestureEvent.position());
+ currentHitTest = EventHandler::hitTestResultInFrame(m_frame, adjustedPoint, hitType);
+ }
+
+ // Capture data for showUnhandledTapUIIfNeeded.
+ Node* tappedNode = currentHitTest.innerNode();
+ IntPoint tappedPosition = gestureEvent.position();
+ Node* tappedNonTextNode = tappedNode;
+
+ if (tappedNonTextNode && tappedNonTextNode->isTextNode())
+ tappedNonTextNode = FlatTreeTraversal::parent(*tappedNonTextNode);
+
+ m_frame->eventHandler().setClickNode(tappedNonTextNode);
+
+ PlatformMouseEvent fakeMouseDown(gestureEvent.position(), gestureEvent.globalPosition(),
+ LeftButton, PlatformEvent::MousePressed, gestureEvent.tapCount(),
+ static_cast<PlatformEvent::Modifiers>(modifiers | PlatformEvent::LeftButtonDown),
+ PlatformMouseEvent::FromTouch, gestureEvent.timestamp(), WebPointerProperties::PointerType::Mouse);
+
+ // TODO(mustaq): We suppress MEs plus all it's side effects. What would that
+ // mean for for TEs? What's the right balance here? crbug.com/617255
+ WebInputEventResult mouseDownEventResult = WebInputEventResult::HandledSuppressed;
+ if (!m_suppressMouseEventsFromGestures) {
+ mouseDownEventResult = m_frame->eventHandler().dispatchMouseEvent(EventTypeNames::mousedown, currentHitTest.innerNode(), gestureEvent.tapCount(), fakeMouseDown);
+ m_selectionController->initializeSelectionState();
+ if (mouseDownEventResult == WebInputEventResult::NotHandled)
+ mouseDownEventResult = m_frame->eventHandler().handleMouseFocus(MouseEventWithHitTestResults(fakeMouseDown, currentHitTest), InputDeviceCapabilities::firesTouchEventsSourceCapabilities());
+ if (mouseDownEventResult == WebInputEventResult::NotHandled)
+ mouseDownEventResult = m_frame->eventHandler().handleMousePressEvent(MouseEventWithHitTestResults(fakeMouseDown, currentHitTest));
+ }
+
+ if (currentHitTest.innerNode()) {
+ DCHECK(gestureEvent.type() == PlatformEvent::GestureTap);
+ HitTestResult result = currentHitTest;
+ result.setToShadowHostIfInUserAgentShadowRoot();
+ m_frame->chromeClient().onMouseDown(result.innerNode());
+ }
+
+ // FIXME: Use a hit-test cache to avoid unnecessary hit tests. http://crbug.com/398920
+ if (currentHitTest.innerNode()) {
+ LocalFrame* mainFrame = m_frame->localFrameRoot();
+ if (mainFrame && mainFrame->view())
+ mainFrame->view()->updateAllLifecyclePhases();
+ adjustedPoint = frameView->rootFrameToContents(gestureEvent.position());
+ currentHitTest = EventHandler::hitTestResultInFrame(m_frame, adjustedPoint, hitType);
+ }
+
+ PlatformMouseEvent fakeMouseUp(gestureEvent.position(), gestureEvent.globalPosition(),
+ LeftButton, PlatformEvent::MouseReleased, gestureEvent.tapCount(),
+ static_cast<PlatformEvent::Modifiers>(modifiers),
+ PlatformMouseEvent::FromTouch, gestureEvent.timestamp(), WebPointerProperties::PointerType::Mouse);
+ WebInputEventResult mouseUpEventResult = m_suppressMouseEventsFromGestures
+ ? WebInputEventResult::HandledSuppressed
+ : m_frame->eventHandler().dispatchMouseEvent(EventTypeNames::mouseup, currentHitTest.innerNode(), gestureEvent.tapCount(), fakeMouseUp);
+
+ WebInputEventResult clickEventResult = WebInputEventResult::NotHandled;
+ if (tappedNonTextNode) {
+ if (currentHitTest.innerNode()) {
+ // Updates distribution because a mouseup (or mousedown) event listener can make the
+ // tree dirty at dispatchMouseEvent() invocation above.
+ // Unless distribution is updated, commonAncestor would hit DCHECK.
+ // Both tappedNonTextNode and currentHitTest.innerNode()) don't need to be updated
+ // because commonAncestor() will exit early if their documents are different.
+ tappedNonTextNode->updateDistribution();
+ Node* clickTargetNode = currentHitTest.innerNode()->commonAncestor(*tappedNonTextNode, EventHandler::parentForClickEvent);
+ clickEventResult = m_frame->eventHandler().dispatchMouseEvent(EventTypeNames::click, clickTargetNode, gestureEvent.tapCount(), fakeMouseUp);
+ }
+ m_frame->eventHandler().setClickNode(nullptr);
+ }
+
+ if (mouseUpEventResult == WebInputEventResult::NotHandled)
+ mouseUpEventResult = m_frame->eventHandler().handleMouseReleaseEvent(MouseEventWithHitTestResults(fakeMouseUp, currentHitTest));
+ m_frame->eventHandler().clearDragHeuristicState();
+
+ WebInputEventResult eventResult = EventHandler::mergeEventResult(EventHandler::mergeEventResult(mouseDownEventResult, mouseUpEventResult), clickEventResult);
+ if (eventResult == WebInputEventResult::NotHandled && tappedNode && m_frame->page()) {
+ bool domTreeChanged = preDispatchDomTreeVersion != m_frame->document()->domTreeVersion();
+ bool styleChanged = preDispatchStyleVersion != m_frame->document()->styleVersion();
+
+ IntPoint tappedPositionInViewport = frameHost()->visualViewport().rootFrameToViewport(tappedPosition);
+ m_frame->chromeClient().showUnhandledTapUIIfNeeded(tappedPositionInViewport, tappedNode, domTreeChanged || styleChanged);
+ }
+ return eventResult;
+}
+
+WebInputEventResult GestureManager::handleGestureLongPress(const GestureEventWithHitTestResults& targetedEvent)
+{
+ const PlatformGestureEvent& gestureEvent = targetedEvent.event();
+
+ // FIXME: Ideally we should try to remove the extra mouse-specific hit-tests here (re-using the
+ // supplied HitTestResult), but that will require some overhaul of the touch drag-and-drop code
+ // and LongPress is such a special scenario that it's unlikely to matter much in practice.
+
+ m_longTapShouldInvokeContextMenu = false;
+ if (m_frame->eventHandler().handleDragDropIfPossible(targetedEvent)) {
+ m_longTapShouldInvokeContextMenu = true;
+ return WebInputEventResult::HandledSystem;
+ }
+ IntPoint hitTestPoint = m_frame->view()->rootFrameToContents(gestureEvent.position());
+ HitTestResult result = m_frame->eventHandler().hitTestResultAtPoint(hitTestPoint);
+ if (m_selectionController->handleGestureLongPress(gestureEvent, result)) {
+ m_frame->eventHandler().focusDocumentView();
+ return WebInputEventResult::HandledSystem;
+ }
+
+ return m_frame->eventHandler().sendContextMenuEventForGesture(targetedEvent);
+}
+
+WebInputEventResult GestureManager::handleGestureLongTap(const GestureEventWithHitTestResults& targetedEvent)
+{
+#if !OS(ANDROID)
+ if (m_longTapShouldInvokeContextMenu) {
+ m_longTapShouldInvokeContextMenu = false;
+ return m_frame->eventHandler().sendContextMenuEventForGesture(targetedEvent);
+ }
+#endif
+ return WebInputEventResult::NotHandled;
+}
+
+WebInputEventResult GestureManager::handleGestureShowPress()
+{
+ m_lastShowPressTimestamp = WTF::monotonicallyIncreasingTime();
+
+ FrameView* view = m_frame->view();
+ if (!view)
+ return WebInputEventResult::NotHandled;
+ if (ScrollAnimatorBase* scrollAnimator = view->existingScrollAnimator())
+ scrollAnimator->cancelAnimation();
+ const FrameView::ScrollableAreaSet* areas = view->scrollableAreas();
+ if (!areas)
+ return WebInputEventResult::NotHandled;
+ for (const ScrollableArea* scrollableArea : *areas) {
+ ScrollAnimatorBase* animator = scrollableArea->existingScrollAnimator();
+ if (animator)
+ animator->cancelAnimation();
+ }
+ return WebInputEventResult::NotHandled;
+}
+
+
+FrameHost* GestureManager::frameHost() const
+{
+ if (!m_frame->page())
+ return nullptr;
+
+ return &m_frame->page()->frameHost();
+}
+
+double GestureManager::getLastShowPressTimestamp()
+{
+ return m_lastShowPressTimestamp;
+}
+
+} // namespace blink

Powered by Google App Engine
This is Rietveld 408576698