2 * Copyright (C) 2006, 2007, 2009, 2010, 2011 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_INPUT_EVENT_HANDLER_H_
27 #define THIRD_PARTY_BLINK_RENDERER_CORE_INPUT_EVENT_HANDLER_H_
29 #include "base/gtest_prod_util.h"
30 #include "base/time/time.h"
31 #include "third_party/abseil-cpp/absl/types/optional.h"
32 #include "third_party/blink/public/common/input/web_input_event.h"
33 #include "third_party/blink/public/common/input/web_menu_source_type.h"
34 #include "third_party/blink/public/platform/web_input_event_result.h"
35 #include "third_party/blink/renderer/core/core_export.h"
36 #include "third_party/blink/renderer/core/events/text_event_input_type.h"
37 #include "third_party/blink/renderer/core/input/gesture_manager.h"
38 #include "third_party/blink/renderer/core/input/keyboard_event_manager.h"
39 #include "third_party/blink/renderer/core/input/mouse_event_manager.h"
40 #include "third_party/blink/renderer/core/input/mouse_wheel_event_manager.h"
41 #include "third_party/blink/renderer/core/input/pointer_event_manager.h"
42 #include "third_party/blink/renderer/core/input/scroll_manager.h"
43 #include "third_party/blink/renderer/core/layout/hit_test_request.h"
44 #include "third_party/blink/renderer/core/page/event_with_hit_test_results.h"
45 #include "third_party/blink/renderer/core/page/touch_adjustment.h"
46 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
58 class EventHandlerRegistry;
59 template <typename EventType>
60 class EventWithHitTestResults;
61 class HTMLFrameSetElement;
69 class SelectionController;
71 class WebGestureEvent;
73 class WebMouseWheelEvent;
75 // Handles events for Pointers (Mouse/Touch), HitTests, DragAndDrop, etc.
76 class CORE_EXPORT EventHandler final : public GarbageCollected<EventHandler> {
78 explicit EventHandler(LocalFrame&);
79 EventHandler(const EventHandler&) = delete;
80 EventHandler& operator=(const EventHandler&) = delete;
81 void Trace(Visitor*) const;
85 void UpdateSelectionForMouseDrag();
86 void StartMiddleClickAutoscroll(LayoutObject*);
88 // TODO(nzolghadr): Some of the APIs in this class only forward the action
89 // to the corresponding Manager class. We need to investigate whether it is
90 // better to expose the manager instance itself later or can the access to
91 // those APIs be more limited or removed.
93 void StopAutoscroll();
95 HitTestResult HitTestResultAtLocation(
96 const HitTestLocation&,
97 HitTestRequest::HitTestRequestType hit_type = HitTestRequest::kReadOnly |
98 HitTestRequest::kActive,
99 const LayoutObject* stop_node = nullptr,
100 bool no_lifecycle_update = false);
102 bool MousePressed() const { return mouse_event_manager_->MousePressed(); }
103 bool IsMousePositionUnknown() const {
104 return mouse_event_manager_->IsMousePositionUnknown();
106 void ClearMouseEventManager() const { mouse_event_manager_->Clear(); }
108 WebInputEventResult UpdateDragAndDrop(const WebMouseEvent&, DataTransfer*);
109 void CancelDragAndDrop(const WebMouseEvent&, DataTransfer*);
110 WebInputEventResult PerformDragAndDrop(const WebMouseEvent&, DataTransfer*);
111 void UpdateDragStateAfterEditDragIfNeeded(Element* root_editable_element);
113 void ScheduleHoverStateUpdate();
114 void ScheduleCursorUpdate();
116 // Return whether a mouse cursor update is currently pending. Used for
118 bool CursorUpdatePending();
120 bool IsHandlingKeyEvent() const;
122 void SetResizingFrameSet(HTMLFrameSetElement*);
124 void ResizeScrollableAreaDestroyed();
126 gfx::PointF LastKnownMousePositionInRootFrame() const;
127 gfx::PointF LastKnownMouseScreenPosition() const;
129 gfx::Point DragDataTransferLocationForTesting();
131 // Performs a logical scroll that chains, crossing frames, starting from
132 // the given node or a reasonable default (focus/last clicked).
133 bool BubblingScroll(mojom::blink::ScrollDirection,
134 ui::ScrollGranularity,
135 Node* starting_node = nullptr);
137 WebInputEventResult HandleMouseMoveEvent(
138 const WebMouseEvent&,
139 const Vector<WebMouseEvent>& coalesced_events,
140 const Vector<WebMouseEvent>& predicted_events);
141 void HandleMouseLeaveEvent(const WebMouseEvent&);
143 WebInputEventResult HandlePointerEvent(
144 const WebPointerEvent&,
145 const Vector<WebPointerEvent>& coalesced_events,
146 const Vector<WebPointerEvent>& predicted_events);
148 WebInputEventResult DispatchBufferedTouchEvents();
150 WebInputEventResult HandleMousePressEvent(const WebMouseEvent&);
151 WebInputEventResult HandleMouseReleaseEvent(const WebMouseEvent&);
152 WebInputEventResult HandleWheelEvent(const WebMouseWheelEvent&);
154 WebInputEventResult HandleTargetedMouseEvent(
156 const WebMouseEvent&,
157 const AtomicString& event_type,
158 const Vector<WebMouseEvent>& coalesced_events,
159 const Vector<WebMouseEvent>& predicted_events);
161 // Called on the local root frame exactly once per gesture event.
162 WebInputEventResult HandleGestureEvent(const WebGestureEvent&);
163 WebInputEventResult HandleGestureEvent(const GestureEventWithHitTestResults&);
165 // Clear the old hover/active state within frames before moving the hover
166 // state to the another frame. |is_active| specifies whether the active state
167 // is being applied to or removed from the given element. This method should
168 // be initially called on the root document, it will recurse into child
170 void UpdateCrossFrameHoverActiveState(bool is_active, Element*);
172 // Hit-test the provided (non-scroll) gesture event, applying touch-adjustment
173 // and updating hover/active state across all frames if necessary. This should
174 // be called at most once per gesture event, and called on the local root
176 // Note: This is similar to (the less clearly named) prepareMouseEvent.
177 // FIXME: Remove readOnly param when there is only ever a single call to this.
178 GestureEventWithHitTestResults TargetGestureEvent(const WebGestureEvent&,
179 bool read_only = false);
180 GestureEventWithHitTestResults HitTestResultForGestureEvent(
181 const WebGestureEvent&,
182 HitTestRequest::HitTestRequestType);
184 // Handle the provided scroll gesture event, propagating down to child frames
186 WebInputEventResult HandleGestureScrollEvent(const WebGestureEvent&);
187 bool IsScrollbarHandlingGestures() const;
189 bool BestNodeForHitTestResult(TouchAdjustmentCandidateType candidate_type,
190 const HitTestLocation& location,
191 const HitTestResult&,
192 gfx::Point& adjusted_point,
193 Node*& adjusted_node);
194 void CacheTouchAdjustmentResult(uint32_t, gfx::PointF);
196 // Dispatch a context menu event. If |override_target_element| is provided,
197 // the context menu event will use that, so that the browser-generated context
198 // menu will be filled with options relevant to it, rather than the element
199 // found via hit testing the event's screen point. This is used so that a
200 // context menu generated via the keyboard reliably uses the correct target.
201 WebInputEventResult SendContextMenuEvent(
202 const WebMouseEvent&,
203 Element* override_target_element = nullptr);
204 WebInputEventResult ShowNonLocatedContextMenu(
205 Element* override_target_element = nullptr,
206 WebMenuSourceType = kMenuSourceNone);
208 // Returns whether pointerId is active or not
209 bool IsPointerEventActive(PointerId);
211 void SetPointerCapture(PointerId, Element*, bool explicit_capture = false);
212 void ReleasePointerCapture(PointerId, Element*);
213 void ReleaseMousePointerCapture();
214 bool HasPointerCapture(PointerId, const Element*) const;
216 void ElementRemoved(Element*);
218 void SetMouseDownMayStartAutoscroll();
220 bool HandleAccessKey(const WebKeyboardEvent&);
221 WebInputEventResult KeyEvent(const WebKeyboardEvent&);
222 void DefaultKeyboardEventHandler(KeyboardEvent*);
224 bool HandleTextInputEvent(const String& text,
225 Event* underlying_event = nullptr,
226 TextEventInputType = kTextEventInputKeyboard);
227 void DefaultTextInputEventHandler(TextEvent*);
229 void DragSourceEndedAt(const WebMouseEvent&, ui::mojom::blink::DragOperation);
231 void CapsLockStateMayHaveChanged(); // Only called by FrameSelection
233 static bool UsesHandCursor(const Node*);
235 void NotifyElementActivated();
237 SelectionController& GetSelectionController() const {
238 return *selection_controller_;
241 bool IsPointerIdActiveOnFrame(PointerId, LocalFrame*) const;
243 LocalFrame* DetermineActivePointerTrackerFrame(PointerId pointer_id) const;
244 #if BUILDFLAG(IS_EFL)
245 void ContextMenuEventForWordOrLinkSelection(const WebGestureEvent&);
248 #if BUILDFLAG(IS_TIZEN)
249 void EnterDragState();
252 // Clears drag target and related states. It is called when drag is done or
254 void ClearDragState();
256 #if BUILDFLAG(IS_TIZEN_TV)
257 bool MousePressEventSwallowed() const { return mouse_press_event_swallowed_; }
258 bool PressedScrollbar() const { return pressed_scrollbar_; }
259 bool ScrollNewPosition(const ScrollOffset&, LocalFrameView*);
260 bool ScrollWithMultiplier(const ScrollOffset&, Node*);
263 EventHandlerRegistry& GetEventHandlerRegistry() const {
264 return *event_handler_registry_;
267 GestureManager& GetGestureManager() const { return *gesture_manager_; }
269 KeyboardEventManager& GetKeyboardEventManager() const {
270 return *keyboard_event_manager_;
273 void RecomputeMouseHoverStateIfNeeded();
275 void MarkHoverStateDirty();
277 // Reset the last mouse position so that movement after unlock will be
278 // restart from the lock position.
279 void ResetMousePositionForPointerUnlock();
281 bool LongTapShouldInvokeContextMenu();
285 float cursor_accessibility_scale_factor() const {
286 return cursor_accessibility_scale_factor_;
288 void set_cursor_accessibility_scale_factor(float scale) {
289 cursor_accessibility_scale_factor_ = scale;
292 Element* GetElementUnderMouse();
294 Element* CurrentTouchDownElement();
296 void SetDelayedNavigationTaskHandle(TaskHandle task_handle);
298 TaskHandle& GetDelayedNavigationTaskHandle();
301 WebInputEventResult HandleMouseMoveOrLeaveEvent(
302 const WebMouseEvent&,
303 const Vector<WebMouseEvent>& coalesced_events,
304 const Vector<WebMouseEvent>& predicted_events,
305 HitTestResult* hovered_node = nullptr,
306 HitTestLocation* hit_test_location = nullptr);
308 // Updates the event, location and result to the adjusted target.
309 void ApplyTouchAdjustment(WebGestureEvent*, HitTestLocation&, HitTestResult&);
311 void PerformHitTest(const HitTestLocation& location,
313 bool no_lifecycle_update) const;
315 void UpdateGestureTargetNodeForMouseEvent(
316 const GestureEventWithHitTestResults&);
318 // Handle the provided non-scroll gesture event. Should be called only on the
320 WebInputEventResult HandleGestureEventInFrame(
321 const GestureEventWithHitTestResults&);
323 bool ShouldApplyTouchAdjustment(const WebGestureEvent&) const;
324 bool GestureCorrespondsToAdjustedTouch(const WebGestureEvent&);
325 bool IsSelectingLink(const HitTestResult&);
326 bool ShouldShowIBeamForNode(const Node*, const HitTestResult&);
327 bool ShouldShowResizeForNode(const LayoutObject&, const HitTestLocation&);
328 absl::optional<ui::Cursor> SelectCursor(const HitTestLocation& location,
329 const HitTestResult&);
330 absl::optional<ui::Cursor> SelectAutoCursor(const HitTestResult&,
332 const ui::Cursor& i_beam);
334 #if BUILDFLAG(IS_TIZEN_TV)
335 bool CanRunArrowScrolling(const HitTestResult&);
338 void HoverTimerFired(TimerBase*);
339 void CursorUpdateTimerFired(TimerBase*);
340 void ActiveIntervalTimerFired(TimerBase*);
342 ScrollableArea* AssociatedScrollableArea(const PaintLayer*) const;
344 Element* EffectiveMouseEventTargetElement(Element*);
346 // Task handle used to distinguish single/double click with some modifiers.
348 // When single click with some modifiers occurred, this task handle is set.
349 // If double click follows, this is cancelled and renderer emit double click
350 // event. (By default, it is handled by renderer as text selection.) If not,
351 // the delayed navigation is emitted.
353 // Currently, the target navigations are the followings:
355 // - Download (Alt-click with/without some other modifiers.)
356 // - Link Preview (Alt-click)
358 // For more details, see https://crbug.com/1428816.
359 TaskHandle delayed_navigation_task_handle_;
361 // Dispatches ME after corresponding PE provided the PE has not been
362 // canceled. The |mouse_event_type| arg must be one of {mousedown,
363 // mousemove, mouseup}.
364 WebInputEventResult DispatchMousePointerEvent(
365 const WebInputEvent::Type,
367 const WebMouseEvent&,
368 const Vector<WebMouseEvent>& coalesced_events,
369 const Vector<WebMouseEvent>& predicted_events,
370 bool skip_click_dispatch = false);
372 WebInputEventResult PassMousePressEventToSubframe(
373 MouseEventWithHitTestResults&,
374 LocalFrame* subframe);
375 WebInputEventResult PassMouseMoveEventToSubframe(
376 MouseEventWithHitTestResults&,
377 const Vector<WebMouseEvent>& coalesced_events,
378 const Vector<WebMouseEvent>& predicted_events,
379 LocalFrame* subframe,
380 HitTestResult* hovered_node = nullptr,
381 HitTestLocation* hit_test_location = nullptr);
382 WebInputEventResult PassMouseReleaseEventToSubframe(
383 MouseEventWithHitTestResults&,
384 LocalFrame* subframe);
386 bool PassMousePressEventToScrollbar(MouseEventWithHitTestResults&);
388 // |last_scrollbar_under_mouse_| is set when the mouse moves off of a
389 // scrollbar, and used to notify it of MouseUp events to release mouse
391 void UpdateLastScrollbarUnderMouse(Scrollbar*, bool);
393 WebInputEventResult HandleGestureShowPress();
395 bool RootFrameTrackedActivePointerInCurrentFrame(PointerId pointer_id) const;
397 void CaptureMouseEventsToWidget(bool);
399 void ReleaseMouseCaptureFromLocalRoot();
400 void ReleaseMouseCaptureFromCurrentFrame();
402 MouseEventWithHitTestResults GetMouseEventTarget(
403 const HitTestRequest& request,
404 const WebMouseEvent& mev);
406 // Returned rect is in local root frame coordinates.
407 gfx::Rect GetFocusedElementRectForNonLocatedContextMenu(
408 Element* focused_element);
410 // NOTE: If adding a new field to this class please ensure that it is
411 // cleared in |EventHandler::clear()|.
413 const Member<LocalFrame> frame_;
415 const Member<SelectionController> selection_controller_;
417 // TODO(lanwei): Remove the below timers for updating hover and cursor.
418 HeapTaskRunnerTimer<EventHandler> hover_timer_;
420 // TODO(rbyers): Mouse cursor update is page-wide, not per-frame. Page-wide
421 // state should move out of EventHandler to a new PageEventHandler class.
423 HeapTaskRunnerTimer<EventHandler> cursor_update_timer_;
425 Member<Element> capturing_mouse_events_element_;
426 // |capturing_subframe_element_| has similar functionality as
427 // |capturing_mouse_events_element_|. It replaces |capturing_..| when
428 // UnifiedPointerCapture enabled.
429 Member<Element> capturing_subframe_element_;
431 // Indicates whether the current widget is capturing mouse input.
432 // Only used for local frame root EventHandlers.
433 bool is_widget_capturing_mouse_events_ = false;
435 Member<LocalFrame> last_mouse_move_event_subframe_;
436 Member<Scrollbar> last_scrollbar_under_mouse_;
438 Member<Node> drag_target_;
439 bool should_only_fire_drag_over_event_;
441 Member<HTMLFrameSetElement> frame_set_being_resized_;
443 // Local frames in the same local root share the same EventHandlerRegistry.
444 Member<EventHandlerRegistry> event_handler_registry_;
445 Member<ScrollManager> scroll_manager_;
446 Member<MouseEventManager> mouse_event_manager_;
447 Member<MouseWheelEventManager> mouse_wheel_event_manager_;
448 Member<KeyboardEventManager> keyboard_event_manager_;
449 Member<PointerEventManager> pointer_event_manager_;
450 Member<GestureManager> gesture_manager_;
452 double max_mouse_moved_duration_;
454 float cursor_accessibility_scale_factor_ = 1.f;
456 HeapTaskRunnerTimer<EventHandler> active_interval_timer_;
458 // last_show_press_timestamp_ prevents the active state rewrited by
459 // following events too soon (less than 0.15s). It is ok we only record
460 // last_show_press_timestamp_ in root frame since root frame will have
461 // subframe as active element if subframe has active element.
462 absl::optional<base::TimeTicks> last_show_press_timestamp_;
463 Member<Element> last_deferred_tap_element_;
465 // Set on GestureTapDown if unique_touch_event_id_ matches cached adjusted
466 // touchstart event id.
467 bool should_use_touch_event_adjusted_point_;
469 // Stored the last touch type primary pointer down adjustment result.
470 // This is used in gesture event hit test.
471 TouchAdjustmentResult touch_adjustment_result_;
474 DOMNodeId mouse_down_target = kInvalidDOMNodeId;
475 DOMNodeId tap_target = kInvalidDOMNodeId;
476 base::TimeTicks mouse_down_time;
477 base::TimeTicks tap_time;
480 #if BUILDFLAG(IS_TIZEN_TV)
481 bool handled_mouse_left_button_press_event_ = false;
482 bool mouse_press_event_swallowed_ = false;
483 bool pressed_scrollbar_ = false;
486 // ShouldShowIBeamForNode's unit tests:
487 FRIEND_TEST_ALL_PREFIXES(EventHandlerTest, HitOnNothingDoesNotShowIBeam);
488 FRIEND_TEST_ALL_PREFIXES(EventHandlerTest, HitOnTextShowsIBeam);
489 FRIEND_TEST_ALL_PREFIXES(EventHandlerTest,
490 HitOnUserSelectNoneDoesNotShowIBeam);
491 FRIEND_TEST_ALL_PREFIXES(EventHandlerTest,
492 ShadowChildCanOverrideUserSelectNone);
493 FRIEND_TEST_ALL_PREFIXES(EventHandlerTest,
494 UserSelectAllCanOverrideUserSelectNone);
495 FRIEND_TEST_ALL_PREFIXES(EventHandlerTest,
496 UserSelectNoneCanOverrideUserSelectAll);
497 FRIEND_TEST_ALL_PREFIXES(EventHandlerTest,
498 UserSelectTextCanOverrideUserSelectNone);
499 FRIEND_TEST_ALL_PREFIXES(EventHandlerTest,
500 UserSelectNoneCanOverrideUserSelectText);
501 FRIEND_TEST_ALL_PREFIXES(EventHandlerTest,
502 ShadowChildCanOverrideUserSelectText);
503 FRIEND_TEST_ALL_PREFIXES(EventHandlerTest, InputFieldsCanStartSelection);
504 FRIEND_TEST_ALL_PREFIXES(EventHandlerTest, ImagesCannotStartSelection);
505 FRIEND_TEST_ALL_PREFIXES(EventHandlerTest, AnchorTextCannotStartSelection);
506 FRIEND_TEST_ALL_PREFIXES(EventHandlerTest,
507 EditableAnchorTextCanStartSelection);
508 FRIEND_TEST_ALL_PREFIXES(EventHandlerTest,
509 ReadOnlyInputDoesNotInheritUserSelect);
510 FRIEND_TEST_ALL_PREFIXES(EventHandlerTest,
511 CursorForVerticalResizableTextArea);
512 FRIEND_TEST_ALL_PREFIXES(EventHandlerTest,
513 CursorForHorizontalResizableTextArea);
514 FRIEND_TEST_ALL_PREFIXES(EventHandlerTest, CursorForResizableTextArea);
515 FRIEND_TEST_ALL_PREFIXES(EventHandlerTest, CursorForRtlResizableTextArea);
516 FRIEND_TEST_ALL_PREFIXES(EventHandlerTest,
517 CursorForInlineVerticalWritingMode);
518 FRIEND_TEST_ALL_PREFIXES(EventHandlerTest, CursorForBlockVerticalWritingMode);
523 #endif // THIRD_PARTY_BLINK_RENDERER_CORE_INPUT_EVENT_HANDLER_H_