blob: ad9f3b462d856a1f4b5601ee1bfae69175ffeca6 [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 "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "core/CoreExport.h"
#include "core/dom/UserGestureIndicator.h"
#include "core/events/TextEventInputType.h"
#include "core/input/GestureManager.h"
#include "core/input/KeyboardEventManager.h"
#include "core/input/MouseEventManager.h"
#include "core/input/MouseWheelEventManager.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/geometry/LayoutPoint.h"
#include "platform/heap/Handle.h"
#include "platform/scroll/ScrollTypes.h"
#include "platform/wtf/Forward.h"
#include "platform/wtf/HashMap.h"
#include "platform/wtf/HashTraits.h"
#include "public/platform/WebInputEvent.h"
#include "public/platform/WebInputEventResult.h"
#include "public/platform/WebMenuSourceType.h"
namespace blink {
class DataTransfer;
class PaintLayer;
class Element;
class Event;
class EventTarget;
template <typename EventType>
class EventWithHitTestResults;
class FloatQuad;
class HTMLFrameSetElement;
class HitTestRequest;
class HitTestResult;
class LayoutObject;
class LocalFrame;
class Node;
class ScrollableArea;
class Scrollbar;
class SelectionController;
class TextEvent;
class WebGestureEvent;
class WebMouseEvent;
class WebMouseWheelEvent;
class WebTouchEvent;
class CORE_EXPORT EventHandler final
: public GarbageCollectedFinalized<EventHandler> {
public:
explicit EventHandler(LocalFrame&);
void Trace(blink::Visitor*);
void Clear();
void UpdateSelectionForMouseDrag();
void StartMiddleClickAutoscroll(LayoutObject*);
// 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(MouseEventManager::FakeMouseMoveReason);
void DispatchFakeMouseMoveEventSoonInQuad(const FloatQuad&);
HitTestResult HitTestResultAtPoint(
const LayoutPoint&,
HitTestRequest::HitTestRequestType hit_type = HitTestRequest::kReadOnly |
HitTestRequest::kActive,
const LayoutSize& padding = LayoutSize());
bool MousePressed() const { return mouse_event_manager_->MousePressed(); }
bool IsMousePositionUnknown() const {
return mouse_event_manager_->IsMousePositionUnknown();
}
void ClearMouseEventManager() const { mouse_event_manager_->Clear(); }
void SetCapturingMouseEventsNode(
Node*); // A caller is responsible for resetting capturing node to 0.
WebInputEventResult UpdateDragAndDrop(const WebMouseEvent&, DataTransfer*);
void CancelDragAndDrop(const WebMouseEvent&, DataTransfer*);
WebInputEventResult PerformDragAndDrop(const WebMouseEvent&, DataTransfer*);
void UpdateDragStateAfterEditDragIfNeeded(Element* root_editable_element);
void ScheduleHoverStateUpdate();
void ScheduleCursorUpdate();
// Return whether a mouse cursor update is currently pending. Used for
// testing.
bool CursorUpdatePending();
// Return whether sending a fake mouse move is currently pending. Used for
// testing.
bool FakeMouseMovePending() const;
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* starting_node = nullptr);
WebInputEventResult HandleMouseMoveEvent(
const WebMouseEvent&,
const Vector<WebMouseEvent>& coalesced_events);
void HandleMouseLeaveEvent(const WebMouseEvent&);
WebInputEventResult HandlePointerEvent(
const WebPointerEvent&,
const Vector<WebPointerEvent>& coalesced_events);
WebInputEventResult HandleMousePressEvent(const WebMouseEvent&);
WebInputEventResult HandleMouseReleaseEvent(const WebMouseEvent&);
WebInputEventResult HandleWheelEvent(const WebMouseWheelEvent&);
// Called on the local root frame exactly once per gesture event.
WebInputEventResult HandleGestureEvent(const WebGestureEvent&);
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 WebGestureEvent&,
bool read_only = false);
GestureEventWithHitTestResults HitTestResultForGestureEvent(
const WebGestureEvent&,
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 WebGestureEvent&);
WebInputEventResult HandleGestureScrollEnd(const WebGestureEvent&);
bool IsScrollbarHandlingGestures() const;
bool BestClickableNodeForHitTestResult(const HitTestResult&,
IntPoint& target_point,
Node*& target_node);
bool BestContextMenuNodeForHitTestResult(const HitTestResult&,
IntPoint& target_point,
Node*& target_node);
// 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& touch_center,
const IntSize& touch_radius,
IntRect& target_area,
Node*& target_node);
WebInputEventResult SendContextMenuEvent(
const WebMouseEvent&,
Node* override_target_node = nullptr);
WebInputEventResult ShowNonLocatedContextMenu(
Element* override_target_element = nullptr,
WebMenuSourceType = kMenuSourceNone);
// Returns whether pointerId is active or not
bool IsPointerEventActive(int);
void SetPointerCapture(int, EventTarget*);
void ReleasePointerCapture(int, EventTarget*);
void ReleaseMousePointerCapture();
bool HasPointerCapture(int, const EventTarget*) const;
bool HasProcessedPointerCapture(int, const EventTarget*) const;
void ProcessPendingPointerCaptureForPointerLock(const WebMouseEvent&);
void ElementRemoved(EventTarget*);
void SetMouseDownMayStartAutoscroll();
bool HandleAccessKey(const WebKeyboardEvent&);
WebInputEventResult KeyEvent(const WebKeyboardEvent&);
void DefaultKeyboardEventHandler(KeyboardEvent*);
bool HandleTextInputEvent(const String& text,
Event* underlying_event = nullptr,
TextEventInputType = kTextEventInputKeyboard);
void DefaultTextInputEventHandler(TextEvent*);
void DragSourceEndedAt(const WebMouseEvent&, DragOperation);
void CapsLockStateMayHaveChanged(); // Only called by FrameSelection
WebInputEventResult HandleTouchEvent(
const WebTouchEvent&,
const Vector<WebTouchEvent>& coalesced_events);
bool UseHandCursor(Node*, bool is_over_link);
void NotifyElementActivated();
scoped_refptr<UserGestureToken> TakeLastMouseDownGestureToken() {
return std::move(last_mouse_down_user_gesture_token_);
}
SelectionController& GetSelectionController() const {
return *selection_controller_;
}
// 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* start_node = nullptr);
bool IsTouchPointerIdActiveOnFrame(int, LocalFrame*) const;
// Clears drag target and related states. It is called when drag is done or
// canceled.
void ClearDragState();
private:
enum NoCursorChangeType { kNoCursorChange };
class OptionalCursor {
public:
OptionalCursor(NoCursorChangeType) : is_cursor_change_(false) {}
OptionalCursor(const Cursor& cursor)
: is_cursor_change_(true), cursor_(cursor) {}
bool IsCursorChange() const { return is_cursor_change_; }
const Cursor& GetCursor() const {
DCHECK(is_cursor_change_);
return cursor_;
}
private:
bool is_cursor_change_;
Cursor cursor_;
};
WebInputEventResult HandleMouseMoveOrLeaveEvent(
const WebMouseEvent&,
const Vector<WebMouseEvent>&,
HitTestResult* hovered_node = nullptr,
bool only_update_scrollbars = false,
bool force_leave = false);
void ApplyTouchAdjustment(WebGestureEvent*, HitTestResult*);
WebInputEventResult HandleGestureTapDown(
const GestureEventWithHitTestResults&);
WebInputEventResult HandleGestureTap(const GestureEventWithHitTestResults&);
WebInputEventResult HandleGestureLongPress(
const GestureEventWithHitTestResults&);
WebInputEventResult HandleGestureLongTap(
const GestureEventWithHitTestResults&);
void UpdateGestureTargetNodeForMouseEvent(
const GestureEventWithHitTestResults&);
bool ShouldApplyTouchAdjustment(const WebGestureEvent&) const;
bool IsSelectingLink(const HitTestResult&);
bool ShouldShowIBeamForNode(const Node*, const HitTestResult&);
bool ShouldShowResizeForNode(const Node*, const HitTestResult&);
OptionalCursor SelectCursor(const HitTestResult&);
OptionalCursor SelectAutoCursor(const HitTestResult&,
Node*,
const Cursor& i_beam);
void HoverTimerFired(TimerBase*);
void CursorUpdateTimerFired(TimerBase*);
void ActiveIntervalTimerFired(TimerBase*);
void UpdateCursor();
ScrollableArea* AssociatedScrollableArea(const PaintLayer*) const;
Node* UpdateMouseEventTargetNode(Node*);
// 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
// WebmMouseEvent's count?
// Same applied to dispatchMouseEvent() above.
WebInputEventResult UpdatePointerTargetAndDispatchEvents(
const AtomicString& mouse_event_type,
Node* target,
const String& canvas_region_id,
const WebMouseEvent&,
const Vector<WebMouseEvent>& coalesced_events);
WebInputEventResult PassMousePressEventToSubframe(
MouseEventWithHitTestResults&,
LocalFrame* subframe);
WebInputEventResult PassMouseMoveEventToSubframe(
MouseEventWithHitTestResults&,
const Vector<WebMouseEvent>&,
LocalFrame* subframe,
HitTestResult* hovered_node = 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);
WebInputEventResult HandleGestureShowPress();
bool ShouldBrowserControlsConsumeScroll(FloatSize) const;
bool RootFrameTouchPointerActiveInCurrentFrame(int pointer_id) const;
// NOTE: If adding a new field to this class please ensure that it is
// cleared in |EventHandler::clear()|.
const Member<LocalFrame> frame_;
const Member<SelectionController> selection_controller_;
TaskRunnerTimer<EventHandler> hover_timer_;
// 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
TaskRunnerTimer<EventHandler> cursor_update_timer_;
Member<Node> capturing_mouse_events_node_;
bool event_handler_will_reset_capturing_mouse_events_node_;
Member<LocalFrame> last_mouse_move_event_subframe_;
Member<Scrollbar> last_scrollbar_under_mouse_;
Member<Node> drag_target_;
bool should_only_fire_drag_over_event_;
Member<HTMLFrameSetElement> frame_set_being_resized_;
scoped_refptr<UserGestureToken> last_mouse_down_user_gesture_token_;
Member<ScrollManager> scroll_manager_;
Member<MouseEventManager> mouse_event_manager_;
Member<MouseWheelEventManager> mouse_wheel_event_manager_;
Member<KeyboardEventManager> keyboard_event_manager_;
Member<PointerEventManager> pointer_event_manager_;
Member<GestureManager> gesture_manager_;
double max_mouse_moved_duration_;
bool long_tap_should_invoke_context_menu_;
TaskRunnerTimer<EventHandler> active_interval_timer_;
double last_show_press_timestamp_;
Member<Element> last_deferred_tap_element_;
// 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 suppress_mouse_events_from_gestures_;
// ShouldShowIBeamForNode's unit tests:
FRIEND_TEST_ALL_PREFIXES(EventHandlerTest, HitOnNothingDoesNotShowIBeam);
FRIEND_TEST_ALL_PREFIXES(EventHandlerTest, HitOnTextShowsIBeam);
FRIEND_TEST_ALL_PREFIXES(EventHandlerTest,
HitOnUserSelectNoneDoesNotShowIBeam);
FRIEND_TEST_ALL_PREFIXES(EventHandlerTest, ChildCanOverrideUserSelectNone);
FRIEND_TEST_ALL_PREFIXES(EventHandlerTest,
ShadowChildCanOverrideUserSelectNone);
FRIEND_TEST_ALL_PREFIXES(EventHandlerTest, ChildCanOverrideUserSelectText);
FRIEND_TEST_ALL_PREFIXES(EventHandlerTest,
ShadowChildCanOverrideUserSelectText);
FRIEND_TEST_ALL_PREFIXES(EventHandlerTest, InputFieldsCanStartSelection);
FRIEND_TEST_ALL_PREFIXES(EventHandlerTest, ImagesCannotStartSelection);
FRIEND_TEST_ALL_PREFIXES(EventHandlerTest, AnchorTextCannotStartSelection);
FRIEND_TEST_ALL_PREFIXES(EventHandlerTest,
EditableAnchorTextCanStartSelection);
FRIEND_TEST_ALL_PREFIXES(EventHandlerTest,
ReadOnlyInputDoesNotInheritUserSelect);
DISALLOW_COPY_AND_ASSIGN(EventHandler);
};
} // namespace blink
#endif // EventHandler_h