6404005d0fbbeb2c1dca164bd8daec6daa83b936
[platform/framework/web/chromium-efl.git] / third_party / blink / renderer / core / input / event_handler.cc
1 /*
2  * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights
3  * reserved.
4  * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
5  * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies)
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "third_party/blink/renderer/core/input/event_handler.h"
30
31 #include <memory>
32 #include <utility>
33
34 #include "build/build_config.h"
35 #include "third_party/blink/public/common/input/web_input_event.h"
36 #include "third_party/blink/public/common/input/web_mouse_wheel_event.h"
37 #include "third_party/blink/public/mojom/frame/user_activation_notification_type.mojom-blink.h"
38 #include "third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom-blink.h"
39 #include "third_party/blink/public/platform/task_type.h"
40 #include "third_party/blink/renderer/core/clipboard/data_transfer.h"
41 #include "third_party/blink/renderer/core/css/style_engine.h"
42 #include "third_party/blink/renderer/core/dom/document.h"
43 #include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"
44 #include "third_party/blink/renderer/core/dom/shadow_root.h"
45 #include "third_party/blink/renderer/core/editing/editing_utilities.h"
46 #include "third_party/blink/renderer/core/editing/editor.h"
47 #include "third_party/blink/renderer/core/editing/frame_selection.h"
48 #include "third_party/blink/renderer/core/editing/local_caret_rect.h"
49 #include "third_party/blink/renderer/core/editing/selection_controller.h"
50 #include "third_party/blink/renderer/core/editing/selection_template.h"
51 #include "third_party/blink/renderer/core/editing/text_affinity.h"
52 #include "third_party/blink/renderer/core/editing/visible_selection.h"
53 #include "third_party/blink/renderer/core/events/keyboard_event.h"
54 #include "third_party/blink/renderer/core/events/mouse_event.h"
55 #include "third_party/blink/renderer/core/events/pointer_event.h"
56 #include "third_party/blink/renderer/core/events/pointer_event_factory.h"
57 #include "third_party/blink/renderer/core/events/text_event.h"
58 #include "third_party/blink/renderer/core/events/touch_event.h"
59 #include "third_party/blink/renderer/core/frame/event_handler_registry.h"
60 #include "third_party/blink/renderer/core/frame/local_frame.h"
61 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
62 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
63 #include "third_party/blink/renderer/core/frame/settings.h"
64 #include "third_party/blink/renderer/core/frame/visual_viewport.h"
65 #include "third_party/blink/renderer/core/html/forms/html_input_element.h"
66 #include "third_party/blink/renderer/core/html/html_dialog_element.h"
67 #include "third_party/blink/renderer/core/html/html_frame_element_base.h"
68 #include "third_party/blink/renderer/core/html/html_frame_set_element.h"
69 #include "third_party/blink/renderer/core/html/portal/html_portal_element.h"
70 #include "third_party/blink/renderer/core/input/event_handling_util.h"
71 #include "third_party/blink/renderer/core/input/input_device_capabilities.h"
72 #include "third_party/blink/renderer/core/input_type_names.h"
73 #include "third_party/blink/renderer/core/layout/geometry/physical_offset.h"
74 #include "third_party/blink/renderer/core/layout/hit_test_request.h"
75 #include "third_party/blink/renderer/core/layout/hit_test_result.h"
76 #include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
77 #include "third_party/blink/renderer/core/layout/layout_view.h"
78 #include "third_party/blink/renderer/core/loader/anchor_element_interaction_tracker.h"
79 #include "third_party/blink/renderer/core/loader/resource/image_resource_content.h"
80 #include "third_party/blink/renderer/core/page/autoscroll_controller.h"
81 #include "third_party/blink/renderer/core/page/chrome_client.h"
82 #include "third_party/blink/renderer/core/page/drag_state.h"
83 #include "third_party/blink/renderer/core/page/frame_tree.h"
84 #include "third_party/blink/renderer/core/page/page.h"
85 #include "third_party/blink/renderer/core/page/touch_adjustment.h"
86 #include "third_party/blink/renderer/core/paint/paint_layer.h"
87 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
88 #include "third_party/blink/renderer/core/scroll/scrollbar.h"
89 #include "third_party/blink/renderer/core/style/computed_style.h"
90 #include "third_party/blink/renderer/core/style/cursor_data.h"
91 #include "third_party/blink/renderer/core/svg/graphics/svg_image.h"
92 #include "third_party/blink/renderer/core/svg/graphics/svg_image_for_container.h"
93 #include "third_party/blink/renderer/core/svg/svg_use_element.h"
94 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
95 #include "third_party/blink/renderer/platform/cursors.h"
96 #include "third_party/blink/renderer/platform/graphics/image_orientation.h"
97 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
98 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
99 #include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
100 #include "third_party/blink/renderer/platform/windows_keyboard_codes.h"
101 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
102 #include "third_party/skia/include/core/SkBitmap.h"
103 #include "ui/base/cursor/cursor.h"
104 #include "ui/base/cursor/mojom/cursor_type.mojom-blink.h"
105 #include "ui/base/dragdrop/mojom/drag_drop_types.mojom-blink.h"
106 #include "ui/display/screen_info.h"
107 #include "ui/display/screen_infos.h"
108 #include "ui/gfx/geometry/point.h"
109 #include "ui/gfx/geometry/point_conversions.h"
110 #include "ui/gfx/geometry/point_f.h"
111 #include "ui/gfx/geometry/rect.h"
112 #include "ui/gfx/geometry/rect_conversions.h"
113 #include "ui/gfx/geometry/size.h"
114 #include "ui/gfx/geometry/size_conversions.h"
115 #include "ui/gfx/geometry/size_f.h"
116
117 namespace blink {
118
119 using mojom::blink::FormControlType;
120
121 namespace {
122
123 // Refetch the event target node if it is removed or currently is the shadow
124 // node inside an <input> element.  If a mouse event handler changes the input
125 // element type to one that has a EmbeddedContentView associated, we'd like to
126 // EventHandler::handleMousePressEvent to pass the event to the
127 // EmbeddedContentView and thus the event target node can't still be the shadow
128 // node.
129 bool ShouldRefetchEventTarget(const MouseEventWithHitTestResults& mev) {
130   Node* target_node = mev.InnerNode();
131   if (!target_node || !target_node->parentNode())
132     return true;
133   if (auto* shadow_root = DynamicTo<ShadowRoot>(target_node))
134     return IsA<HTMLInputElement>(shadow_root->host());
135   return false;
136 }
137
138 gfx::Point GetMiddleSelectionCaretOfPosition(
139     const PositionWithAffinity& position) {
140   const LocalCaretRect& local_caret_rect = LocalCaretRectOfPosition(position);
141   if (local_caret_rect.IsEmpty())
142     return gfx::Point();
143   const gfx::Rect rect = AbsoluteCaretBoundsOf(position);
144   // In a multiline edit, rect.bottom() would end up on the next line, so
145   // take the midpoint in order to use this corner point directly.
146   if (local_caret_rect.layout_object->IsHorizontalWritingMode())
147     return {rect.x(), (rect.y() + rect.bottom()) / 2};
148
149   // When text is vertical, rect.right() would end up on the next line, so
150   // take the midpoint in order to use this corner point directly.
151   return {(rect.x() + rect.right()) / 2, rect.y()};
152 }
153
154 bool ContainsEvenAtEdge(const gfx::Rect& rect, const gfx::Point& point) {
155   return point.x() >= rect.x() && point.x() <= rect.right() &&
156          point.y() >= rect.y() && point.y() <= rect.bottom();
157 }
158
159 gfx::Point DetermineHotSpot(const Image& image,
160                             bool hot_spot_specified,
161                             const gfx::Point& specified_hot_spot) {
162   if (hot_spot_specified) {
163     return specified_hot_spot;
164   }
165
166   // If hot spot is not specified externally, it can be extracted from some
167   // image formats (e.g. .cur).
168   gfx::Point intrinsic_hot_spot;
169   const bool image_has_intrinsic_hot_spot =
170       image.GetHotSpot(intrinsic_hot_spot);
171   const gfx::Rect image_rect = image.Rect();
172   if (image_has_intrinsic_hot_spot && image_rect.Contains(intrinsic_hot_spot))
173     return intrinsic_hot_spot;
174
175   // If neither is provided, use a default value of (0, 0).
176   return gfx::Point();
177 }
178
179 // Returns whether the hit element contains a title and isn't a SVGUseElement or
180 // part of an SVGUseElement.
181 bool HasTitleAndNotSVGUseElement(const HitTestResult& hovered_node_result) {
182   // TODO(crbug.com/1473774): Remove flag check if no issues arise.
183   if (!RuntimeEnabledFeatures::SkipShadowHostWhenHoveringForTooltipEnabled()) {
184     return false;
185   }
186   Node* inner_node = hovered_node_result.InnerNode();
187   if (!inner_node) {
188     return false;
189   }
190   auto* element = DynamicTo<Element>(inner_node);
191   if (!element || element->title().IsNull()) {
192     return false;
193   }
194   ShadowRoot* containing_shadow_root = inner_node->ContainingShadowRoot();
195   if (IsA<SVGUseElement>(element) ||
196       (containing_shadow_root &&
197        IsA<SVGUseElement>(containing_shadow_root->host()))) {
198     return false;
199   }
200   return true;
201 }
202
203 }  // namespace
204
205 // The amount of time to wait for a cursor update on style and layout changes
206 // Set to 50Hz, no need to be faster than common screen refresh rate
207 static constexpr base::TimeDelta kCursorUpdateInterval = base::Milliseconds(20);
208
209 // The maximum size a cursor can be without falling back to the default cursor
210 // when intersecting browser native UI.
211 // https://developer.mozilla.org/en-US/docs/Web/CSS/cursor#icon_size_limits.
212 static const int kMaximumCursorSizeWithoutFallback = 32;
213
214 // The minimum amount of time an element stays active after a ShowPress
215 // This is roughly 9 frames, which should be long enough to be noticeable.
216 constexpr base::TimeDelta kMinimumActiveInterval = base::Seconds(0.15);
217
218 EventHandler::EventHandler(LocalFrame& frame)
219     : frame_(frame),
220       selection_controller_(MakeGarbageCollected<SelectionController>(frame)),
221       hover_timer_(frame.GetTaskRunner(TaskType::kUserInteraction),
222                    this,
223                    &EventHandler::HoverTimerFired),
224       cursor_update_timer_(
225           frame.GetTaskRunner(TaskType::kInternalUserInteraction),
226           this,
227           &EventHandler::CursorUpdateTimerFired),
228       should_only_fire_drag_over_event_(false),
229       event_handler_registry_(
230           frame_->IsLocalRoot()
231               ? MakeGarbageCollected<EventHandlerRegistry>(*frame_)
232               : &frame_->LocalFrameRoot().GetEventHandlerRegistry()),
233       scroll_manager_(MakeGarbageCollected<ScrollManager>(frame)),
234       mouse_event_manager_(
235           MakeGarbageCollected<MouseEventManager>(frame, *scroll_manager_)),
236       mouse_wheel_event_manager_(
237           MakeGarbageCollected<MouseWheelEventManager>(frame,
238                                                        *scroll_manager_)),
239       keyboard_event_manager_(
240           MakeGarbageCollected<KeyboardEventManager>(frame, *scroll_manager_)),
241       pointer_event_manager_(
242           MakeGarbageCollected<PointerEventManager>(frame,
243                                                     *mouse_event_manager_)),
244       gesture_manager_(
245           MakeGarbageCollected<GestureManager>(frame,
246                                                *scroll_manager_,
247                                                *mouse_event_manager_,
248                                                *pointer_event_manager_,
249                                                *selection_controller_)),
250       active_interval_timer_(frame.GetTaskRunner(TaskType::kUserInteraction),
251                              this,
252                              &EventHandler::ActiveIntervalTimerFired) {}
253
254 void EventHandler::Trace(Visitor* visitor) const {
255   visitor->Trace(frame_);
256   visitor->Trace(selection_controller_);
257   visitor->Trace(hover_timer_);
258   visitor->Trace(cursor_update_timer_);
259   visitor->Trace(capturing_mouse_events_element_);
260   visitor->Trace(capturing_subframe_element_);
261   visitor->Trace(last_mouse_move_event_subframe_);
262   visitor->Trace(last_scrollbar_under_mouse_);
263   visitor->Trace(drag_target_);
264   visitor->Trace(frame_set_being_resized_);
265   visitor->Trace(event_handler_registry_);
266   visitor->Trace(scroll_manager_);
267   visitor->Trace(mouse_event_manager_);
268   visitor->Trace(mouse_wheel_event_manager_);
269   visitor->Trace(keyboard_event_manager_);
270   visitor->Trace(pointer_event_manager_);
271   visitor->Trace(gesture_manager_);
272   visitor->Trace(active_interval_timer_);
273   visitor->Trace(last_deferred_tap_element_);
274 }
275
276 void EventHandler::Clear() {
277   hover_timer_.Stop();
278   cursor_update_timer_.Stop();
279   active_interval_timer_.Stop();
280   last_mouse_move_event_subframe_ = nullptr;
281   last_scrollbar_under_mouse_ = nullptr;
282   frame_set_being_resized_ = nullptr;
283   drag_target_ = nullptr;
284   should_only_fire_drag_over_event_ = false;
285   capturing_mouse_events_element_ = nullptr;
286   capturing_subframe_element_ = nullptr;
287   pointer_event_manager_->Clear();
288   scroll_manager_->Clear();
289   gesture_manager_->Clear();
290   mouse_event_manager_->Clear();
291   mouse_wheel_event_manager_->Clear();
292   last_show_press_timestamp_.reset();
293   last_deferred_tap_element_ = nullptr;
294   should_use_touch_event_adjusted_point_ = false;
295   touch_adjustment_result_.unique_event_id = 0;
296 }
297
298 void EventHandler::UpdateSelectionForMouseDrag() {
299   mouse_event_manager_->UpdateSelectionForMouseDrag();
300 }
301
302 void EventHandler::StartMiddleClickAutoscroll(LayoutObject* layout_object) {
303   DCHECK(RuntimeEnabledFeatures::MiddleClickAutoscrollEnabled());
304   if (!layout_object->IsBox())
305     return;
306   AutoscrollController* controller = scroll_manager_->GetAutoscrollController();
307   if (!controller)
308     return;
309
310   LayoutBox* scrollable = LayoutBox::FindAutoscrollable(
311       layout_object, /*is_middle_click_autoscroll*/ true);
312
313   controller->StartMiddleClickAutoscroll(
314       layout_object->GetFrame(), scrollable,
315       LastKnownMousePositionInRootFrame(),
316       mouse_event_manager_->LastKnownMouseScreenPosition());
317   mouse_event_manager_->InvalidateClick();
318 }
319
320 void EventHandler::PerformHitTest(const HitTestLocation& location,
321                                   HitTestResult& result,
322                                   bool no_lifecycle_update) const {
323   // LayoutView::hitTest causes a layout, and we don't want to hit that until
324   // the first layout because until then, there is nothing shown on the screen -
325   // the user can't have intentionally clicked on something belonging to this
326   // page.  Furthermore, mousemove events before the first layout should not
327   // lead to a premature layout() happening, which could show a flash of white.
328   // See also the similar code in Document::performMouseEventHitTest.
329   // The check to LifecycleUpdatesActive() prevents hit testing to frames
330   // that have already had layout but are throttled to prevent painting
331   // because the current Document isn't ready to render yet. In that case
332   // the lifecycle update prompted by HitTest() would fail.
333   if (!frame_->ContentLayoutObject() || !frame_->View() ||
334       !frame_->View()->DidFirstLayout() ||
335       !frame_->View()->LifecycleUpdatesActive())
336     return;
337
338   if (no_lifecycle_update) {
339     frame_->ContentLayoutObject()->HitTestNoLifecycleUpdate(location, result);
340   } else {
341     frame_->ContentLayoutObject()->HitTest(location, result);
342   }
343   const HitTestRequest& request = result.GetHitTestRequest();
344   if (!request.ReadOnly()) {
345     frame_->GetDocument()->UpdateHoverActiveState(
346         request.Active(), !request.Move(), result.InnerElement());
347   }
348 }
349
350 HitTestResult EventHandler::HitTestResultAtLocation(
351     const HitTestLocation& location,
352     HitTestRequest::HitTestRequestType hit_type,
353     const LayoutObject* stop_node,
354     bool no_lifecycle_update) {
355   TRACE_EVENT0("blink", "EventHandler::HitTestResultAtLocation");
356
357   // We always send HitTestResultAtLocation to the main frame if we have one,
358   // otherwise we might hit areas that are obscured by higher frames.
359   if (frame_->GetPage()) {
360     LocalFrame& main_frame = frame_->LocalFrameRoot();
361     if (frame_ != &main_frame) {
362       LocalFrameView* frame_view = frame_->View();
363       LocalFrameView* main_view = main_frame.View();
364       if (frame_view && main_view) {
365         HitTestLocation adjusted_location;
366         if (location.IsRectBasedTest()) {
367           DCHECK(location.IsRectilinear());
368           if (hit_type & HitTestRequest::kHitTestVisualOverflow) {
369             // Apply ancestor transforms to location rect
370             PhysicalRect local_rect = location.BoundingBox();
371             PhysicalRect main_frame_rect =
372                 frame_view->GetLayoutView()->LocalToAncestorRect(
373                     local_rect, main_view->GetLayoutView(),
374                     kTraverseDocumentBoundaries);
375             adjusted_location = HitTestLocation(main_frame_rect);
376           } else {
377             // Don't apply ancestor transforms to bounding box
378             PhysicalOffset main_content_point = main_view->ConvertFromRootFrame(
379                 frame_view->ConvertToRootFrame(location.BoundingBox().offset));
380             adjusted_location = HitTestLocation(
381                 PhysicalRect(main_content_point, location.BoundingBox().size));
382           }
383         } else {
384           adjusted_location = HitTestLocation(main_view->ConvertFromRootFrame(
385               frame_view->ConvertToRootFrame(location.Point())));
386         }
387         return main_frame.GetEventHandler().HitTestResultAtLocation(
388             adjusted_location, hit_type, stop_node, no_lifecycle_update);
389       }
390     }
391   }
392   // HitTestResultAtLocation is specifically used to hitTest into all frames,
393   // thus it always allows child frame content.
394   HitTestRequest request(hit_type | HitTestRequest::kAllowChildFrameContent,
395                          stop_node);
396   HitTestResult result(request, location);
397   PerformHitTest(location, result, no_lifecycle_update);
398   return result;
399 }
400
401 void EventHandler::StopAutoscroll() {
402   scroll_manager_->StopMiddleClickAutoscroll();
403   scroll_manager_->StopAutoscroll();
404 }
405
406 // TODO(bokan): This should be merged with logicalScroll assuming
407 // defaultSpaceEventHandler's chaining scroll can be done crossing frames.
408 bool EventHandler::BubblingScroll(mojom::blink::ScrollDirection direction,
409                                   ui::ScrollGranularity granularity,
410                                   Node* starting_node) {
411   return scroll_manager_->BubblingScroll(
412       direction, granularity, starting_node,
413       mouse_event_manager_->MousePressNode());
414 }
415
416 gfx::PointF EventHandler::LastKnownMousePositionInRootFrame() const {
417   return frame_->GetPage()->GetVisualViewport().ViewportToRootFrame(
418       mouse_event_manager_->LastKnownMousePositionInViewport());
419 }
420
421 gfx::PointF EventHandler::LastKnownMouseScreenPosition() const {
422   return mouse_event_manager_->LastKnownMouseScreenPosition();
423 }
424
425 gfx::Point EventHandler::DragDataTransferLocationForTesting() {
426   if (mouse_event_manager_->GetDragState().drag_data_transfer_)
427     return mouse_event_manager_->GetDragState()
428         .drag_data_transfer_->DragLocation();
429
430   return gfx::Point();
431 }
432
433 static bool IsSubmitImage(const Node* node) {
434   auto* html_input_element = DynamicTo<HTMLInputElement>(node);
435   return html_input_element &&
436          html_input_element->FormControlType() == FormControlType::kInputImage;
437 }
438
439 bool EventHandler::UsesHandCursor(const Node* node) {
440   if (!node)
441     return false;
442   return ((node->IsLink() || IsSubmitImage(node)) && !IsEditable(*node));
443 }
444
445 void EventHandler::CursorUpdateTimerFired(TimerBase*) {
446   DCHECK(frame_);
447   DCHECK(frame_->GetDocument());
448
449   UpdateCursor();
450 }
451
452 void EventHandler::UpdateCursor() {
453   TRACE_EVENT0("input", "EventHandler::updateCursor");
454
455   // We must do a cross-frame hit test because the frame that triggered the
456   // cursor update could be occluded by a different frame.
457   DCHECK_EQ(frame_, &frame_->LocalFrameRoot());
458
459   LocalFrameView* view = frame_->View();
460   if (!view || !view->ShouldSetCursor())
461     return;
462
463   auto* layout_view = view->GetLayoutView();
464   if (!layout_view)
465     return;
466
467   frame_->GetDocument()->UpdateStyleAndLayout(DocumentUpdateReason::kInput);
468
469   HitTestRequest request(HitTestRequest::kReadOnly |
470                          HitTestRequest::kAllowChildFrameContent);
471   HitTestLocation location(view->ViewportToFrame(
472       mouse_event_manager_->LastKnownMousePositionInViewport()));
473   HitTestResult result(request, location);
474   layout_view->HitTest(location, result);
475
476   if (LocalFrame* frame = result.InnerNodeFrame()) {
477     absl::optional<ui::Cursor> optional_cursor =
478         frame->GetEventHandler().SelectCursor(location, result);
479     if (optional_cursor.has_value()) {
480       view->SetCursor(optional_cursor.value());
481     }
482   }
483 }
484
485 bool EventHandler::ShouldShowResizeForNode(const LayoutObject& layout_object,
486                                            const HitTestLocation& location) {
487   const PaintLayer* layer = layout_object.EnclosingLayer();
488   const PaintLayerScrollableArea* scrollable_area = layer->GetScrollableArea();
489   return scrollable_area &&
490          scrollable_area->IsAbsolutePointInResizeControl(
491              ToRoundedPoint(location.Point()), kResizerForPointer);
492 }
493
494 bool EventHandler::IsSelectingLink(const HitTestResult& result) {
495   // If a drag may be starting or we're capturing mouse events for a particular
496   // node, don't treat this as a selection. Note calling
497   // ComputeVisibleSelectionInDOMTreeDeprecated may update layout.
498   const bool mouse_selection =
499       !capturing_mouse_events_element_ &&
500       mouse_event_manager_->MousePressed() &&
501       GetSelectionController().MouseDownMayStartSelect() &&
502       !mouse_event_manager_->MouseDownMayStartDrag() &&
503       !frame_->Selection()
504            .ComputeVisibleSelectionInDOMTreeDeprecated()
505            .IsNone();
506   return mouse_selection && result.IsOverLink();
507 }
508
509 bool EventHandler::ShouldShowIBeamForNode(const Node* node,
510                                           const HitTestResult& result) {
511   if (!node)
512     return false;
513
514   if (node->IsTextNode() && (node->CanStartSelection() || result.IsOverLink()))
515     return true;
516
517   return IsEditable(*node);
518 }
519
520 absl::optional<ui::Cursor> EventHandler::SelectCursor(
521     const HitTestLocation& location,
522     const HitTestResult& result) {
523   if (scroll_manager_->InResizeMode())
524     return absl::nullopt;
525
526   Page* page = frame_->GetPage();
527   if (!page)
528     return absl::nullopt;
529   if (scroll_manager_->MiddleClickAutoscrollInProgress())
530     return absl::nullopt;
531
532   if (result.GetScrollbar() && !result.GetScrollbar()->IsCustomScrollbar())
533     return PointerCursor();
534
535   Node* node = result.InnerPossiblyPseudoNode();
536   if (!node || !node->GetLayoutObject()) {
537     return SelectAutoCursor(result, node, IBeamCursor());
538   }
539
540   const LayoutObject& layout_object = *node->GetLayoutObject();
541   if (ShouldShowResizeForNode(layout_object, location)) {
542     const LayoutBox* box = layout_object.EnclosingLayer()->GetLayoutBox();
543     EResize resize = box->StyleRef().UsedResize();
544     switch (resize) {
545       case EResize::kVertical:
546         return NorthSouthResizeCursor();
547       case EResize::kHorizontal:
548         return EastWestResizeCursor();
549       case EResize::kBoth:
550         if (box->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
551           return SouthWestResizeCursor();
552         } else {
553           return SouthEastResizeCursor();
554         }
555       default:
556         return PointerCursor();
557     }
558   }
559
560   {
561     ui::Cursor override_cursor;
562     switch (layout_object.GetCursor(result.LocalPoint(), override_cursor)) {
563       case kSetCursorBasedOnStyle:
564         break;
565       case kSetCursor:
566         return override_cursor;
567       case kDoNotSetCursor:
568         return absl::nullopt;
569     }
570   }
571
572   const ComputedStyle& style = layout_object.StyleRef();
573   if (const CursorList* cursors = style.Cursors()) {
574     for (const auto& cursor : *cursors) {
575       const StyleImage* style_image = cursor.GetImage();
576       if (!style_image || !style_image->CanRender()) {
577         continue;
578       }
579       // The 'cursor' property only allow url() and image-set(). Either of
580       // those will return false from their CanRender() implementation if they
581       // don't have an ImageResourceContent (and the former should always have
582       // one).
583       CHECK(style_image->CachedImage());
584
585       // Compute the concrete object size in DIP based on the
586       // default cursor size obtained from the OS.
587       gfx::SizeF size =
588           style_image->ImageSize(1,
589                                  gfx::SizeF(page->GetChromeClient()
590                                                 .GetScreenInfos(*frame_)
591                                                 .system_cursor_size),
592                                  kRespectImageOrientation);
593
594       float scale = style_image->ImageScaleFactor();
595       Image* image = style_image->CachedImage()->GetImage();
596       if (image->IsSVGImage()) {
597         // `StyleImage::ImageSize` does not take `StyleImage::ImageScaleFactor`
598         // into account when computing the size for SVG images.
599         size.Scale(1 / scale);
600       }
601
602       if (size.IsEmpty() ||
603           !ui::Cursor::AreDimensionsValidForWeb(
604               gfx::ToCeiledSize(gfx::ScaleSize(size, scale)), scale)) {
605         continue;
606       }
607
608       const float device_scale_factor =
609           page->GetChromeClient().GetScreenInfo(*frame_).device_scale_factor;
610
611       // If the image is an SVG, then adjust the scale to reflect the device
612       // scale factor so that the SVG can be rasterized in the native
613       // resolution and scaled down to the correct size for the cursor.
614       scoped_refptr<Image> svg_image_holder;
615       if (auto* svg_image = DynamicTo<SVGImage>(image)) {
616         scale *= device_scale_factor;
617         // Re-scale back from DIP to device pixels.
618         size.Scale(scale);
619
620         // TODO(fs): Should pass proper URL. Use StyleImage::GetImage.
621         svg_image_holder = SVGImageForContainer::Create(
622             svg_image, size, device_scale_factor, NullURL(),
623             frame_->GetDocument()
624                 ->GetStyleEngine()
625                 .ResolveColorSchemeForEmbedding(&style));
626         image = svg_image_holder.get();
627       }
628
629       // Convert from DIP to physical pixels.
630       gfx::Point hot_spot = gfx::ScaleToRoundedPoint(cursor.HotSpot(), scale);
631
632       const bool hot_spot_specified = cursor.HotSpotSpecified();
633       ui::Cursor custom_cursor = ui::Cursor::NewCustom(
634           image->AsSkBitmapForCurrentFrame(kRespectImageOrientation),
635           DetermineHotSpot(*image, hot_spot_specified, hot_spot), scale);
636
637       // For large cursors below the max size, limit their ability to cover UI
638       // elements by removing them when they are not fully contained by the
639       // visual viewport. Careful, we need to make sure to translate coordinate
640       // spaces if we are in an OOPIF.
641       //
642       // TODO(csharrison): Consider sending a fallback cursor in the IPC to the
643       // browser process so we can do that calculation there instead, this would
644       // ensure even a compromised renderer could not obscure browser UI with a
645       // large cursor. Also, consider augmenting the intervention to drop the
646       // cursor for iframes if the cursor image obscures content in the parent
647       // frame.
648       gfx::SizeF custom_bitmap_size(custom_cursor.custom_bitmap().width(),
649                                     custom_cursor.custom_bitmap().height());
650       custom_bitmap_size.Scale(1.f / custom_cursor.image_scale_factor());
651       if (custom_bitmap_size.width() > kMaximumCursorSizeWithoutFallback ||
652           custom_bitmap_size.height() > kMaximumCursorSizeWithoutFallback) {
653         PhysicalOffset ancestor_location =
654             frame_->ContentLayoutObject()->LocalToAncestorPoint(
655                 location.Point(),
656                 nullptr,  // no ancestor maps all the way up the hierarchy
657                 kTraverseDocumentBoundaries | kApplyRemoteMainFrameTransform);
658
659         // Check the cursor rect with device and accessibility scaling applied.
660         const float scale_factor =
661             cursor_accessibility_scale_factor_ *
662             (image->IsSVGImage() ? 1.f : device_scale_factor);
663         gfx::SizeF scaled_size(custom_bitmap_size);
664         scaled_size.Scale(scale_factor);
665         gfx::PointF scaled_hot_spot(custom_cursor.custom_hotspot());
666         scaled_hot_spot.Scale(scale_factor /
667                               custom_cursor.image_scale_factor());
668         PhysicalRect cursor_rect(
669             ancestor_location -
670                 PhysicalOffset::FromPointFFloor(scaled_hot_spot),
671             PhysicalSize::FromSizeFFloor(scaled_size));
672
673         PhysicalRect frame_rect(page->GetVisualViewport().VisibleContentRect());
674         frame_->ContentLayoutObject()->MapToVisualRectInAncestorSpace(
675             nullptr, frame_rect);
676
677         if (!frame_rect.Contains(cursor_rect)) {
678           continue;
679         }
680       }
681
682       return custom_cursor;
683     }
684   }
685
686   const ui::Cursor& i_beam =
687       style.IsHorizontalWritingMode() ? IBeamCursor() : VerticalTextCursor();
688
689   switch (style.Cursor()) {
690     case ECursor::kAuto:
691       return SelectAutoCursor(result, node, i_beam);
692     case ECursor::kCrosshair:
693       return CrossCursor();
694     case ECursor::kPointer:
695       return IsSelectingLink(result) ? i_beam : HandCursor();
696     case ECursor::kMove:
697       return MoveCursor();
698     case ECursor::kAllScroll:
699       return MoveCursor();
700     case ECursor::kEResize:
701       return EastResizeCursor();
702     case ECursor::kWResize:
703       return WestResizeCursor();
704     case ECursor::kNResize:
705       return NorthResizeCursor();
706     case ECursor::kSResize:
707       return SouthResizeCursor();
708     case ECursor::kNeResize:
709       return NorthEastResizeCursor();
710     case ECursor::kSwResize:
711       return SouthWestResizeCursor();
712     case ECursor::kNwResize:
713       return NorthWestResizeCursor();
714     case ECursor::kSeResize:
715       return SouthEastResizeCursor();
716     case ECursor::kNsResize:
717       return NorthSouthResizeCursor();
718     case ECursor::kEwResize:
719       return EastWestResizeCursor();
720     case ECursor::kNeswResize:
721       return NorthEastSouthWestResizeCursor();
722     case ECursor::kNwseResize:
723       return NorthWestSouthEastResizeCursor();
724     case ECursor::kColResize:
725       return ColumnResizeCursor();
726     case ECursor::kRowResize:
727       return RowResizeCursor();
728     case ECursor::kText:
729       return i_beam;
730     case ECursor::kWait:
731       return WaitCursor();
732     case ECursor::kHelp:
733       return HelpCursor();
734     case ECursor::kVerticalText:
735       return VerticalTextCursor();
736     case ECursor::kCell:
737       return CellCursor();
738     case ECursor::kContextMenu:
739       return ContextMenuCursor();
740     case ECursor::kProgress:
741       return ProgressCursor();
742     case ECursor::kNoDrop:
743       return NoDropCursor();
744     case ECursor::kAlias:
745       return AliasCursor();
746     case ECursor::kCopy:
747       return CopyCursor();
748     case ECursor::kNone:
749       return NoneCursor();
750     case ECursor::kNotAllowed:
751       return NotAllowedCursor();
752     case ECursor::kDefault:
753       return PointerCursor();
754     case ECursor::kZoomIn:
755       return ZoomInCursor();
756     case ECursor::kZoomOut:
757       return ZoomOutCursor();
758     case ECursor::kGrab:
759       return GrabCursor();
760     case ECursor::kGrabbing:
761       return GrabbingCursor();
762   }
763   return PointerCursor();
764 }
765
766 absl::optional<ui::Cursor> EventHandler::SelectAutoCursor(
767     const HitTestResult& result,
768     Node* node,
769     const ui::Cursor& i_beam) {
770   if (ShouldShowIBeamForNode(node, result))
771     return i_beam;
772
773   return PointerCursor();
774 }
775
776 WebInputEventResult EventHandler::DispatchBufferedTouchEvents() {
777   return pointer_event_manager_->FlushEvents();
778 }
779
780 WebInputEventResult EventHandler::HandlePointerEvent(
781     const WebPointerEvent& web_pointer_event,
782     const Vector<WebPointerEvent>& coalesced_events,
783     const Vector<WebPointerEvent>& predicted_events) {
784   return pointer_event_manager_->HandlePointerEvent(
785       web_pointer_event, coalesced_events, predicted_events);
786 }
787
788 WebInputEventResult EventHandler::HandleMousePressEvent(
789     const WebMouseEvent& mouse_event) {
790   TRACE_EVENT0("blink", "EventHandler::handleMousePressEvent");
791
792   // For 4th/5th button in the mouse since Chrome does not yet send
793   // button value to Blink but in some cases it does send the event.
794   // This check is needed to suppress such an event (crbug.com/574959)
795   if (mouse_event.button == WebPointerProperties::Button::kNoButton)
796     return WebInputEventResult::kHandledSuppressed;
797
798   capturing_mouse_events_element_ = nullptr;
799   mouse_event_manager_->HandleMousePressEventUpdateStates(mouse_event);
800   if (!frame_->View())
801     return WebInputEventResult::kNotHandled;
802
803 #if BUILDFLAG(IS_TIZEN_TV)
804   handled_mouse_left_button_press_event_ = false;
805 #endif
806
807   HitTestRequest request(HitTestRequest::kActive);
808   // Save the document point we generate in case the window coordinate is
809   // invalidated by what happens when we dispatch the event.
810   PhysicalOffset document_point = frame_->View()->ConvertFromRootFrame(
811       PhysicalOffset(gfx::ToFlooredPoint(mouse_event.PositionInRootFrame())));
812   MouseEventWithHitTestResults mev = GetMouseEventTarget(request, mouse_event);
813   if (!mev.InnerNode()) {
814     // An anonymous box can be scrollable.
815     if (PassMousePressEventToScrollbar(mev))
816       return WebInputEventResult::kHandledSystem;
817
818     mouse_event_manager_->InvalidateClick();
819     return WebInputEventResult::kNotHandled;
820   }
821
822   mouse_event_manager_->SetMousePressNode(mev.InnerNode());
823   frame_->GetDocument()->SetSequentialFocusNavigationStartingPoint(
824       mev.InnerNode());
825
826   LocalFrame* subframe = event_handling_util::GetTargetSubframe(mev);
827   if (subframe) {
828     WebInputEventResult result = PassMousePressEventToSubframe(mev, subframe);
829     // Start capturing future events for this frame.  We only do this if we
830     // didn't clear the m_mousePressed flag, which may happen if an AppKit
831     // EmbeddedContentView entered a modal event loop.  The capturing should be
832     // done only when the result indicates it has been handled. See
833     // crbug.com/269917
834     mouse_event_manager_->SetCapturesDragging(
835         subframe->GetEventHandler().mouse_event_manager_->CapturesDragging());
836     if (mouse_event_manager_->MousePressed() &&
837         mouse_event_manager_->CapturesDragging()) {
838       capturing_mouse_events_element_ = mev.InnerElement();
839       capturing_subframe_element_ = mev.InnerElement();
840     }
841
842     mouse_event_manager_->InvalidateClick();
843     return result;
844   }
845
846   if (discarded_events_.mouse_down_target != kInvalidDOMNodeId &&
847       discarded_events_.mouse_down_target == mev.InnerNode()->GetDomNodeId() &&
848       mouse_event.TimeStamp() - discarded_events_.mouse_down_time <
849           event_handling_util::kDiscardedEventMistakeInterval) {
850     mev.InnerNode()->GetDocument().CountUse(
851         WebFeature::kInputEventToRecentlyMovedIframeMistakenlyDiscarded);
852   }
853   if (event_handling_util::ShouldDiscardEventTargetingFrame(mev.Event(),
854                                                             *frame_)) {
855     discarded_events_.mouse_down_target = mev.InnerNode()->GetDomNodeId();
856     discarded_events_.mouse_down_time = mouse_event.TimeStamp();
857     return WebInputEventResult::kHandledSuppressed;
858   } else {
859     discarded_events_.mouse_down_target = kInvalidDOMNodeId;
860     discarded_events_.mouse_down_time = base::TimeTicks();
861   }
862
863   LocalFrame::NotifyUserActivation(
864       frame_, mojom::blink::UserActivationNotificationType::kInteraction,
865       RuntimeEnabledFeatures::BrowserVerifiedUserActivationMouseEnabled());
866
867   if (RuntimeEnabledFeatures::MiddleClickAutoscrollEnabled()) {
868     // We store whether middle click autoscroll is in progress before calling
869     // stopAutoscroll() because it will set m_autoscrollType to NoAutoscroll on
870     // return.
871     bool is_middle_click_autoscroll_in_progress =
872         scroll_manager_->MiddleClickAutoscrollInProgress();
873     scroll_manager_->StopMiddleClickAutoscroll();
874     if (is_middle_click_autoscroll_in_progress) {
875       // We invalidate the click when exiting middle click auto scroll so that
876       // we don't inadvertently navigate away from the current page (e.g. the
877       // click was on a hyperlink). See <rdar://problem/6095023>.
878       mouse_event_manager_->InvalidateClick();
879       return WebInputEventResult::kHandledSuppressed;
880     }
881   }
882
883   mouse_event_manager_->SetClickCount(mouse_event.click_count);
884   mouse_event_manager_->SetClickElement(mev.InnerElement());
885
886   if (!mouse_event.FromTouch())
887     frame_->Selection().SetCaretBlinkingSuspended(true);
888
889   WebInputEventResult event_result = DispatchMousePointerEvent(
890       WebInputEvent::Type::kPointerDown, mev.InnerElement(), mev.Event(),
891       Vector<WebMouseEvent>(), Vector<WebMouseEvent>());
892
893   // Disabled form controls still need to resize the scrollable area.
894   if ((event_result == WebInputEventResult::kNotHandled ||
895        event_result == WebInputEventResult::kHandledSuppressed) &&
896       frame_->View()) {
897     LocalFrameView* view = frame_->View();
898     PaintLayer* layer =
899         mev.InnerNode()->GetLayoutObject()
900             ? mev.InnerNode()->GetLayoutObject()->EnclosingLayer()
901             : nullptr;
902     gfx::Point p = view->ConvertFromRootFrame(
903         gfx::ToFlooredPoint(mouse_event.PositionInRootFrame()));
904     if (layer && layer->GetScrollableArea() &&
905         layer->GetScrollableArea()->IsAbsolutePointInResizeControl(
906             p, kResizerForPointer)) {
907       scroll_manager_->SetResizeScrollableArea(layer, p);
908       return WebInputEventResult::kHandledSystem;
909     }
910   }
911
912   // m_selectionInitiationState is initialized after dispatching mousedown
913   // event in order not to keep the selection by DOM APIs because we can't
914   // give the user the chance to handle the selection by user action like
915   // dragging if we keep the selection in case of mousedown. FireFox also has
916   // the same behavior and it's more compatible with other browsers.
917   GetSelectionController().InitializeSelectionState();
918   HitTestResult hit_test_result = event_handling_util::HitTestResultInFrame(
919       frame_, HitTestLocation(document_point), HitTestRequest::kReadOnly);
920   InputDeviceCapabilities* source_capabilities =
921       frame_->DomWindow()->GetInputDeviceCapabilities()->FiresTouchEvents(
922           mouse_event.FromTouch());
923
924   if (event_result == WebInputEventResult::kNotHandled) {
925     event_result = mouse_event_manager_->HandleMouseFocus(hit_test_result,
926                                                           source_capabilities);
927   }
928
929   if (event_result == WebInputEventResult::kNotHandled || mev.GetScrollbar()) {
930     mouse_event_manager_->SetCapturesDragging(true);
931     // Outermost main frames don't implicitly capture mouse input on MouseDown,
932     // all subframes do (regardless of whether local or remote or fenced).
933     if (frame_->IsAttached() && !frame_->IsOutermostMainFrame())
934       CaptureMouseEventsToWidget(true);
935   } else {
936     mouse_event_manager_->SetCapturesDragging(false);
937   }
938 #if BUILDFLAG(IS_TIZEN_TV)
939   if (frame_->GetSettings() && frame_->GetSettings()->GetUseArrowScroll() &&
940       mouse_event.button == WebPointerProperties::Button::kLeft) {
941     handled_mouse_left_button_press_event_ =
942         (SelectCursor(mev.GetHitTestLocation(), mev.GetHitTestResult())
943              .value()
944              .type() == ui::mojom::blink::CursorType::kPointer)
945             ? event_result != WebInputEventResult::kNotHandled
946             : true;
947   }
948 #endif
949
950   if (PassMousePressEventToScrollbar(mev))
951     event_result = WebInputEventResult::kHandledSystem;
952
953   if (event_result == WebInputEventResult::kNotHandled) {
954     if (ShouldRefetchEventTarget(mev)) {
955       HitTestRequest read_only_request(HitTestRequest::kReadOnly |
956                                        HitTestRequest::kActive);
957       mev = frame_->GetDocument()->PerformMouseEventHitTest(
958           read_only_request, document_point, mouse_event);
959     }
960     event_result = mouse_event_manager_->HandleMousePressEvent(mev);
961   }
962
963   if (mev.GetHitTestResult().InnerNode() &&
964       mouse_event.button == WebPointerProperties::Button::kLeft) {
965     DCHECK_EQ(WebInputEvent::Type::kMouseDown, mouse_event.GetType());
966     HitTestResult result = mev.GetHitTestResult();
967     result.SetToShadowHostIfInUAShadowRoot();
968     frame_->GetChromeClient().OnMouseDown(*result.InnerNode());
969   }
970
971   return event_result;
972 }
973
974 WebInputEventResult EventHandler::HandleMouseMoveEvent(
975     const WebMouseEvent& event,
976     const Vector<WebMouseEvent>& coalesced_events,
977     const Vector<WebMouseEvent>& predicted_events) {
978   TRACE_EVENT0("blink", "EventHandler::handleMouseMoveEvent");
979   DCHECK(event.GetType() == WebInputEvent::Type::kMouseMove);
980   HitTestResult hovered_node_result;
981   HitTestLocation location;
982   WebInputEventResult result =
983       HandleMouseMoveOrLeaveEvent(event, coalesced_events, predicted_events,
984                                   &hovered_node_result, &location);
985
986   Page* page = frame_->GetPage();
987   if (!page)
988     return result;
989
990   if (PaintLayer* layer =
991           event_handling_util::LayerForNode(hovered_node_result.InnerNode())) {
992     if (ScrollableArea* layer_scrollable_area =
993             event_handling_util::AssociatedScrollableArea(layer))
994       layer_scrollable_area->MouseMovedInContentArea();
995   }
996
997   // Should not convert the hit shadow element to its shadow host, so that
998   // tooltips in the shadow tree appear correctly.
999   if (!HasTitleAndNotSVGUseElement(hovered_node_result)) {
1000     hovered_node_result.SetToShadowHostIfInUAShadowRoot();
1001   }
1002   page->GetChromeClient().MouseDidMoveOverElement(*frame_, location,
1003                                                   hovered_node_result);
1004
1005   return result;
1006 }
1007
1008 void EventHandler::HandleMouseLeaveEvent(const WebMouseEvent& event) {
1009   TRACE_EVENT0("blink", "EventHandler::handleMouseLeaveEvent");
1010   DCHECK(event.GetType() == WebInputEvent::Type::kMouseLeave);
1011
1012   Page* page = frame_->GetPage();
1013   if (page)
1014     page->GetChromeClient().ClearToolTip(*frame_);
1015   HandleMouseMoveOrLeaveEvent(event, Vector<WebMouseEvent>(),
1016                               Vector<WebMouseEvent>());
1017   pointer_event_manager_->RemoveLastMousePosition();
1018 }
1019
1020 WebInputEventResult EventHandler::HandleMouseMoveOrLeaveEvent(
1021     const WebMouseEvent& mouse_event,
1022     const Vector<WebMouseEvent>& coalesced_events,
1023     const Vector<WebMouseEvent>& predicted_events,
1024     HitTestResult* hovered_node_result,
1025     HitTestLocation* hit_test_location) {
1026   DCHECK(frame_);
1027   DCHECK(frame_->View());
1028   DCHECK(mouse_event.GetType() == WebInputEvent::Type::kMouseMove ||
1029          mouse_event.GetType() == WebInputEvent::Type::kMouseLeave);
1030   mouse_event_manager_->SetLastKnownMousePosition(mouse_event);
1031
1032   hover_timer_.Stop();
1033   cursor_update_timer_.Stop();
1034
1035   mouse_event_manager_->HandleSvgPanIfNeeded(false);
1036
1037   if (mouse_event.GetType() == WebInputEvent::Type::kMouseMove) {
1038     AnchorElementInteractionTracker* tracker =
1039         frame_->GetDocument()->GetAnchorElementInteractionTracker();
1040     if (tracker) {
1041       tracker->OnMouseMoveEvent(mouse_event);
1042     }
1043   }
1044
1045   // Mouse states need to be reset when mouse move with no button down.
1046   // This is for popup/context_menu opened at mouse_down event and
1047   // mouse_release is not handled in page.
1048   // crbug.com/527582
1049   if (mouse_event.button == WebPointerProperties::Button::kNoButton &&
1050       !(mouse_event.GetModifiers() &
1051         WebInputEvent::Modifiers::kRelativeMotionEvent)) {
1052     mouse_event_manager_->ClearDragHeuristicState();
1053     capturing_mouse_events_element_ = nullptr;
1054     ReleaseMouseCaptureFromLocalRoot();
1055
1056     // If the scrollbar still thinks it's being dragged, tell it to stop.
1057     // Can happen on Win if we lose focus (e.g. from Alt-Tab) mid-drag.
1058     if (last_scrollbar_under_mouse_ &&
1059         last_scrollbar_under_mouse_->PressedPart() != ScrollbarPart::kNoPart)
1060       last_scrollbar_under_mouse_->MouseUp(mouse_event);
1061   }
1062
1063   if (RuntimeEnabledFeatures::MiddleClickAutoscrollEnabled()) {
1064     if (Page* page = frame_->GetPage()) {
1065       page->GetAutoscrollController().HandleMouseMoveForMiddleClickAutoscroll(
1066           frame_, mouse_event_manager_->LastKnownMouseScreenPosition(),
1067           mouse_event.button == WebPointerProperties::Button::kMiddle);
1068     }
1069   }
1070
1071   if (frame_set_being_resized_) {
1072     return DispatchMousePointerEvent(
1073         WebInputEvent::Type::kPointerMove, frame_set_being_resized_.Get(),
1074         mouse_event, coalesced_events, predicted_events);
1075   }
1076
1077   // Send events right to a scrollbar if the mouse is pressed.
1078   if (last_scrollbar_under_mouse_ && mouse_event_manager_->MousePressed()) {
1079     last_scrollbar_under_mouse_->MouseMoved(mouse_event);
1080     return WebInputEventResult::kHandledSystem;
1081   }
1082
1083   HitTestRequest::HitTestRequestType hit_type = HitTestRequest::kMove;
1084   if (mouse_event_manager_->MousePressed()) {
1085     hit_type |= HitTestRequest::kActive;
1086   }
1087
1088   // Treat any mouse move events as readonly if the user is currently touching
1089   // the screen.
1090   if (pointer_event_manager_->IsAnyTouchActive() &&
1091       mouse_event.GetType() == WebInputEvent::Type::kMouseMove) {
1092     hit_type |= HitTestRequest::kActive | HitTestRequest::kReadOnly;
1093   }
1094   HitTestRequest request(hit_type);
1095   HitTestLocation out_location((PhysicalOffset()));
1096   MouseEventWithHitTestResults mev = MouseEventWithHitTestResults(
1097       mouse_event, out_location, HitTestResult(request, out_location));
1098
1099   // We don't want to do a hit-test in MouseLeave scenarios because there
1100   // might actually be some other frame above this one at the specified
1101   // coordinate. So we avoid the hit test but still clear the hover/active
1102   // state.
1103   if (mouse_event.GetType() == WebInputEvent::Type::kMouseLeave) {
1104     frame_->GetDocument()->UpdateHoverActiveState(request.Active(),
1105                                                   /*update_active_chain=*/false,
1106                                                   nullptr);
1107   } else {
1108     mev = GetMouseEventTarget(request, mouse_event);
1109   }
1110
1111   if (hovered_node_result)
1112     *hovered_node_result = mev.GetHitTestResult();
1113
1114   if (hit_test_location)
1115     *hit_test_location = mev.GetHitTestLocation();
1116
1117   Scrollbar* scrollbar = nullptr;
1118
1119   if (scroll_manager_->InResizeMode()) {
1120     scroll_manager_->Resize(mev.Event());
1121   } else {
1122     scrollbar = mev.GetScrollbar();
1123
1124     UpdateLastScrollbarUnderMouse(scrollbar,
1125                                   !mouse_event_manager_->MousePressed());
1126   }
1127
1128   WebInputEventResult event_result = WebInputEventResult::kNotHandled;
1129   bool is_portal =
1130       mev.InnerElement() && IsA<HTMLPortalElement>(*mev.InnerElement());
1131   bool is_remote_frame = false;
1132   LocalFrame* current_subframe = event_handling_util::GetTargetSubframe(
1133       mev, capturing_mouse_events_element_, &is_remote_frame);
1134
1135   // We want mouseouts to happen first, from the inside out.  First send a
1136   // move event to the last subframe so that it will fire mouseouts.
1137   // TODO(lanwei): figure out here if we should call HandleMouseLeaveEvent on a
1138   // mouse move event.
1139   if (last_mouse_move_event_subframe_ &&
1140       last_mouse_move_event_subframe_->Tree().IsDescendantOf(frame_) &&
1141       last_mouse_move_event_subframe_ != current_subframe) {
1142     WebMouseEvent event = mev.Event();
1143     event.SetType(WebInputEvent::Type::kMouseLeave);
1144     last_mouse_move_event_subframe_->GetEventHandler().HandleMouseLeaveEvent(
1145         event);
1146     last_mouse_move_event_subframe_->GetEventHandler()
1147         .mouse_event_manager_->SetLastMousePositionAsUnknown();
1148   }
1149
1150   if (current_subframe) {
1151     // Update over/out state before passing the event to the subframe.
1152     pointer_event_manager_->SendMouseAndPointerBoundaryEvents(
1153         EffectiveMouseEventTargetElement(mev.InnerElement()), mev.Event());
1154
1155     // Event dispatch in sendMouseAndPointerBoundaryEvents may have caused the
1156     // subframe of the target node to be detached from its LocalFrameView, in
1157     // which case the event should not be passed.
1158     if (current_subframe->View()) {
1159       event_result =
1160           PassMouseMoveEventToSubframe(mev, coalesced_events, predicted_events,
1161                                        current_subframe, hovered_node_result);
1162     }
1163   } else {
1164     if (scrollbar && !mouse_event_manager_->MousePressed()) {
1165       // Handle hover effects on platforms that support visual feedback on
1166       // scrollbar hovering.
1167       scrollbar->MouseMoved(mev.Event());
1168     }
1169
1170     // Set Effective pan action before Pointer cursor is updated.
1171     const WebPointerEvent web_pointer_event(WebInputEvent::Type::kPointerMove,
1172                                             mev.Event().FlattenTransform());
1173     pointer_event_manager_->SendEffectivePanActionAtPointer(web_pointer_event,
1174                                                             mev.InnerNode());
1175
1176     LocalFrameView* view = frame_->View();
1177     if ((!is_remote_frame || is_portal) && view) {
1178       absl::optional<ui::Cursor> optional_cursor =
1179           SelectCursor(mev.GetHitTestLocation(), mev.GetHitTestResult());
1180       if (optional_cursor.has_value()) {
1181         view->SetCursor(optional_cursor.value());
1182       }
1183     }
1184   }
1185
1186   last_mouse_move_event_subframe_ = current_subframe;
1187
1188   if (event_result != WebInputEventResult::kNotHandled)
1189     return event_result;
1190
1191   event_result = DispatchMousePointerEvent(WebInputEvent::Type::kPointerMove,
1192                                            mev.InnerElement(), mev.Event(),
1193                                            coalesced_events, predicted_events);
1194   // TODO(crbug.com/346473): Since there is no default action for the mousemove
1195   // event we should consider doing drag&drop even when js cancels the
1196   // mouse move event.
1197   // https://w3c.github.io/uievents/#event-type-mousemove
1198   if (event_result != WebInputEventResult::kNotHandled)
1199     return event_result;
1200
1201   return mouse_event_manager_->HandleMouseDraggedEvent(mev);
1202 }
1203
1204 WebInputEventResult EventHandler::HandleMouseReleaseEvent(
1205     const WebMouseEvent& mouse_event) {
1206   TRACE_EVENT0("blink", "EventHandler::handleMouseReleaseEvent");
1207
1208   // For 4th/5th button in the mouse since Chrome does not yet send
1209   // button value to Blink but in some cases it does send the event.
1210   // This check is needed to suppress such an event (crbug.com/574959)
1211   if (mouse_event.button == WebPointerProperties::Button::kNoButton)
1212     return WebInputEventResult::kHandledSuppressed;
1213
1214   if (!mouse_event.FromTouch())
1215     frame_->Selection().SetCaretBlinkingSuspended(false);
1216
1217   if (RuntimeEnabledFeatures::MiddleClickAutoscrollEnabled()) {
1218     if (Page* page = frame_->GetPage()) {
1219       page->GetAutoscrollController()
1220           .HandleMouseReleaseForMiddleClickAutoscroll(
1221               frame_,
1222               mouse_event.button == WebPointerProperties::Button::kMiddle);
1223     }
1224   }
1225
1226   mouse_event_manager_->ReleaseMousePress();
1227   mouse_event_manager_->SetLastKnownMousePosition(mouse_event);
1228   mouse_event_manager_->HandleSvgPanIfNeeded(true);
1229
1230   if (frame_set_being_resized_) {
1231     WebInputEventResult result =
1232         mouse_event_manager_->SetMousePositionAndDispatchMouseEvent(
1233             EffectiveMouseEventTargetElement(frame_set_being_resized_.Get()),
1234             event_type_names::kMouseup, mouse_event);
1235     // crbug.com/1053385 release mouse capture only if there are no more mouse
1236     // buttons depressed
1237     if (MouseEvent::WebInputEventModifiersToButtons(
1238             mouse_event.GetModifiers()) == 0)
1239       ReleaseMouseCaptureFromLocalRoot();
1240     return result;
1241   }
1242
1243   if (last_scrollbar_under_mouse_) {
1244     mouse_event_manager_->InvalidateClick();
1245     last_scrollbar_under_mouse_->MouseUp(mouse_event);
1246     // crbug.com/1053385 release mouse capture only if there are no more mouse
1247     // buttons depressed
1248     if (MouseEvent::WebInputEventModifiersToButtons(
1249             mouse_event.GetModifiers()) == 0) {
1250       ReleaseMouseCaptureFromLocalRoot();
1251     }
1252     return DispatchMousePointerEvent(
1253         WebInputEvent::Type::kPointerUp,
1254         mouse_event_manager_->GetElementUnderMouse(), mouse_event,
1255         Vector<WebMouseEvent>(), Vector<WebMouseEvent>());
1256   }
1257
1258   // Mouse events simulated from touch should not hit-test again.
1259   DCHECK(!mouse_event.FromTouch());
1260   HitTestRequest::HitTestRequestType hit_type = HitTestRequest::kRelease;
1261   HitTestRequest request(hit_type);
1262   MouseEventWithHitTestResults mev = GetMouseEventTarget(request, mouse_event);
1263   LocalFrame* subframe = event_handling_util::GetTargetSubframe(
1264       mev, capturing_mouse_events_element_.Get());
1265   capturing_mouse_events_element_ = nullptr;
1266   if (subframe)
1267     return PassMouseReleaseEventToSubframe(mev, subframe);
1268
1269   WebInputEventResult event_result = WebInputEventResult::kNotHandled;
1270
1271   if (event_handling_util::ShouldDiscardEventTargetingFrame(mev.Event(),
1272                                                             *frame_)) {
1273     event_result = WebInputEventResult::kHandledSuppressed;
1274   } else {
1275     event_result = DispatchMousePointerEvent(
1276         WebInputEvent::Type::kPointerUp, mev.InnerElement(), mev.Event(),
1277         Vector<WebMouseEvent>(), Vector<WebMouseEvent>(),
1278         (GetSelectionController().HasExtendedSelection() &&
1279          IsSelectionOverLink(mev)));
1280   }
1281   scroll_manager_->ClearResizeScrollableArea(false);
1282 #if BUILDFLAG(IS_TIZEN_TV)
1283   if (frame_->GetSettings() && frame_->GetSettings()->GetUseArrowScroll() &&
1284       mouse_event.button == WebPointerProperties::Button::kLeft) {
1285     bool handled_mouse_left_button_release_event =
1286         (SelectCursor(mev.GetHitTestLocation(), mev.GetHitTestResult())
1287              .value()
1288              .type() == ui::mojom::blink::CursorType::kPointer)
1289             ? (event_result != WebInputEventResult::kNotHandled)
1290             : true;
1291     if (!handled_mouse_left_button_press_event_ &&
1292         !handled_mouse_left_button_release_event &&
1293         CanRunArrowScrolling(mev.GetHitTestResult())) {
1294       if (frame_) {
1295         frame_->Client()->RunArrowScroll();
1296       }
1297     }
1298   }
1299 #endif
1300
1301   if (event_result == WebInputEventResult::kNotHandled)
1302     event_result = mouse_event_manager_->HandleMouseReleaseEvent(mev);
1303
1304   mouse_event_manager_->HandleMouseReleaseEventUpdateStates();
1305
1306   // crbug.com/1053385 release mouse capture only if there are no more mouse
1307   // buttons depressed
1308   if (MouseEvent::WebInputEventModifiersToButtons(mouse_event.GetModifiers()) ==
1309       0)
1310     ReleaseMouseCaptureFromLocalRoot();
1311
1312   return event_result;
1313 }
1314
1315 static LocalFrame* LocalFrameFromTargetNode(Node* target) {
1316   auto* html_frame_base_element = DynamicTo<HTMLFrameElementBase>(target);
1317   if (!html_frame_base_element)
1318     return nullptr;
1319
1320   // Cross-process drag and drop is not yet supported.
1321   return DynamicTo<LocalFrame>(html_frame_base_element->ContentFrame());
1322 }
1323
1324 WebInputEventResult EventHandler::UpdateDragAndDrop(
1325     const WebMouseEvent& event,
1326     DataTransfer* data_transfer) {
1327   WebInputEventResult event_result = WebInputEventResult::kNotHandled;
1328
1329   if (!frame_->View())
1330     return event_result;
1331
1332   HitTestRequest request(HitTestRequest::kReadOnly);
1333   MouseEventWithHitTestResults mev =
1334       event_handling_util::PerformMouseEventHitTest(frame_, request, event);
1335
1336   // Drag events should never go to text nodes (following IE, and proper
1337   // mouseover/out dispatch)
1338   Node* new_target = mev.InnerNode();
1339   if (new_target && new_target->IsTextNode())
1340     new_target = FlatTreeTraversal::Parent(*new_target);
1341
1342   if (AutoscrollController* controller =
1343           scroll_manager_->GetAutoscrollController()) {
1344     controller->UpdateDragAndDrop(new_target, event.PositionInRootFrame(),
1345                                   event.TimeStamp());
1346   }
1347
1348   if (drag_target_ != new_target) {
1349     // FIXME: this ordering was explicitly chosen to match WinIE. However,
1350     // it is sometimes incorrect when dragging within subframes, as seen with
1351     // web_tests/fast/events/drag-in-frames.html.
1352     //
1353     // Moreover, this ordering conforms to section 7.9.4 of the HTML 5 spec.
1354     // <http://dev.w3.org/html5/spec/Overview.html#drag-and-drop-processing-model>.
1355     if (auto* target_frame = LocalFrameFromTargetNode(new_target)) {
1356       event_result = target_frame->GetEventHandler().UpdateDragAndDrop(
1357           event, data_transfer);
1358     } else if (new_target) {
1359       // As per section 7.9.4 of the HTML 5 spec., we must always fire a drag
1360       // event before firing a dragenter, dragleave, or dragover event.
1361       if (mouse_event_manager_->GetDragState().drag_src_) {
1362         // For now we don't care if event handler cancels default behavior,
1363         // since there is none.
1364         mouse_event_manager_->DispatchDragSrcEvent(event_type_names::kDrag,
1365                                                    event);
1366       }
1367       event_result = mouse_event_manager_->DispatchDragEvent(
1368           event_type_names::kDragenter, new_target, drag_target_, event,
1369           data_transfer);
1370     }
1371
1372     if (auto* target_frame = LocalFrameFromTargetNode(drag_target_.Get())) {
1373       event_result = target_frame->GetEventHandler().UpdateDragAndDrop(
1374           event, data_transfer);
1375     } else if (drag_target_) {
1376       mouse_event_manager_->DispatchDragEvent(event_type_names::kDragleave,
1377                                               drag_target_.Get(), new_target,
1378                                               event, data_transfer);
1379     }
1380
1381     if (new_target) {
1382       // We do not explicitly call m_mouseEventManager->dispatchDragEvent here
1383       // because it could ultimately result in the appearance that two dragover
1384       // events fired. So, we mark that we should only fire a dragover event on
1385       // the next call to this function.
1386       should_only_fire_drag_over_event_ = true;
1387     }
1388   } else {
1389     if (auto* target_frame = LocalFrameFromTargetNode(new_target)) {
1390       event_result = target_frame->GetEventHandler().UpdateDragAndDrop(
1391           event, data_transfer);
1392     } else if (new_target) {
1393       // Note, when dealing with sub-frames, we may need to fire only a dragover
1394       // event as a drag event may have been fired earlier.
1395       if (!should_only_fire_drag_over_event_ &&
1396           mouse_event_manager_->GetDragState().drag_src_) {
1397         // For now we don't care if event handler cancels default behavior,
1398         // since there is none.
1399         mouse_event_manager_->DispatchDragSrcEvent(event_type_names::kDrag,
1400                                                    event);
1401       }
1402       event_result = mouse_event_manager_->DispatchDragEvent(
1403           event_type_names::kDragover, new_target, nullptr, event,
1404           data_transfer);
1405       should_only_fire_drag_over_event_ = false;
1406     }
1407   }
1408   drag_target_ = new_target;
1409
1410   return event_result;
1411 }
1412
1413 void EventHandler::CancelDragAndDrop(const WebMouseEvent& event,
1414                                      DataTransfer* data_transfer) {
1415   if (auto* target_frame = LocalFrameFromTargetNode(drag_target_.Get())) {
1416     target_frame->GetEventHandler().CancelDragAndDrop(event, data_transfer);
1417   } else if (drag_target_.Get()) {
1418     if (mouse_event_manager_->GetDragState().drag_src_) {
1419       mouse_event_manager_->DispatchDragSrcEvent(event_type_names::kDrag,
1420                                                  event);
1421     }
1422     mouse_event_manager_->DispatchDragEvent(event_type_names::kDragleave,
1423                                             drag_target_.Get(), nullptr, event,
1424                                             data_transfer);
1425   }
1426   ClearDragState();
1427 }
1428
1429 WebInputEventResult EventHandler::PerformDragAndDrop(
1430     const WebMouseEvent& event,
1431     DataTransfer* data_transfer) {
1432   WebInputEventResult result = WebInputEventResult::kNotHandled;
1433   if (auto* target_frame = LocalFrameFromTargetNode(drag_target_.Get())) {
1434     result = target_frame->GetEventHandler().PerformDragAndDrop(event,
1435                                                                 data_transfer);
1436   } else if (drag_target_.Get()) {
1437     result = mouse_event_manager_->DispatchDragEvent(
1438         event_type_names::kDrop, drag_target_.Get(), nullptr, event,
1439         data_transfer);
1440   }
1441   ClearDragState();
1442   return result;
1443 }
1444
1445 #if BUILDFLAG(IS_TIZEN)
1446 void EventHandler::EnterDragState() {
1447   gesture_manager_->EnterDragState();
1448 }
1449 #endif
1450
1451 void EventHandler::ClearDragState() {
1452   scroll_manager_->StopAutoscroll();
1453   drag_target_ = nullptr;
1454   capturing_mouse_events_element_ = nullptr;
1455   ReleaseMouseCaptureFromLocalRoot();
1456   should_only_fire_drag_over_event_ = false;
1457 }
1458
1459 #if BUILDFLAG(IS_TIZEN_TV)
1460 bool EventHandler::ScrollNewPosition(const ScrollOffset& scroll_offset,
1461                                      LocalFrameView* frame_view) {
1462   ScrollableArea* const scrollable_area = frame_view->LayoutViewport();
1463   if (!scrollable_area)
1464     return false;
1465
1466   gfx::PointF ori_point = scrollable_area->ScrollPosition();
1467   scrollable_area->ScrollBy(scroll_offset, mojom::blink::ScrollType::kUser);
1468   gfx::PointF new_point = scrollable_area->ScrollPosition();
1469   return new_point != ori_point;
1470 }
1471
1472 bool EventHandler::ScrollWithMultiplier(const ScrollOffset& scroll_offset,
1473                                         Node* start_node) {
1474   LocalFrame* frame = frame_;
1475   while (frame) {
1476     mojom::blink::ScrollDirection vertical_direction =
1477         (scroll_offset.y() < 0)
1478             ? mojom::blink::ScrollDirection::kScrollUpIgnoringWritingMode
1479             : mojom::blink::ScrollDirection::kScrollDownIgnoringWritingMode;
1480     mojom::blink::ScrollDirection horizontal_direction =
1481         (scroll_offset.x() < 0)
1482             ? mojom::blink::ScrollDirection::kScrollLeftIgnoringWritingMode
1483             : mojom::blink::ScrollDirection::kScrollRightIgnoringWritingMode;
1484     if (scroll_manager_->LogicalScroll(
1485             vertical_direction, ui::ScrollGranularity::kScrollByPixel, start_node,
1486             nullptr, std::abs(scroll_offset.y())))
1487       return true;
1488
1489     if (scroll_manager_->LogicalScroll(
1490             horizontal_direction, ui::ScrollGranularity::kScrollByPixel, start_node,
1491             nullptr, std::abs(scroll_offset.x())))
1492       return true;
1493
1494     LocalFrameView* frame_view = frame->View();
1495     if (frame_view && ScrollNewPosition(scroll_offset, frame_view))
1496       return true;
1497
1498     frame = DynamicTo<LocalFrame>(frame->Tree().Parent());
1499     if (frame)
1500       start_node = frame->DeprecatedLocalOwner();
1501   }
1502   return false;
1503 }
1504 #endif
1505
1506 void EventHandler::RecomputeMouseHoverStateIfNeeded() {
1507   mouse_event_manager_->RecomputeMouseHoverStateIfNeeded();
1508 }
1509
1510 void EventHandler::MarkHoverStateDirty() {
1511   mouse_event_manager_->MarkHoverStateDirty();
1512 }
1513
1514 Element* EventHandler::EffectiveMouseEventTargetElement(
1515     Element* target_element) {
1516   Element* new_element_under_mouse = target_element;
1517   if (pointer_event_manager_->GetMouseCaptureTarget())
1518     new_element_under_mouse = pointer_event_manager_->GetMouseCaptureTarget();
1519   return new_element_under_mouse;
1520 }
1521
1522 Element* EventHandler::GetElementUnderMouse() {
1523   return mouse_event_manager_->GetElementUnderMouse();
1524 }
1525
1526 Element* EventHandler::CurrentTouchDownElement() {
1527   return pointer_event_manager_->CurrentTouchDownElement();
1528 }
1529
1530 void EventHandler::SetDelayedNavigationTaskHandle(TaskHandle task_handle) {
1531   delayed_navigation_task_handle_ = std::move(task_handle);
1532 }
1533
1534 TaskHandle& EventHandler::GetDelayedNavigationTaskHandle() {
1535   return delayed_navigation_task_handle_;
1536 }
1537
1538 bool EventHandler::IsPointerIdActiveOnFrame(PointerId pointer_id,
1539                                             LocalFrame* frame) const {
1540   DCHECK(frame_ == &frame_->LocalFrameRoot() || frame_ == frame);
1541   return pointer_event_manager_->IsPointerIdActiveOnFrame(pointer_id, frame);
1542 }
1543
1544 bool EventHandler::RootFrameTrackedActivePointerInCurrentFrame(
1545     PointerId pointer_id) const {
1546   return frame_ != &frame_->LocalFrameRoot() &&
1547          frame_->LocalFrameRoot().GetEventHandler().IsPointerIdActiveOnFrame(
1548              pointer_id, frame_);
1549 }
1550
1551 bool EventHandler::IsPointerEventActive(PointerId pointer_id) {
1552   return pointer_event_manager_->IsActive(pointer_id) ||
1553          RootFrameTrackedActivePointerInCurrentFrame(pointer_id);
1554 }
1555
1556 LocalFrame* EventHandler::DetermineActivePointerTrackerFrame(
1557     PointerId pointer_id) const {
1558   // If pointer_id is active on current |frame_|, pointer states are in
1559   // current frame's PEM; otherwise, check if it's a touch-like pointer that
1560   // have its active states in the local frame root's PEM.
1561   if (IsPointerIdActiveOnFrame(pointer_id, frame_))
1562     return frame_.Get();
1563   if (RootFrameTrackedActivePointerInCurrentFrame(pointer_id))
1564     return &frame_->LocalFrameRoot();
1565   return nullptr;
1566 }
1567
1568 void EventHandler::SetPointerCapture(PointerId pointer_id,
1569                                      Element* target,
1570                                      bool explicit_capture) {
1571   // TODO(crbug.com/591387): This functionality should be per page not per
1572   // frame.
1573   LocalFrame* tracking_frame = DetermineActivePointerTrackerFrame(pointer_id);
1574
1575   bool captured =
1576       tracking_frame && tracking_frame->GetEventHandler()
1577                             .pointer_event_manager_->SetPointerCapture(
1578                                 pointer_id, target, explicit_capture);
1579
1580   if (captured && pointer_id == PointerEventFactory::kMouseId) {
1581     CaptureMouseEventsToWidget(true);
1582   }
1583 }
1584
1585 void EventHandler::ReleasePointerCapture(PointerId pointer_id,
1586                                          Element* target) {
1587   LocalFrame* tracking_frame = DetermineActivePointerTrackerFrame(pointer_id);
1588
1589   bool released =
1590       tracking_frame &&
1591       tracking_frame->GetEventHandler()
1592           .pointer_event_manager_->ReleasePointerCapture(pointer_id, target);
1593
1594   if (released && pointer_id == PointerEventFactory::kMouseId) {
1595     CaptureMouseEventsToWidget(false);
1596   }
1597 }
1598
1599 void EventHandler::ReleaseMousePointerCapture() {
1600   ReleaseMouseCaptureFromLocalRoot();
1601 }
1602
1603 bool EventHandler::HasPointerCapture(PointerId pointer_id,
1604                                      const Element* target) const {
1605   if (LocalFrame* tracking_frame =
1606           DetermineActivePointerTrackerFrame(pointer_id)) {
1607     return tracking_frame->GetEventHandler()
1608         .pointer_event_manager_->HasPointerCapture(pointer_id, target);
1609   }
1610   return false;
1611 }
1612
1613 void EventHandler::ElementRemoved(Element* target) {
1614   pointer_event_manager_->ElementRemoved(target);
1615   if (target)
1616     mouse_wheel_event_manager_->ElementRemoved(target);
1617 }
1618
1619 void EventHandler::ResetMousePositionForPointerUnlock() {
1620   pointer_event_manager_->RemoveLastMousePosition();
1621 }
1622
1623 bool EventHandler::LongTapShouldInvokeContextMenu() {
1624   return gesture_manager_->GestureContextMenuDeferred();
1625 }
1626
1627 WebInputEventResult EventHandler::DispatchMousePointerEvent(
1628     const WebInputEvent::Type event_type,
1629     Element* target_element,
1630     const WebMouseEvent& mouse_event,
1631     const Vector<WebMouseEvent>& coalesced_events,
1632     const Vector<WebMouseEvent>& predicted_events,
1633     bool skip_click_dispatch) {
1634   const auto& event_result = pointer_event_manager_->SendMousePointerEvent(
1635       EffectiveMouseEventTargetElement(target_element), event_type, mouse_event,
1636       coalesced_events, predicted_events, skip_click_dispatch);
1637   return event_result;
1638 }
1639
1640 WebInputEventResult EventHandler::HandleWheelEvent(
1641     const WebMouseWheelEvent& event) {
1642   return mouse_wheel_event_manager_->HandleWheelEvent(event);
1643 }
1644
1645 // TODO(crbug.com/665924): This function bypasses all Handle*Event path.
1646 // It should be using that flow instead of creating/sending events directly.
1647 WebInputEventResult EventHandler::HandleTargetedMouseEvent(
1648     Element* target,
1649     const WebMouseEvent& event,
1650     const AtomicString& mouse_event_type,
1651     const Vector<WebMouseEvent>& coalesced_events,
1652     const Vector<WebMouseEvent>& predicted_events) {
1653   mouse_event_manager_->SetClickCount(event.click_count);
1654   return pointer_event_manager_->DirectDispatchMousePointerEvent(
1655       target, event, mouse_event_type, coalesced_events, predicted_events);
1656 }
1657
1658 WebInputEventResult EventHandler::HandleGestureEvent(
1659     const WebGestureEvent& gesture_event) {
1660   // Propagation to inner frames is handled below this function.
1661   DCHECK_EQ(frame_, &frame_->LocalFrameRoot());
1662   DCHECK_NE(0, gesture_event.FrameScale());
1663
1664   // Gesture scroll events are handled on the compositor thread.
1665   DCHECK(!gesture_event.IsScrollEvent());
1666
1667   // Hit test across all frames and do touch adjustment as necessary for the
1668   // event type.
1669   GestureEventWithHitTestResults targeted_event =
1670       TargetGestureEvent(gesture_event);
1671
1672   return HandleGestureEvent(targeted_event);
1673 }
1674
1675 WebInputEventResult EventHandler::HandleGestureEvent(
1676     const GestureEventWithHitTestResults& targeted_event) {
1677   TRACE_EVENT0("input", "EventHandler::handleGestureEvent");
1678   if (!frame_->GetPage())
1679     return WebInputEventResult::kNotHandled;
1680
1681   // Propagation to inner frames is handled below this function.
1682   DCHECK_EQ(frame_, &frame_->LocalFrameRoot());
1683
1684   // Non-scrolling related gesture events do a single cross-frame hit-test and
1685   // jump directly to the inner most frame. This matches handleMousePressEvent
1686   // etc.
1687   DCHECK(!targeted_event.Event().IsScrollEvent());
1688
1689   if (targeted_event.Event().GetType() ==
1690       WebInputEvent::Type::kGestureShowPress)
1691     last_show_press_timestamp_ = base::TimeTicks::Now();
1692
1693   // Update mouseout/leave/over/enter events before jumping directly to the
1694   // inner most frame.
1695   if (targeted_event.Event().GetType() == WebInputEvent::Type::kGestureTap)
1696     UpdateGestureTargetNodeForMouseEvent(targeted_event);
1697
1698   // Route to the correct frame.
1699   if (LocalFrame* inner_frame =
1700           targeted_event.GetHitTestResult().InnerNodeFrame())
1701     return inner_frame->GetEventHandler().HandleGestureEventInFrame(
1702         targeted_event);
1703
1704   // No hit test result, handle in root instance. Perhaps we should just return
1705   // false instead?
1706   return gesture_manager_->HandleGestureEventInFrame(targeted_event);
1707 }
1708
1709 WebInputEventResult EventHandler::HandleGestureEventInFrame(
1710     const GestureEventWithHitTestResults& targeted_event) {
1711   bool is_tap =
1712       targeted_event.Event().GetType() == WebInputEvent::Type::kGestureTap;
1713   if (is_tap && discarded_events_.tap_target != kInvalidDOMNodeId &&
1714       discarded_events_.tap_target ==
1715           targeted_event.InnerNode()->GetDomNodeId() &&
1716       targeted_event.Event().TimeStamp() - discarded_events_.tap_time <
1717           event_handling_util::kDiscardedEventMistakeInterval) {
1718     targeted_event.InnerNode()->GetDocument().CountUse(
1719         WebFeature::kInputEventToRecentlyMovedIframeMistakenlyDiscarded);
1720   }
1721   if (event_handling_util::ShouldDiscardEventTargetingFrame(
1722           targeted_event.Event(), *frame_)) {
1723     if (is_tap) {
1724       discarded_events_.tap_target = targeted_event.InnerNode()->GetDomNodeId();
1725       discarded_events_.tap_time = targeted_event.Event().TimeStamp();
1726     }
1727     return WebInputEventResult::kHandledSuppressed;
1728   }
1729   if (is_tap) {
1730     discarded_events_.tap_target = kInvalidDOMNodeId;
1731     discarded_events_.tap_time = base::TimeTicks();
1732   }
1733   return gesture_manager_->HandleGestureEventInFrame(targeted_event);
1734 }
1735
1736 WebInputEventResult EventHandler::HandleGestureScrollEvent(
1737     const WebGestureEvent& gesture_event) {
1738   TRACE_EVENT0("input", "EventHandler::handleGestureScrollEvent");
1739   if (!frame_->GetPage())
1740     return WebInputEventResult::kNotHandled;
1741
1742   return scroll_manager_->HandleGestureScrollEvent(gesture_event);
1743 }
1744
1745 void EventHandler::SetMouseDownMayStartAutoscroll() {
1746   mouse_event_manager_->SetMouseDownMayStartAutoscroll();
1747 }
1748
1749 bool EventHandler::IsScrollbarHandlingGestures() const {
1750   return scroll_manager_->IsScrollbarHandlingGestures();
1751 }
1752
1753 bool EventHandler::ShouldApplyTouchAdjustment(
1754     const WebGestureEvent& event) const {
1755   if (event.primary_pointer_type == WebPointerProperties::PointerType::kPen)
1756     return false;
1757
1758   return !event.TapAreaInRootFrame().IsEmpty();
1759 }
1760
1761 void EventHandler::CacheTouchAdjustmentResult(uint32_t id,
1762                                               gfx::PointF adjusted_point) {
1763   touch_adjustment_result_.unique_event_id = id;
1764   touch_adjustment_result_.adjusted_point = adjusted_point;
1765 }
1766
1767 bool EventHandler::GestureCorrespondsToAdjustedTouch(
1768     const WebGestureEvent& event) {
1769   // Gesture events start with a GestureTapDown. If GestureTapDown's unique id
1770   // matches stored adjusted touchstart event id, then we can use the stored
1771   // result for following gesture event.
1772   if (event.GetType() == WebInputEvent::Type::kGestureTapDown) {
1773     should_use_touch_event_adjusted_point_ =
1774         (event.unique_touch_event_id != 0 &&
1775          event.unique_touch_event_id ==
1776              touch_adjustment_result_.unique_event_id);
1777   }
1778
1779   // Check if the adjusted point is in the gesture event tap rect.
1780   // If not, should not use this touch point in following events.
1781   if (should_use_touch_event_adjusted_point_) {
1782     gfx::SizeF size = event.TapAreaInRootFrame();
1783     gfx::RectF tap_rect(
1784         event.PositionInRootFrame() -
1785             gfx::Vector2dF(size.width() * 0.5, size.height() * 0.5),
1786         size);
1787     should_use_touch_event_adjusted_point_ =
1788         tap_rect.InclusiveContains(touch_adjustment_result_.adjusted_point);
1789   }
1790
1791   return should_use_touch_event_adjusted_point_;
1792 }
1793
1794 bool EventHandler::BestNodeForHitTestResult(
1795     TouchAdjustmentCandidateType candidate_type,
1796     const HitTestLocation& location,
1797     const HitTestResult& result,
1798     gfx::Point& adjusted_point,
1799     Node*& adjusted_node) {
1800   TRACE_EVENT0("input", "EventHandler::BestNodeForHitTestResult");
1801   CHECK(location.IsRectBasedTest());
1802
1803   // If the touch is over a scrollbar or a resizer, we don't adjust the touch
1804   // point.  This is because touch adjustment only takes into account DOM nodes
1805   // so a touch over a scrollbar or a resizer would be adjusted towards a nearby
1806   // DOM node, making the scrollbar/resizer unusable.
1807   //
1808   // Context-menu hittests are excluded from this consideration because a
1809   // right-click/long-press doesn't drag the scrollbar therefore prefers DOM
1810   // nodes with relevant contextmenu properties.
1811   if (candidate_type != TouchAdjustmentCandidateType::kContextMenu &&
1812       (result.GetScrollbar() || result.IsOverResizer())) {
1813     return false;
1814   }
1815
1816   gfx::Point touch_hotspot =
1817       frame_->View()->ConvertToRootFrame(location.RoundedPoint());
1818   gfx::Rect touch_rect =
1819       frame_->View()->ConvertToRootFrame(location.ToEnclosingRect());
1820
1821   if (touch_rect.IsEmpty()) {
1822     return false;
1823   }
1824
1825   HeapVector<Member<Node>, 11> nodes(result.ListBasedTestResult());
1826
1827   return FindBestTouchAdjustmentCandidate(candidate_type, adjusted_node,
1828                                           adjusted_point, touch_hotspot,
1829                                           touch_rect, nodes);
1830 }
1831
1832 // Update the hover and active state across all frames.  This logic is
1833 // different than the mouse case because mice send MouseLeave events to frames
1834 // as they're exited.  With gestures or manual applications, a single event
1835 // conceptually both 'leaves' whatever frame currently had hover and enters a
1836 // new frame so we need to update state in the old frame chain as well.
1837 void EventHandler::UpdateCrossFrameHoverActiveState(bool is_active,
1838                                                     Element* inner_element) {
1839   DCHECK_EQ(frame_, &frame_->LocalFrameRoot());
1840
1841   HeapVector<Member<LocalFrame>> new_hover_frame_chain;
1842   LocalFrame* new_hover_frame_in_document =
1843       inner_element ? inner_element->GetDocument().GetFrame() : nullptr;
1844   // Insert the ancestors of the frame having the new hovered element to the
1845   // frame chain.  The frame chain doesn't include the main frame to avoid the
1846   // redundant work that cleans the hover state because the hover state for the
1847   // main frame is updated by calling Document::UpdateHoverActiveState.
1848   while (new_hover_frame_in_document && new_hover_frame_in_document != frame_) {
1849     new_hover_frame_chain.push_back(new_hover_frame_in_document);
1850     Frame* parent_frame = new_hover_frame_in_document->Tree().Parent();
1851     new_hover_frame_in_document = DynamicTo<LocalFrame>(parent_frame);
1852   }
1853
1854   Element* old_hover_element_in_cur_doc = frame_->GetDocument()->HoverElement();
1855   Element* new_innermost_hover_element = inner_element;
1856
1857   if (new_innermost_hover_element != old_hover_element_in_cur_doc) {
1858     wtf_size_t index_frame_chain = new_hover_frame_chain.size();
1859
1860     // Clear the hover state on any frames which are no longer in the frame
1861     // chain of the hovered element.
1862     while (old_hover_element_in_cur_doc &&
1863            old_hover_element_in_cur_doc->IsFrameOwnerElement()) {
1864       LocalFrame* new_hover_frame = nullptr;
1865       // If we can't get the frame from the new hover frame chain,
1866       // the newHoverFrame will be null and the old hover state will be cleared.
1867       if (index_frame_chain > 0)
1868         new_hover_frame = new_hover_frame_chain[--index_frame_chain];
1869
1870       auto* owner = To<HTMLFrameOwnerElement>(old_hover_element_in_cur_doc);
1871       LocalFrame* old_hover_frame =
1872           DynamicTo<LocalFrame>(owner->ContentFrame());
1873       if (!old_hover_frame)
1874         break;
1875
1876       Document* doc = old_hover_frame->GetDocument();
1877       if (!doc)
1878         break;
1879
1880       old_hover_element_in_cur_doc = doc->HoverElement();
1881       // If the old hovered frame is different from the new hovered frame.
1882       // we should clear the old hovered element from the old hovered frame.
1883       if (new_hover_frame != old_hover_frame) {
1884         doc->UpdateHoverActiveState(is_active,
1885                                     /*update_active_chain=*/true, nullptr);
1886       }
1887     }
1888   }
1889
1890   // Recursively set the new active/hover states on every frame in the chain of
1891   // innerElement.
1892   frame_->GetDocument()->UpdateHoverActiveState(is_active,
1893                                                 /*update_active_chain=*/true,
1894                                                 inner_element);
1895 }
1896
1897 // Update the mouseover/mouseenter/mouseout/mouseleave events across all frames
1898 // for this gesture, before passing the targeted gesture event directly to a hit
1899 // frame.
1900 void EventHandler::UpdateGestureTargetNodeForMouseEvent(
1901     const GestureEventWithHitTestResults& targeted_event) {
1902   DCHECK_EQ(frame_, &frame_->LocalFrameRoot());
1903
1904   // Behaviour of this function is as follows:
1905   // - Create the chain of all entered frames.
1906   // - Compare the last frame chain under the gesture to newly entered frame
1907   //   chain from the main frame one by one.
1908   // - If the last frame doesn't match with the entered frame, then create the
1909   //   chain of exited frames from the last frame chain.
1910   // - Dispatch mouseout/mouseleave events of the exited frames from the inside
1911   //   out.
1912   // - Dispatch mouseover/mouseenter events of the entered frames into the
1913   //   inside.
1914
1915   // Insert the ancestors of the frame having the new target node to the entered
1916   // frame chain.
1917   HeapVector<Member<LocalFrame>, 2> entered_frame_chain;
1918   LocalFrame* entered_frame_in_document =
1919       targeted_event.GetHitTestResult().InnerNodeFrame();
1920   while (entered_frame_in_document) {
1921     entered_frame_chain.push_back(entered_frame_in_document);
1922     Frame* parent_frame = entered_frame_in_document->Tree().Parent();
1923     entered_frame_in_document = DynamicTo<LocalFrame>(parent_frame);
1924   }
1925
1926   wtf_size_t index_entered_frame_chain = entered_frame_chain.size();
1927   LocalFrame* exited_frame_in_document = frame_;
1928   HeapVector<Member<LocalFrame>, 2> exited_frame_chain;
1929   // Insert the frame from the disagreement between last frames and entered
1930   // frames.
1931   while (exited_frame_in_document) {
1932     Node* last_node_under_tap =
1933         exited_frame_in_document->GetEventHandler()
1934             .mouse_event_manager_->GetElementUnderMouse();
1935     if (!last_node_under_tap)
1936       break;
1937
1938     LocalFrame* next_exited_frame_in_document = nullptr;
1939     if (auto* owner = DynamicTo<HTMLFrameOwnerElement>(last_node_under_tap)) {
1940       next_exited_frame_in_document =
1941           DynamicTo<LocalFrame>(owner->ContentFrame());
1942     }
1943
1944     if (exited_frame_chain.size() > 0) {
1945       exited_frame_chain.push_back(exited_frame_in_document);
1946     } else {
1947       LocalFrame* last_entered_frame_in_document =
1948           index_entered_frame_chain
1949               ? entered_frame_chain[index_entered_frame_chain - 1]
1950               : nullptr;
1951       if (exited_frame_in_document != last_entered_frame_in_document)
1952         exited_frame_chain.push_back(exited_frame_in_document);
1953       else if (next_exited_frame_in_document && index_entered_frame_chain)
1954         --index_entered_frame_chain;
1955     }
1956     exited_frame_in_document = next_exited_frame_in_document;
1957   }
1958
1959   const WebGestureEvent& gesture_event = targeted_event.Event();
1960   unsigned modifiers = gesture_event.GetModifiers();
1961   WebMouseEvent fake_mouse_move(
1962       WebInputEvent::Type::kMouseMove, gesture_event,
1963       WebPointerProperties::Button::kNoButton,
1964       /* clickCount */ 0,
1965       modifiers | WebInputEvent::Modifiers::kIsCompatibilityEventForTouch,
1966       gesture_event.TimeStamp());
1967
1968   // Update the mouseout/mouseleave event
1969   wtf_size_t index_exited_frame_chain = exited_frame_chain.size();
1970   while (index_exited_frame_chain) {
1971     LocalFrame* leave_frame = exited_frame_chain[--index_exited_frame_chain];
1972     leave_frame->GetEventHandler().mouse_event_manager_->SetElementUnderMouse(
1973         EffectiveMouseEventTargetElement(nullptr), fake_mouse_move);
1974   }
1975
1976   // update the mouseover/mouseenter event
1977   while (index_entered_frame_chain) {
1978     Frame* parent_frame =
1979         entered_frame_chain[--index_entered_frame_chain]->Tree().Parent();
1980     if (auto* parent_local_frame = DynamicTo<LocalFrame>(parent_frame)) {
1981       parent_local_frame->GetEventHandler()
1982           .mouse_event_manager_->SetElementUnderMouse(
1983               EffectiveMouseEventTargetElement(To<HTMLFrameOwnerElement>(
1984                   entered_frame_chain[index_entered_frame_chain]->Owner())),
1985               fake_mouse_move);
1986     }
1987   }
1988 }
1989
1990 GestureEventWithHitTestResults EventHandler::TargetGestureEvent(
1991     const WebGestureEvent& gesture_event,
1992     bool read_only) {
1993   TRACE_EVENT0("input", "EventHandler::targetGestureEvent");
1994
1995   DCHECK_EQ(frame_, &frame_->LocalFrameRoot());
1996   // Scrolling events get hit tested per frame (like wheel events do).
1997   DCHECK(!gesture_event.IsScrollEvent());
1998
1999   HitTestRequest::HitTestRequestType hit_type =
2000       gesture_manager_->GetHitTypeForGestureType(gesture_event.GetType());
2001   base::TimeDelta active_interval;
2002   bool should_keep_active_for_min_interval = false;
2003   if (read_only) {
2004     hit_type |= HitTestRequest::kReadOnly;
2005   } else if (
2006 #if BUILDFLAG(IS_EFL)
2007       !RuntimeEnabledFeatures::TizenCompatibilityModeEnabled() &&
2008 #endif
2009       gesture_event.GetType() == WebInputEvent::Type::kGestureTap &&
2010       last_show_press_timestamp_) {
2011     // If the Tap is received very shortly after ShowPress, we want to
2012     // delay clearing of the active state so that it's visible to the user
2013     // for at least a couple of frames.
2014     active_interval =
2015         base::TimeTicks::Now() - last_show_press_timestamp_.value();
2016     should_keep_active_for_min_interval =
2017         active_interval < kMinimumActiveInterval;
2018     if (should_keep_active_for_min_interval)
2019       hit_type |= HitTestRequest::kReadOnly;
2020   }
2021
2022   GestureEventWithHitTestResults event_with_hit_test_results =
2023       HitTestResultForGestureEvent(gesture_event, hit_type);
2024   // Now apply hover/active state to the final target.
2025   HitTestRequest request(hit_type | HitTestRequest::kAllowChildFrameContent);
2026   if (!request.ReadOnly()) {
2027     UpdateCrossFrameHoverActiveState(
2028         request.Active(),
2029         event_with_hit_test_results.GetHitTestResult().InnerElement());
2030   }
2031
2032   if (should_keep_active_for_min_interval) {
2033     last_deferred_tap_element_ =
2034         event_with_hit_test_results.GetHitTestResult().InnerElement();
2035     // TODO(https://crbug.com/668758): Use a normal BeginFrame update for this.
2036     active_interval_timer_.StartOneShot(
2037         kMinimumActiveInterval - active_interval, FROM_HERE);
2038   }
2039
2040   return event_with_hit_test_results;
2041 }
2042
2043 GestureEventWithHitTestResults EventHandler::HitTestResultForGestureEvent(
2044     const WebGestureEvent& gesture_event,
2045     HitTestRequest::HitTestRequestType hit_type) {
2046   // Perform the rect-based hit-test (or point-based if adjustment is
2047   // disabled). Note that we don't yet apply hover/active state here because
2048   // we need to resolve touch adjustment first so that we apply hover/active
2049   // it to the final adjusted node.
2050   hit_type |= HitTestRequest::kReadOnly;
2051   WebGestureEvent adjusted_event = gesture_event;
2052   PhysicalSize hit_rect_size;
2053   if (ShouldApplyTouchAdjustment(gesture_event)) {
2054     // If gesture_event unique id matches the stored touch event result, do
2055     // point-base hit test. Otherwise add padding and do rect-based hit test.
2056     if (GestureCorrespondsToAdjustedTouch(gesture_event)) {
2057       adjusted_event.ApplyTouchAdjustment(
2058           touch_adjustment_result_.adjusted_point);
2059     } else {
2060       gfx::SizeF tap_area = adjusted_event.TapAreaInRootFrame();
2061       hit_rect_size = GetHitTestRectForAdjustment(
2062           *frame_, PhysicalSize(LayoutUnit(tap_area.width()),
2063                                 LayoutUnit(tap_area.height())));
2064       if (!hit_rect_size.IsEmpty())
2065         hit_type |= HitTestRequest::kListBased;
2066     }
2067   }
2068
2069   HitTestLocation location;
2070   LocalFrame& root_frame = frame_->LocalFrameRoot();
2071   HitTestResult hit_test_result;
2072   if (hit_rect_size.IsEmpty()) {
2073     location = HitTestLocation(adjusted_event.PositionInRootFrame());
2074     hit_test_result = root_frame.GetEventHandler().HitTestResultAtLocation(
2075         location, hit_type);
2076   } else {
2077     PhysicalOffset top_left =
2078         PhysicalOffset::FromPointFRound(adjusted_event.PositionInRootFrame());
2079     top_left -= PhysicalOffset(LayoutUnit(hit_rect_size.width * 0.5f),
2080                                LayoutUnit(hit_rect_size.height * 0.5f));
2081     location = HitTestLocation(PhysicalRect(top_left, hit_rect_size));
2082     hit_test_result = root_frame.GetEventHandler().HitTestResultAtLocation(
2083         location, hit_type);
2084
2085     // Adjust the location of the gesture to the most likely nearby node, as
2086     // appropriate for the type of event.
2087     ApplyTouchAdjustment(&adjusted_event, location, hit_test_result);
2088     // Do a new hit-test at the (adjusted) gesture coordinates. This is
2089     // necessary because rect-based hit testing and touch adjustment sometimes
2090     // return a different node than what a point-based hit test would return for
2091     // the same point.
2092     // FIXME: Fix touch adjustment to avoid the need for a redundant hit test.
2093     // http://crbug.com/398914
2094     LocalFrame* hit_frame = hit_test_result.InnerNodeFrame();
2095     if (!hit_frame)
2096       hit_frame = frame_;
2097     location = HitTestLocation(adjusted_event.PositionInRootFrame());
2098     hit_test_result = root_frame.GetEventHandler().HitTestResultAtLocation(
2099         location,
2100         (hit_type | HitTestRequest::kReadOnly) & ~HitTestRequest::kListBased);
2101   }
2102
2103   // If we did a rect-based hit test it must be resolved to the best single node
2104   // by now to ensure consumers don't accidentally use one of the other
2105   // candidates.
2106   DCHECK(!location.IsRectBasedTest());
2107
2108   return GestureEventWithHitTestResults(adjusted_event, location,
2109                                         hit_test_result);
2110 }
2111
2112 void EventHandler::ApplyTouchAdjustment(WebGestureEvent* gesture_event,
2113                                         HitTestLocation& location,
2114                                         HitTestResult& hit_test_result) {
2115   TouchAdjustmentCandidateType touch_adjustment_candiate_type =
2116       TouchAdjustmentCandidateType::kClickable;
2117   switch (gesture_event->GetType()) {
2118     case WebInputEvent::Type::kGestureTap:
2119     case WebInputEvent::Type::kGestureTapUnconfirmed:
2120     case WebInputEvent::Type::kGestureTapDown:
2121     case WebInputEvent::Type::kGestureShowPress:
2122       break;
2123     case WebInputEvent::Type::kGestureShortPress:
2124     case WebInputEvent::Type::kGestureLongPress:
2125     case WebInputEvent::Type::kGestureLongTap:
2126     case WebInputEvent::Type::kGestureTwoFingerTap:
2127       touch_adjustment_candiate_type =
2128           TouchAdjustmentCandidateType::kContextMenu;
2129       break;
2130     default:
2131       NOTREACHED();
2132   }
2133
2134   Node* adjusted_node = nullptr;
2135   gfx::Point adjusted_point;
2136   if (BestNodeForHitTestResult(touch_adjustment_candiate_type, location,
2137                                hit_test_result, adjusted_point,
2138                                adjusted_node)) {
2139     // Update the hit-test result to be a point-based result instead of a
2140     // rect-based result.
2141     PhysicalOffset point(frame_->View()->ConvertFromRootFrame(adjusted_point));
2142     DCHECK(location.ContainsPoint(gfx::PointF(point)));
2143     DCHECK(location.IsRectBasedTest());
2144     location = hit_test_result.ResolveRectBasedTest(adjusted_node, point);
2145     gesture_event->ApplyTouchAdjustment(
2146         gfx::PointF(adjusted_point.x(), adjusted_point.y()));
2147   }
2148 }
2149
2150 WebInputEventResult EventHandler::SendContextMenuEvent(
2151     const WebMouseEvent& event,
2152     Element* override_target_element) {
2153   LocalFrameView* v = frame_->View();
2154   if (!v)
2155     return WebInputEventResult::kNotHandled;
2156
2157   // Clear mouse press state to avoid initiating a drag while context menu is
2158   // up.
2159   mouse_event_manager_->ReleaseMousePress();
2160   if (last_scrollbar_under_mouse_)
2161     last_scrollbar_under_mouse_->MouseUp(event);
2162
2163   PhysicalOffset position_in_contents(v->ConvertFromRootFrame(
2164       gfx::ToFlooredPoint(event.PositionInRootFrame())));
2165   HitTestRequest request(HitTestRequest::kActive);
2166   MouseEventWithHitTestResults mev =
2167       frame_->GetDocument()->PerformMouseEventHitTest(
2168           request, position_in_contents, event);
2169   // Since |Document::performMouseEventHitTest()| modifies layout tree for
2170   // setting hover element, we need to update layout tree for requirement of
2171   // |SelectionController::sendContextMenuEvent()|.
2172   frame_->GetDocument()->UpdateStyleAndLayout(
2173       DocumentUpdateReason::kContextMenu);
2174
2175   Element* target_element =
2176       override_target_element ? override_target_element : mev.InnerElement();
2177   return mouse_event_manager_->DispatchMouseEvent(
2178       EffectiveMouseEventTargetElement(target_element),
2179       event_type_names::kContextmenu, event, nullptr, nullptr, false, event.id,
2180       PointerEventFactory::PointerTypeNameForWebPointPointerType(
2181           event.pointer_type));
2182 }
2183
2184 static bool ShouldShowContextMenuAtSelection(const FrameSelection& selection) {
2185   // TODO(editing-dev): The use of UpdateStyleAndLayout
2186   // needs to be audited.  See http://crbug.com/590369 for more details.
2187   selection.GetDocument().UpdateStyleAndLayout(
2188       DocumentUpdateReason::kContextMenu);
2189
2190   const VisibleSelection& visible_selection =
2191       selection.ComputeVisibleSelectionInDOMTree();
2192   if (!visible_selection.IsRange() && !visible_selection.RootEditableElement())
2193     return false;
2194   return selection.SelectionHasFocus();
2195 }
2196
2197 WebInputEventResult EventHandler::ShowNonLocatedContextMenu(
2198     Element* override_target_element,
2199     WebMenuSourceType source_type) {
2200   LocalFrameView* view = frame_->View();
2201   if (!view)
2202     return WebInputEventResult::kNotHandled;
2203
2204   Document* doc = frame_->GetDocument();
2205   if (!doc)
2206     return WebInputEventResult::kNotHandled;
2207
2208   static const int kContextMenuMargin = 1;
2209
2210   gfx::Point location_in_root_frame;
2211
2212   Element* focused_element =
2213       override_target_element ? override_target_element : doc->FocusedElement();
2214   FrameSelection& selection = frame_->Selection();
2215   VisualViewport& visual_viewport = frame_->GetPage()->GetVisualViewport();
2216
2217   if (!override_target_element && ShouldShowContextMenuAtSelection(selection)) {
2218     DCHECK(!doc->NeedsLayoutTreeUpdate());
2219
2220     // Enclose the selection rect fully between the handles. If the handles are
2221     // on the same line, the selection rect is empty.
2222     const SelectionInDOMTree& visible_selection =
2223         selection.ComputeVisibleSelectionInDOMTree().AsSelection();
2224     const PositionWithAffinity start_position(
2225         visible_selection.ComputeStartPosition(), visible_selection.Affinity());
2226     const gfx::Point start_point =
2227         GetMiddleSelectionCaretOfPosition(start_position);
2228     const PositionWithAffinity end_position(
2229         visible_selection.ComputeEndPosition(), visible_selection.Affinity());
2230     const gfx::Point end_point =
2231         GetMiddleSelectionCaretOfPosition(end_position);
2232
2233     int left = std::min(start_point.x(), end_point.x());
2234     int top = std::min(start_point.y(), end_point.y());
2235     int right = std::max(start_point.x(), end_point.x());
2236     int bottom = std::max(start_point.y(), end_point.y());
2237
2238     // If selection is a caret and is inside an anchor element, then set that
2239     // as the "focused" element so we can show "open link" option in context
2240     // menu.
2241     if (visible_selection.IsCaret()) {
2242       Element* anchor_element =
2243           EnclosingAnchorElement(visible_selection.ComputeStartPosition());
2244       if (anchor_element)
2245         focused_element = anchor_element;
2246     }
2247     // Intersect the selection rect and the visible bounds of focused_element.
2248     if (focused_element) {
2249       gfx::Rect clipped_rect = view->ConvertFromRootFrame(
2250           GetFocusedElementRectForNonLocatedContextMenu(focused_element));
2251       left = std::max(clipped_rect.x(), left);
2252       top = std::max(clipped_rect.y(), top);
2253       right = std::min(clipped_rect.right(), right);
2254       bottom = std::min(clipped_rect.bottom(), bottom);
2255     }
2256     gfx::Rect selection_rect = gfx::Rect(left, top, right - left, bottom - top);
2257
2258     if (ContainsEvenAtEdge(selection_rect, start_point)) {
2259       location_in_root_frame = view->ConvertToRootFrame(start_point);
2260     } else if (ContainsEvenAtEdge(selection_rect, end_point)) {
2261       location_in_root_frame = view->ConvertToRootFrame(end_point);
2262     } else {
2263       location_in_root_frame =
2264           view->ConvertToRootFrame(selection_rect.CenterPoint());
2265     }
2266   } else if (focused_element) {
2267     gfx::Rect clipped_rect =
2268         GetFocusedElementRectForNonLocatedContextMenu(focused_element);
2269     location_in_root_frame = clipped_rect.CenterPoint();
2270   } else {
2271     // TODO(crbug.com/1274078): Should this use ScrollPosition()?
2272     location_in_root_frame =
2273         gfx::Point(visual_viewport.GetScrollOffset().x() + kContextMenuMargin,
2274                    visual_viewport.GetScrollOffset().y() + kContextMenuMargin);
2275   }
2276
2277   frame_->View()->SetCursor(PointerCursor());
2278   gfx::Point global_position =
2279       view->GetChromeClient()
2280           ->LocalRootToScreenDIPs(
2281               gfx::Rect(location_in_root_frame, gfx::Size()), frame_->View())
2282           .origin();
2283
2284   // Use the focused node as the target for hover and active.
2285   HitTestRequest request(HitTestRequest::kActive);
2286   HitTestLocation location(location_in_root_frame);
2287   HitTestResult result(request, location);
2288   result.SetInnerNode(focused_element ? static_cast<Node*>(focused_element)
2289                                       : doc);
2290   doc->UpdateHoverActiveState(request.Active(), !request.Move(),
2291                               result.InnerElement());
2292
2293   // The contextmenu event is a mouse event even when invoked using the
2294   // keyboard.  This is required for web compatibility.
2295   WebInputEvent::Type event_type = WebInputEvent::Type::kMouseDown;
2296   if (frame_->GetSettings() &&
2297       frame_->GetSettings()->GetShowContextMenuOnMouseUp())
2298     event_type = WebInputEvent::Type::kMouseUp;
2299
2300   WebMouseEvent mouse_event(
2301       event_type,
2302       gfx::PointF(location_in_root_frame.x(), location_in_root_frame.y()),
2303       gfx::PointF(global_position.x(), global_position.y()),
2304       WebPointerProperties::Button::kNoButton, /* clickCount */ 0,
2305       WebInputEvent::kNoModifiers, base::TimeTicks::Now(), source_type);
2306   mouse_event.id = PointerEventFactory::kMouseId;
2307
2308   // TODO(dtapuska): Transition the mouseEvent to be created really in viewport
2309   // coordinates instead of root frame coordinates.
2310   mouse_event.SetFrameScale(1);
2311
2312   return SendContextMenuEvent(mouse_event, focused_element);
2313 }
2314
2315 gfx::Rect EventHandler::GetFocusedElementRectForNonLocatedContextMenu(
2316     Element* focused_element) {
2317   gfx::Rect visible_rect = focused_element->VisibleBoundsInLocalRoot();
2318
2319   VisualViewport& visual_viewport = frame_->GetPage()->GetVisualViewport();
2320
2321   // TODO(bokan): This method may not work as expected when the local root
2322   // isn't the main frame since the result won't be transformed and clipped by
2323   // the visual viewport (which is accessible only from the outermost main
2324   // frame).
2325   if (frame_->LocalFrameRoot().IsOutermostMainFrame()) {
2326     visible_rect = visual_viewport.RootFrameToViewport(visible_rect);
2327     visible_rect.Intersect(gfx::Rect(visual_viewport.Size()));
2328   }
2329
2330   gfx::Rect clipped_rect = visible_rect;
2331   // The bounding rect of multiline elements may include points that are
2332   // not within the element. Intersect the clipped rect with the first
2333   // outline rect to ensure that the selection rect only includes visible
2334   // points within the focused element.
2335   Vector<gfx::Rect> outline_rects = focused_element->OutlineRectsInWidget();
2336   if (outline_rects.size() > 1)
2337     clipped_rect.Intersect(outline_rects[0]);
2338
2339   return visual_viewport.ViewportToRootFrame(clipped_rect);
2340 }
2341
2342 void EventHandler::ScheduleHoverStateUpdate() {
2343   // TODO(https://crbug.com/668758): Use a normal BeginFrame update for this.
2344   if (!hover_timer_.IsActive() &&
2345       !mouse_event_manager_->IsMousePositionUnknown())
2346     hover_timer_.StartOneShot(base::TimeDelta(), FROM_HERE);
2347 }
2348
2349 void EventHandler::ScheduleCursorUpdate() {
2350   // We only want one timer for the page, rather than each frame having it's own
2351   // timer competing which eachother (since there's only one mouse cursor).
2352   DCHECK_EQ(frame_, &frame_->LocalFrameRoot());
2353
2354   // TODO(https://crbug.com/668758): Use a normal BeginFrame update for this.
2355   if (!cursor_update_timer_.IsActive())
2356     cursor_update_timer_.StartOneShot(kCursorUpdateInterval, FROM_HERE);
2357 }
2358
2359 bool EventHandler::CursorUpdatePending() {
2360   return cursor_update_timer_.IsActive();
2361 }
2362
2363 bool EventHandler::IsHandlingKeyEvent() const {
2364   return keyboard_event_manager_->is_handling_key_event();
2365 }
2366
2367 void EventHandler::SetResizingFrameSet(HTMLFrameSetElement* frame_set) {
2368   CaptureMouseEventsToWidget(true);
2369   frame_set_being_resized_ = frame_set;
2370 }
2371
2372 void EventHandler::ResizeScrollableAreaDestroyed() {
2373   scroll_manager_->ClearResizeScrollableArea(true);
2374 }
2375
2376 void EventHandler::HoverTimerFired(TimerBase*) {
2377   TRACE_EVENT0("input", "EventHandler::hoverTimerFired");
2378
2379   DCHECK(frame_);
2380   DCHECK(frame_->GetDocument());
2381
2382   if (auto* layout_object = frame_->ContentLayoutObject()) {
2383     if (LocalFrameView* view = frame_->View()) {
2384       HitTestRequest request(HitTestRequest::kMove);
2385       HitTestLocation location(view->ViewportToFrame(
2386           mouse_event_manager_->LastKnownMousePositionInViewport()));
2387       HitTestResult result(request, location);
2388       layout_object->HitTest(location, result);
2389       frame_->GetDocument()->UpdateHoverActiveState(
2390           request.Active(), !request.Move(), result.InnerElement());
2391     }
2392   }
2393 }
2394
2395 void EventHandler::ActiveIntervalTimerFired(TimerBase*) {
2396   TRACE_EVENT0("input", "EventHandler::activeIntervalTimerFired");
2397
2398   if (frame_ && frame_->GetDocument() && last_deferred_tap_element_) {
2399     // FIXME: Enable condition when http://crbug.com/226842 lands
2400     // m_lastDeferredTapElement.get() == m_frame->document()->activeElement()
2401     HitTestRequest request(HitTestRequest::kTouchEvent |
2402                            HitTestRequest::kRelease);
2403     frame_->GetDocument()->UpdateHoverActiveState(
2404         request.Active(), !request.Move(), last_deferred_tap_element_.Get());
2405   }
2406   last_deferred_tap_element_ = nullptr;
2407 }
2408
2409 void EventHandler::NotifyElementActivated() {
2410   // Since another element has been set to active, stop current timer and clear
2411   // reference.
2412   active_interval_timer_.Stop();
2413   last_deferred_tap_element_ = nullptr;
2414 }
2415
2416 bool EventHandler::HandleAccessKey(const WebKeyboardEvent& evt) {
2417   return keyboard_event_manager_->HandleAccessKey(evt);
2418 }
2419
2420 WebInputEventResult EventHandler::KeyEvent(
2421     const WebKeyboardEvent& initial_key_event) {
2422   return keyboard_event_manager_->KeyEvent(initial_key_event);
2423 }
2424
2425 void EventHandler::DefaultKeyboardEventHandler(KeyboardEvent* event) {
2426   keyboard_event_manager_->DefaultKeyboardEventHandler(
2427       event, mouse_event_manager_->MousePressNode());
2428 }
2429
2430 void EventHandler::DragSourceEndedAt(
2431     const WebMouseEvent& event,
2432     ui::mojom::blink::DragOperation operation) {
2433   // Asides from routing the event to the correct frame, the hit test is also an
2434   // opportunity for Layer to update the :hover and :active pseudoclasses.
2435   HitTestRequest request(HitTestRequest::kRelease);
2436   MouseEventWithHitTestResults mev =
2437       event_handling_util::PerformMouseEventHitTest(frame_, request, event);
2438
2439   if (auto* target_frame = LocalFrameFromTargetNode(mev.InnerNode())) {
2440     target_frame->GetEventHandler().DragSourceEndedAt(event, operation);
2441     return;
2442   }
2443
2444   mouse_event_manager_->DragSourceEndedAt(event, operation);
2445
2446   if (frame_->GetSettings() &&
2447       frame_->GetSettings()->GetTouchDragDropEnabled() &&
2448       frame_->GetSettings()->GetTouchDragEndContextMenu()) {
2449     gesture_manager_->SendContextMenuEventTouchDragEnd(event);
2450   }
2451 }
2452
2453 void EventHandler::UpdateDragStateAfterEditDragIfNeeded(
2454     Element* root_editable_element) {
2455   // If inserting the dragged contents removed the drag source, we still want to
2456   // fire dragend at the root editble element.
2457   if (mouse_event_manager_->GetDragState().drag_src_ &&
2458       !mouse_event_manager_->GetDragState().drag_src_->isConnected())
2459     mouse_event_manager_->GetDragState().drag_src_ = root_editable_element;
2460 }
2461
2462 bool EventHandler::HandleTextInputEvent(const String& text,
2463                                         Event* underlying_event,
2464                                         TextEventInputType input_type) {
2465   // Platforms should differentiate real commands like selectAll from text input
2466   // in disguise (like insertNewline), and avoid dispatching text input events
2467   // from keydown default handlers.
2468   auto* keyboard_event = DynamicTo<KeyboardEvent>(underlying_event);
2469   DCHECK(!keyboard_event ||
2470          keyboard_event->type() == event_type_names::kKeypress);
2471
2472   if (!frame_)
2473     return false;
2474
2475   EventTarget* target;
2476   if (underlying_event)
2477     target = underlying_event->target();
2478   else
2479     target = EventTargetNodeForDocument(frame_->GetDocument());
2480   if (!target)
2481     return false;
2482
2483   TextEvent* event = TextEvent::Create(frame_->DomWindow(), text, input_type);
2484   event->SetUnderlyingEvent(underlying_event);
2485
2486   target->DispatchEvent(*event);
2487   return event->DefaultHandled() || event->defaultPrevented();
2488 }
2489
2490 void EventHandler::DefaultTextInputEventHandler(TextEvent* event) {
2491   if (frame_->GetEditor().HandleTextEvent(event))
2492     event->SetDefaultHandled();
2493 }
2494
2495 void EventHandler::CapsLockStateMayHaveChanged() {
2496   keyboard_event_manager_->CapsLockStateMayHaveChanged();
2497 }
2498
2499 bool EventHandler::PassMousePressEventToScrollbar(
2500     MouseEventWithHitTestResults& mev) {
2501   // Do not pass the mouse press to scrollbar if scrollbar pressed. If the
2502   // user's left button is down, then the cursor moves outside the scrollbar
2503   // and presses the middle button , we should not clear
2504   // last_scrollbar_under_mouse_.
2505   if (last_scrollbar_under_mouse_ &&
2506       last_scrollbar_under_mouse_->PressedPart() != ScrollbarPart::kNoPart) {
2507     return false;
2508   }
2509
2510   Scrollbar* scrollbar = mev.GetScrollbar();
2511   UpdateLastScrollbarUnderMouse(scrollbar, true);
2512
2513   if (!scrollbar || !scrollbar->Enabled())
2514     return false;
2515   scrollbar->MouseDown(mev.Event());
2516   if (scrollbar->PressedPart() == ScrollbarPart::kThumbPart)
2517     CaptureMouseEventsToWidget(true);
2518   return true;
2519 }
2520
2521 // If scrollbar (under mouse) is different from last, send a mouse exited. Set
2522 // last to scrollbar if setLast is true; else set last to 0.
2523 void EventHandler::UpdateLastScrollbarUnderMouse(Scrollbar* scrollbar,
2524                                                  bool set_last) {
2525   if (last_scrollbar_under_mouse_ != scrollbar) {
2526     // Send mouse exited to the old scrollbar.
2527     if (last_scrollbar_under_mouse_)
2528       last_scrollbar_under_mouse_->MouseExited();
2529
2530     // Send mouse entered if we're setting a new scrollbar.
2531     if (scrollbar && set_last)
2532       scrollbar->MouseEntered();
2533
2534     last_scrollbar_under_mouse_ = set_last ? scrollbar : nullptr;
2535   }
2536 }
2537
2538 WebInputEventResult EventHandler::PassMousePressEventToSubframe(
2539     MouseEventWithHitTestResults& mev,
2540     LocalFrame* subframe) {
2541   GetSelectionController().PassMousePressEventToSubframe(mev);
2542   WebInputEventResult result =
2543       subframe->GetEventHandler().HandleMousePressEvent(mev.Event());
2544   if (result != WebInputEventResult::kNotHandled)
2545     return result;
2546   return WebInputEventResult::kHandledSystem;
2547 }
2548
2549 WebInputEventResult EventHandler::PassMouseMoveEventToSubframe(
2550     MouseEventWithHitTestResults& mev,
2551     const Vector<WebMouseEvent>& coalesced_events,
2552     const Vector<WebMouseEvent>& predicted_events,
2553     LocalFrame* subframe,
2554     HitTestResult* hovered_node,
2555     HitTestLocation* hit_test_location) {
2556   if (mouse_event_manager_->MouseDownMayStartDrag())
2557     return WebInputEventResult::kNotHandled;
2558   WebInputEventResult result =
2559       subframe->GetEventHandler().HandleMouseMoveOrLeaveEvent(
2560           mev.Event(), coalesced_events, predicted_events, hovered_node,
2561           hit_test_location);
2562   if (result != WebInputEventResult::kNotHandled)
2563     return result;
2564   return WebInputEventResult::kHandledSystem;
2565 }
2566
2567 WebInputEventResult EventHandler::PassMouseReleaseEventToSubframe(
2568     MouseEventWithHitTestResults& mev,
2569     LocalFrame* subframe) {
2570   return subframe->GetEventHandler().HandleMouseReleaseEvent(mev.Event());
2571 }
2572
2573 void EventHandler::CaptureMouseEventsToWidget(bool capture) {
2574   if (!frame_->IsLocalRoot()) {
2575     frame_->LocalFrameRoot().GetEventHandler().CaptureMouseEventsToWidget(
2576         capture);
2577     return;
2578   }
2579
2580   if (capture == is_widget_capturing_mouse_events_)
2581     return;
2582
2583   frame_->LocalFrameRoot().Client()->SetMouseCapture(capture);
2584   is_widget_capturing_mouse_events_ = capture;
2585 }
2586
2587 MouseEventWithHitTestResults EventHandler::GetMouseEventTarget(
2588     const HitTestRequest& request,
2589     const WebMouseEvent& event) {
2590   PhysicalOffset document_point =
2591       event_handling_util::ContentPointFromRootFrame(
2592           frame_, event.PositionInRootFrame());
2593
2594   // TODO(eirage): This does not handle chorded buttons yet.
2595   if (event.GetType() != WebInputEvent::Type::kMouseDown) {
2596     HitTestResult result(request, HitTestLocation(document_point));
2597
2598     Element* capture_target;
2599     if (event_handling_util::SubframeForTargetNode(
2600             capturing_subframe_element_)) {
2601       capture_target = capturing_subframe_element_;
2602       result.SetIsOverEmbeddedContentView(true);
2603     } else {
2604       capture_target = pointer_event_manager_->GetMouseCaptureTarget();
2605     }
2606
2607     if (capture_target) {
2608       LayoutObject* layout_object = capture_target->GetLayoutObject();
2609       PhysicalOffset local_point =
2610           layout_object ? layout_object->AbsoluteToLocalPoint(document_point)
2611                         : document_point;
2612       result.SetNodeAndPosition(capture_target, local_point);
2613
2614       result.SetScrollbar(last_scrollbar_under_mouse_);
2615       result.SetURLElement(capture_target->EnclosingLinkEventParentOrSelf());
2616
2617       if (!request.ReadOnly()) {
2618         frame_->GetDocument()->UpdateHoverActiveState(
2619             request.Active(), !request.Move(), result.InnerElement());
2620       }
2621
2622       return MouseEventWithHitTestResults(
2623           event, HitTestLocation(document_point), result);
2624     }
2625   }
2626   return frame_->GetDocument()->PerformMouseEventHitTest(request,
2627                                                          document_point, event);
2628 }
2629
2630 void EventHandler::ReleaseMouseCaptureFromLocalRoot() {
2631   CaptureMouseEventsToWidget(false);
2632
2633   frame_->LocalFrameRoot()
2634       .GetEventHandler()
2635       .ReleaseMouseCaptureFromCurrentFrame();
2636 }
2637
2638 void EventHandler::ReleaseMouseCaptureFromCurrentFrame() {
2639   if (LocalFrame* subframe = event_handling_util::SubframeForTargetNode(
2640           capturing_subframe_element_))
2641     subframe->GetEventHandler().ReleaseMouseCaptureFromCurrentFrame();
2642   pointer_event_manager_->ReleaseMousePointerCapture();
2643   capturing_subframe_element_ = nullptr;
2644 }
2645
2646 #if BUILDFLAG(IS_TIZEN_TV)
2647 bool EventHandler::CanRunArrowScrolling(const HitTestResult& result) {
2648   if (result.IsContentEditable() || result.GetScrollbar() ||
2649       result.MediaHasAudio() || result.MediaIsVideo())
2650     return false;
2651
2652   if (Node* node = result.InnerNode()) {
2653     if (node->HasMediaControlAncestor() || node->IsMediaControls() ||
2654         node->IsMediaControlElement() || node->WillRespondToMouseClickEvents())
2655       return false;
2656   }
2657
2658   return true;
2659 }
2660 #endif
2661
2662 #if BUILDFLAG(IS_EFL)
2663 void EventHandler::ContextMenuEventForWordOrLinkSelection(
2664     const WebGestureEvent& gesture_event) {
2665   LocalFrameView* frame_view = frame_->View();
2666   if (!frame_view)
2667     return;
2668
2669   // Hit-test the provided gesture event, applying touch-adjustment and
2670   // adjusting the location to the most likely nearby node.
2671   WebMouseEvent web_mouse_event(WebInputEvent::Type::kMouseMove, gesture_event,
2672                                 WebPointerProperties::Button::kNoButton, 0,
2673                                 WebInputEvent::kNoModifiers,
2674                                 gesture_event.TimeStamp(), 0);
2675
2676   gfx::Point viewport_position = frame_view->ViewportToFrame(
2677       gfx::ToFlooredPoint(web_mouse_event.PositionInRootFrame()));
2678   HitTestRequest request(HitTestRequest::kActive);
2679   MouseEventWithHitTestResults mouse_event =
2680       frame_->GetDocument()->PerformMouseEventHitTest(
2681           request, PhysicalOffset(viewport_position), web_mouse_event);
2682
2683   if (!frame_->Selection().Contains(PhysicalOffset(viewport_position)) &&
2684       !mouse_event.GetScrollbar() &&
2685       (frame_->Selection()
2686            .ComputeVisibleSelectionInDOMTreeDeprecated()
2687            .IsContentEditable() ||
2688        (mouse_event.InnerNode() && mouse_event.InnerNode()->IsTextNode()) ||
2689        (mouse_event.GetHitTestResult().IsLiveLink()))) {
2690     GetSelectionController().SetMouseDownMayStartSelect(
2691         true);  // context menu events are always allowed to perform a selection
2692     GetSelectionController().SelectClosestWordOrLinkFromMouseEvent(
2693         (MouseEvent*)(&mouse_event.Event()), mouse_event.GetHitTestResult());
2694   }
2695 }
2696 #endif
2697
2698 }  // namespace blink