Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(232)

Side by Side Diff: third_party/WebKit/Source/core/input/MouseEventManager.cpp

Issue 2350433002: Extract more of the mouse logic from EventHandler (Closed)
Patch Set: Yet another rebase because of a presubmit rule bug Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "core/input/MouseEventManager.h" 5 #include "core/input/MouseEventManager.h"
6 6
7 #include "core/clipboard/DataObject.h"
8 #include "core/clipboard/DataTransfer.h"
9 #include "core/dom/Element.h"
7 #include "core/dom/ElementTraversal.h" 10 #include "core/dom/ElementTraversal.h"
11 #include "core/editing/FrameSelection.h"
12 #include "core/editing/SelectionController.h"
13 #include "core/events/DragEvent.h"
8 #include "core/events/MouseEvent.h" 14 #include "core/events/MouseEvent.h"
15 #include "core/frame/FrameView.h"
16 #include "core/frame/LocalFrame.h"
17 #include "core/frame/Settings.h"
9 #include "core/html/HTMLCanvasElement.h" 18 #include "core/html/HTMLCanvasElement.h"
19 #include "core/input/EventHandler.h"
10 #include "core/input/EventHandlingUtil.h" 20 #include "core/input/EventHandlingUtil.h"
21 #include "core/input/InputDeviceCapabilities.h"
22 #include "core/input/KeyboardEventManager.h"
23 #include "core/layout/HitTestResult.h"
24 #include "core/layout/api/LayoutViewItem.h"
25 #include "core/page/AutoscrollController.h"
26 #include "core/page/DragController.h"
27 #include "core/page/DragState.h"
28 #include "core/page/FocusController.h"
29 #include "core/paint/PaintLayer.h"
30 #include "core/svg/SVGDocumentExtensions.h"
31 #include "platform/geometry/FloatQuad.h"
11 32
12 namespace blink { 33 namespace blink {
13 34
14 namespace { 35 namespace {
15 36
16 PlatformMouseEvent mouseEventWithRegion(Node* node, 37 PlatformMouseEvent mouseEventWithRegion(Node* node,
17 const PlatformMouseEvent& mouseEvent) { 38 const PlatformMouseEvent& mouseEvent) {
18 if (!node->isElementNode()) 39 if (!node->isElementNode())
19 return mouseEvent; 40 return mouseEvent;
20 41
21 Element* element = toElement(node); 42 Element* element = toElement(node);
22 if (!element->isInCanvasSubtree()) 43 if (!element->isInCanvasSubtree())
23 return mouseEvent; 44 return mouseEvent;
24 45
25 HTMLCanvasElement* canvas = 46 HTMLCanvasElement* canvas =
26 Traversal<HTMLCanvasElement>::firstAncestorOrSelf(*element); 47 Traversal<HTMLCanvasElement>::firstAncestorOrSelf(*element);
27 // In this case, the event target is canvas and mouse rerouting doesn't happen . 48 // In this case, the event target is canvas and mouse rerouting doesn't happen .
28 if (canvas == element) 49 if (canvas == element)
29 return mouseEvent; 50 return mouseEvent;
30 String region = canvas->getIdFromControl(element); 51 String region = canvas->getIdFromControl(element);
31 PlatformMouseEvent newMouseEvent = mouseEvent; 52 PlatformMouseEvent newMouseEvent = mouseEvent;
32 newMouseEvent.setRegion(region); 53 newMouseEvent.setRegion(region);
33 return newMouseEvent; 54 return newMouseEvent;
34 } 55 }
35 56
57 // The amount of time to wait before sending a fake mouse event triggered
58 // during a scroll.
59 const double kFakeMouseMoveInterval = 0.1;
60
61 #if OS(MACOSX)
62 const double kTextDragDelay = 0.15;
63 #else
64 const double kTextDragDelay = 0.0;
65 #endif
66
67 // The link drag hysteresis is much larger than the others because there
68 // needs to be enough space to cancel the link press without starting a link dra g,
69 // and because dragging links is rare.
70 const int kLinkDragHysteresis = 40;
71 const int kImageDragHysteresis = 5;
72 const int kTextDragHysteresis = 3;
73 const int kGeneralDragHysteresis = 3;
74
36 } // namespace 75 } // namespace
37 76
77 enum class DragInitiator { Mouse, Touch };
78
79 MouseEventManager::MouseEventManager(LocalFrame* frame,
80 ScrollManager* scrollManager)
81 : m_frame(frame),
82 m_scrollManager(scrollManager),
83 m_fakeMouseMoveEventTimer(
84 this,
85 &MouseEventManager::fakeMouseMoveEventTimerFired) {
86 clear();
87 }
88
89 void MouseEventManager::clear() {
90 m_nodeUnderMouse = nullptr;
91 m_mousePressNode = nullptr;
92 m_mouseDownMayStartAutoscroll = false;
93 m_mouseDownMayStartDrag = false;
94 m_capturesDragging = false;
95 m_isMousePositionUnknown = true;
96 m_lastKnownMousePosition = IntPoint();
97 m_lastKnownMouseGlobalPosition = IntPoint();
98 m_mousePressed = false;
99 m_clickCount = 0;
100 m_clickNode = nullptr;
101 m_mouseDownPos = IntPoint();
102 m_mouseDownTimestamp = 0;
103 m_mouseDown = PlatformMouseEvent();
104 m_svgPan = false;
105 m_dragStartPos = LayoutPoint();
106 m_fakeMouseMoveEventTimer.stop();
107 }
108
109 DEFINE_TRACE(MouseEventManager) {
110 visitor->trace(m_frame);
111 visitor->trace(m_scrollManager);
112 visitor->trace(m_nodeUnderMouse);
113 visitor->trace(m_mousePressNode);
114 visitor->trace(m_clickNode);
115 }
116
38 MouseEventManager::MouseEventBoundaryEventDispatcher:: 117 MouseEventManager::MouseEventBoundaryEventDispatcher::
39 MouseEventBoundaryEventDispatcher( 118 MouseEventBoundaryEventDispatcher(
40 MouseEventManager* mouseEventManager, 119 MouseEventManager* mouseEventManager,
41 const PlatformMouseEvent* platformMouseEvent, 120 const PlatformMouseEvent* platformMouseEvent,
42 EventTarget* exitedTarget) 121 EventTarget* exitedTarget)
43 : m_mouseEventManager(mouseEventManager), 122 : m_mouseEventManager(mouseEventManager),
44 m_platformMouseEvent(platformMouseEvent), 123 m_platformMouseEvent(platformMouseEvent),
45 m_exitedTarget(exitedTarget) {} 124 m_exitedTarget(exitedTarget) {}
46 125
47 void MouseEventManager::MouseEventBoundaryEventDispatcher::dispatchOut( 126 void MouseEventManager::MouseEventBoundaryEventDispatcher::dispatchOut(
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
88 return EventTypeNames::mouseenter; 167 return EventTypeNames::mouseenter;
89 } 168 }
90 169
91 void MouseEventManager::MouseEventBoundaryEventDispatcher::dispatch( 170 void MouseEventManager::MouseEventBoundaryEventDispatcher::dispatch(
92 EventTarget* target, 171 EventTarget* target,
93 EventTarget* relatedTarget, 172 EventTarget* relatedTarget,
94 const AtomicString& type, 173 const AtomicString& type,
95 const PlatformMouseEvent& platformMouseEvent, 174 const PlatformMouseEvent& platformMouseEvent,
96 bool checkForListener) { 175 bool checkForListener) {
97 m_mouseEventManager->dispatchMouseEvent(target, type, platformMouseEvent, 176 m_mouseEventManager->dispatchMouseEvent(target, type, platformMouseEvent,
98 relatedTarget, 0, checkForListener); 177 relatedTarget, checkForListener);
99 } 178 }
100 179
101 void MouseEventManager::sendBoundaryEvents( 180 void MouseEventManager::sendBoundaryEvents(
102 EventTarget* exitedTarget, 181 EventTarget* exitedTarget,
103 EventTarget* enteredTarget, 182 EventTarget* enteredTarget,
104 const PlatformMouseEvent& mousePlatformEvent) { 183 const PlatformMouseEvent& mousePlatformEvent) {
105 MouseEventBoundaryEventDispatcher boundaryEventDispatcher( 184 MouseEventBoundaryEventDispatcher boundaryEventDispatcher(
106 this, &mousePlatformEvent, exitedTarget); 185 this, &mousePlatformEvent, exitedTarget);
107 boundaryEventDispatcher.sendBoundaryEvents(exitedTarget, enteredTarget); 186 boundaryEventDispatcher.sendBoundaryEvents(exitedTarget, enteredTarget);
108 } 187 }
109 188
110 WebInputEventResult MouseEventManager::dispatchMouseEvent( 189 WebInputEventResult MouseEventManager::dispatchMouseEvent(
111 EventTarget* target, 190 EventTarget* target,
112 const AtomicString& mouseEventType, 191 const AtomicString& mouseEventType,
113 const PlatformMouseEvent& mouseEvent, 192 const PlatformMouseEvent& mouseEvent,
114 EventTarget* relatedTarget, 193 EventTarget* relatedTarget,
115 int detail,
116 bool checkForListener) { 194 bool checkForListener) {
117 if (target && target->toNode() && 195 if (target && target->toNode() &&
118 (!checkForListener || target->hasEventListeners(mouseEventType))) { 196 (!checkForListener || target->hasEventListeners(mouseEventType))) {
119 Node* targetNode = target->toNode(); 197 Node* targetNode = target->toNode();
198 int clickCount = 0;
199 if (mouseEventType == EventTypeNames::mouseup ||
200 mouseEventType == EventTypeNames::mousedown ||
201 mouseEventType == EventTypeNames::click ||
202 mouseEventType == EventTypeNames::auxclick ||
203 mouseEventType == EventTypeNames::dblclick) {
204 clickCount = m_clickCount;
205 }
120 MouseEvent* event = MouseEvent::create( 206 MouseEvent* event = MouseEvent::create(
121 mouseEventType, targetNode->document().domWindow(), mouseEvent, detail, 207 mouseEventType, targetNode->document().domWindow(), mouseEvent,
122 relatedTarget ? relatedTarget->toNode() : nullptr); 208 clickCount, relatedTarget ? relatedTarget->toNode() : nullptr);
123 DispatchEventResult dispatchResult = target->dispatchEvent(event); 209 DispatchEventResult dispatchResult = target->dispatchEvent(event);
124 return EventHandlingUtil::toWebInputEventResult(dispatchResult); 210 return EventHandlingUtil::toWebInputEventResult(dispatchResult);
125 } 211 }
126 return WebInputEventResult::NotHandled; 212 return WebInputEventResult::NotHandled;
127 } 213 }
128 214
129 MouseEventManager::MouseEventManager(LocalFrame* frame) : m_frame(frame) { 215 WebInputEventResult MouseEventManager::setMousePositionAndDispatchMouseEvent(
130 clear(); 216 Node* targetNode,
131 } 217 const AtomicString& eventType,
132 218 const PlatformMouseEvent& platformMouseEvent) {
133 void MouseEventManager::clear() {} 219 // If the target node is a text node, dispatch on the parent node.
134 220 if (targetNode && targetNode->isTextNode())
135 DEFINE_TRACE(MouseEventManager) { 221 targetNode = FlatTreeTraversal::parent(*targetNode);
136 visitor->trace(m_frame); 222
137 visitor->trace(m_nodeUnderMouse); 223 setNodeUnderMouse(targetNode, platformMouseEvent);
224
225 return dispatchMouseEvent(m_nodeUnderMouse, eventType, platformMouseEvent,
226 nullptr);
227 }
228
229 WebInputEventResult MouseEventManager::dispatchMouseClickIfNeeded(
230 const MouseEventWithHitTestResults& mev) {
231 // We only prevent click event when the click may cause contextmenu to popup.
232 // However, we always send auxclick.
233 bool contextMenuEvent = !RuntimeEnabledFeatures::auxclickEnabled() &&
234 mev.event().pointerProperties().button ==
235 WebPointerProperties::Button::Right;
236 #if OS(MACOSX)
237 // FIXME: The Mac port achieves the same behavior by checking whether the cont ext menu is currently open in WebPage::mouseEvent(). Consider merging the implem entations.
238 if (mev.event().pointerProperties().button ==
239 WebPointerProperties::Button::Left &&
240 mev.event().getModifiers() & PlatformEvent::CtrlKey)
241 contextMenuEvent = true;
242 #endif
243
244 WebInputEventResult clickEventResult = WebInputEventResult::NotHandled;
245 const bool shouldDispatchClickEvent =
246 m_clickCount > 0 && !contextMenuEvent && mev.innerNode() && m_clickNode &&
247 mev.innerNode()->canParticipateInFlatTree() &&
248 m_clickNode->canParticipateInFlatTree() &&
249 !(m_frame->eventHandler().selectionController().hasExtendedSelection() &&
250 isLinkSelection(mev));
251 if (shouldDispatchClickEvent) {
252 Node* clickTargetNode = nullptr;
253 // Updates distribution because a 'mouseup' event listener can make the
254 // tree dirty at dispatchMouseEvent() invocation above.
255 // Unless distribution is updated, commonAncestor would hit ASSERT.
256 if (m_clickNode == mev.innerNode()) {
257 clickTargetNode = m_clickNode;
258 clickTargetNode->updateDistribution();
259 } else if (m_clickNode->document() == mev.innerNode()->document()) {
260 m_clickNode->updateDistribution();
261 mev.innerNode()->updateDistribution();
262 clickTargetNode = mev.innerNode()->commonAncestor(
263 *m_clickNode, EventHandlingUtil::parentForClickEvent);
264 }
265 if (clickTargetNode) {
266 clickEventResult = dispatchMouseEvent(
267 clickTargetNode, !RuntimeEnabledFeatures::auxclickEnabled() ||
268 (mev.event().pointerProperties().button ==
269 WebPointerProperties::Button::Left)
270 ? EventTypeNames::click
271 : EventTypeNames::auxclick,
272 mev.event(), nullptr);
273 }
274 }
275 return clickEventResult;
276 }
277
278 void MouseEventManager::fakeMouseMoveEventTimerFired(TimerBase* timer) {
279 TRACE_EVENT0("input", "MouseEventManager::fakeMouseMoveEventTimerFired");
280 DCHECK(timer == &m_fakeMouseMoveEventTimer);
281 DCHECK(!m_mousePressed);
282
283 Settings* settings = m_frame->settings();
284 if (settings && !settings->deviceSupportsMouse())
285 return;
286
287 FrameView* view = m_frame->view();
288 if (!view)
289 return;
290
291 if (!m_frame->page() || !m_frame->page()->focusController().isActive())
292 return;
293
294 // Don't dispatch a synthetic mouse move event if the mouse cursor is not visi ble to the user.
295 if (!m_frame->page()->isCursorVisible())
296 return;
297
298 PlatformMouseEvent fakeMouseMoveEvent(
299 m_lastKnownMousePosition, m_lastKnownMouseGlobalPosition,
300 WebPointerProperties::Button::NoButton, PlatformEvent::MouseMoved, 0,
301 static_cast<PlatformEvent::Modifiers>(
302 KeyboardEventManager::getCurrentModifierState()),
303 PlatformMouseEvent::RealOrIndistinguishable,
304 monotonicallyIncreasingTime(), WebPointerProperties::PointerType::Mouse);
305 m_frame->eventHandler().handleMouseMoveEvent(fakeMouseMoveEvent);
306 }
307
308 void MouseEventManager::cancelFakeMouseMoveEvent() {
309 m_fakeMouseMoveEventTimer.stop();
310 }
311
312 void MouseEventManager::setNodeUnderMouse(
313 Node* target,
314 const PlatformMouseEvent& platformMouseEvent) {
315 Node* lastNodeUnderMouse = m_nodeUnderMouse;
316 m_nodeUnderMouse = target;
317
318 PaintLayer* layerForLastNode =
319 EventHandlingUtil::layerForNode(lastNodeUnderMouse);
320 PaintLayer* layerForNodeUnderMouse =
321 EventHandlingUtil::layerForNode(m_nodeUnderMouse.get());
322 Page* page = m_frame->page();
323
324 if (lastNodeUnderMouse &&
325 (!m_nodeUnderMouse ||
326 m_nodeUnderMouse->document() != m_frame->document())) {
327 // The mouse has moved between frames.
328 if (LocalFrame* frame = lastNodeUnderMouse->document().frame()) {
329 if (FrameView* frameView = frame->view())
330 frameView->mouseExitedContentArea();
331 }
332 } else if (page && (layerForLastNode &&
333 (!layerForNodeUnderMouse ||
334 layerForNodeUnderMouse != layerForLastNode))) {
335 // The mouse has moved between layers.
336 if (ScrollableArea* scrollableAreaForLastNode =
337 EventHandlingUtil::associatedScrollableArea(layerForLastNode))
338 scrollableAreaForLastNode->mouseExitedContentArea();
339 }
340
341 if (m_nodeUnderMouse &&
342 (!lastNodeUnderMouse ||
343 lastNodeUnderMouse->document() != m_frame->document())) {
344 // The mouse has moved between frames.
345 if (LocalFrame* frame = m_nodeUnderMouse->document().frame()) {
346 if (FrameView* frameView = frame->view())
347 frameView->mouseEnteredContentArea();
348 }
349 } else if (page && (layerForNodeUnderMouse &&
350 (!layerForLastNode ||
351 layerForNodeUnderMouse != layerForLastNode))) {
352 // The mouse has moved between layers.
353 if (ScrollableArea* scrollableAreaForNodeUnderMouse =
354 EventHandlingUtil::associatedScrollableArea(layerForNodeUnderMouse))
355 scrollableAreaForNodeUnderMouse->mouseEnteredContentArea();
356 }
357
358 if (lastNodeUnderMouse &&
359 lastNodeUnderMouse->document() != m_frame->document()) {
360 lastNodeUnderMouse = nullptr;
361 }
362
363 sendBoundaryEvents(lastNodeUnderMouse, m_nodeUnderMouse, platformMouseEvent);
364 }
365
366 void MouseEventManager::nodeWillBeRemoved(Node& nodeToBeRemoved) {
367 if (nodeToBeRemoved.isShadowIncludingInclusiveAncestorOf(m_clickNode.get())) {
368 // We don't dispatch click events if the mousedown node is removed
369 // before a mouseup event. It is compatible with IE and Firefox.
370 m_clickNode = nullptr;
371 }
372 }
373
374 Node* MouseEventManager::getNodeUnderMouse() {
375 return m_nodeUnderMouse;
376 }
377
378 WebInputEventResult MouseEventManager::handleMouseFocus(
379 const HitTestResult& hitTestResult,
380 InputDeviceCapabilities* sourceCapabilities) {
381 // If clicking on a frame scrollbar, do not mess up with content focus.
382 if (hitTestResult.scrollbar() && !m_frame->contentLayoutItem().isNull()) {
383 if (hitTestResult.scrollbar()->getScrollableArea() ==
384 m_frame->contentLayoutItem().getScrollableArea())
385 return WebInputEventResult::NotHandled;
386 }
387
388 // The layout needs to be up to date to determine if an element is focusable.
389 m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets();
390
391 Element* element = nullptr;
392 if (m_nodeUnderMouse) {
393 element = m_nodeUnderMouse->isElementNode()
394 ? toElement(m_nodeUnderMouse)
395 : m_nodeUnderMouse->parentOrShadowHostElement();
396 }
397 for (; element; element = element->parentOrShadowHostElement()) {
398 if (element->isFocusable() && element->isFocusedElementInDocument())
399 return WebInputEventResult::NotHandled;
400 if (element->isMouseFocusable())
401 break;
402 }
403 DCHECK(!element || element->isMouseFocusable());
404
405 // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus
406 // a node on mouse down if it's selected and inside a focused node. It will
407 // be focused if the user does a mouseup over it, however, because the
408 // mouseup will set a selection inside it, which will call
409 // FrameSelection::setFocusedNodeIfNeeded.
410 if (element && m_frame->selection().isRange()) {
411 // TODO(yosin) We should not create |Range| object for calling
412 // |isNodeFullyContained()|.
413 if (createRange(
414 m_frame->selection().selection().toNormalizedEphemeralRange())
415 ->isNodeFullyContained(*element) &&
416 element->isDescendantOf(m_frame->document()->focusedElement()))
417 return WebInputEventResult::NotHandled;
418 }
419
420 // Only change the focus when clicking scrollbars if it can transfered to a
421 // mouse focusable node.
422 if (!element && hitTestResult.scrollbar())
423 return WebInputEventResult::HandledSystem;
424
425 if (Page* page = m_frame->page()) {
426 // If focus shift is blocked, we eat the event. Note we should never
427 // clear swallowEvent if the page already set it (e.g., by canceling
428 // default behavior).
429 if (element) {
430 if (slideFocusOnShadowHostIfNecessary(*element))
431 return WebInputEventResult::HandledSystem;
432 if (!page->focusController().setFocusedElement(
433 element, m_frame,
434 FocusParams(SelectionBehaviorOnFocus::None, WebFocusTypeMouse,
435 sourceCapabilities)))
436 return WebInputEventResult::HandledSystem;
437 } else {
438 // We call setFocusedElement even with !element in order to blur
439 // current focus element when a link is clicked; this is expected by
440 // some sites that rely on onChange handlers running from form
441 // fields before the button click is processed.
442 if (!page->focusController().setFocusedElement(
443 nullptr, m_frame,
444 FocusParams(SelectionBehaviorOnFocus::None, WebFocusTypeNone,
445 sourceCapabilities)))
446 return WebInputEventResult::HandledSystem;
447 }
448 }
449
450 return WebInputEventResult::NotHandled;
451 }
452
453 bool MouseEventManager::slideFocusOnShadowHostIfNecessary(
454 const Element& element) {
455 if (element.authorShadowRoot() &&
456 element.authorShadowRoot()->delegatesFocus()) {
457 Document* doc = m_frame->document();
458 if (element.isShadowIncludingInclusiveAncestorOf(doc->focusedElement())) {
459 // If the inner element is already focused, do nothing.
460 return true;
461 }
462
463 // If the host has a focusable inner element, focus it. Otherwise, the host takes focus.
464 Page* page = m_frame->page();
465 DCHECK(page);
466 Element* found =
467 page->focusController().findFocusableElementInShadowHost(element);
468 if (found && element.isShadowIncludingInclusiveAncestorOf(found)) {
469 // Use WebFocusTypeForward instead of WebFocusTypeMouse here to mean the f ocus has slided.
470 found->focus(FocusParams(SelectionBehaviorOnFocus::Reset,
471 WebFocusTypeForward, nullptr));
472 return true;
473 }
474 }
475 return false;
476 }
477
478 void MouseEventManager::handleMousePressEventUpdateStates(
479 const PlatformMouseEvent& mouseEvent) {
480 cancelFakeMouseMoveEvent();
481 m_mousePressed = true;
482 m_capturesDragging = true;
483 setLastKnownMousePosition(mouseEvent);
484 m_mouseDownMayStartDrag = false;
485 m_mouseDownMayStartAutoscroll = false;
486 m_mouseDownTimestamp = mouseEvent.timestamp();
487
488 if (FrameView* view = m_frame->view()) {
489 m_mouseDownPos = view->rootFrameToContents(mouseEvent.position());
490 } else {
491 invalidateClick();
492 }
493 }
494
495 bool MouseEventManager::isMousePositionUnknown() {
496 return m_isMousePositionUnknown;
497 }
498
499 IntPoint MouseEventManager::lastKnownMousePosition() {
500 return m_lastKnownMousePosition;
501 }
502
503 void MouseEventManager::setLastKnownMousePosition(
504 const PlatformMouseEvent& event) {
505 m_isMousePositionUnknown = false;
506 m_lastKnownMousePosition = event.position();
507 m_lastKnownMouseGlobalPosition = event.globalPosition();
508 }
509
510 void MouseEventManager::dispatchFakeMouseMoveEventSoon() {
511 if (m_mousePressed)
512 return;
513
514 if (m_isMousePositionUnknown)
515 return;
516
517 Settings* settings = m_frame->settings();
518 if (settings && !settings->deviceSupportsMouse())
519 return;
520
521 // Reschedule the timer, to prevent dispatching mouse move events
522 // during a scroll. This avoids a potential source of scroll jank.
523 if (m_fakeMouseMoveEventTimer.isActive())
524 m_fakeMouseMoveEventTimer.stop();
525 m_fakeMouseMoveEventTimer.startOneShot(kFakeMouseMoveInterval,
526 BLINK_FROM_HERE);
527 }
528
529 void MouseEventManager::dispatchFakeMouseMoveEventSoonInQuad(
530 const FloatQuad& quad) {
531 FrameView* view = m_frame->view();
532 if (!view)
533 return;
534
535 if (!quad.containsPoint(view->rootFrameToContents(m_lastKnownMousePosition)))
536 return;
537
538 dispatchFakeMouseMoveEventSoon();
539 }
540
541 WebInputEventResult MouseEventManager::handleMousePressEvent(
542 const MouseEventWithHitTestResults& event) {
543 TRACE_EVENT0("blink", "MouseEventManager::handleMousePressEvent");
544
545 // Reset drag state.
546 dragState().m_dragSrc = nullptr;
547
548 cancelFakeMouseMoveEvent();
549
550 m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets();
551
552 if (FrameView* frameView = m_frame->view()) {
553 if (frameView->isPointInScrollbarCorner(event.event().position()))
554 return WebInputEventResult::NotHandled;
555 }
556
557 bool singleClick = event.event().clickCount() <= 1;
558
559 m_mouseDownMayStartDrag =
560 singleClick && !isLinkSelection(event) && !isExtendingSelection(event);
561
562 m_frame->eventHandler().selectionController().handleMousePressEvent(event);
563
564 m_mouseDown = event.event();
565
566 if (m_frame->document()->isSVGDocument() &&
567 m_frame->document()->accessSVGExtensions().zoomAndPanEnabled()) {
568 if (event.event().shiftKey() && singleClick) {
569 m_svgPan = true;
570 m_frame->document()->accessSVGExtensions().startPan(
571 m_frame->view()->rootFrameToContents(event.event().position()));
572 return WebInputEventResult::HandledSystem;
573 }
574 }
575
576 // We don't do this at the start of mouse down handling,
577 // because we don't want to do it until we know we didn't hit a widget.
578 if (singleClick)
579 focusDocumentView();
580
581 Node* innerNode = event.innerNode();
582
583 m_mousePressNode = innerNode;
584 m_frame->document()->setSequentialFocusNavigationStartingPoint(innerNode);
585 m_dragStartPos = event.event().position();
586
587 bool swallowEvent = false;
588 m_mousePressed = true;
589
590 if (event.event().clickCount() == 2) {
591 swallowEvent = m_frame->eventHandler()
592 .selectionController()
593 .handleMousePressEventDoubleClick(event);
594 } else if (event.event().clickCount() >= 3) {
595 swallowEvent = m_frame->eventHandler()
596 .selectionController()
597 .handleMousePressEventTripleClick(event);
598 } else {
599 swallowEvent = m_frame->eventHandler()
600 .selectionController()
601 .handleMousePressEventSingleClick(event);
602 }
603
604 m_mouseDownMayStartAutoscroll =
605 m_frame->eventHandler().selectionController().mouseDownMayStartSelect() ||
606 (m_mousePressNode && m_mousePressNode->layoutBox() &&
607 m_mousePressNode->layoutBox()->canBeProgramaticallyScrolled());
608
609 return swallowEvent ? WebInputEventResult::HandledSystem
610 : WebInputEventResult::NotHandled;
611 }
612
613 WebInputEventResult MouseEventManager::handleMouseReleaseEvent(
614 const MouseEventWithHitTestResults& event) {
615 AutoscrollController* controller = m_scrollManager->autoscrollController();
616 if (controller && controller->autoscrollInProgress())
617 m_scrollManager->stopAutoscroll();
618
619 return m_frame->eventHandler().selectionController().handleMouseReleaseEvent(
620 event, m_dragStartPos)
621 ? WebInputEventResult::HandledSystem
622 : WebInputEventResult::NotHandled;
623 }
624
625 void MouseEventManager::updateSelectionForMouseDrag() {
626 m_frame->eventHandler().selectionController().updateSelectionForMouseDrag(
627 m_mousePressNode, m_dragStartPos, m_lastKnownMousePosition);
628 }
629
630 bool MouseEventManager::handleDragDropIfPossible(
631 const GestureEventWithHitTestResults& targetedEvent) {
632 if (m_frame->settings() && m_frame->settings()->touchDragDropEnabled() &&
633 m_frame->view()) {
634 const PlatformGestureEvent& gestureEvent = targetedEvent.event();
635 IntPoint adjustedPoint = gestureEvent.position();
636 unsigned modifiers = gestureEvent.getModifiers();
637
638 // TODO(mustaq): Suppressing long-tap MouseEvents could break
639 // drag-drop. Will do separately because of the risk. crbug.com/606938.
640 PlatformMouseEvent mouseDownEvent(
641 adjustedPoint, gestureEvent.globalPosition(),
642 WebPointerProperties::Button::Left, PlatformEvent::MousePressed, 1,
643 static_cast<PlatformEvent::Modifiers>(modifiers |
644 PlatformEvent::LeftButtonDown),
645 PlatformMouseEvent::FromTouch, WTF::monotonicallyIncreasingTime(),
646 WebPointerProperties::PointerType::Mouse);
647 m_mouseDown = mouseDownEvent;
648
649 PlatformMouseEvent mouseDragEvent(
650 adjustedPoint, gestureEvent.globalPosition(),
651 WebPointerProperties::Button::Left, PlatformEvent::MouseMoved, 1,
652 static_cast<PlatformEvent::Modifiers>(modifiers |
653 PlatformEvent::LeftButtonDown),
654 PlatformMouseEvent::FromTouch, WTF::monotonicallyIncreasingTime(),
655 WebPointerProperties::PointerType::Mouse);
656 HitTestRequest request(HitTestRequest::ReadOnly);
657 MouseEventWithHitTestResults mev =
658 EventHandlingUtil::performMouseEventHitTest(m_frame, request,
659 mouseDragEvent);
660 m_mouseDownMayStartDrag = true;
661 dragState().m_dragSrc = nullptr;
662 m_mouseDownPos =
663 m_frame->view()->rootFrameToContents(mouseDragEvent.position());
664 return handleDrag(mev, DragInitiator::Touch);
665 }
666 return false;
667 }
668
669 void MouseEventManager::focusDocumentView() {
670 Page* page = m_frame->page();
671 if (!page)
672 return;
673 page->focusController().focusDocumentView(m_frame);
674 }
675
676 WebInputEventResult MouseEventManager::handleMouseDraggedEvent(
677 const MouseEventWithHitTestResults& event) {
678 TRACE_EVENT0("blink", "MouseEventManager::handleMouseDraggedEvent");
679
680 // While resetting m_mousePressed here may seem out of place, it turns out
681 // to be needed to handle some bugs^Wfeatures in Blink mouse event handling:
682 // 1. Certain elements, such as <embed>, capture mouse events. They do not
683 // bubble back up. One way for a <embed> to start capturing mouse events
684 // is on a mouse press. The problem is the <embed> node only starts
685 // capturing mouse events *after* m_mousePressed for the containing frame
686 // has already been set to true. As a result, the frame's EventHandler
687 // never sees the mouse release event, which is supposed to reset
688 // m_mousePressed... so m_mousePressed ends up remaining true until the
689 // event handler finally gets another mouse released event. Oops.
690 // 2. Dragging doesn't start until after a mouse press event, but a drag
691 // that ends as a result of a mouse release does not send a mouse release
692 // event. As a result, m_mousePressed also ends up remaining true until
693 // the next mouse release event seen by the EventHandler.
694 if (event.event().pointerProperties().button !=
695 WebPointerProperties::Button::Left)
696 m_mousePressed = false;
697
698 if (!m_mousePressed)
699 return WebInputEventResult::NotHandled;
700
701 if (handleDrag(event, DragInitiator::Mouse))
702 return WebInputEventResult::HandledSystem;
703
704 Node* targetNode = event.innerNode();
705 if (!targetNode)
706 return WebInputEventResult::NotHandled;
707
708 LayoutObject* layoutObject = targetNode->layoutObject();
709 if (!layoutObject) {
710 Node* parent = FlatTreeTraversal::parent(*targetNode);
711 if (!parent)
712 return WebInputEventResult::NotHandled;
713
714 layoutObject = parent->layoutObject();
715 if (!layoutObject || !layoutObject->isListBox())
716 return WebInputEventResult::NotHandled;
717 }
718
719 m_mouseDownMayStartDrag = false;
720
721 if (m_mouseDownMayStartAutoscroll &&
722 !m_scrollManager->middleClickAutoscrollInProgress()) {
723 if (AutoscrollController* controller =
724 m_scrollManager->autoscrollController()) {
725 controller->startAutoscrollForSelection(layoutObject);
726 m_mouseDownMayStartAutoscroll = false;
727 }
728 }
729
730 m_frame->eventHandler().selectionController().handleMouseDraggedEvent(
731 event, m_mouseDownPos, m_dragStartPos, m_mousePressNode.get(),
732 m_lastKnownMousePosition);
733 return WebInputEventResult::HandledSystem;
734 }
735
736 bool MouseEventManager::handleDrag(const MouseEventWithHitTestResults& event,
737 DragInitiator initiator) {
738 DCHECK(event.event().type() == PlatformEvent::MouseMoved);
739 // Callers must protect the reference to FrameView, since this function may di spatch DOM
740 // events, causing page/FrameView to go away.
741 DCHECK(m_frame);
742 DCHECK(m_frame->view());
743 if (!m_frame->page())
744 return false;
745
746 if (m_mouseDownMayStartDrag) {
747 HitTestRequest request(HitTestRequest::ReadOnly);
748 HitTestResult result(request, m_mouseDownPos);
749 m_frame->contentLayoutItem().hitTest(result);
750 Node* node = result.innerNode();
751 if (node) {
752 DragController::SelectionDragPolicy selectionDragPolicy =
753 event.event().timestamp() - m_mouseDownTimestamp < kTextDragDelay
754 ? DragController::DelayedSelectionDragResolution
755 : DragController::ImmediateSelectionDragResolution;
756 dragState().m_dragSrc = m_frame->page()->dragController().draggableNode(
757 m_frame, node, m_mouseDownPos, selectionDragPolicy,
758 dragState().m_dragType);
759 } else {
760 dragState().m_dragSrc = nullptr;
761 }
762
763 if (!dragState().m_dragSrc)
764 m_mouseDownMayStartDrag = false; // no element is draggable
765 }
766
767 if (!m_mouseDownMayStartDrag) {
768 return initiator == DragInitiator::Mouse &&
769 !m_frame->eventHandler()
770 .selectionController()
771 .mouseDownMayStartSelect() &&
772 !m_mouseDownMayStartAutoscroll;
773 }
774
775 // We are starting a text/image/url drag, so the cursor should be an arrow
776 // FIXME <rdar://7577595>: Custom cursors aren't supported during drag and dro p (default to pointer).
777 m_frame->view()->setCursor(pointerCursor());
778
779 if (initiator == DragInitiator::Mouse &&
780 !dragHysteresisExceeded(event.event().position()))
781 return true;
782
783 // Once we're past the hysteresis point, we don't want to treat this gesture a s a click
784 invalidateClick();
785
786 if (!tryStartDrag(event)) {
787 // Something failed to start the drag, clean up.
788 clearDragDataTransfer();
789 dragState().m_dragSrc = nullptr;
790 }
791
792 m_mouseDownMayStartDrag = false;
793 // Whether or not the drag actually started, no more default handling (like se lection).
794 return true;
795 }
796
797 DataTransfer* MouseEventManager::createDraggingDataTransfer() const {
798 return DataTransfer::create(DataTransfer::DragAndDrop, DataTransferWritable,
799 DataObject::create());
800 }
801
802 bool MouseEventManager::tryStartDrag(
803 const MouseEventWithHitTestResults& event) {
804 // The DataTransfer would only be non-empty if we missed a dragEnd.
805 // Clear it anyway, just to make sure it gets numbified.
806 clearDragDataTransfer();
807
808 dragState().m_dragDataTransfer = createDraggingDataTransfer();
809
810 // Check to see if this a DOM based drag, if it is get the DOM specified drag
811 // image and offset
812 if (dragState().m_dragType == DragSourceActionDHTML) {
813 if (LayoutObject* layoutObject = dragState().m_dragSrc->layoutObject()) {
814 IntRect boundingIncludingDescendants =
815 layoutObject->absoluteBoundingBoxRectIncludingDescendants();
816 IntSize delta = m_mouseDownPos - boundingIncludingDescendants.location();
817 dragState().m_dragDataTransfer->setDragImageElement(
818 dragState().m_dragSrc.get(), IntPoint(delta));
819 } else {
820 // The layoutObject has disappeared, this can happen if the onStartDrag ha ndler has hidden
821 // the element in some way. In this case we just kill the drag.
822 return false;
823 }
824 }
825
826 DragController& dragController = m_frame->page()->dragController();
827 if (!dragController.populateDragDataTransfer(m_frame, dragState(),
828 m_mouseDownPos))
829 return false;
830
831 // If dispatching dragstart brings about another mouse down -- one way
832 // this will happen is if a DevTools user breaks within a dragstart
833 // handler and then clicks on the suspended page -- the drag state is
834 // reset. Hence, need to check if this particular drag operation can
835 // continue even if dispatchEvent() indicates no (direct) cancellation.
836 // Do that by checking if m_dragSrc is still set.
837 m_mouseDownMayStartDrag =
838 dispatchDragSrcEvent(EventTypeNames::dragstart, m_mouseDown) ==
839 WebInputEventResult::NotHandled &&
840 !m_frame->selection().isInPasswordField() && dragState().m_dragSrc;
841
842 // Invalidate clipboard here against anymore pasteboard writing for security. The drag
843 // image can still be changed as we drag, but not the pasteboard data.
844 dragState().m_dragDataTransfer->setAccessPolicy(DataTransferImageWritable);
845
846 if (m_mouseDownMayStartDrag) {
847 // Dispatching the event could cause Page to go away. Make sure it's still v alid before trying to use DragController.
848 if (m_frame->page() &&
849 dragController.startDrag(m_frame, dragState(), event.event(),
850 m_mouseDownPos))
851 return true;
852 // Drag was canned at the last minute - we owe m_dragSrc a DRAGEND event
853 dispatchDragSrcEvent(EventTypeNames::dragend, event.event());
854 }
855
856 return false;
857 }
858
859 // returns if we should continue "default processing", i.e., whether eventhandle r canceled
860 WebInputEventResult MouseEventManager::dispatchDragSrcEvent(
861 const AtomicString& eventType,
862 const PlatformMouseEvent& event) {
863 return dispatchDragEvent(eventType, dragState().m_dragSrc.get(), event,
864 dragState().m_dragDataTransfer.get());
865 }
866
867 WebInputEventResult MouseEventManager::dispatchDragEvent(
868 const AtomicString& eventType,
869 Node* dragTarget,
870 const PlatformMouseEvent& event,
871 DataTransfer* dataTransfer) {
872 FrameView* view = m_frame->view();
873
874 // FIXME: We might want to dispatch a dragleave even if the view is gone.
875 if (!view)
876 return WebInputEventResult::NotHandled;
877
878 DragEvent* me = DragEvent::create(
879 eventType, true, true, m_frame->document()->domWindow(), 0,
880 event.globalPosition().x(), event.globalPosition().y(),
881 event.position().x(), event.position().y(), event.movementDelta().x(),
882 event.movementDelta().y(), event.getModifiers(), 0,
883 MouseEvent::platformModifiersToButtons(event.getModifiers()), nullptr,
884 event.timestamp(), dataTransfer, event.getSyntheticEventType());
885
886 return EventHandlingUtil::toWebInputEventResult(
887 dragTarget->dispatchEvent(me));
888 }
889
890 void MouseEventManager::clearDragDataTransfer() {
891 if (dragState().m_dragDataTransfer) {
892 dragState().m_dragDataTransfer->clearDragImage();
893 dragState().m_dragDataTransfer->setAccessPolicy(DataTransferNumb);
894 }
895 }
896
897 void MouseEventManager::dragSourceEndedAt(const PlatformMouseEvent& event,
898 DragOperation operation) {
899 // Send a hit test request so that Layer gets a chance to update the :hover an d :active pseudoclasses.
900 HitTestRequest request(HitTestRequest::Release);
901 EventHandlingUtil::performMouseEventHitTest(m_frame, request, event);
902
903 if (dragState().m_dragSrc) {
904 dragState().m_dragDataTransfer->setDestinationOperation(operation);
905 // for now we don't care if event handler cancels default behavior, since th ere is none
906 dispatchDragSrcEvent(EventTypeNames::dragend, event);
907 }
908 clearDragDataTransfer();
909 dragState().m_dragSrc = nullptr;
910 // In case the drag was ended due to an escape key press we need to ensure
911 // that consecutive mousemove events don't reinitiate the drag and drop.
912 m_mouseDownMayStartDrag = false;
913 }
914
915 DragState& MouseEventManager::dragState() {
916 DEFINE_STATIC_LOCAL(DragState, state, (new DragState));
917 return state;
918 }
919
920 bool MouseEventManager::dragHysteresisExceeded(
921 const IntPoint& dragLocationInRootFrame) const {
922 FrameView* view = m_frame->view();
923 if (!view)
924 return false;
925 IntPoint dragLocation = view->rootFrameToContents(dragLocationInRootFrame);
926 IntSize delta = dragLocation - m_mouseDownPos;
927
928 int threshold = kGeneralDragHysteresis;
929 switch (dragState().m_dragType) {
930 case DragSourceActionSelection:
931 threshold = kTextDragHysteresis;
932 break;
933 case DragSourceActionImage:
934 threshold = kImageDragHysteresis;
935 break;
936 case DragSourceActionLink:
937 threshold = kLinkDragHysteresis;
938 break;
939 case DragSourceActionDHTML:
940 break;
941 case DragSourceActionNone:
942 NOTREACHED();
943 }
944
945 return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold;
946 }
947
948 void MouseEventManager::clearDragHeuristicState() {
949 // Used to prevent mouseMoveEvent from initiating a drag before
950 // the mouse is pressed again.
951 m_mousePressed = false;
952 m_capturesDragging = false;
953 m_mouseDownMayStartDrag = false;
954 m_mouseDownMayStartAutoscroll = false;
955 }
956
957 bool MouseEventManager::handleSvgPanIfNeeded(bool isReleaseEvent) {
958 if (!m_svgPan)
959 return false;
960 m_svgPan = !isReleaseEvent;
961 m_frame->document()->accessSVGExtensions().updatePan(
962 m_frame->view()->rootFrameToContents(m_lastKnownMousePosition));
963 return true;
964 }
965
966 void MouseEventManager::invalidateClick() {
967 m_clickCount = 0;
968 m_clickNode = nullptr;
969 }
970
971 bool MouseEventManager::mousePressed() {
972 return m_mousePressed;
973 }
974
975 void MouseEventManager::setMousePressed(bool mousePressed) {
976 m_mousePressed = mousePressed;
977 }
978
979 bool MouseEventManager::capturesDragging() const {
980 return m_capturesDragging;
981 }
982
983 void MouseEventManager::setCapturesDragging(bool capturesDragging) {
984 m_capturesDragging = capturesDragging;
985 }
986
987 Node* MouseEventManager::mousePressNode() {
988 return m_mousePressNode;
989 }
990
991 void MouseEventManager::setMousePressNode(Node* node) {
992 m_mousePressNode = node;
993 }
994
995 void MouseEventManager::setClickNode(Node* node) {
996 m_clickNode = node;
997 }
998
999 void MouseEventManager::setClickCount(int clickCount) {
1000 m_clickCount = clickCount;
1001 }
1002
1003 bool MouseEventManager::mouseDownMayStartDrag() {
1004 return m_mouseDownMayStartDrag;
138 } 1005 }
139 1006
140 } // namespace blink 1007 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/input/MouseEventManager.h ('k') | third_party/WebKit/Source/core/input/PointerEventManager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698