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