| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "third_party/blink/renderer/core/input/widget_event_handler.h" |
| |
| #include "third_party/blink/public/common/input/web_coalesced_input_event.h" |
| #include "third_party/blink/renderer/core/accessibility/ax_object_cache.h" |
| #include "third_party/blink/renderer/core/dom/document.h" |
| #include "third_party/blink/renderer/core/events/web_input_event_conversion.h" |
| #include "third_party/blink/renderer/core/frame/local_frame.h" |
| #include "third_party/blink/renderer/core/input/event_handler.h" |
| #include "third_party/blink/renderer/core/layout/layout_shift_tracker.h" |
| #include "third_party/blink/renderer/core/timing/dom_window_performance.h" |
| #include "third_party/blink/renderer/core/timing/window_performance.h" |
| #include "ui/gfx/geometry/point_conversions.h" |
| |
| namespace blink { |
| |
| namespace { |
| // The list of eligible event types should match with |
| // the corresponding blink event types in IsEventTypeForInteractionId |
| // (window_performance.cc) and EventTiming::IsEventTypeForEventTiming |
| // (event_timing.cc) |
| bool IsWebInteractionEvent(WebInputEvent::Type event_type) { |
| return event_type == WebInputEvent::Type::kMouseDown || |
| event_type == WebInputEvent::Type::kMouseUp || |
| event_type == WebInputEvent::Type::kKeyDown || |
| event_type == WebInputEvent::Type::kRawKeyDown || |
| event_type == WebInputEvent::Type::kKeyUp || |
| event_type == WebInputEvent::Type::kChar || |
| event_type == WebInputEvent::Type::kGestureTapDown || |
| event_type == WebInputEvent::Type::kGestureTap || |
| event_type == WebInputEvent::Type::kPointerDown || |
| event_type == WebInputEvent::Type::kPointerUp; |
| } |
| } // namespace |
| |
| WebInputEventResult WidgetEventHandler::HandleInputEvent( |
| const WebCoalescedInputEvent& coalesced_event, |
| LocalFrame* root) { |
| const WebInputEvent& event = coalesced_event.Event(); |
| if (root) { |
| Document* document = root->GetDocument(); |
| DCHECK(document); |
| if (LocalFrameView* view = document->View()) |
| view->GetLayoutShiftTracker().NotifyInput(event); |
| if (IsWebInteractionEvent(event.GetType())) { |
| WindowPerformance* performance = |
| DOMWindowPerformance::performance(*root->DomWindow()); |
| performance->GetResponsivenessMetrics() |
| .SetCurrentInteractionEventQueuedTimestamp(event.QueuedTimeStamp()); |
| } |
| } |
| |
| if (event.GetModifiers() & WebInputEvent::kIsTouchAccessibility && |
| WebInputEvent::IsMouseEventType(event.GetType())) { |
| WebMouseEvent mouse_event = TransformWebMouseEvent( |
| root->View(), static_cast<const WebMouseEvent&>(event)); |
| |
| HitTestLocation location(root->View()->ConvertFromRootFrame( |
| gfx::ToFlooredPoint(mouse_event.PositionInRootFrame()))); |
| HitTestResult result = root->GetEventHandler().HitTestResultAtLocation( |
| location, HitTestRequest::kReadOnly | HitTestRequest::kActive); |
| result.SetToShadowHostIfInUAShadowRoot(); |
| if (result.InnerNodeFrame()) { |
| Document* document = result.InnerNodeFrame()->GetDocument(); |
| if (document) { |
| AXObjectCache* cache = document->ExistingAXObjectCache(); |
| if (cache) { |
| cache->OnTouchAccessibilityHover( |
| result.RoundedPointInInnerNodeFrame()); |
| } |
| } |
| } |
| } |
| |
| switch (event.GetType()) { |
| // FIXME: WebKit seems to always return false on mouse events processing |
| // methods. For now we'll assume it has processed them (as we are only |
| // interested in whether keyboard events are processed). |
| // FIXME: Why do we return HandleSuppressed when there is no root or |
| // the root is detached? |
| case WebInputEvent::Type::kMouseMove: |
| if (!root || !root->View()) |
| return WebInputEventResult::kHandledSuppressed; |
| HandleMouseMove(*root, static_cast<const WebMouseEvent&>(event), |
| coalesced_event.GetCoalescedEventsPointers(), |
| coalesced_event.GetPredictedEventsPointers()); |
| return WebInputEventResult::kHandledSystem; |
| case WebInputEvent::Type::kMouseLeave: |
| if (!root || !root->View()) |
| return WebInputEventResult::kHandledSuppressed; |
| HandleMouseLeave(*root, static_cast<const WebMouseEvent&>(event)); |
| return WebInputEventResult::kHandledSystem; |
| case WebInputEvent::Type::kMouseDown: |
| if (!root || !root->View()) |
| return WebInputEventResult::kHandledSuppressed; |
| HandleMouseDown(*root, static_cast<const WebMouseEvent&>(event)); |
| return WebInputEventResult::kHandledSystem; |
| case WebInputEvent::Type::kMouseUp: |
| if (!root || !root->View()) |
| return WebInputEventResult::kHandledSuppressed; |
| return HandleMouseUp(*root, static_cast<const WebMouseEvent&>(event)); |
| case WebInputEvent::Type::kMouseWheel: |
| if (!root || !root->View()) |
| return WebInputEventResult::kNotHandled; |
| return HandleMouseWheel(*root, |
| static_cast<const WebMouseWheelEvent&>(event)); |
| |
| case WebInputEvent::Type::kRawKeyDown: |
| case WebInputEvent::Type::kKeyDown: |
| case WebInputEvent::Type::kKeyUp: |
| return HandleKeyEvent(static_cast<const WebKeyboardEvent&>(event)); |
| |
| case WebInputEvent::Type::kChar: |
| return HandleCharEvent(static_cast<const WebKeyboardEvent&>(event)); |
| case WebInputEvent::Type::kGestureScrollBegin: |
| case WebInputEvent::Type::kGestureScrollEnd: |
| case WebInputEvent::Type::kGestureScrollUpdate: |
| case WebInputEvent::Type::kGestureFlingStart: |
| case WebInputEvent::Type::kGestureFlingCancel: |
| case WebInputEvent::Type::kGestureTap: |
| case WebInputEvent::Type::kGestureTapUnconfirmed: |
| case WebInputEvent::Type::kGestureTapDown: |
| case WebInputEvent::Type::kGestureShowPress: |
| case WebInputEvent::Type::kGestureTapCancel: |
| case WebInputEvent::Type::kGestureDoubleTap: |
| case WebInputEvent::Type::kGestureTwoFingerTap: |
| case WebInputEvent::Type::kGestureShortPress: |
| case WebInputEvent::Type::kGestureLongPress: |
| case WebInputEvent::Type::kGestureLongTap: |
| return HandleGestureEvent(static_cast<const WebGestureEvent&>(event)); |
| |
| case WebInputEvent::Type::kPointerDown: |
| case WebInputEvent::Type::kPointerUp: |
| case WebInputEvent::Type::kPointerMove: |
| case WebInputEvent::Type::kPointerRawUpdate: |
| case WebInputEvent::Type::kPointerCancel: |
| case WebInputEvent::Type::kPointerCausedUaAction: |
| if (!root || !root->View()) |
| return WebInputEventResult::kNotHandled; |
| return HandlePointerEvent(*root, |
| static_cast<const WebPointerEvent&>(event), |
| coalesced_event.GetCoalescedEventsPointers(), |
| coalesced_event.GetPredictedEventsPointers()); |
| |
| case WebInputEvent::Type::kTouchStart: |
| case WebInputEvent::Type::kTouchMove: |
| case WebInputEvent::Type::kTouchEnd: |
| case WebInputEvent::Type::kTouchCancel: |
| case WebInputEvent::Type::kTouchScrollStarted: |
| NOTREACHED(); |
| return WebInputEventResult::kNotHandled; |
| |
| case WebInputEvent::Type::kGesturePinchBegin: |
| // Gesture pinch events are handled entirely on the compositor. |
| DLOG(INFO) << "Gesture pinch ignored by main thread."; |
| [[fallthrough]]; |
| case WebInputEvent::Type::kGesturePinchEnd: |
| case WebInputEvent::Type::kGesturePinchUpdate: |
| return WebInputEventResult::kNotHandled; |
| default: |
| return WebInputEventResult::kNotHandled; |
| } |
| } |
| |
| void WidgetEventHandler::HandleMouseMove( |
| LocalFrame& local_root, |
| const WebMouseEvent& event, |
| const std::vector<std::unique_ptr<WebInputEvent>>& coalesced_events, |
| const std::vector<std::unique_ptr<WebInputEvent>>& predicted_events) { |
| WebMouseEvent transformed_event = |
| TransformWebMouseEvent(local_root.View(), event); |
| local_root.GetEventHandler().HandleMouseMoveEvent( |
| transformed_event, |
| TransformWebMouseEventVector(local_root.View(), coalesced_events), |
| TransformWebMouseEventVector(local_root.View(), predicted_events)); |
| } |
| |
| void WidgetEventHandler::HandleMouseLeave(LocalFrame& local_root, |
| const WebMouseEvent& event) { |
| WebMouseEvent transformed_event = |
| TransformWebMouseEvent(local_root.View(), event); |
| local_root.GetEventHandler().HandleMouseLeaveEvent(transformed_event); |
| } |
| |
| namespace { |
| |
| bool IsDoubleAltClick(const blink::WebMouseEvent& mouse_event) { |
| bool is_alt_pressed = |
| mouse_event.GetModifiers() & blink::WebInputEvent::kAltKey; |
| if (!is_alt_pressed) { |
| return false; |
| } |
| return mouse_event.click_count == 2; |
| } |
| |
| } // namespace |
| |
| void WidgetEventHandler::HandleMouseDown(LocalFrame& local_root, |
| const WebMouseEvent& event) { |
| if (IsDoubleAltClick(event)) { |
| local_root.GetEventHandler().GetDelayedNavigationTaskHandle().Cancel(); |
| } |
| |
| WebMouseEvent transformed_event = |
| TransformWebMouseEvent(local_root.View(), event); |
| local_root.GetEventHandler().HandleMousePressEvent(transformed_event); |
| } |
| |
| WebInputEventResult WidgetEventHandler::HandleMouseUp( |
| LocalFrame& local_root, |
| const WebMouseEvent& event) { |
| WebMouseEvent transformed_event = |
| TransformWebMouseEvent(local_root.View(), event); |
| return local_root.GetEventHandler().HandleMouseReleaseEvent( |
| transformed_event); |
| } |
| |
| WebInputEventResult WidgetEventHandler::HandleMouseWheel( |
| LocalFrame& local_root, |
| const WebMouseWheelEvent& event) { |
| WebMouseWheelEvent transformed_event = |
| TransformWebMouseWheelEvent(local_root.View(), event); |
| return local_root.GetEventHandler().HandleWheelEvent(transformed_event); |
| } |
| |
| WebInputEventResult WidgetEventHandler::HandlePointerEvent( |
| LocalFrame& local_root, |
| const WebPointerEvent& event, |
| const std::vector<std::unique_ptr<WebInputEvent>>& coalesced_events, |
| const std::vector<std::unique_ptr<WebInputEvent>>& predicted_events) { |
| WebPointerEvent transformed_event = |
| TransformWebPointerEvent(local_root.View(), event); |
| return local_root.GetEventHandler().HandlePointerEvent( |
| transformed_event, |
| TransformWebPointerEventVector(local_root.View(), coalesced_events), |
| TransformWebPointerEventVector(local_root.View(), predicted_events)); |
| } |
| |
| } // namespace blink |