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