blob: 019e3ee1d79f250cc640c6086c56b32c8f97b3a6 [file] [log] [blame]
/*
* Copyright (C) 2006, 2007, 2009, 2010, 2011 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EventHandler_h
#define EventHandler_h
#include "core/CoreExport.h"
#include "core/events/TextEventInputType.h"
#include "core/input/KeyboardEventManager.h"
#include "core/input/PointerEventManager.h"
#include "core/input/ScrollManager.h"
#include "core/layout/HitTestRequest.h"
#include "core/page/DragActions.h"
#include "core/page/EventWithHitTestResults.h"
#include "core/style/ComputedStyleConstants.h"
#include "platform/Cursor.h"
#include "platform/PlatformMouseEvent.h"
#include "platform/PlatformTouchPoint.h"
#include "platform/Timer.h"
#include "platform/UserGestureIndicator.h"
#include "platform/geometry/LayoutPoint.h"
#include "platform/heap/Handle.h"
#include "platform/scroll/ScrollTypes.h"
#include "public/platform/WebInputEventResult.h"
#include "wtf/Forward.h"
#include "wtf/HashMap.h"
#include "wtf/HashTraits.h"
#include "wtf/RefPtr.h"
namespace blink {
class DataTransfer;
class PaintLayer;
class Document;
class DragState;
class Element;
class Event;
class EventTarget;
template <typename EventType>
class EventWithHitTestResults;
class FloatPoint;
class FloatQuad;
class FrameHost;
class HTMLFrameSetElement;
class HitTestRequest;
class HitTestResult;
class LayoutObject;
class LocalFrame;
class Node;
class OptionalCursor;
class PlatformGestureEvent;
class PlatformKeyboardEvent;
class PlatformTouchEvent;
class PlatformWheelEvent;
class ScrollableArea;
class Scrollbar;
class SelectionController;
class TextEvent;
class WheelEvent;
class Widget;
enum class DragInitiator;
class CORE_EXPORT EventHandler final : public GarbageCollectedFinalized<EventHandler> {
WTF_MAKE_NONCOPYABLE(EventHandler);
public:
explicit EventHandler(LocalFrame*);
~EventHandler();
DECLARE_TRACE();
void clear();
void nodeWillBeRemoved(Node&);
void updateSelectionForMouseDrag();
#if OS(WIN)
void startPanScrolling(LayoutObject*);
#endif
// TODO(nzolghadr): Some of the APIs in this class only forward the action
// to the corresponding Manager class. We need to investigate whether it is
// better to expose the manager instance itself later or can the access to
// those APIs be more limited or removed.
void stopAutoscroll();
void dispatchFakeMouseMoveEventSoon();
void dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad&);
static HitTestResult hitTestResultInFrame(LocalFrame*, const LayoutPoint&, HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active);
HitTestResult hitTestResultAtPoint(const LayoutPoint&,
HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active,
const LayoutSize& padding = LayoutSize());
bool mousePressed() const { return m_mousePressed; }
void setCapturingMouseEventsNode(Node*); // A caller is responsible for resetting capturing node to 0.
WebInputEventResult updateDragAndDrop(const PlatformMouseEvent&, DataTransfer*);
void cancelDragAndDrop(const PlatformMouseEvent&, DataTransfer*);
WebInputEventResult performDragAndDrop(const PlatformMouseEvent&, DataTransfer*);
void updateDragStateAfterEditDragIfNeeded(Element* rootEditableElement);
void scheduleHoverStateUpdate();
void scheduleCursorUpdate();
// Return whether a mouse cursor update is currently pending. Used for testing.
bool cursorUpdatePending();
void setResizingFrameSet(HTMLFrameSetElement*);
void resizeScrollableAreaDestroyed();
IntPoint lastKnownMousePosition() const;
IntPoint dragDataTransferLocationForTesting();
// Performs a logical scroll that chains, crossing frames, starting from
// the given node or a reasonable default (focus/last clicked).
bool bubblingScroll(ScrollDirection, ScrollGranularity, Node* startingNode = nullptr);
WebInputEventResult handleMouseMoveEvent(const PlatformMouseEvent&);
void handleMouseLeaveEvent(const PlatformMouseEvent&);
WebInputEventResult handleMousePressEvent(const PlatformMouseEvent&);
WebInputEventResult handleMouseReleaseEvent(const PlatformMouseEvent&);
WebInputEventResult handleWheelEvent(const PlatformWheelEvent&);
// Called on the local root frame exactly once per gesture event.
WebInputEventResult handleGestureEvent(const PlatformGestureEvent&);
WebInputEventResult handleGestureEvent(const GestureEventWithHitTestResults&);
// Clear the old hover/active state within frames before moving the hover state to the another frame
void updateGestureHoverActiveState(const HitTestRequest&, Element*);
// Hit-test the provided (non-scroll) gesture event, applying touch-adjustment and updating
// hover/active state across all frames if necessary. This should be called at most once
// per gesture event, and called on the local root frame.
// Note: This is similar to (the less clearly named) prepareMouseEvent.
// FIXME: Remove readOnly param when there is only ever a single call to this.
GestureEventWithHitTestResults targetGestureEvent(const PlatformGestureEvent&, bool readOnly = false);
GestureEventWithHitTestResults hitTestResultForGestureEvent(const PlatformGestureEvent&, HitTestRequest::HitTestRequestType);
// Handle the provided non-scroll gesture event. Should be called only on the inner frame.
WebInputEventResult handleGestureEventInFrame(const GestureEventWithHitTestResults&);
// Handle the provided scroll gesture event, propagating down to child frames as necessary.
WebInputEventResult handleGestureScrollEvent(const PlatformGestureEvent&);
WebInputEventResult handleGestureScrollEnd(const PlatformGestureEvent&);
bool isScrollbarHandlingGestures() const;
bool bestClickableNodeForHitTestResult(const HitTestResult&, IntPoint& targetPoint, Node*& targetNode);
bool bestContextMenuNodeForHitTestResult(const HitTestResult&, IntPoint& targetPoint, Node*& targetNode);
// FIXME: This doesn't appear to be used outside tests anymore, what path are we using now and is it tested?
bool bestZoomableAreaForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntRect& targetArea, Node*& targetNode);
WebInputEventResult sendContextMenuEvent(const PlatformMouseEvent&, Node* overrideTargetNode = nullptr);
WebInputEventResult sendContextMenuEventForKey(Element* overrideTargetElement = nullptr);
WebInputEventResult sendContextMenuEventForGesture(const GestureEventWithHitTestResults&);
// Returns whether pointerId is active or not
bool isPointerEventActive(int);
void setPointerCapture(int, EventTarget*);
void releasePointerCapture(int, EventTarget*);
void elementRemoved(EventTarget*);
void setMouseDownMayStartAutoscroll() { m_mouseDownMayStartAutoscroll = true; }
static WebInputEventResult mergeEventResult(WebInputEventResult resultA, WebInputEventResult resultB);
static WebInputEventResult toWebInputEventResult(DispatchEventResult);
bool handleAccessKey(const PlatformKeyboardEvent&);
WebInputEventResult keyEvent(const PlatformKeyboardEvent&);
void defaultKeyboardEventHandler(KeyboardEvent*);
bool handleTextInputEvent(const String& text, Event* underlyingEvent = nullptr, TextEventInputType = TextEventInputKeyboard);
void defaultTextInputEventHandler(TextEvent*);
void dragSourceEndedAt(const PlatformMouseEvent&, DragOperation);
void focusDocumentView();
void capsLockStateMayHaveChanged(); // Only called by FrameSelection
WebInputEventResult handleTouchEvent(const PlatformTouchEvent&);
bool useHandCursor(Node*, bool isOverLink);
void notifyElementActivated();
PassRefPtr<UserGestureToken> takeLastMouseDownGestureToken() { return m_lastMouseDownUserGestureToken.release(); }
int clickCount() { return m_clickCount; }
SelectionController& selectionController() const { return *m_selectionController; }
// FIXME(nzolghadr): This function is technically a private function of
// EventHandler class. Making it public temporary to make it possible to
// move some code around in the refactoring process.
// Performs a chaining logical scroll, within a *single* frame, starting
// from either a provided starting node or a default based on the focused or
// most recently clicked node, falling back to the frame.
// Returns true if the scroll was consumed.
// direction - The logical direction to scroll in. This will be converted to
// a physical direction for each LayoutBox we try to scroll
// based on that box's writing mode.
// granularity - The units that the scroll delta parameter is in.
// startNode - Optional. If provided, start chaining from the given node.
// If not, use the current focus or last clicked node.
bool logicalScroll(ScrollDirection, ScrollGranularity, Node* startNode = nullptr);
private:
static DragState& dragState();
DataTransfer* createDraggingDataTransfer() const;
WebInputEventResult handleMouseMoveOrLeaveEvent(const PlatformMouseEvent&, HitTestResult* hoveredNode = nullptr, bool onlyUpdateScrollbars = false, bool forceLeave = false);
WebInputEventResult handleMousePressEvent(const MouseEventWithHitTestResults&);
WebInputEventResult handleMouseFocus(const MouseEventWithHitTestResults&, InputDeviceCapabilities* sourceCapabilities);
WebInputEventResult handleMouseDraggedEvent(const MouseEventWithHitTestResults&);
WebInputEventResult handleMouseReleaseEvent(const MouseEventWithHitTestResults&);
HitTestRequest::HitTestRequestType getHitTypeForGestureType(PlatformEvent::EventType);
void applyTouchAdjustment(PlatformGestureEvent*, HitTestResult*);
WebInputEventResult handleGestureTapDown(const GestureEventWithHitTestResults&);
WebInputEventResult handleGestureTap(const GestureEventWithHitTestResults&);
WebInputEventResult handleGestureLongPress(const GestureEventWithHitTestResults&);
WebInputEventResult handleGestureLongTap(const GestureEventWithHitTestResults&);
void updateGestureTargetNodeForMouseEvent(const GestureEventWithHitTestResults&);
bool shouldApplyTouchAdjustment(const PlatformGestureEvent&) const;
OptionalCursor selectCursor(const HitTestResult&);
OptionalCursor selectAutoCursor(const HitTestResult&, Node*, const Cursor& iBeam);
void hoverTimerFired(Timer<EventHandler>*);
void cursorUpdateTimerFired(Timer<EventHandler>*);
void activeIntervalTimerFired(Timer<EventHandler>*);
void fakeMouseMoveEventTimerFired(Timer<EventHandler>*);
void cancelFakeMouseMoveEvent();
bool isCursorVisible() const;
void updateCursor();
ScrollableArea* associatedScrollableArea(const PaintLayer*) const;
void invalidateClick();
Node* updateMouseEventTargetNode(Node*, const PlatformMouseEvent&);
void updateMouseEventTargetNodeAndSendEvents(Node*, const PlatformMouseEvent&, bool isFrameBoundaryTransition = false);
MouseEventWithHitTestResults prepareMouseEvent(const HitTestRequest&, const PlatformMouseEvent&);
WebInputEventResult dispatchMouseEvent(const AtomicString& eventType, Node* target, int clickCount, const PlatformMouseEvent&);
// Dispatches ME after corresponding PE provided the PE has not been canceled. The eventType arg
// must be a mouse event that can be gated though a preventDefaulted pointerdown (i.e., one of
// {mousedown, mousemove, mouseup}).
// TODO(mustaq): Can we avoid the clickCount param, instead use PlatformMouseEvent's count?
// Same applied to dispatchMouseEvent() above.
WebInputEventResult updatePointerTargetAndDispatchEvents(const AtomicString& mouseEventType, Node* target,
int clickCount, const PlatformMouseEvent&);
WebInputEventResult dispatchDragEvent(const AtomicString& eventType, Node* target, const PlatformMouseEvent&, DataTransfer*);
void clearDragDataTransfer();
bool handleDrag(const MouseEventWithHitTestResults&, DragInitiator);
bool tryStartDrag(const MouseEventWithHitTestResults&);
void clearDragState();
WebInputEventResult dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent&);
bool dragHysteresisExceeded(const IntPoint&) const;
WebInputEventResult passMousePressEventToSubframe(MouseEventWithHitTestResults&, LocalFrame* subframe);
WebInputEventResult passMouseMoveEventToSubframe(MouseEventWithHitTestResults&, LocalFrame* subframe, HitTestResult* hoveredNode = nullptr);
WebInputEventResult passMouseReleaseEventToSubframe(MouseEventWithHitTestResults&, LocalFrame* subframe);
bool passMousePressEventToScrollbar(MouseEventWithHitTestResults&);
void defaultSpaceEventHandler(KeyboardEvent*);
void defaultBackspaceEventHandler(KeyboardEvent*);
void defaultTabEventHandler(KeyboardEvent*);
void defaultEscapeEventHandler(KeyboardEvent*);
void defaultArrowEventHandler(WebFocusType, KeyboardEvent*);
void updateLastScrollbarUnderMouse(Scrollbar*, bool);
bool capturesDragging() const { return m_capturesDragging; }
WebInputEventResult handleGestureShowPress();
void setLastKnownMousePosition(const PlatformMouseEvent&);
bool shouldTopControlsConsumeScroll(FloatSize) const;
// If the given element is a shadow host and its root has delegatesFocus=false flag,
// slide focus to its inner element. Returns true if the resulting focus is different from
// the given element.
bool slideFocusOnShadowHostIfNecessary(const Element&);
FrameHost* frameHost() const;
// NOTE: If adding a new field to this class please ensure that it is
// cleared in |EventHandler::clear()|.
const Member<LocalFrame> m_frame;
// Current button-press state for mouse/mouse-like-stylus.
// TODO(crbug.com/563676): Buggy for chorded buttons.
bool m_mousePressed;
bool m_capturesDragging;
Member<Node> m_mousePressNode;
bool m_mouseDownMayStartDrag;
const Member<SelectionController> m_selectionController;
LayoutPoint m_dragStartPos;
Timer<EventHandler> m_hoverTimer;
// TODO(rbyers): Mouse cursor update is page-wide, not per-frame. Page-wide state
// should move out of EventHandler to a new PageEventHandler class. crbug.com/449649
Timer<EventHandler> m_cursorUpdateTimer;
bool m_mouseDownMayStartAutoscroll;
Timer<EventHandler> m_fakeMouseMoveEventTimer;
bool m_svgPan;
Member<Node> m_capturingMouseEventsNode;
bool m_eventHandlerWillResetCapturingMouseEventsNode;
// Note the difference of this and m_nodeUnderPointer in PointerEventManager
Member<Node> m_nodeUnderMouse;
Member<LocalFrame> m_lastMouseMoveEventSubframe;
Member<Scrollbar> m_lastScrollbarUnderMouse;
int m_clickCount;
Member<Node> m_clickNode;
Member<Node> m_dragTarget;
bool m_shouldOnlyFireDragOverEvent;
Member<HTMLFrameSetElement> m_frameSetBeingResized;
bool m_mousePositionIsUnknown;
// The last mouse movement position this frame has seen in root frame coordinates.
IntPoint m_lastKnownMousePosition;
IntPoint m_lastKnownMouseGlobalPosition;
IntPoint m_mouseDownPos; // In our view's coords.
double m_mouseDownTimestamp;
PlatformMouseEvent m_mouseDown;
RefPtr<UserGestureToken> m_lastMouseDownUserGestureToken;
PointerEventManager m_pointerEventManager;
ScrollManager m_scrollManager;
KeyboardEventManager m_keyboardEventManager;
double m_maxMouseMovedDuration;
bool m_longTapShouldInvokeContextMenu;
Timer<EventHandler> m_activeIntervalTimer;
double m_lastShowPressTimestamp;
Member<Element> m_lastDeferredTapElement;
// Set on GestureTapDown if the |pointerdown| event corresponding to the
// triggering |touchstart| event was canceled. This suppresses mouse event
// firing for the current gesture sequence (i.e. until next GestureTapDown).
bool m_suppressMouseEventsFromGestures;
};
} // namespace blink
#endif // EventHandler_h