[M120 Migration] Fix show IME
[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   mouse_press_event_swallowed_ = false;
806 #endif
807
808   HitTestRequest request(HitTestRequest::kActive);
809   // Save the document point we generate in case the window coordinate is
810   // invalidated by what happens when we dispatch the event.
811   PhysicalOffset document_point = frame_->View()->ConvertFromRootFrame(
812       PhysicalOffset(gfx::ToFlooredPoint(mouse_event.PositionInRootFrame())));
813   MouseEventWithHitTestResults mev = GetMouseEventTarget(request, mouse_event);
814   if (!mev.InnerNode()) {
815     // An anonymous box can be scrollable.
816     if (PassMousePressEventToScrollbar(mev))
817       return WebInputEventResult::kHandledSystem;
818
819     mouse_event_manager_->InvalidateClick();
820     return WebInputEventResult::kNotHandled;
821   }
822
823   mouse_event_manager_->SetMousePressNode(mev.InnerNode());
824   frame_->GetDocument()->SetSequentialFocusNavigationStartingPoint(
825       mev.InnerNode());
826
827   LocalFrame* subframe = event_handling_util::GetTargetSubframe(mev);
828   if (subframe) {
829     WebInputEventResult result = PassMousePressEventToSubframe(mev, subframe);
830     // Start capturing future events for this frame.  We only do this if we
831     // didn't clear the m_mousePressed flag, which may happen if an AppKit
832     // EmbeddedContentView entered a modal event loop.  The capturing should be
833     // done only when the result indicates it has been handled. See
834     // crbug.com/269917
835     mouse_event_manager_->SetCapturesDragging(
836         subframe->GetEventHandler().mouse_event_manager_->CapturesDragging());
837     if (mouse_event_manager_->MousePressed() &&
838         mouse_event_manager_->CapturesDragging()) {
839       capturing_mouse_events_element_ = mev.InnerElement();
840       capturing_subframe_element_ = mev.InnerElement();
841     }
842
843     mouse_event_manager_->InvalidateClick();
844     return result;
845   }
846
847   if (discarded_events_.mouse_down_target != kInvalidDOMNodeId &&
848       discarded_events_.mouse_down_target == mev.InnerNode()->GetDomNodeId() &&
849       mouse_event.TimeStamp() - discarded_events_.mouse_down_time <
850           event_handling_util::kDiscardedEventMistakeInterval) {
851     mev.InnerNode()->GetDocument().CountUse(
852         WebFeature::kInputEventToRecentlyMovedIframeMistakenlyDiscarded);
853   }
854   if (event_handling_util::ShouldDiscardEventTargetingFrame(mev.Event(),
855                                                             *frame_)) {
856     discarded_events_.mouse_down_target = mev.InnerNode()->GetDomNodeId();
857     discarded_events_.mouse_down_time = mouse_event.TimeStamp();
858     return WebInputEventResult::kHandledSuppressed;
859   } else {
860     discarded_events_.mouse_down_target = kInvalidDOMNodeId;
861     discarded_events_.mouse_down_time = base::TimeTicks();
862   }
863
864   LocalFrame::NotifyUserActivation(
865       frame_, mojom::blink::UserActivationNotificationType::kInteraction,
866       RuntimeEnabledFeatures::BrowserVerifiedUserActivationMouseEnabled());
867
868   if (RuntimeEnabledFeatures::MiddleClickAutoscrollEnabled()) {
869     // We store whether middle click autoscroll is in progress before calling
870     // stopAutoscroll() because it will set m_autoscrollType to NoAutoscroll on
871     // return.
872     bool is_middle_click_autoscroll_in_progress =
873         scroll_manager_->MiddleClickAutoscrollInProgress();
874     scroll_manager_->StopMiddleClickAutoscroll();
875     if (is_middle_click_autoscroll_in_progress) {
876       // We invalidate the click when exiting middle click auto scroll so that
877       // we don't inadvertently navigate away from the current page (e.g. the
878       // click was on a hyperlink). See <rdar://problem/6095023>.
879       mouse_event_manager_->InvalidateClick();
880       return WebInputEventResult::kHandledSuppressed;
881     }
882   }
883
884   mouse_event_manager_->SetClickCount(mouse_event.click_count);
885   mouse_event_manager_->SetClickElement(mev.InnerElement());
886
887   if (!mouse_event.FromTouch())
888     frame_->Selection().SetCaretBlinkingSuspended(true);
889
890   WebInputEventResult event_result = DispatchMousePointerEvent(
891       WebInputEvent::Type::kPointerDown, mev.InnerElement(), mev.Event(),
892       Vector<WebMouseEvent>(), Vector<WebMouseEvent>());
893
894   // Disabled form controls still need to resize the scrollable area.
895   if ((event_result == WebInputEventResult::kNotHandled ||
896        event_result == WebInputEventResult::kHandledSuppressed) &&
897       frame_->View()) {
898     LocalFrameView* view = frame_->View();
899     PaintLayer* layer =
900         mev.InnerNode()->GetLayoutObject()
901             ? mev.InnerNode()->GetLayoutObject()->EnclosingLayer()
902             : nullptr;
903     gfx::Point p = view->ConvertFromRootFrame(
904         gfx::ToFlooredPoint(mouse_event.PositionInRootFrame()));
905     if (layer && layer->GetScrollableArea() &&
906         layer->GetScrollableArea()->IsAbsolutePointInResizeControl(
907             p, kResizerForPointer)) {
908       scroll_manager_->SetResizeScrollableArea(layer, p);
909       return WebInputEventResult::kHandledSystem;
910     }
911   }
912
913   // m_selectionInitiationState is initialized after dispatching mousedown
914   // event in order not to keep the selection by DOM APIs because we can't
915   // give the user the chance to handle the selection by user action like
916   // dragging if we keep the selection in case of mousedown. FireFox also has
917   // the same behavior and it's more compatible with other browsers.
918   GetSelectionController().InitializeSelectionState();
919   HitTestResult hit_test_result = event_handling_util::HitTestResultInFrame(
920       frame_, HitTestLocation(document_point), HitTestRequest::kReadOnly);
921   InputDeviceCapabilities* source_capabilities =
922       frame_->DomWindow()->GetInputDeviceCapabilities()->FiresTouchEvents(
923           mouse_event.FromTouch());
924
925   if (event_result == WebInputEventResult::kNotHandled) {
926     event_result = mouse_event_manager_->HandleMouseFocus(hit_test_result,
927                                                           source_capabilities);
928   }
929
930   if (event_result == WebInputEventResult::kNotHandled || mev.GetScrollbar()) {
931     mouse_event_manager_->SetCapturesDragging(true);
932     // Outermost main frames don't implicitly capture mouse input on MouseDown,
933     // all subframes do (regardless of whether local or remote or fenced).
934     if (frame_->IsAttached() && !frame_->IsOutermostMainFrame())
935       CaptureMouseEventsToWidget(true);
936   } else {
937     mouse_event_manager_->SetCapturesDragging(false);
938   }
939 #if BUILDFLAG(IS_TIZEN_TV)
940   if (frame_->GetSettings() && frame_->GetSettings()->GetUseArrowScroll() &&
941       mouse_event.button == WebPointerProperties::Button::kLeft) {
942     handled_mouse_left_button_press_event_ =
943         (SelectCursor(mev.GetHitTestLocation(), mev.GetHitTestResult())
944              .value()
945              .type() == ui::mojom::blink::CursorType::kPointer)
946             ? event_result != WebInputEventResult::kNotHandled
947             : true;
948   }
949
950   if (mev.GetScrollbar())
951     pressed_scrollbar_ = true;
952 #endif
953
954   if (PassMousePressEventToScrollbar(mev))
955     event_result = WebInputEventResult::kHandledSystem;
956
957   if (event_result == WebInputEventResult::kNotHandled) {
958     if (ShouldRefetchEventTarget(mev)) {
959       HitTestRequest read_only_request(HitTestRequest::kReadOnly |
960                                        HitTestRequest::kActive);
961       mev = frame_->GetDocument()->PerformMouseEventHitTest(
962           read_only_request, document_point, mouse_event);
963     }
964     event_result = mouse_event_manager_->HandleMousePressEvent(mev);
965   }
966
967   if (mev.GetHitTestResult().InnerNode() &&
968       mouse_event.button == WebPointerProperties::Button::kLeft) {
969     DCHECK_EQ(WebInputEvent::Type::kMouseDown, mouse_event.GetType());
970     HitTestResult result = mev.GetHitTestResult();
971     result.SetToShadowHostIfInUAShadowRoot();
972     frame_->GetChromeClient().OnMouseDown(*result.InnerNode());
973   }
974
975 #if BUILDFLAG(IS_TIZEN_TV)
976   mouse_press_event_swallowed_ =
977       (event_result == WebInputEventResult::kHandledApplication);
978 #endif
979
980   return event_result;
981 }
982
983 WebInputEventResult EventHandler::HandleMouseMoveEvent(
984     const WebMouseEvent& event,
985     const Vector<WebMouseEvent>& coalesced_events,
986     const Vector<WebMouseEvent>& predicted_events) {
987   TRACE_EVENT0("blink", "EventHandler::handleMouseMoveEvent");
988   DCHECK(event.GetType() == WebInputEvent::Type::kMouseMove);
989   HitTestResult hovered_node_result;
990   HitTestLocation location;
991   WebInputEventResult result =
992       HandleMouseMoveOrLeaveEvent(event, coalesced_events, predicted_events,
993                                   &hovered_node_result, &location);
994
995   Page* page = frame_->GetPage();
996   if (!page)
997     return result;
998
999   if (PaintLayer* layer =
1000           event_handling_util::LayerForNode(hovered_node_result.InnerNode())) {
1001     if (ScrollableArea* layer_scrollable_area =
1002             event_handling_util::AssociatedScrollableArea(layer))
1003       layer_scrollable_area->MouseMovedInContentArea();
1004   }
1005
1006   // Should not convert the hit shadow element to its shadow host, so that
1007   // tooltips in the shadow tree appear correctly.
1008   if (!HasTitleAndNotSVGUseElement(hovered_node_result)) {
1009     hovered_node_result.SetToShadowHostIfInUAShadowRoot();
1010   }
1011   page->GetChromeClient().MouseDidMoveOverElement(*frame_, location,
1012                                                   hovered_node_result);
1013
1014   return result;
1015 }
1016
1017 void EventHandler::HandleMouseLeaveEvent(const WebMouseEvent& event) {
1018   TRACE_EVENT0("blink", "EventHandler::handleMouseLeaveEvent");
1019   DCHECK(event.GetType() == WebInputEvent::Type::kMouseLeave);
1020
1021   Page* page = frame_->GetPage();
1022   if (page)
1023     page->GetChromeClient().ClearToolTip(*frame_);
1024   HandleMouseMoveOrLeaveEvent(event, Vector<WebMouseEvent>(),
1025                               Vector<WebMouseEvent>());
1026   pointer_event_manager_->RemoveLastMousePosition();
1027 }
1028
1029 WebInputEventResult EventHandler::HandleMouseMoveOrLeaveEvent(
1030     const WebMouseEvent& mouse_event,
1031     const Vector<WebMouseEvent>& coalesced_events,
1032     const Vector<WebMouseEvent>& predicted_events,
1033     HitTestResult* hovered_node_result,
1034     HitTestLocation* hit_test_location) {
1035   DCHECK(frame_);
1036   DCHECK(frame_->View());
1037   DCHECK(mouse_event.GetType() == WebInputEvent::Type::kMouseMove ||
1038          mouse_event.GetType() == WebInputEvent::Type::kMouseLeave);
1039   mouse_event_manager_->SetLastKnownMousePosition(mouse_event);
1040
1041   hover_timer_.Stop();
1042   cursor_update_timer_.Stop();
1043
1044   mouse_event_manager_->HandleSvgPanIfNeeded(false);
1045
1046   if (mouse_event.GetType() == WebInputEvent::Type::kMouseMove) {
1047     AnchorElementInteractionTracker* tracker =
1048         frame_->GetDocument()->GetAnchorElementInteractionTracker();
1049     if (tracker) {
1050       tracker->OnMouseMoveEvent(mouse_event);
1051     }
1052   }
1053
1054   // Mouse states need to be reset when mouse move with no button down.
1055   // This is for popup/context_menu opened at mouse_down event and
1056   // mouse_release is not handled in page.
1057   // crbug.com/527582
1058   if (mouse_event.button == WebPointerProperties::Button::kNoButton &&
1059       !(mouse_event.GetModifiers() &
1060         WebInputEvent::Modifiers::kRelativeMotionEvent)) {
1061     mouse_event_manager_->ClearDragHeuristicState();
1062     capturing_mouse_events_element_ = nullptr;
1063     ReleaseMouseCaptureFromLocalRoot();
1064
1065     // If the scrollbar still thinks it's being dragged, tell it to stop.
1066     // Can happen on Win if we lose focus (e.g. from Alt-Tab) mid-drag.
1067     if (last_scrollbar_under_mouse_ &&
1068         last_scrollbar_under_mouse_->PressedPart() != ScrollbarPart::kNoPart)
1069       last_scrollbar_under_mouse_->MouseUp(mouse_event);
1070   }
1071
1072   if (RuntimeEnabledFeatures::MiddleClickAutoscrollEnabled()) {
1073     if (Page* page = frame_->GetPage()) {
1074       page->GetAutoscrollController().HandleMouseMoveForMiddleClickAutoscroll(
1075           frame_, mouse_event_manager_->LastKnownMouseScreenPosition(),
1076           mouse_event.button == WebPointerProperties::Button::kMiddle);
1077     }
1078   }
1079
1080   if (frame_set_being_resized_) {
1081     return DispatchMousePointerEvent(
1082         WebInputEvent::Type::kPointerMove, frame_set_being_resized_.Get(),
1083         mouse_event, coalesced_events, predicted_events);
1084   }
1085
1086   // Send events right to a scrollbar if the mouse is pressed.
1087   if (last_scrollbar_under_mouse_ && mouse_event_manager_->MousePressed()) {
1088     last_scrollbar_under_mouse_->MouseMoved(mouse_event);
1089     return WebInputEventResult::kHandledSystem;
1090   }
1091
1092   HitTestRequest::HitTestRequestType hit_type = HitTestRequest::kMove;
1093   if (mouse_event_manager_->MousePressed()) {
1094     hit_type |= HitTestRequest::kActive;
1095   }
1096
1097   // Treat any mouse move events as readonly if the user is currently touching
1098   // the screen.
1099   if (pointer_event_manager_->IsAnyTouchActive() &&
1100       mouse_event.GetType() == WebInputEvent::Type::kMouseMove) {
1101     hit_type |= HitTestRequest::kActive | HitTestRequest::kReadOnly;
1102   }
1103   HitTestRequest request(hit_type);
1104   HitTestLocation out_location((PhysicalOffset()));
1105   MouseEventWithHitTestResults mev = MouseEventWithHitTestResults(
1106       mouse_event, out_location, HitTestResult(request, out_location));
1107
1108   // We don't want to do a hit-test in MouseLeave scenarios because there
1109   // might actually be some other frame above this one at the specified
1110   // coordinate. So we avoid the hit test but still clear the hover/active
1111   // state.
1112   if (mouse_event.GetType() == WebInputEvent::Type::kMouseLeave) {
1113     frame_->GetDocument()->UpdateHoverActiveState(request.Active(),
1114                                                   /*update_active_chain=*/false,
1115                                                   nullptr);
1116   } else {
1117     mev = GetMouseEventTarget(request, mouse_event);
1118   }
1119
1120   if (hovered_node_result)
1121     *hovered_node_result = mev.GetHitTestResult();
1122
1123   if (hit_test_location)
1124     *hit_test_location = mev.GetHitTestLocation();
1125
1126   Scrollbar* scrollbar = nullptr;
1127
1128   if (scroll_manager_->InResizeMode()) {
1129     scroll_manager_->Resize(mev.Event());
1130   } else {
1131     scrollbar = mev.GetScrollbar();
1132
1133     UpdateLastScrollbarUnderMouse(scrollbar,
1134                                   !mouse_event_manager_->MousePressed());
1135   }
1136
1137   WebInputEventResult event_result = WebInputEventResult::kNotHandled;
1138   bool is_portal =
1139       mev.InnerElement() && IsA<HTMLPortalElement>(*mev.InnerElement());
1140   bool is_remote_frame = false;
1141   LocalFrame* current_subframe = event_handling_util::GetTargetSubframe(
1142       mev, capturing_mouse_events_element_, &is_remote_frame);
1143
1144   // We want mouseouts to happen first, from the inside out.  First send a
1145   // move event to the last subframe so that it will fire mouseouts.
1146   // TODO(lanwei): figure out here if we should call HandleMouseLeaveEvent on a
1147   // mouse move event.
1148   if (last_mouse_move_event_subframe_ &&
1149       last_mouse_move_event_subframe_->Tree().IsDescendantOf(frame_) &&
1150       last_mouse_move_event_subframe_ != current_subframe) {
1151     WebMouseEvent event = mev.Event();
1152     event.SetType(WebInputEvent::Type::kMouseLeave);
1153     last_mouse_move_event_subframe_->GetEventHandler().HandleMouseLeaveEvent(
1154         event);
1155     last_mouse_move_event_subframe_->GetEventHandler()
1156         .mouse_event_manager_->SetLastMousePositionAsUnknown();
1157   }
1158
1159   if (current_subframe) {
1160     // Update over/out state before passing the event to the subframe.
1161     pointer_event_manager_->SendMouseAndPointerBoundaryEvents(
1162         EffectiveMouseEventTargetElement(mev.InnerElement()), mev.Event());
1163
1164     // Event dispatch in sendMouseAndPointerBoundaryEvents may have caused the
1165     // subframe of the target node to be detached from its LocalFrameView, in
1166     // which case the event should not be passed.
1167     if (current_subframe->View()) {
1168       event_result =
1169           PassMouseMoveEventToSubframe(mev, coalesced_events, predicted_events,
1170                                        current_subframe, hovered_node_result);
1171     }
1172   } else {
1173     if (scrollbar && !mouse_event_manager_->MousePressed()) {
1174       // Handle hover effects on platforms that support visual feedback on
1175       // scrollbar hovering.
1176       scrollbar->MouseMoved(mev.Event());
1177     }
1178
1179     // Set Effective pan action before Pointer cursor is updated.
1180     const WebPointerEvent web_pointer_event(WebInputEvent::Type::kPointerMove,
1181                                             mev.Event().FlattenTransform());
1182     pointer_event_manager_->SendEffectivePanActionAtPointer(web_pointer_event,
1183                                                             mev.InnerNode());
1184
1185     LocalFrameView* view = frame_->View();
1186     if ((!is_remote_frame || is_portal) && view) {
1187       absl::optional<ui::Cursor> optional_cursor =
1188           SelectCursor(mev.GetHitTestLocation(), mev.GetHitTestResult());
1189       if (optional_cursor.has_value()) {
1190         view->SetCursor(optional_cursor.value());
1191       }
1192     }
1193   }
1194
1195   last_mouse_move_event_subframe_ = current_subframe;
1196
1197   if (event_result != WebInputEventResult::kNotHandled)
1198     return event_result;
1199
1200   event_result = DispatchMousePointerEvent(WebInputEvent::Type::kPointerMove,
1201                                            mev.InnerElement(), mev.Event(),
1202                                            coalesced_events, predicted_events);
1203   // TODO(crbug.com/346473): Since there is no default action for the mousemove
1204   // event we should consider doing drag&drop even when js cancels the
1205   // mouse move event.
1206   // https://w3c.github.io/uievents/#event-type-mousemove
1207   if (event_result != WebInputEventResult::kNotHandled)
1208     return event_result;
1209
1210   return mouse_event_manager_->HandleMouseDraggedEvent(mev);
1211 }
1212
1213 WebInputEventResult EventHandler::HandleMouseReleaseEvent(
1214     const WebMouseEvent& mouse_event) {
1215   TRACE_EVENT0("blink", "EventHandler::handleMouseReleaseEvent");
1216
1217   // For 4th/5th button in the mouse since Chrome does not yet send
1218   // button value to Blink but in some cases it does send the event.
1219   // This check is needed to suppress such an event (crbug.com/574959)
1220   if (mouse_event.button == WebPointerProperties::Button::kNoButton)
1221     return WebInputEventResult::kHandledSuppressed;
1222
1223   if (!mouse_event.FromTouch())
1224     frame_->Selection().SetCaretBlinkingSuspended(false);
1225
1226   if (RuntimeEnabledFeatures::MiddleClickAutoscrollEnabled()) {
1227     if (Page* page = frame_->GetPage()) {
1228       page->GetAutoscrollController()
1229           .HandleMouseReleaseForMiddleClickAutoscroll(
1230               frame_,
1231               mouse_event.button == WebPointerProperties::Button::kMiddle);
1232     }
1233   }
1234
1235   mouse_event_manager_->ReleaseMousePress();
1236   mouse_event_manager_->SetLastKnownMousePosition(mouse_event);
1237   mouse_event_manager_->HandleSvgPanIfNeeded(true);
1238
1239 #if BUILDFLAG(IS_TIZEN_TV)
1240   pressed_scrollbar_ = false;
1241 #endif
1242
1243   if (frame_set_being_resized_) {
1244     WebInputEventResult result =
1245         mouse_event_manager_->SetMousePositionAndDispatchMouseEvent(
1246             EffectiveMouseEventTargetElement(frame_set_being_resized_.Get()),
1247             event_type_names::kMouseup, mouse_event);
1248     // crbug.com/1053385 release mouse capture only if there are no more mouse
1249     // buttons depressed
1250     if (MouseEvent::WebInputEventModifiersToButtons(
1251             mouse_event.GetModifiers()) == 0)
1252       ReleaseMouseCaptureFromLocalRoot();
1253     return result;
1254   }
1255
1256   if (last_scrollbar_under_mouse_) {
1257     mouse_event_manager_->InvalidateClick();
1258     last_scrollbar_under_mouse_->MouseUp(mouse_event);
1259     // crbug.com/1053385 release mouse capture only if there are no more mouse
1260     // buttons depressed
1261     if (MouseEvent::WebInputEventModifiersToButtons(
1262             mouse_event.GetModifiers()) == 0) {
1263       ReleaseMouseCaptureFromLocalRoot();
1264     }
1265     return DispatchMousePointerEvent(
1266         WebInputEvent::Type::kPointerUp,
1267         mouse_event_manager_->GetElementUnderMouse(), mouse_event,
1268         Vector<WebMouseEvent>(), Vector<WebMouseEvent>());
1269   }
1270
1271   // Mouse events simulated from touch should not hit-test again.
1272   DCHECK(!mouse_event.FromTouch());
1273   HitTestRequest::HitTestRequestType hit_type = HitTestRequest::kRelease;
1274   HitTestRequest request(hit_type);
1275   MouseEventWithHitTestResults mev = GetMouseEventTarget(request, mouse_event);
1276   LocalFrame* subframe = event_handling_util::GetTargetSubframe(
1277       mev, capturing_mouse_events_element_.Get());
1278   capturing_mouse_events_element_ = nullptr;
1279   if (subframe)
1280     return PassMouseReleaseEventToSubframe(mev, subframe);
1281
1282   WebInputEventResult event_result = WebInputEventResult::kNotHandled;
1283
1284   if (event_handling_util::ShouldDiscardEventTargetingFrame(mev.Event(),
1285                                                             *frame_)) {
1286     event_result = WebInputEventResult::kHandledSuppressed;
1287   } else {
1288     event_result = DispatchMousePointerEvent(
1289         WebInputEvent::Type::kPointerUp, mev.InnerElement(), mev.Event(),
1290         Vector<WebMouseEvent>(), Vector<WebMouseEvent>(),
1291         (GetSelectionController().HasExtendedSelection() &&
1292          IsSelectionOverLink(mev)));
1293   }
1294   scroll_manager_->ClearResizeScrollableArea(false);
1295 #if BUILDFLAG(IS_TIZEN_TV)
1296   if (frame_->GetSettings() && frame_->GetSettings()->GetUseArrowScroll() &&
1297       mouse_event.button == WebPointerProperties::Button::kLeft) {
1298     bool handled_mouse_left_button_release_event =
1299         (SelectCursor(mev.GetHitTestLocation(), mev.GetHitTestResult())
1300              .value()
1301              .type() == ui::mojom::blink::CursorType::kPointer)
1302             ? (event_result != WebInputEventResult::kNotHandled)
1303             : true;
1304     if (!handled_mouse_left_button_press_event_ &&
1305         !handled_mouse_left_button_release_event &&
1306         CanRunArrowScrolling(mev.GetHitTestResult())) {
1307       if (frame_) {
1308         frame_->Client()->RunArrowScroll();
1309       }
1310     }
1311   }
1312 #endif
1313
1314   if (event_result == WebInputEventResult::kNotHandled)
1315     event_result = mouse_event_manager_->HandleMouseReleaseEvent(mev);
1316
1317   mouse_event_manager_->HandleMouseReleaseEventUpdateStates();
1318
1319   // crbug.com/1053385 release mouse capture only if there are no more mouse
1320   // buttons depressed
1321   if (MouseEvent::WebInputEventModifiersToButtons(mouse_event.GetModifiers()) ==
1322       0)
1323     ReleaseMouseCaptureFromLocalRoot();
1324
1325   return event_result;
1326 }
1327
1328 static LocalFrame* LocalFrameFromTargetNode(Node* target) {
1329   auto* html_frame_base_element = DynamicTo<HTMLFrameElementBase>(target);
1330   if (!html_frame_base_element)
1331     return nullptr;
1332
1333   // Cross-process drag and drop is not yet supported.
1334   return DynamicTo<LocalFrame>(html_frame_base_element->ContentFrame());
1335 }
1336
1337 WebInputEventResult EventHandler::UpdateDragAndDrop(
1338     const WebMouseEvent& event,
1339     DataTransfer* data_transfer) {
1340   WebInputEventResult event_result = WebInputEventResult::kNotHandled;
1341
1342   if (!frame_->View())
1343     return event_result;
1344
1345   HitTestRequest request(HitTestRequest::kReadOnly);
1346   MouseEventWithHitTestResults mev =
1347       event_handling_util::PerformMouseEventHitTest(frame_, request, event);
1348
1349   // Drag events should never go to text nodes (following IE, and proper
1350   // mouseover/out dispatch)
1351   Node* new_target = mev.InnerNode();
1352   if (new_target && new_target->IsTextNode())
1353     new_target = FlatTreeTraversal::Parent(*new_target);
1354
1355   if (AutoscrollController* controller =
1356           scroll_manager_->GetAutoscrollController()) {
1357     controller->UpdateDragAndDrop(new_target, event.PositionInRootFrame(),
1358                                   event.TimeStamp());
1359   }
1360
1361   if (drag_target_ != new_target) {
1362     // FIXME: this ordering was explicitly chosen to match WinIE. However,
1363     // it is sometimes incorrect when dragging within subframes, as seen with
1364     // web_tests/fast/events/drag-in-frames.html.
1365     //
1366     // Moreover, this ordering conforms to section 7.9.4 of the HTML 5 spec.
1367     // <http://dev.w3.org/html5/spec/Overview.html#drag-and-drop-processing-model>.
1368     if (auto* target_frame = LocalFrameFromTargetNode(new_target)) {
1369       event_result = target_frame->GetEventHandler().UpdateDragAndDrop(
1370           event, data_transfer);
1371     } else if (new_target) {
1372       // As per section 7.9.4 of the HTML 5 spec., we must always fire a drag
1373       // event before firing a dragenter, dragleave, or dragover event.
1374       if (mouse_event_manager_->GetDragState().drag_src_) {
1375         // For now we don't care if event handler cancels default behavior,
1376         // since there is none.
1377         mouse_event_manager_->DispatchDragSrcEvent(event_type_names::kDrag,
1378                                                    event);
1379       }
1380       event_result = mouse_event_manager_->DispatchDragEvent(
1381           event_type_names::kDragenter, new_target, drag_target_, event,
1382           data_transfer);
1383     }
1384
1385     if (auto* target_frame = LocalFrameFromTargetNode(drag_target_.Get())) {
1386       event_result = target_frame->GetEventHandler().UpdateDragAndDrop(
1387           event, data_transfer);
1388     } else if (drag_target_) {
1389       mouse_event_manager_->DispatchDragEvent(event_type_names::kDragleave,
1390                                               drag_target_.Get(), new_target,
1391                                               event, data_transfer);
1392     }
1393
1394     if (new_target) {
1395       // We do not explicitly call m_mouseEventManager->dispatchDragEvent here
1396       // because it could ultimately result in the appearance that two dragover
1397       // events fired. So, we mark that we should only fire a dragover event on
1398       // the next call to this function.
1399       should_only_fire_drag_over_event_ = true;
1400     }
1401   } else {
1402     if (auto* target_frame = LocalFrameFromTargetNode(new_target)) {
1403       event_result = target_frame->GetEventHandler().UpdateDragAndDrop(
1404           event, data_transfer);
1405     } else if (new_target) {
1406       // Note, when dealing with sub-frames, we may need to fire only a dragover
1407       // event as a drag event may have been fired earlier.
1408       if (!should_only_fire_drag_over_event_ &&
1409           mouse_event_manager_->GetDragState().drag_src_) {
1410         // For now we don't care if event handler cancels default behavior,
1411         // since there is none.
1412         mouse_event_manager_->DispatchDragSrcEvent(event_type_names::kDrag,
1413                                                    event);
1414       }
1415       event_result = mouse_event_manager_->DispatchDragEvent(
1416           event_type_names::kDragover, new_target, nullptr, event,
1417           data_transfer);
1418       should_only_fire_drag_over_event_ = false;
1419     }
1420   }
1421   drag_target_ = new_target;
1422
1423   return event_result;
1424 }
1425
1426 void EventHandler::CancelDragAndDrop(const WebMouseEvent& event,
1427                                      DataTransfer* data_transfer) {
1428   if (auto* target_frame = LocalFrameFromTargetNode(drag_target_.Get())) {
1429     target_frame->GetEventHandler().CancelDragAndDrop(event, data_transfer);
1430   } else if (drag_target_.Get()) {
1431     if (mouse_event_manager_->GetDragState().drag_src_) {
1432       mouse_event_manager_->DispatchDragSrcEvent(event_type_names::kDrag,
1433                                                  event);
1434     }
1435     mouse_event_manager_->DispatchDragEvent(event_type_names::kDragleave,
1436                                             drag_target_.Get(), nullptr, event,
1437                                             data_transfer);
1438   }
1439   ClearDragState();
1440 }
1441
1442 WebInputEventResult EventHandler::PerformDragAndDrop(
1443     const WebMouseEvent& event,
1444     DataTransfer* data_transfer) {
1445   WebInputEventResult result = WebInputEventResult::kNotHandled;
1446   if (auto* target_frame = LocalFrameFromTargetNode(drag_target_.Get())) {
1447     result = target_frame->GetEventHandler().PerformDragAndDrop(event,
1448                                                                 data_transfer);
1449   } else if (drag_target_.Get()) {
1450     result = mouse_event_manager_->DispatchDragEvent(
1451         event_type_names::kDrop, drag_target_.Get(), nullptr, event,
1452         data_transfer);
1453   }
1454   ClearDragState();
1455   return result;
1456 }
1457
1458 #if BUILDFLAG(IS_TIZEN)
1459 void EventHandler::EnterDragState() {
1460   gesture_manager_->EnterDragState();
1461 }
1462 #endif
1463
1464 void EventHandler::ClearDragState() {
1465   scroll_manager_->StopAutoscroll();
1466   drag_target_ = nullptr;
1467   capturing_mouse_events_element_ = nullptr;
1468   ReleaseMouseCaptureFromLocalRoot();
1469   should_only_fire_drag_over_event_ = false;
1470 }
1471
1472 #if BUILDFLAG(IS_TIZEN_TV)
1473 bool EventHandler::ScrollNewPosition(const ScrollOffset& scroll_offset,
1474                                      LocalFrameView* frame_view) {
1475   ScrollableArea* const scrollable_area = frame_view->LayoutViewport();
1476   if (!scrollable_area)
1477     return false;
1478
1479   gfx::PointF ori_point = scrollable_area->ScrollPosition();
1480   scrollable_area->ScrollBy(scroll_offset, mojom::blink::ScrollType::kUser);
1481   gfx::PointF new_point = scrollable_area->ScrollPosition();
1482   return new_point != ori_point;
1483 }
1484
1485 bool EventHandler::ScrollWithMultiplier(const ScrollOffset& scroll_offset,
1486                                         Node* start_node) {
1487   LocalFrame* frame = frame_;
1488   while (frame) {
1489     mojom::blink::ScrollDirection vertical_direction =
1490         (scroll_offset.y() < 0)
1491             ? mojom::blink::ScrollDirection::kScrollUpIgnoringWritingMode
1492             : mojom::blink::ScrollDirection::kScrollDownIgnoringWritingMode;
1493     mojom::blink::ScrollDirection horizontal_direction =
1494         (scroll_offset.x() < 0)
1495             ? mojom::blink::ScrollDirection::kScrollLeftIgnoringWritingMode
1496             : mojom::blink::ScrollDirection::kScrollRightIgnoringWritingMode;
1497     if (scroll_manager_->LogicalScroll(
1498             vertical_direction, ui::ScrollGranularity::kScrollByPixel, start_node,
1499             nullptr, std::abs(scroll_offset.y())))
1500       return true;
1501
1502     if (scroll_manager_->LogicalScroll(
1503             horizontal_direction, ui::ScrollGranularity::kScrollByPixel, start_node,
1504             nullptr, std::abs(scroll_offset.x())))
1505       return true;
1506
1507     LocalFrameView* frame_view = frame->View();
1508     if (frame_view && ScrollNewPosition(scroll_offset, frame_view))
1509       return true;
1510
1511     frame = DynamicTo<LocalFrame>(frame->Tree().Parent());
1512     if (frame)
1513       start_node = frame->DeprecatedLocalOwner();
1514   }
1515   return false;
1516 }
1517 #endif
1518
1519 void EventHandler::RecomputeMouseHoverStateIfNeeded() {
1520   mouse_event_manager_->RecomputeMouseHoverStateIfNeeded();
1521 }
1522
1523 void EventHandler::MarkHoverStateDirty() {
1524   mouse_event_manager_->MarkHoverStateDirty();
1525 }
1526
1527 Element* EventHandler::EffectiveMouseEventTargetElement(
1528     Element* target_element) {
1529   Element* new_element_under_mouse = target_element;
1530   if (pointer_event_manager_->GetMouseCaptureTarget())
1531     new_element_under_mouse = pointer_event_manager_->GetMouseCaptureTarget();
1532   return new_element_under_mouse;
1533 }
1534
1535 Element* EventHandler::GetElementUnderMouse() {
1536   return mouse_event_manager_->GetElementUnderMouse();
1537 }
1538
1539 Element* EventHandler::CurrentTouchDownElement() {
1540   return pointer_event_manager_->CurrentTouchDownElement();
1541 }
1542
1543 void EventHandler::SetDelayedNavigationTaskHandle(TaskHandle task_handle) {
1544   delayed_navigation_task_handle_ = std::move(task_handle);
1545 }
1546
1547 TaskHandle& EventHandler::GetDelayedNavigationTaskHandle() {
1548   return delayed_navigation_task_handle_;
1549 }
1550
1551 bool EventHandler::IsPointerIdActiveOnFrame(PointerId pointer_id,
1552                                             LocalFrame* frame) const {
1553   DCHECK(frame_ == &frame_->LocalFrameRoot() || frame_ == frame);
1554   return pointer_event_manager_->IsPointerIdActiveOnFrame(pointer_id, frame);
1555 }
1556
1557 bool EventHandler::RootFrameTrackedActivePointerInCurrentFrame(
1558     PointerId pointer_id) const {
1559   return frame_ != &frame_->LocalFrameRoot() &&
1560          frame_->LocalFrameRoot().GetEventHandler().IsPointerIdActiveOnFrame(
1561              pointer_id, frame_);
1562 }
1563
1564 bool EventHandler::IsPointerEventActive(PointerId pointer_id) {
1565   return pointer_event_manager_->IsActive(pointer_id) ||
1566          RootFrameTrackedActivePointerInCurrentFrame(pointer_id);
1567 }
1568
1569 LocalFrame* EventHandler::DetermineActivePointerTrackerFrame(
1570     PointerId pointer_id) const {
1571   // If pointer_id is active on current |frame_|, pointer states are in
1572   // current frame's PEM; otherwise, check if it's a touch-like pointer that
1573   // have its active states in the local frame root's PEM.
1574   if (IsPointerIdActiveOnFrame(pointer_id, frame_))
1575     return frame_.Get();
1576   if (RootFrameTrackedActivePointerInCurrentFrame(pointer_id))
1577     return &frame_->LocalFrameRoot();
1578   return nullptr;
1579 }
1580
1581 void EventHandler::SetPointerCapture(PointerId pointer_id,
1582                                      Element* target,
1583                                      bool explicit_capture) {
1584   // TODO(crbug.com/591387): This functionality should be per page not per
1585   // frame.
1586   LocalFrame* tracking_frame = DetermineActivePointerTrackerFrame(pointer_id);
1587
1588   bool captured =
1589       tracking_frame && tracking_frame->GetEventHandler()
1590                             .pointer_event_manager_->SetPointerCapture(
1591                                 pointer_id, target, explicit_capture);
1592
1593   if (captured && pointer_id == PointerEventFactory::kMouseId) {
1594     CaptureMouseEventsToWidget(true);
1595   }
1596 }
1597
1598 void EventHandler::ReleasePointerCapture(PointerId pointer_id,
1599                                          Element* target) {
1600   LocalFrame* tracking_frame = DetermineActivePointerTrackerFrame(pointer_id);
1601
1602   bool released =
1603       tracking_frame &&
1604       tracking_frame->GetEventHandler()
1605           .pointer_event_manager_->ReleasePointerCapture(pointer_id, target);
1606
1607   if (released && pointer_id == PointerEventFactory::kMouseId) {
1608     CaptureMouseEventsToWidget(false);
1609   }
1610 }
1611
1612 void EventHandler::ReleaseMousePointerCapture() {
1613   ReleaseMouseCaptureFromLocalRoot();
1614 }
1615
1616 bool EventHandler::HasPointerCapture(PointerId pointer_id,
1617                                      const Element* target) const {
1618   if (LocalFrame* tracking_frame =
1619           DetermineActivePointerTrackerFrame(pointer_id)) {
1620     return tracking_frame->GetEventHandler()
1621         .pointer_event_manager_->HasPointerCapture(pointer_id, target);
1622   }
1623   return false;
1624 }
1625
1626 void EventHandler::ElementRemoved(Element* target) {
1627   pointer_event_manager_->ElementRemoved(target);
1628   if (target)
1629     mouse_wheel_event_manager_->ElementRemoved(target);
1630 }
1631
1632 void EventHandler::ResetMousePositionForPointerUnlock() {
1633   pointer_event_manager_->RemoveLastMousePosition();
1634 }
1635
1636 bool EventHandler::LongTapShouldInvokeContextMenu() {
1637   return gesture_manager_->GestureContextMenuDeferred();
1638 }
1639
1640 WebInputEventResult EventHandler::DispatchMousePointerEvent(
1641     const WebInputEvent::Type event_type,
1642     Element* target_element,
1643     const WebMouseEvent& mouse_event,
1644     const Vector<WebMouseEvent>& coalesced_events,
1645     const Vector<WebMouseEvent>& predicted_events,
1646     bool skip_click_dispatch) {
1647   const auto& event_result = pointer_event_manager_->SendMousePointerEvent(
1648       EffectiveMouseEventTargetElement(target_element), event_type, mouse_event,
1649       coalesced_events, predicted_events, skip_click_dispatch);
1650   return event_result;
1651 }
1652
1653 WebInputEventResult EventHandler::HandleWheelEvent(
1654     const WebMouseWheelEvent& event) {
1655   return mouse_wheel_event_manager_->HandleWheelEvent(event);
1656 }
1657
1658 // TODO(crbug.com/665924): This function bypasses all Handle*Event path.
1659 // It should be using that flow instead of creating/sending events directly.
1660 WebInputEventResult EventHandler::HandleTargetedMouseEvent(
1661     Element* target,
1662     const WebMouseEvent& event,
1663     const AtomicString& mouse_event_type,
1664     const Vector<WebMouseEvent>& coalesced_events,
1665     const Vector<WebMouseEvent>& predicted_events) {
1666   mouse_event_manager_->SetClickCount(event.click_count);
1667   return pointer_event_manager_->DirectDispatchMousePointerEvent(
1668       target, event, mouse_event_type, coalesced_events, predicted_events);
1669 }
1670
1671 WebInputEventResult EventHandler::HandleGestureEvent(
1672     const WebGestureEvent& gesture_event) {
1673   // Propagation to inner frames is handled below this function.
1674   DCHECK_EQ(frame_, &frame_->LocalFrameRoot());
1675   DCHECK_NE(0, gesture_event.FrameScale());
1676
1677   // Gesture scroll events are handled on the compositor thread.
1678   DCHECK(!gesture_event.IsScrollEvent());
1679
1680   // Hit test across all frames and do touch adjustment as necessary for the
1681   // event type.
1682   GestureEventWithHitTestResults targeted_event =
1683       TargetGestureEvent(gesture_event);
1684
1685   return HandleGestureEvent(targeted_event);
1686 }
1687
1688 WebInputEventResult EventHandler::HandleGestureEvent(
1689     const GestureEventWithHitTestResults& targeted_event) {
1690   TRACE_EVENT0("input", "EventHandler::handleGestureEvent");
1691   if (!frame_->GetPage())
1692     return WebInputEventResult::kNotHandled;
1693
1694   // Propagation to inner frames is handled below this function.
1695   DCHECK_EQ(frame_, &frame_->LocalFrameRoot());
1696
1697   // Non-scrolling related gesture events do a single cross-frame hit-test and
1698   // jump directly to the inner most frame. This matches handleMousePressEvent
1699   // etc.
1700   DCHECK(!targeted_event.Event().IsScrollEvent());
1701
1702   if (targeted_event.Event().GetType() ==
1703       WebInputEvent::Type::kGestureShowPress)
1704     last_show_press_timestamp_ = base::TimeTicks::Now();
1705
1706   // Update mouseout/leave/over/enter events before jumping directly to the
1707   // inner most frame.
1708   if (targeted_event.Event().GetType() == WebInputEvent::Type::kGestureTap)
1709     UpdateGestureTargetNodeForMouseEvent(targeted_event);
1710
1711   // Route to the correct frame.
1712   if (LocalFrame* inner_frame =
1713           targeted_event.GetHitTestResult().InnerNodeFrame())
1714     return inner_frame->GetEventHandler().HandleGestureEventInFrame(
1715         targeted_event);
1716
1717   // No hit test result, handle in root instance. Perhaps we should just return
1718   // false instead?
1719   return gesture_manager_->HandleGestureEventInFrame(targeted_event);
1720 }
1721
1722 WebInputEventResult EventHandler::HandleGestureEventInFrame(
1723     const GestureEventWithHitTestResults& targeted_event) {
1724   bool is_tap =
1725       targeted_event.Event().GetType() == WebInputEvent::Type::kGestureTap;
1726   if (is_tap && discarded_events_.tap_target != kInvalidDOMNodeId &&
1727       discarded_events_.tap_target ==
1728           targeted_event.InnerNode()->GetDomNodeId() &&
1729       targeted_event.Event().TimeStamp() - discarded_events_.tap_time <
1730           event_handling_util::kDiscardedEventMistakeInterval) {
1731     targeted_event.InnerNode()->GetDocument().CountUse(
1732         WebFeature::kInputEventToRecentlyMovedIframeMistakenlyDiscarded);
1733   }
1734   if (event_handling_util::ShouldDiscardEventTargetingFrame(
1735           targeted_event.Event(), *frame_)) {
1736     if (is_tap) {
1737       discarded_events_.tap_target = targeted_event.InnerNode()->GetDomNodeId();
1738       discarded_events_.tap_time = targeted_event.Event().TimeStamp();
1739     }
1740     return WebInputEventResult::kHandledSuppressed;
1741   }
1742   if (is_tap) {
1743     discarded_events_.tap_target = kInvalidDOMNodeId;
1744     discarded_events_.tap_time = base::TimeTicks();
1745   }
1746   return gesture_manager_->HandleGestureEventInFrame(targeted_event);
1747 }
1748
1749 WebInputEventResult EventHandler::HandleGestureScrollEvent(
1750     const WebGestureEvent& gesture_event) {
1751   TRACE_EVENT0("input", "EventHandler::handleGestureScrollEvent");
1752   if (!frame_->GetPage())
1753     return WebInputEventResult::kNotHandled;
1754
1755   return scroll_manager_->HandleGestureScrollEvent(gesture_event);
1756 }
1757
1758 void EventHandler::SetMouseDownMayStartAutoscroll() {
1759   mouse_event_manager_->SetMouseDownMayStartAutoscroll();
1760 }
1761
1762 bool EventHandler::IsScrollbarHandlingGestures() const {
1763   return scroll_manager_->IsScrollbarHandlingGestures();
1764 }
1765
1766 bool EventHandler::ShouldApplyTouchAdjustment(
1767     const WebGestureEvent& event) const {
1768   if (event.primary_pointer_type == WebPointerProperties::PointerType::kPen)
1769     return false;
1770
1771   return !event.TapAreaInRootFrame().IsEmpty();
1772 }
1773
1774 void EventHandler::CacheTouchAdjustmentResult(uint32_t id,
1775                                               gfx::PointF adjusted_point) {
1776   touch_adjustment_result_.unique_event_id = id;
1777   touch_adjustment_result_.adjusted_point = adjusted_point;
1778 }
1779
1780 bool EventHandler::GestureCorrespondsToAdjustedTouch(
1781     const WebGestureEvent& event) {
1782   // Gesture events start with a GestureTapDown. If GestureTapDown's unique id
1783   // matches stored adjusted touchstart event id, then we can use the stored
1784   // result for following gesture event.
1785   if (event.GetType() == WebInputEvent::Type::kGestureTapDown) {
1786     should_use_touch_event_adjusted_point_ =
1787         (event.unique_touch_event_id != 0 &&
1788          event.unique_touch_event_id ==
1789              touch_adjustment_result_.unique_event_id);
1790   }
1791
1792   // Check if the adjusted point is in the gesture event tap rect.
1793   // If not, should not use this touch point in following events.
1794   if (should_use_touch_event_adjusted_point_) {
1795     gfx::SizeF size = event.TapAreaInRootFrame();
1796     gfx::RectF tap_rect(
1797         event.PositionInRootFrame() -
1798             gfx::Vector2dF(size.width() * 0.5, size.height() * 0.5),
1799         size);
1800     should_use_touch_event_adjusted_point_ =
1801         tap_rect.InclusiveContains(touch_adjustment_result_.adjusted_point);
1802   }
1803
1804   return should_use_touch_event_adjusted_point_;
1805 }
1806
1807 bool EventHandler::BestNodeForHitTestResult(
1808     TouchAdjustmentCandidateType candidate_type,
1809     const HitTestLocation& location,
1810     const HitTestResult& result,
1811     gfx::Point& adjusted_point,
1812     Node*& adjusted_node) {
1813   TRACE_EVENT0("input", "EventHandler::BestNodeForHitTestResult");
1814   CHECK(location.IsRectBasedTest());
1815
1816   // If the touch is over a scrollbar or a resizer, we don't adjust the touch
1817   // point.  This is because touch adjustment only takes into account DOM nodes
1818   // so a touch over a scrollbar or a resizer would be adjusted towards a nearby
1819   // DOM node, making the scrollbar/resizer unusable.
1820   //
1821   // Context-menu hittests are excluded from this consideration because a
1822   // right-click/long-press doesn't drag the scrollbar therefore prefers DOM
1823   // nodes with relevant contextmenu properties.
1824   if (candidate_type != TouchAdjustmentCandidateType::kContextMenu &&
1825       (result.GetScrollbar() || result.IsOverResizer())) {
1826     return false;
1827   }
1828
1829   gfx::Point touch_hotspot =
1830       frame_->View()->ConvertToRootFrame(location.RoundedPoint());
1831   gfx::Rect touch_rect =
1832       frame_->View()->ConvertToRootFrame(location.ToEnclosingRect());
1833
1834   if (touch_rect.IsEmpty()) {
1835     return false;
1836   }
1837
1838   HeapVector<Member<Node>, 11> nodes(result.ListBasedTestResult());
1839
1840   return FindBestTouchAdjustmentCandidate(candidate_type, adjusted_node,
1841                                           adjusted_point, touch_hotspot,
1842                                           touch_rect, nodes);
1843 }
1844
1845 // Update the hover and active state across all frames.  This logic is
1846 // different than the mouse case because mice send MouseLeave events to frames
1847 // as they're exited.  With gestures or manual applications, a single event
1848 // conceptually both 'leaves' whatever frame currently had hover and enters a
1849 // new frame so we need to update state in the old frame chain as well.
1850 void EventHandler::UpdateCrossFrameHoverActiveState(bool is_active,
1851                                                     Element* inner_element) {
1852   DCHECK_EQ(frame_, &frame_->LocalFrameRoot());
1853
1854   HeapVector<Member<LocalFrame>> new_hover_frame_chain;
1855   LocalFrame* new_hover_frame_in_document =
1856       inner_element ? inner_element->GetDocument().GetFrame() : nullptr;
1857   // Insert the ancestors of the frame having the new hovered element to the
1858   // frame chain.  The frame chain doesn't include the main frame to avoid the
1859   // redundant work that cleans the hover state because the hover state for the
1860   // main frame is updated by calling Document::UpdateHoverActiveState.
1861   while (new_hover_frame_in_document && new_hover_frame_in_document != frame_) {
1862     new_hover_frame_chain.push_back(new_hover_frame_in_document);
1863     Frame* parent_frame = new_hover_frame_in_document->Tree().Parent();
1864     new_hover_frame_in_document = DynamicTo<LocalFrame>(parent_frame);
1865   }
1866
1867   Element* old_hover_element_in_cur_doc = frame_->GetDocument()->HoverElement();
1868   Element* new_innermost_hover_element = inner_element;
1869
1870   if (new_innermost_hover_element != old_hover_element_in_cur_doc) {
1871     wtf_size_t index_frame_chain = new_hover_frame_chain.size();
1872
1873     // Clear the hover state on any frames which are no longer in the frame
1874     // chain of the hovered element.
1875     while (old_hover_element_in_cur_doc &&
1876            old_hover_element_in_cur_doc->IsFrameOwnerElement()) {
1877       LocalFrame* new_hover_frame = nullptr;
1878       // If we can't get the frame from the new hover frame chain,
1879       // the newHoverFrame will be null and the old hover state will be cleared.
1880       if (index_frame_chain > 0)
1881         new_hover_frame = new_hover_frame_chain[--index_frame_chain];
1882
1883       auto* owner = To<HTMLFrameOwnerElement>(old_hover_element_in_cur_doc);
1884       LocalFrame* old_hover_frame =
1885           DynamicTo<LocalFrame>(owner->ContentFrame());
1886       if (!old_hover_frame)
1887         break;
1888
1889       Document* doc = old_hover_frame->GetDocument();
1890       if (!doc)
1891         break;
1892
1893       old_hover_element_in_cur_doc = doc->HoverElement();
1894       // If the old hovered frame is different from the new hovered frame.
1895       // we should clear the old hovered element from the old hovered frame.
1896       if (new_hover_frame != old_hover_frame) {
1897         doc->UpdateHoverActiveState(is_active,
1898                                     /*update_active_chain=*/true, nullptr);
1899       }
1900     }
1901   }
1902
1903   // Recursively set the new active/hover states on every frame in the chain of
1904   // innerElement.
1905   frame_->GetDocument()->UpdateHoverActiveState(is_active,
1906                                                 /*update_active_chain=*/true,
1907                                                 inner_element);
1908 }
1909
1910 // Update the mouseover/mouseenter/mouseout/mouseleave events across all frames
1911 // for this gesture, before passing the targeted gesture event directly to a hit
1912 // frame.
1913 void EventHandler::UpdateGestureTargetNodeForMouseEvent(
1914     const GestureEventWithHitTestResults& targeted_event) {
1915   DCHECK_EQ(frame_, &frame_->LocalFrameRoot());
1916
1917   // Behaviour of this function is as follows:
1918   // - Create the chain of all entered frames.
1919   // - Compare the last frame chain under the gesture to newly entered frame
1920   //   chain from the main frame one by one.
1921   // - If the last frame doesn't match with the entered frame, then create the
1922   //   chain of exited frames from the last frame chain.
1923   // - Dispatch mouseout/mouseleave events of the exited frames from the inside
1924   //   out.
1925   // - Dispatch mouseover/mouseenter events of the entered frames into the
1926   //   inside.
1927
1928   // Insert the ancestors of the frame having the new target node to the entered
1929   // frame chain.
1930   HeapVector<Member<LocalFrame>, 2> entered_frame_chain;
1931   LocalFrame* entered_frame_in_document =
1932       targeted_event.GetHitTestResult().InnerNodeFrame();
1933   while (entered_frame_in_document) {
1934     entered_frame_chain.push_back(entered_frame_in_document);
1935     Frame* parent_frame = entered_frame_in_document->Tree().Parent();
1936     entered_frame_in_document = DynamicTo<LocalFrame>(parent_frame);
1937   }
1938
1939   wtf_size_t index_entered_frame_chain = entered_frame_chain.size();
1940   LocalFrame* exited_frame_in_document = frame_;
1941   HeapVector<Member<LocalFrame>, 2> exited_frame_chain;
1942   // Insert the frame from the disagreement between last frames and entered
1943   // frames.
1944   while (exited_frame_in_document) {
1945     Node* last_node_under_tap =
1946         exited_frame_in_document->GetEventHandler()
1947             .mouse_event_manager_->GetElementUnderMouse();
1948     if (!last_node_under_tap)
1949       break;
1950
1951     LocalFrame* next_exited_frame_in_document = nullptr;
1952     if (auto* owner = DynamicTo<HTMLFrameOwnerElement>(last_node_under_tap)) {
1953       next_exited_frame_in_document =
1954           DynamicTo<LocalFrame>(owner->ContentFrame());
1955     }
1956
1957     if (exited_frame_chain.size() > 0) {
1958       exited_frame_chain.push_back(exited_frame_in_document);
1959     } else {
1960       LocalFrame* last_entered_frame_in_document =
1961           index_entered_frame_chain
1962               ? entered_frame_chain[index_entered_frame_chain - 1]
1963               : nullptr;
1964       if (exited_frame_in_document != last_entered_frame_in_document)
1965         exited_frame_chain.push_back(exited_frame_in_document);
1966       else if (next_exited_frame_in_document && index_entered_frame_chain)
1967         --index_entered_frame_chain;
1968     }
1969     exited_frame_in_document = next_exited_frame_in_document;
1970   }
1971
1972   const WebGestureEvent& gesture_event = targeted_event.Event();
1973   unsigned modifiers = gesture_event.GetModifiers();
1974   WebMouseEvent fake_mouse_move(
1975       WebInputEvent::Type::kMouseMove, gesture_event,
1976       WebPointerProperties::Button::kNoButton,
1977       /* clickCount */ 0,
1978       modifiers | WebInputEvent::Modifiers::kIsCompatibilityEventForTouch,
1979       gesture_event.TimeStamp());
1980
1981   // Update the mouseout/mouseleave event
1982   wtf_size_t index_exited_frame_chain = exited_frame_chain.size();
1983   while (index_exited_frame_chain) {
1984     LocalFrame* leave_frame = exited_frame_chain[--index_exited_frame_chain];
1985     leave_frame->GetEventHandler().mouse_event_manager_->SetElementUnderMouse(
1986         EffectiveMouseEventTargetElement(nullptr), fake_mouse_move);
1987   }
1988
1989   // update the mouseover/mouseenter event
1990   while (index_entered_frame_chain) {
1991     Frame* parent_frame =
1992         entered_frame_chain[--index_entered_frame_chain]->Tree().Parent();
1993     if (auto* parent_local_frame = DynamicTo<LocalFrame>(parent_frame)) {
1994       parent_local_frame->GetEventHandler()
1995           .mouse_event_manager_->SetElementUnderMouse(
1996               EffectiveMouseEventTargetElement(To<HTMLFrameOwnerElement>(
1997                   entered_frame_chain[index_entered_frame_chain]->Owner())),
1998               fake_mouse_move);
1999     }
2000   }
2001 }
2002
2003 GestureEventWithHitTestResults EventHandler::TargetGestureEvent(
2004     const WebGestureEvent& gesture_event,
2005     bool read_only) {
2006   TRACE_EVENT0("input", "EventHandler::targetGestureEvent");
2007
2008   DCHECK_EQ(frame_, &frame_->LocalFrameRoot());
2009   // Scrolling events get hit tested per frame (like wheel events do).
2010   DCHECK(!gesture_event.IsScrollEvent());
2011
2012   HitTestRequest::HitTestRequestType hit_type =
2013       gesture_manager_->GetHitTypeForGestureType(gesture_event.GetType());
2014   base::TimeDelta active_interval;
2015   bool should_keep_active_for_min_interval = false;
2016   if (read_only) {
2017     hit_type |= HitTestRequest::kReadOnly;
2018   } else if (
2019 #if BUILDFLAG(IS_EFL)
2020       !RuntimeEnabledFeatures::TizenCompatibilityModeEnabled() &&
2021 #endif
2022       gesture_event.GetType() == WebInputEvent::Type::kGestureTap &&
2023       last_show_press_timestamp_) {
2024     // If the Tap is received very shortly after ShowPress, we want to
2025     // delay clearing of the active state so that it's visible to the user
2026     // for at least a couple of frames.
2027     active_interval =
2028         base::TimeTicks::Now() - last_show_press_timestamp_.value();
2029     should_keep_active_for_min_interval =
2030         active_interval < kMinimumActiveInterval;
2031     if (should_keep_active_for_min_interval)
2032       hit_type |= HitTestRequest::kReadOnly;
2033   }
2034
2035   GestureEventWithHitTestResults event_with_hit_test_results =
2036       HitTestResultForGestureEvent(gesture_event, hit_type);
2037   // Now apply hover/active state to the final target.
2038   HitTestRequest request(hit_type | HitTestRequest::kAllowChildFrameContent);
2039   if (!request.ReadOnly()) {
2040     UpdateCrossFrameHoverActiveState(
2041         request.Active(),
2042         event_with_hit_test_results.GetHitTestResult().InnerElement());
2043   }
2044
2045   if (should_keep_active_for_min_interval) {
2046     last_deferred_tap_element_ =
2047         event_with_hit_test_results.GetHitTestResult().InnerElement();
2048     // TODO(https://crbug.com/668758): Use a normal BeginFrame update for this.
2049     active_interval_timer_.StartOneShot(
2050         kMinimumActiveInterval - active_interval, FROM_HERE);
2051   }
2052
2053   return event_with_hit_test_results;
2054 }
2055
2056 GestureEventWithHitTestResults EventHandler::HitTestResultForGestureEvent(
2057     const WebGestureEvent& gesture_event,
2058     HitTestRequest::HitTestRequestType hit_type) {
2059   // Perform the rect-based hit-test (or point-based if adjustment is
2060   // disabled). Note that we don't yet apply hover/active state here because
2061   // we need to resolve touch adjustment first so that we apply hover/active
2062   // it to the final adjusted node.
2063   hit_type |= HitTestRequest::kReadOnly;
2064   WebGestureEvent adjusted_event = gesture_event;
2065   PhysicalSize hit_rect_size;
2066   if (ShouldApplyTouchAdjustment(gesture_event)) {
2067     // If gesture_event unique id matches the stored touch event result, do
2068     // point-base hit test. Otherwise add padding and do rect-based hit test.
2069     if (GestureCorrespondsToAdjustedTouch(gesture_event)) {
2070       adjusted_event.ApplyTouchAdjustment(
2071           touch_adjustment_result_.adjusted_point);
2072     } else {
2073       gfx::SizeF tap_area = adjusted_event.TapAreaInRootFrame();
2074       hit_rect_size = GetHitTestRectForAdjustment(
2075           *frame_, PhysicalSize(LayoutUnit(tap_area.width()),
2076                                 LayoutUnit(tap_area.height())));
2077       if (!hit_rect_size.IsEmpty())
2078         hit_type |= HitTestRequest::kListBased;
2079     }
2080   }
2081
2082   HitTestLocation location;
2083   LocalFrame& root_frame = frame_->LocalFrameRoot();
2084   HitTestResult hit_test_result;
2085   if (hit_rect_size.IsEmpty()) {
2086     location = HitTestLocation(adjusted_event.PositionInRootFrame());
2087     hit_test_result = root_frame.GetEventHandler().HitTestResultAtLocation(
2088         location, hit_type);
2089   } else {
2090     PhysicalOffset top_left =
2091         PhysicalOffset::FromPointFRound(adjusted_event.PositionInRootFrame());
2092     top_left -= PhysicalOffset(LayoutUnit(hit_rect_size.width * 0.5f),
2093                                LayoutUnit(hit_rect_size.height * 0.5f));
2094     location = HitTestLocation(PhysicalRect(top_left, hit_rect_size));
2095     hit_test_result = root_frame.GetEventHandler().HitTestResultAtLocation(
2096         location, hit_type);
2097
2098     // Adjust the location of the gesture to the most likely nearby node, as
2099     // appropriate for the type of event.
2100     ApplyTouchAdjustment(&adjusted_event, location, hit_test_result);
2101     // Do a new hit-test at the (adjusted) gesture coordinates. This is
2102     // necessary because rect-based hit testing and touch adjustment sometimes
2103     // return a different node than what a point-based hit test would return for
2104     // the same point.
2105     // FIXME: Fix touch adjustment to avoid the need for a redundant hit test.
2106     // http://crbug.com/398914
2107     LocalFrame* hit_frame = hit_test_result.InnerNodeFrame();
2108     if (!hit_frame)
2109       hit_frame = frame_;
2110     location = HitTestLocation(adjusted_event.PositionInRootFrame());
2111     hit_test_result = root_frame.GetEventHandler().HitTestResultAtLocation(
2112         location,
2113         (hit_type | HitTestRequest::kReadOnly) & ~HitTestRequest::kListBased);
2114   }
2115
2116   // If we did a rect-based hit test it must be resolved to the best single node
2117   // by now to ensure consumers don't accidentally use one of the other
2118   // candidates.
2119   DCHECK(!location.IsRectBasedTest());
2120
2121   return GestureEventWithHitTestResults(adjusted_event, location,
2122                                         hit_test_result);
2123 }
2124
2125 void EventHandler::ApplyTouchAdjustment(WebGestureEvent* gesture_event,
2126                                         HitTestLocation& location,
2127                                         HitTestResult& hit_test_result) {
2128   TouchAdjustmentCandidateType touch_adjustment_candiate_type =
2129       TouchAdjustmentCandidateType::kClickable;
2130   switch (gesture_event->GetType()) {
2131     case WebInputEvent::Type::kGestureTap:
2132     case WebInputEvent::Type::kGestureTapUnconfirmed:
2133     case WebInputEvent::Type::kGestureTapDown:
2134     case WebInputEvent::Type::kGestureShowPress:
2135       break;
2136     case WebInputEvent::Type::kGestureShortPress:
2137     case WebInputEvent::Type::kGestureLongPress:
2138     case WebInputEvent::Type::kGestureLongTap:
2139     case WebInputEvent::Type::kGestureTwoFingerTap:
2140       touch_adjustment_candiate_type =
2141           TouchAdjustmentCandidateType::kContextMenu;
2142       break;
2143     default:
2144       NOTREACHED();
2145   }
2146
2147   Node* adjusted_node = nullptr;
2148   gfx::Point adjusted_point;
2149   if (BestNodeForHitTestResult(touch_adjustment_candiate_type, location,
2150                                hit_test_result, adjusted_point,
2151                                adjusted_node)) {
2152     // Update the hit-test result to be a point-based result instead of a
2153     // rect-based result.
2154     PhysicalOffset point(frame_->View()->ConvertFromRootFrame(adjusted_point));
2155     DCHECK(location.ContainsPoint(gfx::PointF(point)));
2156     DCHECK(location.IsRectBasedTest());
2157     location = hit_test_result.ResolveRectBasedTest(adjusted_node, point);
2158     gesture_event->ApplyTouchAdjustment(
2159         gfx::PointF(adjusted_point.x(), adjusted_point.y()));
2160   }
2161 }
2162
2163 WebInputEventResult EventHandler::SendContextMenuEvent(
2164     const WebMouseEvent& event,
2165     Element* override_target_element) {
2166   LocalFrameView* v = frame_->View();
2167   if (!v)
2168     return WebInputEventResult::kNotHandled;
2169
2170   // Clear mouse press state to avoid initiating a drag while context menu is
2171   // up.
2172   mouse_event_manager_->ReleaseMousePress();
2173   if (last_scrollbar_under_mouse_)
2174     last_scrollbar_under_mouse_->MouseUp(event);
2175
2176   PhysicalOffset position_in_contents(v->ConvertFromRootFrame(
2177       gfx::ToFlooredPoint(event.PositionInRootFrame())));
2178   HitTestRequest request(HitTestRequest::kActive);
2179   MouseEventWithHitTestResults mev =
2180       frame_->GetDocument()->PerformMouseEventHitTest(
2181           request, position_in_contents, event);
2182   // Since |Document::performMouseEventHitTest()| modifies layout tree for
2183   // setting hover element, we need to update layout tree for requirement of
2184   // |SelectionController::sendContextMenuEvent()|.
2185   frame_->GetDocument()->UpdateStyleAndLayout(
2186       DocumentUpdateReason::kContextMenu);
2187
2188   Element* target_element =
2189       override_target_element ? override_target_element : mev.InnerElement();
2190   return mouse_event_manager_->DispatchMouseEvent(
2191       EffectiveMouseEventTargetElement(target_element),
2192       event_type_names::kContextmenu, event, nullptr, nullptr, false, event.id,
2193       PointerEventFactory::PointerTypeNameForWebPointPointerType(
2194           event.pointer_type));
2195 }
2196
2197 static bool ShouldShowContextMenuAtSelection(const FrameSelection& selection) {
2198   // TODO(editing-dev): The use of UpdateStyleAndLayout
2199   // needs to be audited.  See http://crbug.com/590369 for more details.
2200   selection.GetDocument().UpdateStyleAndLayout(
2201       DocumentUpdateReason::kContextMenu);
2202
2203   const VisibleSelection& visible_selection =
2204       selection.ComputeVisibleSelectionInDOMTree();
2205   if (!visible_selection.IsRange() && !visible_selection.RootEditableElement())
2206     return false;
2207   return selection.SelectionHasFocus();
2208 }
2209
2210 WebInputEventResult EventHandler::ShowNonLocatedContextMenu(
2211     Element* override_target_element,
2212     WebMenuSourceType source_type) {
2213   LocalFrameView* view = frame_->View();
2214   if (!view)
2215     return WebInputEventResult::kNotHandled;
2216
2217   Document* doc = frame_->GetDocument();
2218   if (!doc)
2219     return WebInputEventResult::kNotHandled;
2220
2221   static const int kContextMenuMargin = 1;
2222
2223   gfx::Point location_in_root_frame;
2224
2225   Element* focused_element =
2226       override_target_element ? override_target_element : doc->FocusedElement();
2227   FrameSelection& selection = frame_->Selection();
2228   VisualViewport& visual_viewport = frame_->GetPage()->GetVisualViewport();
2229
2230   if (!override_target_element && ShouldShowContextMenuAtSelection(selection)) {
2231     DCHECK(!doc->NeedsLayoutTreeUpdate());
2232
2233     // Enclose the selection rect fully between the handles. If the handles are
2234     // on the same line, the selection rect is empty.
2235     const SelectionInDOMTree& visible_selection =
2236         selection.ComputeVisibleSelectionInDOMTree().AsSelection();
2237     const PositionWithAffinity start_position(
2238         visible_selection.ComputeStartPosition(), visible_selection.Affinity());
2239     const gfx::Point start_point =
2240         GetMiddleSelectionCaretOfPosition(start_position);
2241     const PositionWithAffinity end_position(
2242         visible_selection.ComputeEndPosition(), visible_selection.Affinity());
2243     const gfx::Point end_point =
2244         GetMiddleSelectionCaretOfPosition(end_position);
2245
2246     int left = std::min(start_point.x(), end_point.x());
2247     int top = std::min(start_point.y(), end_point.y());
2248     int right = std::max(start_point.x(), end_point.x());
2249     int bottom = std::max(start_point.y(), end_point.y());
2250
2251     // If selection is a caret and is inside an anchor element, then set that
2252     // as the "focused" element so we can show "open link" option in context
2253     // menu.
2254     if (visible_selection.IsCaret()) {
2255       Element* anchor_element =
2256           EnclosingAnchorElement(visible_selection.ComputeStartPosition());
2257       if (anchor_element)
2258         focused_element = anchor_element;
2259     }
2260     // Intersect the selection rect and the visible bounds of focused_element.
2261     if (focused_element) {
2262       gfx::Rect clipped_rect = view->ConvertFromRootFrame(
2263           GetFocusedElementRectForNonLocatedContextMenu(focused_element));
2264       left = std::max(clipped_rect.x(), left);
2265       top = std::max(clipped_rect.y(), top);
2266       right = std::min(clipped_rect.right(), right);
2267       bottom = std::min(clipped_rect.bottom(), bottom);
2268     }
2269     gfx::Rect selection_rect = gfx::Rect(left, top, right - left, bottom - top);
2270
2271     if (ContainsEvenAtEdge(selection_rect, start_point)) {
2272       location_in_root_frame = view->ConvertToRootFrame(start_point);
2273     } else if (ContainsEvenAtEdge(selection_rect, end_point)) {
2274       location_in_root_frame = view->ConvertToRootFrame(end_point);
2275     } else {
2276       location_in_root_frame =
2277           view->ConvertToRootFrame(selection_rect.CenterPoint());
2278     }
2279   } else if (focused_element) {
2280     gfx::Rect clipped_rect =
2281         GetFocusedElementRectForNonLocatedContextMenu(focused_element);
2282     location_in_root_frame = clipped_rect.CenterPoint();
2283   } else {
2284     // TODO(crbug.com/1274078): Should this use ScrollPosition()?
2285     location_in_root_frame =
2286         gfx::Point(visual_viewport.GetScrollOffset().x() + kContextMenuMargin,
2287                    visual_viewport.GetScrollOffset().y() + kContextMenuMargin);
2288   }
2289
2290   frame_->View()->SetCursor(PointerCursor());
2291   gfx::Point global_position =
2292       view->GetChromeClient()
2293           ->LocalRootToScreenDIPs(
2294               gfx::Rect(location_in_root_frame, gfx::Size()), frame_->View())
2295           .origin();
2296
2297   // Use the focused node as the target for hover and active.
2298   HitTestRequest request(HitTestRequest::kActive);
2299   HitTestLocation location(location_in_root_frame);
2300   HitTestResult result(request, location);
2301   result.SetInnerNode(focused_element ? static_cast<Node*>(focused_element)
2302                                       : doc);
2303   doc->UpdateHoverActiveState(request.Active(), !request.Move(),
2304                               result.InnerElement());
2305
2306   // The contextmenu event is a mouse event even when invoked using the
2307   // keyboard.  This is required for web compatibility.
2308   WebInputEvent::Type event_type = WebInputEvent::Type::kMouseDown;
2309   if (frame_->GetSettings() &&
2310       frame_->GetSettings()->GetShowContextMenuOnMouseUp())
2311     event_type = WebInputEvent::Type::kMouseUp;
2312
2313   WebMouseEvent mouse_event(
2314       event_type,
2315       gfx::PointF(location_in_root_frame.x(), location_in_root_frame.y()),
2316       gfx::PointF(global_position.x(), global_position.y()),
2317       WebPointerProperties::Button::kNoButton, /* clickCount */ 0,
2318       WebInputEvent::kNoModifiers, base::TimeTicks::Now(), source_type);
2319   mouse_event.id = PointerEventFactory::kMouseId;
2320
2321   // TODO(dtapuska): Transition the mouseEvent to be created really in viewport
2322   // coordinates instead of root frame coordinates.
2323   mouse_event.SetFrameScale(1);
2324
2325   return SendContextMenuEvent(mouse_event, focused_element);
2326 }
2327
2328 gfx::Rect EventHandler::GetFocusedElementRectForNonLocatedContextMenu(
2329     Element* focused_element) {
2330   gfx::Rect visible_rect = focused_element->VisibleBoundsInLocalRoot();
2331
2332   VisualViewport& visual_viewport = frame_->GetPage()->GetVisualViewport();
2333
2334   // TODO(bokan): This method may not work as expected when the local root
2335   // isn't the main frame since the result won't be transformed and clipped by
2336   // the visual viewport (which is accessible only from the outermost main
2337   // frame).
2338   if (frame_->LocalFrameRoot().IsOutermostMainFrame()) {
2339     visible_rect = visual_viewport.RootFrameToViewport(visible_rect);
2340     visible_rect.Intersect(gfx::Rect(visual_viewport.Size()));
2341   }
2342
2343   gfx::Rect clipped_rect = visible_rect;
2344   // The bounding rect of multiline elements may include points that are
2345   // not within the element. Intersect the clipped rect with the first
2346   // outline rect to ensure that the selection rect only includes visible
2347   // points within the focused element.
2348   Vector<gfx::Rect> outline_rects = focused_element->OutlineRectsInWidget();
2349   if (outline_rects.size() > 1)
2350     clipped_rect.Intersect(outline_rects[0]);
2351
2352   return visual_viewport.ViewportToRootFrame(clipped_rect);
2353 }
2354
2355 void EventHandler::ScheduleHoverStateUpdate() {
2356   // TODO(https://crbug.com/668758): Use a normal BeginFrame update for this.
2357   if (!hover_timer_.IsActive() &&
2358       !mouse_event_manager_->IsMousePositionUnknown())
2359     hover_timer_.StartOneShot(base::TimeDelta(), FROM_HERE);
2360 }
2361
2362 void EventHandler::ScheduleCursorUpdate() {
2363   // We only want one timer for the page, rather than each frame having it's own
2364   // timer competing which eachother (since there's only one mouse cursor).
2365   DCHECK_EQ(frame_, &frame_->LocalFrameRoot());
2366
2367   // TODO(https://crbug.com/668758): Use a normal BeginFrame update for this.
2368   if (!cursor_update_timer_.IsActive())
2369     cursor_update_timer_.StartOneShot(kCursorUpdateInterval, FROM_HERE);
2370 }
2371
2372 bool EventHandler::CursorUpdatePending() {
2373   return cursor_update_timer_.IsActive();
2374 }
2375
2376 bool EventHandler::IsHandlingKeyEvent() const {
2377   return keyboard_event_manager_->is_handling_key_event();
2378 }
2379
2380 void EventHandler::SetResizingFrameSet(HTMLFrameSetElement* frame_set) {
2381   CaptureMouseEventsToWidget(true);
2382   frame_set_being_resized_ = frame_set;
2383 }
2384
2385 void EventHandler::ResizeScrollableAreaDestroyed() {
2386   scroll_manager_->ClearResizeScrollableArea(true);
2387 }
2388
2389 void EventHandler::HoverTimerFired(TimerBase*) {
2390   TRACE_EVENT0("input", "EventHandler::hoverTimerFired");
2391
2392   DCHECK(frame_);
2393   DCHECK(frame_->GetDocument());
2394
2395   if (auto* layout_object = frame_->ContentLayoutObject()) {
2396     if (LocalFrameView* view = frame_->View()) {
2397       HitTestRequest request(HitTestRequest::kMove);
2398       HitTestLocation location(view->ViewportToFrame(
2399           mouse_event_manager_->LastKnownMousePositionInViewport()));
2400       HitTestResult result(request, location);
2401       layout_object->HitTest(location, result);
2402       frame_->GetDocument()->UpdateHoverActiveState(
2403           request.Active(), !request.Move(), result.InnerElement());
2404     }
2405   }
2406 }
2407
2408 void EventHandler::ActiveIntervalTimerFired(TimerBase*) {
2409   TRACE_EVENT0("input", "EventHandler::activeIntervalTimerFired");
2410
2411   if (frame_ && frame_->GetDocument() && last_deferred_tap_element_) {
2412     // FIXME: Enable condition when http://crbug.com/226842 lands
2413     // m_lastDeferredTapElement.get() == m_frame->document()->activeElement()
2414     HitTestRequest request(HitTestRequest::kTouchEvent |
2415                            HitTestRequest::kRelease);
2416     frame_->GetDocument()->UpdateHoverActiveState(
2417         request.Active(), !request.Move(), last_deferred_tap_element_.Get());
2418   }
2419   last_deferred_tap_element_ = nullptr;
2420 }
2421
2422 void EventHandler::NotifyElementActivated() {
2423   // Since another element has been set to active, stop current timer and clear
2424   // reference.
2425   active_interval_timer_.Stop();
2426   last_deferred_tap_element_ = nullptr;
2427 }
2428
2429 bool EventHandler::HandleAccessKey(const WebKeyboardEvent& evt) {
2430   return keyboard_event_manager_->HandleAccessKey(evt);
2431 }
2432
2433 WebInputEventResult EventHandler::KeyEvent(
2434     const WebKeyboardEvent& initial_key_event) {
2435   return keyboard_event_manager_->KeyEvent(initial_key_event);
2436 }
2437
2438 void EventHandler::DefaultKeyboardEventHandler(KeyboardEvent* event) {
2439   keyboard_event_manager_->DefaultKeyboardEventHandler(
2440       event, mouse_event_manager_->MousePressNode());
2441 }
2442
2443 void EventHandler::DragSourceEndedAt(
2444     const WebMouseEvent& event,
2445     ui::mojom::blink::DragOperation operation) {
2446   // Asides from routing the event to the correct frame, the hit test is also an
2447   // opportunity for Layer to update the :hover and :active pseudoclasses.
2448   HitTestRequest request(HitTestRequest::kRelease);
2449   MouseEventWithHitTestResults mev =
2450       event_handling_util::PerformMouseEventHitTest(frame_, request, event);
2451
2452   if (auto* target_frame = LocalFrameFromTargetNode(mev.InnerNode())) {
2453     target_frame->GetEventHandler().DragSourceEndedAt(event, operation);
2454     return;
2455   }
2456
2457   mouse_event_manager_->DragSourceEndedAt(event, operation);
2458
2459   if (frame_->GetSettings() &&
2460       frame_->GetSettings()->GetTouchDragDropEnabled() &&
2461       frame_->GetSettings()->GetTouchDragEndContextMenu()) {
2462     gesture_manager_->SendContextMenuEventTouchDragEnd(event);
2463   }
2464 }
2465
2466 void EventHandler::UpdateDragStateAfterEditDragIfNeeded(
2467     Element* root_editable_element) {
2468   // If inserting the dragged contents removed the drag source, we still want to
2469   // fire dragend at the root editble element.
2470   if (mouse_event_manager_->GetDragState().drag_src_ &&
2471       !mouse_event_manager_->GetDragState().drag_src_->isConnected())
2472     mouse_event_manager_->GetDragState().drag_src_ = root_editable_element;
2473 }
2474
2475 bool EventHandler::HandleTextInputEvent(const String& text,
2476                                         Event* underlying_event,
2477                                         TextEventInputType input_type) {
2478   // Platforms should differentiate real commands like selectAll from text input
2479   // in disguise (like insertNewline), and avoid dispatching text input events
2480   // from keydown default handlers.
2481   auto* keyboard_event = DynamicTo<KeyboardEvent>(underlying_event);
2482   DCHECK(!keyboard_event ||
2483          keyboard_event->type() == event_type_names::kKeypress);
2484
2485   if (!frame_)
2486     return false;
2487
2488   EventTarget* target;
2489   if (underlying_event)
2490     target = underlying_event->target();
2491   else
2492     target = EventTargetNodeForDocument(frame_->GetDocument());
2493   if (!target)
2494     return false;
2495
2496   TextEvent* event = TextEvent::Create(frame_->DomWindow(), text, input_type);
2497   event->SetUnderlyingEvent(underlying_event);
2498
2499   target->DispatchEvent(*event);
2500   return event->DefaultHandled() || event->defaultPrevented();
2501 }
2502
2503 void EventHandler::DefaultTextInputEventHandler(TextEvent* event) {
2504   if (frame_->GetEditor().HandleTextEvent(event))
2505     event->SetDefaultHandled();
2506 }
2507
2508 void EventHandler::CapsLockStateMayHaveChanged() {
2509   keyboard_event_manager_->CapsLockStateMayHaveChanged();
2510 }
2511
2512 bool EventHandler::PassMousePressEventToScrollbar(
2513     MouseEventWithHitTestResults& mev) {
2514   // Do not pass the mouse press to scrollbar if scrollbar pressed. If the
2515   // user's left button is down, then the cursor moves outside the scrollbar
2516   // and presses the middle button , we should not clear
2517   // last_scrollbar_under_mouse_.
2518   if (last_scrollbar_under_mouse_ &&
2519       last_scrollbar_under_mouse_->PressedPart() != ScrollbarPart::kNoPart) {
2520     return false;
2521   }
2522
2523   Scrollbar* scrollbar = mev.GetScrollbar();
2524   UpdateLastScrollbarUnderMouse(scrollbar, true);
2525
2526   if (!scrollbar || !scrollbar->Enabled())
2527     return false;
2528   scrollbar->MouseDown(mev.Event());
2529   if (scrollbar->PressedPart() == ScrollbarPart::kThumbPart)
2530     CaptureMouseEventsToWidget(true);
2531   return true;
2532 }
2533
2534 // If scrollbar (under mouse) is different from last, send a mouse exited. Set
2535 // last to scrollbar if setLast is true; else set last to 0.
2536 void EventHandler::UpdateLastScrollbarUnderMouse(Scrollbar* scrollbar,
2537                                                  bool set_last) {
2538   if (last_scrollbar_under_mouse_ != scrollbar) {
2539     // Send mouse exited to the old scrollbar.
2540     if (last_scrollbar_under_mouse_)
2541       last_scrollbar_under_mouse_->MouseExited();
2542
2543     // Send mouse entered if we're setting a new scrollbar.
2544     if (scrollbar && set_last)
2545       scrollbar->MouseEntered();
2546
2547     last_scrollbar_under_mouse_ = set_last ? scrollbar : nullptr;
2548   }
2549 }
2550
2551 WebInputEventResult EventHandler::PassMousePressEventToSubframe(
2552     MouseEventWithHitTestResults& mev,
2553     LocalFrame* subframe) {
2554   GetSelectionController().PassMousePressEventToSubframe(mev);
2555   WebInputEventResult result =
2556       subframe->GetEventHandler().HandleMousePressEvent(mev.Event());
2557   if (result != WebInputEventResult::kNotHandled)
2558     return result;
2559   return WebInputEventResult::kHandledSystem;
2560 }
2561
2562 WebInputEventResult EventHandler::PassMouseMoveEventToSubframe(
2563     MouseEventWithHitTestResults& mev,
2564     const Vector<WebMouseEvent>& coalesced_events,
2565     const Vector<WebMouseEvent>& predicted_events,
2566     LocalFrame* subframe,
2567     HitTestResult* hovered_node,
2568     HitTestLocation* hit_test_location) {
2569   if (mouse_event_manager_->MouseDownMayStartDrag())
2570     return WebInputEventResult::kNotHandled;
2571   WebInputEventResult result =
2572       subframe->GetEventHandler().HandleMouseMoveOrLeaveEvent(
2573           mev.Event(), coalesced_events, predicted_events, hovered_node,
2574           hit_test_location);
2575   if (result != WebInputEventResult::kNotHandled)
2576     return result;
2577   return WebInputEventResult::kHandledSystem;
2578 }
2579
2580 WebInputEventResult EventHandler::PassMouseReleaseEventToSubframe(
2581     MouseEventWithHitTestResults& mev,
2582     LocalFrame* subframe) {
2583   return subframe->GetEventHandler().HandleMouseReleaseEvent(mev.Event());
2584 }
2585
2586 void EventHandler::CaptureMouseEventsToWidget(bool capture) {
2587   if (!frame_->IsLocalRoot()) {
2588     frame_->LocalFrameRoot().GetEventHandler().CaptureMouseEventsToWidget(
2589         capture);
2590     return;
2591   }
2592
2593   if (capture == is_widget_capturing_mouse_events_)
2594     return;
2595
2596   frame_->LocalFrameRoot().Client()->SetMouseCapture(capture);
2597   is_widget_capturing_mouse_events_ = capture;
2598 }
2599
2600 MouseEventWithHitTestResults EventHandler::GetMouseEventTarget(
2601     const HitTestRequest& request,
2602     const WebMouseEvent& event) {
2603   PhysicalOffset document_point =
2604       event_handling_util::ContentPointFromRootFrame(
2605           frame_, event.PositionInRootFrame());
2606
2607   // TODO(eirage): This does not handle chorded buttons yet.
2608   if (event.GetType() != WebInputEvent::Type::kMouseDown) {
2609     HitTestResult result(request, HitTestLocation(document_point));
2610
2611     Element* capture_target;
2612     if (event_handling_util::SubframeForTargetNode(
2613             capturing_subframe_element_)) {
2614       capture_target = capturing_subframe_element_;
2615       result.SetIsOverEmbeddedContentView(true);
2616     } else {
2617       capture_target = pointer_event_manager_->GetMouseCaptureTarget();
2618     }
2619
2620     if (capture_target) {
2621       LayoutObject* layout_object = capture_target->GetLayoutObject();
2622       PhysicalOffset local_point =
2623           layout_object ? layout_object->AbsoluteToLocalPoint(document_point)
2624                         : document_point;
2625       result.SetNodeAndPosition(capture_target, local_point);
2626
2627       result.SetScrollbar(last_scrollbar_under_mouse_);
2628       result.SetURLElement(capture_target->EnclosingLinkEventParentOrSelf());
2629
2630       if (!request.ReadOnly()) {
2631         frame_->GetDocument()->UpdateHoverActiveState(
2632             request.Active(), !request.Move(), result.InnerElement());
2633       }
2634
2635       return MouseEventWithHitTestResults(
2636           event, HitTestLocation(document_point), result);
2637     }
2638   }
2639   return frame_->GetDocument()->PerformMouseEventHitTest(request,
2640                                                          document_point, event);
2641 }
2642
2643 void EventHandler::ReleaseMouseCaptureFromLocalRoot() {
2644   CaptureMouseEventsToWidget(false);
2645
2646   frame_->LocalFrameRoot()
2647       .GetEventHandler()
2648       .ReleaseMouseCaptureFromCurrentFrame();
2649 }
2650
2651 void EventHandler::ReleaseMouseCaptureFromCurrentFrame() {
2652   if (LocalFrame* subframe = event_handling_util::SubframeForTargetNode(
2653           capturing_subframe_element_))
2654     subframe->GetEventHandler().ReleaseMouseCaptureFromCurrentFrame();
2655   pointer_event_manager_->ReleaseMousePointerCapture();
2656   capturing_subframe_element_ = nullptr;
2657 }
2658
2659 #if BUILDFLAG(IS_TIZEN_TV)
2660 bool EventHandler::CanRunArrowScrolling(const HitTestResult& result) {
2661   if (result.IsContentEditable() || result.GetScrollbar() ||
2662       result.MediaHasAudio() || result.MediaIsVideo())
2663     return false;
2664
2665   if (Node* node = result.InnerNode()) {
2666     if (node->HasMediaControlAncestor() || node->IsMediaControls() ||
2667         node->IsMediaControlElement() || node->WillRespondToMouseClickEvents())
2668       return false;
2669   }
2670
2671   return true;
2672 }
2673 #endif
2674
2675 #if BUILDFLAG(IS_EFL)
2676 void EventHandler::ContextMenuEventForWordOrLinkSelection(
2677     const WebGestureEvent& gesture_event) {
2678   LocalFrameView* frame_view = frame_->View();
2679   if (!frame_view)
2680     return;
2681
2682   // Hit-test the provided gesture event, applying touch-adjustment and
2683   // adjusting the location to the most likely nearby node.
2684   WebMouseEvent web_mouse_event(WebInputEvent::Type::kMouseMove, gesture_event,
2685                                 WebPointerProperties::Button::kNoButton, 0,
2686                                 WebInputEvent::kNoModifiers,
2687                                 gesture_event.TimeStamp(), 0);
2688
2689   gfx::Point viewport_position = frame_view->ViewportToFrame(
2690       gfx::ToFlooredPoint(web_mouse_event.PositionInRootFrame()));
2691   HitTestRequest request(HitTestRequest::kActive);
2692   MouseEventWithHitTestResults mouse_event =
2693       frame_->GetDocument()->PerformMouseEventHitTest(
2694           request, PhysicalOffset(viewport_position), web_mouse_event);
2695
2696   if (!frame_->Selection().Contains(PhysicalOffset(viewport_position)) &&
2697       !mouse_event.GetScrollbar() &&
2698       (frame_->Selection()
2699            .ComputeVisibleSelectionInDOMTreeDeprecated()
2700            .IsContentEditable() ||
2701        (mouse_event.InnerNode() && mouse_event.InnerNode()->IsTextNode()) ||
2702        (mouse_event.GetHitTestResult().IsLiveLink()))) {
2703     GetSelectionController().SetMouseDownMayStartSelect(
2704         true);  // context menu events are always allowed to perform a selection
2705     GetSelectionController().SelectClosestWordOrLinkFromMouseEvent(
2706         (MouseEvent*)(&mouse_event.Event()), mouse_event.GetHitTestResult());
2707   }
2708 }
2709 #endif
2710
2711 }  // namespace blink