1/* 2 * Copyright (C) 2006-2014 Apple Inc. All rights reserved. 3 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) 4 * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies) 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "config.h" 29#include "EventHandler.h" 30 31#include "AXObjectCache.h" 32#include "AutoscrollController.h" 33#include "BackForwardController.h" 34#include "CachedImage.h" 35#include "Chrome.h" 36#include "ChromeClient.h" 37#include "Cursor.h" 38#include "CursorList.h" 39#include "Document.h" 40#include "DocumentEventQueue.h" 41#include "DragController.h" 42#include "DragState.h" 43#include "Editor.h" 44#include "EditorClient.h" 45#include "EventNames.h" 46#include "ExceptionCodePlaceholder.h" 47#include "FileList.h" 48#include "FloatPoint.h" 49#include "FloatRect.h" 50#include "FocusController.h" 51#include "FrameLoader.h" 52#include "FrameSelection.h" 53#include "FrameTree.h" 54#include "FrameView.h" 55#include "htmlediting.h" 56#include "HTMLFrameElementBase.h" 57#include "HTMLFrameSetElement.h" 58#include "HTMLInputElement.h" 59#include "HTMLNames.h" 60#include "HitTestRequest.h" 61#include "HitTestResult.h" 62#include "Image.h" 63#include "InspectorInstrumentation.h" 64#include "KeyboardEvent.h" 65#include "MainFrame.h" 66#include "MouseEvent.h" 67#include "MouseEventWithHitTestResults.h" 68#include "Page.h" 69#include "PlatformEvent.h" 70#include "PlatformKeyboardEvent.h" 71#include "PlatformWheelEvent.h" 72#include "PluginDocument.h" 73#include "RenderFrameSet.h" 74#include "RenderLayer.h" 75#include "RenderListBox.h" 76#include "RenderTextControlSingleLine.h" 77#include "RenderView.h" 78#include "RenderWidget.h" 79#include "RuntimeApplicationChecks.h" 80#include "SVGDocument.h" 81#include "SVGElementInstance.h" 82#include "SVGNames.h" 83#include "SVGUseElement.h" 84#include "ScrollAnimator.h" 85#include "Scrollbar.h" 86#include "Settings.h" 87#include "ShadowRoot.h" 88#include "SpatialNavigation.h" 89#include "StyleCachedImage.h" 90#include "TextEvent.h" 91#include "TextIterator.h" 92#include "UserGestureIndicator.h" 93#include "UserTypingGestureIndicator.h" 94#include "VisibleUnits.h" 95#include "WheelEvent.h" 96#include "WindowsKeyboardCodes.h" 97#include <wtf/Assertions.h> 98#include <wtf/CurrentTime.h> 99#include <wtf/StdLibExtras.h> 100#include <wtf/TemporaryChange.h> 101 102#if ENABLE(CSS_IMAGE_SET) 103#include "StyleCachedImageSet.h" 104#endif 105 106#if ENABLE(IOS_TOUCH_EVENTS) 107#include "PlatformTouchEventIOS.h" 108#endif 109 110#if ENABLE(TOUCH_EVENTS) 111#include "TouchEvent.h" 112#include "TouchList.h" 113#endif 114 115#if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS) 116#include "PlatformTouchEvent.h" 117#endif 118 119namespace WebCore { 120 121using namespace HTMLNames; 122 123#if ENABLE(DRAG_SUPPORT) 124// The link drag hysteresis is much larger than the others because there 125// needs to be enough space to cancel the link press without starting a link drag, 126// and because dragging links is rare. 127const int LinkDragHysteresis = 40; 128const int ImageDragHysteresis = 5; 129const int TextDragHysteresis = 3; 130const int GeneralDragHysteresis = 3; 131#endif // ENABLE(DRAG_SUPPORT) 132 133#if ENABLE(IOS_GESTURE_EVENTS) 134const float GestureUnknown = 0; 135#endif 136 137#if ENABLE(IOS_TOUCH_EVENTS) 138// FIXME: Share this constant with EventHandler and SliderThumbElement. 139const unsigned InvalidTouchIdentifier = 0; 140#endif 141 142// Match key code of composition keydown event on windows. 143// IE sends VK_PROCESSKEY which has value 229; 144const int CompositionEventKeyCode = 229; 145 146using namespace SVGNames; 147 148#if !ENABLE(IOS_TOUCH_EVENTS) 149// The amount of time to wait before sending a fake mouse event, triggered 150// during a scroll. The short interval is used if the content responds to the mouse events 151// in fakeMouseMoveDurationThreshold or less, otherwise the long interval is used. 152const double fakeMouseMoveDurationThreshold = 0.01; 153const double fakeMouseMoveShortInterval = 0.1; 154const double fakeMouseMoveLongInterval = 0.25; 155#endif 156 157#if ENABLE(CURSOR_SUPPORT) 158// The amount of time to wait for a cursor update on style and layout changes 159// Set to 50Hz, no need to be faster than common screen refresh rate 160const double cursorUpdateInterval = 0.02; 161 162const int maximumCursorSize = 128; 163#endif 164 165#if ENABLE(MOUSE_CURSOR_SCALE) 166// It's pretty unlikely that a scale of less than one would ever be used. But all we really 167// need to ensure here is that the scale isn't so small that integer overflow can occur when 168// dividing cursor sizes (limited above) by the scale. 169const double minimumCursorScale = 0.001; 170#endif 171 172enum NoCursorChangeType { NoCursorChange }; 173 174class OptionalCursor { 175public: 176 OptionalCursor(NoCursorChangeType) : m_isCursorChange(false) { } 177 OptionalCursor(const Cursor& cursor) : m_isCursorChange(true), m_cursor(cursor) { } 178 179 bool isCursorChange() const { return m_isCursorChange; } 180 const Cursor& cursor() const { ASSERT(m_isCursorChange); return m_cursor; } 181 182private: 183 bool m_isCursorChange; 184 Cursor m_cursor; 185}; 186 187class MaximumDurationTracker { 188public: 189 explicit MaximumDurationTracker(double *maxDuration) 190 : m_maxDuration(maxDuration) 191 , m_start(monotonicallyIncreasingTime()) 192 { 193 } 194 195 ~MaximumDurationTracker() 196 { 197 *m_maxDuration = std::max(*m_maxDuration, monotonicallyIncreasingTime() - m_start); 198 } 199 200private: 201 double* m_maxDuration; 202 double m_start; 203}; 204 205#if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS) 206class SyntheticTouchPoint : public PlatformTouchPoint { 207public: 208 209 // The default values are based on http://dvcs.w3.org/hg/webevents/raw-file/tip/touchevents.html 210 explicit SyntheticTouchPoint(const PlatformMouseEvent& event) 211 { 212 const static int idDefaultValue = 0; 213 const static int radiusYDefaultValue = 1; 214 const static int radiusXDefaultValue = 1; 215 const static float rotationAngleDefaultValue = 0.0f; 216 const static float forceDefaultValue = 1.0f; 217 218 m_id = idDefaultValue; // There is only one active TouchPoint. 219 m_screenPos = event.globalPosition(); 220 m_pos = event.position(); 221 m_radiusY = radiusYDefaultValue; 222 m_radiusX = radiusXDefaultValue; 223 m_rotationAngle = rotationAngleDefaultValue; 224 m_force = forceDefaultValue; 225 226 PlatformEvent::Type type = event.type(); 227 ASSERT(type == PlatformEvent::MouseMoved || type == PlatformEvent::MousePressed || type == PlatformEvent::MouseReleased); 228 229 switch (type) { 230 case PlatformEvent::MouseMoved: 231 m_state = TouchMoved; 232 break; 233 case PlatformEvent::MousePressed: 234 m_state = TouchPressed; 235 break; 236 case PlatformEvent::MouseReleased: 237 m_state = TouchReleased; 238 break; 239 default: 240 ASSERT_NOT_REACHED(); 241 break; 242 } 243 } 244}; 245 246class SyntheticSingleTouchEvent : public PlatformTouchEvent { 247public: 248 explicit SyntheticSingleTouchEvent(const PlatformMouseEvent& event) 249 { 250 switch (event.type()) { 251 case PlatformEvent::MouseMoved: 252 m_type = TouchMove; 253 break; 254 case PlatformEvent::MousePressed: 255 m_type = TouchStart; 256 break; 257 case PlatformEvent::MouseReleased: 258 m_type = TouchEnd; 259 break; 260 default: 261 ASSERT_NOT_REACHED(); 262 m_type = NoType; 263 break; 264 } 265 m_timestamp = event.timestamp(); 266 m_modifiers = event.modifiers(); 267 m_touchPoints.append(SyntheticTouchPoint(event)); 268 } 269}; 270#endif // ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS) 271 272static inline ScrollGranularity wheelGranularityToScrollGranularity(unsigned deltaMode) 273{ 274 switch (deltaMode) { 275 case WheelEvent::DOM_DELTA_PAGE: 276 return ScrollByPage; 277 case WheelEvent::DOM_DELTA_LINE: 278 return ScrollByLine; 279 case WheelEvent::DOM_DELTA_PIXEL: 280 return ScrollByPixel; 281 default: 282 return ScrollByPixel; 283 } 284} 285 286static inline bool scrollNode(float delta, ScrollGranularity granularity, ScrollDirection positiveDirection, ScrollDirection negativeDirection, Node* node, Element** stopElement, const IntPoint& wheelEventAbsolutePoint) 287{ 288 if (!delta) 289 return false; 290 if (!node->renderer()) 291 return false; 292 RenderBox& enclosingBox = node->renderer()->enclosingBox(); 293 float absDelta = delta > 0 ? delta : -delta; 294 295 return enclosingBox.scroll(delta < 0 ? negativeDirection : positiveDirection, granularity, absDelta, stopElement, &enclosingBox, wheelEventAbsolutePoint); 296} 297 298#if (ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS)) 299static inline bool shouldGesturesTriggerActive() 300{ 301 // If the platform we're on supports GestureTapDown and GestureTapCancel then we'll 302 // rely on them to set the active state. Unfortunately there's no generic way to 303 // know in advance what event types are supported. 304 return false; 305} 306#endif 307 308#if !PLATFORM(COCOA) 309 310inline bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&) 311{ 312 return false; 313} 314 315#if ENABLE(DRAG_SUPPORT) 316inline bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&) 317{ 318 return false; 319} 320#endif 321 322#endif 323 324EventHandler::EventHandler(Frame& frame) 325 : m_frame(frame) 326 , m_mousePressed(false) 327 , m_capturesDragging(false) 328 , m_mouseDownMayStartSelect(false) 329#if ENABLE(DRAG_SUPPORT) 330 , m_mouseDownMayStartDrag(false) 331 , m_dragMayStartSelectionInstead(false) 332#endif 333 , m_mouseDownWasSingleClickInSelection(false) 334 , m_selectionInitiationState(HaveNotStartedSelection) 335 , m_hoverTimer(this, &EventHandler::hoverTimerFired) 336#if ENABLE(CURSOR_SUPPORT) 337 , m_cursorUpdateTimer(this, &EventHandler::cursorUpdateTimerFired) 338#endif 339 , m_autoscrollController(std::make_unique<AutoscrollController>()) 340 , m_mouseDownMayStartAutoscroll(false) 341 , m_mouseDownWasInSubframe(false) 342#if !ENABLE(IOS_TOUCH_EVENTS) 343 , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFired) 344#endif 345 , m_svgPan(false) 346 , m_resizeLayer(0) 347 , m_eventHandlerWillResetCapturingMouseEventsElement(nullptr) 348 , m_clickCount(0) 349#if ENABLE(IOS_GESTURE_EVENTS) 350 , m_gestureInitialDiameter(GestureUnknown) 351 , m_gestureLastDiameter(GestureUnknown) 352 , m_gestureInitialRotation(GestureUnknown) 353 , m_gestureLastRotation(GestureUnknown) 354#endif 355#if ENABLE(IOS_TOUCH_EVENTS) 356 , m_firstTouchID(InvalidTouchIdentifier) 357#endif 358 , m_mousePositionIsUnknown(true) 359 , m_mouseDownTimestamp(0) 360 , m_recentWheelEventDeltaTracker(std::make_unique<WheelEventDeltaTracker>()) 361 , m_widgetIsLatched(false) 362#if PLATFORM(COCOA) 363 , m_mouseDownView(nil) 364 , m_sendingEventToSubview(false) 365 , m_startedGestureAtScrollLimit(false) 366#if !PLATFORM(IOS) 367 , m_activationEventNumber(-1) 368#endif // !PLATFORM(IOS) 369#endif 370#if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS) 371 , m_originatingTouchPointTargetKey(0) 372 , m_touchPressed(false) 373#endif 374 , m_maxMouseMovedDuration(0) 375 , m_baseEventType(PlatformEvent::NoType) 376 , m_didStartDrag(false) 377 , m_didLongPressInvokeContextMenu(false) 378 , m_isHandlingWheelEvent(false) 379#if ENABLE(CURSOR_VISIBILITY) 380 , m_autoHideCursorTimer(this, &EventHandler::autoHideCursorTimerFired) 381#endif 382{ 383} 384 385EventHandler::~EventHandler() 386{ 387#if !ENABLE(IOS_TOUCH_EVENTS) 388 ASSERT(!m_fakeMouseMoveEventTimer.isActive()); 389#endif 390#if ENABLE(CURSOR_VISIBILITY) 391 ASSERT(!m_autoHideCursorTimer.isActive()); 392#endif 393} 394 395#if ENABLE(DRAG_SUPPORT) 396DragState& EventHandler::dragState() 397{ 398 DEPRECATED_DEFINE_STATIC_LOCAL(DragState, state, ()); 399 return state; 400} 401#endif // ENABLE(DRAG_SUPPORT) 402 403void EventHandler::clear() 404{ 405 m_hoverTimer.stop(); 406#if ENABLE(CURSOR_SUPPORT) 407 m_cursorUpdateTimer.stop(); 408#endif 409#if !ENABLE(IOS_TOUCH_EVENTS) 410 m_fakeMouseMoveEventTimer.stop(); 411#endif 412#if ENABLE(CURSOR_VISIBILITY) 413 cancelAutoHideCursorTimer(); 414#endif 415 m_resizeLayer = 0; 416 m_elementUnderMouse = nullptr; 417 m_lastElementUnderMouse = nullptr; 418 m_instanceUnderMouse = 0; 419 m_lastInstanceUnderMouse = 0; 420 m_lastMouseMoveEventSubframe = 0; 421 m_lastScrollbarUnderMouse = 0; 422 m_clickCount = 0; 423 m_clickNode = 0; 424#if ENABLE(IOS_GESTURE_EVENTS) 425 m_gestureInitialDiameter = GestureUnknown; 426 m_gestureLastDiameter = GestureUnknown; 427 m_gestureInitialRotation = GestureUnknown; 428 m_gestureLastRotation = GestureUnknown; 429 m_gestureTargets.clear(); 430#endif 431#if ENABLE(IOS_TOUCH_EVENTS) 432 m_touches.clear(); 433 m_firstTouchID = InvalidTouchIdentifier; 434 m_touchEventTargetSubframe = 0; 435#endif 436 m_frameSetBeingResized = 0; 437#if ENABLE(DRAG_SUPPORT) 438 m_dragTarget = 0; 439 m_shouldOnlyFireDragOverEvent = false; 440#endif 441 m_mousePositionIsUnknown = true; 442 m_lastKnownMousePosition = IntPoint(); 443 m_lastKnownMouseGlobalPosition = IntPoint(); 444 m_mousePressNode = 0; 445 m_mousePressed = false; 446 m_capturesDragging = false; 447 m_capturingMouseEventsElement = nullptr; 448 m_latchedWheelEventElement = nullptr; 449#if PLATFORM(COCOA) 450 m_latchedScrollableContainer = nullptr; 451#endif 452 m_previousWheelScrolledElement = nullptr; 453#if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS) 454 m_originatingTouchPointTargets.clear(); 455 m_originatingTouchPointDocument.clear(); 456 m_originatingTouchPointTargetKey = 0; 457#endif 458 m_maxMouseMovedDuration = 0; 459 m_baseEventType = PlatformEvent::NoType; 460 m_didStartDrag = false; 461 m_didLongPressInvokeContextMenu = false; 462} 463 464void EventHandler::nodeWillBeRemoved(Node* nodeToBeRemoved) 465{ 466 if (nodeToBeRemoved->contains(m_clickNode.get())) 467 m_clickNode = 0; 468} 469 470static void setSelectionIfNeeded(FrameSelection& selection, const VisibleSelection& newSelection) 471{ 472 if (selection.selection() != newSelection && selection.shouldChangeSelection(newSelection)) 473 selection.setSelection(newSelection); 474} 475 476static inline bool dispatchSelectStart(Node* node) 477{ 478 if (!node || !node->renderer()) 479 return true; 480 481 return node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true)); 482} 483 484static VisibleSelection expandSelectionToRespectUserSelectAll(Node* targetNode, const VisibleSelection& selection) 485{ 486#if ENABLE(USERSELECT_ALL) 487 Node* rootUserSelectAll = Position::rootUserSelectAllForNode(targetNode); 488 if (!rootUserSelectAll) 489 return selection; 490 491 VisibleSelection newSelection(selection); 492 newSelection.setBase(positionBeforeNode(rootUserSelectAll).upstream(CanCrossEditingBoundary)); 493 newSelection.setExtent(positionAfterNode(rootUserSelectAll).downstream(CanCrossEditingBoundary)); 494 495 return newSelection; 496#else 497 UNUSED_PARAM(targetNode); 498 return selection; 499#endif 500} 501 502bool EventHandler::updateSelectionForMouseDownDispatchingSelectStart(Node* targetNode, const VisibleSelection& selection, TextGranularity granularity) 503{ 504 if (Position::nodeIsUserSelectNone(targetNode)) 505 return false; 506 507 if (!dispatchSelectStart(targetNode)) 508 return false; 509 510 if (selection.isRange()) 511 m_selectionInitiationState = ExtendedSelection; 512 else { 513 granularity = CharacterGranularity; 514 m_selectionInitiationState = PlacedCaret; 515 } 516 517 m_frame.selection().setSelectionByMouseIfDifferent(selection, granularity); 518 519 return true; 520} 521 522void EventHandler::selectClosestWordFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace) 523{ 524 Node* targetNode = result.targetNode(); 525 VisibleSelection newSelection; 526 527 if (targetNode && targetNode->renderer()) { 528 VisiblePosition pos(targetNode->renderer()->positionForPoint(result.localPoint(), nullptr)); 529 if (pos.isNotNull()) { 530 newSelection = VisibleSelection(pos); 531 newSelection.expandUsingGranularity(WordGranularity); 532 } 533 534 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange()) 535 newSelection.appendTrailingWhitespace(); 536 537 updateSelectionForMouseDownDispatchingSelectStart(targetNode, expandSelectionToRespectUserSelectAll(targetNode, newSelection), WordGranularity); 538 } 539} 540 541void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result) 542{ 543 if (m_mouseDownMayStartSelect) { 544 selectClosestWordFromHitTestResult(result.hitTestResult(), 545 (result.event().clickCount() == 2 && m_frame.editor().isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace); 546 } 547} 548 549void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result) 550{ 551 if (!result.hitTestResult().isLiveLink()) 552 return selectClosestWordFromMouseEvent(result); 553 554 Node* targetNode = result.targetNode(); 555 556 if (targetNode && targetNode->renderer() && m_mouseDownMayStartSelect) { 557 VisibleSelection newSelection; 558 Element* URLElement = result.hitTestResult().URLElement(); 559 VisiblePosition pos(targetNode->renderer()->positionForPoint(result.localPoint(), nullptr)); 560 if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescendantOf(URLElement)) 561 newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement); 562 563 updateSelectionForMouseDownDispatchingSelectStart(targetNode, expandSelectionToRespectUserSelectAll(targetNode, newSelection), WordGranularity); 564 } 565} 566 567bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event) 568{ 569 if (event.event().button() != LeftButton) 570 return false; 571 572 if (m_frame.selection().isRange()) 573 // A double-click when range is already selected 574 // should not change the selection. So, do not call 575 // selectClosestWordFromMouseEvent, but do set 576 // m_beganSelectingText to prevent handleMouseReleaseEvent 577 // from setting caret selection. 578 m_selectionInitiationState = ExtendedSelection; 579 else 580 selectClosestWordFromMouseEvent(event); 581 582 return true; 583} 584 585bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event) 586{ 587 if (event.event().button() != LeftButton) 588 return false; 589 590 Node* targetNode = event.targetNode(); 591 if (!(targetNode && targetNode->renderer() && m_mouseDownMayStartSelect)) 592 return false; 593 594 VisibleSelection newSelection; 595 VisiblePosition pos(targetNode->renderer()->positionForPoint(event.localPoint(), nullptr)); 596 if (pos.isNotNull()) { 597 newSelection = VisibleSelection(pos); 598 newSelection.expandUsingGranularity(ParagraphGranularity); 599 } 600 601 return updateSelectionForMouseDownDispatchingSelectStart(targetNode, expandSelectionToRespectUserSelectAll(targetNode, newSelection), ParagraphGranularity); 602} 603 604static int textDistance(const Position& start, const Position& end) 605{ 606 RefPtr<Range> range = Range::create(start.anchorNode()->document(), start, end); 607 return TextIterator::rangeLength(range.get(), true); 608} 609 610bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event) 611{ 612 m_frame.document()->updateLayoutIgnorePendingStylesheets(); 613 Node* targetNode = event.targetNode(); 614 if (!(targetNode && targetNode->renderer() && m_mouseDownMayStartSelect)) 615 return false; 616 617 // Extend the selection if the Shift key is down, unless the click is in a link. 618 bool extendSelection = event.event().shiftKey() && !event.isOverLink(); 619 620 // Don't restart the selection when the mouse is pressed on an 621 // existing selection so we can allow for text dragging. 622 if (FrameView* view = m_frame.view()) { 623 LayoutPoint vPoint = view->windowToContents(event.event().position()); 624 if (!extendSelection && m_frame.selection().contains(vPoint)) { 625 m_mouseDownWasSingleClickInSelection = true; 626 return false; 627 } 628 } 629 630 VisiblePosition visiblePos(targetNode->renderer()->positionForPoint(event.localPoint(), nullptr)); 631 if (visiblePos.isNull()) 632 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(targetNode), DOWNSTREAM); 633 Position pos = visiblePos.deepEquivalent(); 634 635 VisibleSelection newSelection = m_frame.selection().selection(); 636 TextGranularity granularity = CharacterGranularity; 637 638 if (extendSelection && newSelection.isCaretOrRange()) { 639 VisibleSelection selectionInUserSelectAll = expandSelectionToRespectUserSelectAll(targetNode, VisibleSelection(pos)); 640 if (selectionInUserSelectAll.isRange()) { 641 if (comparePositions(selectionInUserSelectAll.start(), newSelection.start()) < 0) 642 pos = selectionInUserSelectAll.start(); 643 else if (comparePositions(newSelection.end(), selectionInUserSelectAll.end()) < 0) 644 pos = selectionInUserSelectAll.end(); 645 } 646 647 if (!m_frame.editor().behavior().shouldConsiderSelectionAsDirectional() && pos.isNotNull()) { 648 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection 649 // was created right-to-left 650 Position start = newSelection.start(); 651 Position end = newSelection.end(); 652 int distanceToStart = textDistance(start, pos); 653 int distanceToEnd = textDistance(pos, end); 654 if (distanceToStart <= distanceToEnd) 655 newSelection = VisibleSelection(end, pos); 656 else 657 newSelection = VisibleSelection(start, pos); 658 } else 659 newSelection.setExtent(pos); 660 661 if (m_frame.selection().granularity() != CharacterGranularity) { 662 granularity = m_frame.selection().granularity(); 663 newSelection.expandUsingGranularity(m_frame.selection().granularity()); 664 } 665 } else 666 newSelection = expandSelectionToRespectUserSelectAll(targetNode, visiblePos); 667 668 bool handled = updateSelectionForMouseDownDispatchingSelectStart(targetNode, newSelection, granularity); 669 670 if (event.event().button() == MiddleButton) { 671 // Ignore handled, since we want to paste to where the caret was placed anyway. 672 handled = handlePasteGlobalSelection(event.event()) || handled; 673 } 674 return handled; 675} 676 677static inline bool canMouseDownStartSelect(Node* node) 678{ 679 if (!node || !node->renderer()) 680 return true; 681 682 return node->canStartSelection() || Position::nodeIsUserSelectAll(node); 683} 684 685bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event) 686{ 687#if ENABLE(DRAG_SUPPORT) 688 // Reset drag state. 689 dragState().source = 0; 690#endif 691 692#if !ENABLE(IOS_TOUCH_EVENTS) 693 cancelFakeMouseMoveEvent(); 694#endif 695 696 m_frame.document()->updateLayoutIgnorePendingStylesheets(); 697 698 if (ScrollView* scrollView = m_frame.view()) { 699 if (scrollView->isPointInScrollbarCorner(event.event().position())) 700 return false; 701 } 702 703 bool singleClick = event.event().clickCount() <= 1; 704 705 // If we got the event back, that must mean it wasn't prevented, 706 // so it's allowed to start a drag or selection if it wasn't in a scrollbar. 707 m_mouseDownMayStartSelect = canMouseDownStartSelect(event.targetNode()) && !event.scrollbar(); 708 709#if ENABLE(DRAG_SUPPORT) 710 // Careful that the drag starting logic stays in sync with eventMayStartDrag() 711 m_mouseDownMayStartDrag = singleClick; 712#endif 713 714 m_mouseDownWasSingleClickInSelection = false; 715 716 m_mouseDown = event.event(); 717 718 if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event)) 719 return true; 720 721 if (m_frame.document()->isSVGDocument() 722 && toSVGDocument(m_frame.document())->zoomAndPanEnabled()) { 723 if (event.event().shiftKey() && singleClick) { 724 m_svgPan = true; 725 toSVGDocument(m_frame.document())->startPan(m_frame.view()->windowToContents(event.event().position())); 726 return true; 727 } 728 } 729 730 // We don't do this at the start of mouse down handling, 731 // because we don't want to do it until we know we didn't hit a widget. 732 if (singleClick) 733 focusDocumentView(); 734 735 m_mousePressNode = event.targetNode(); 736#if ENABLE(DRAG_SUPPORT) 737 m_dragStartPos = event.event().position(); 738#endif 739 740 bool swallowEvent = false; 741 m_mousePressed = true; 742 m_selectionInitiationState = HaveNotStartedSelection; 743 744 if (event.event().clickCount() == 2) 745 swallowEvent = handleMousePressEventDoubleClick(event); 746 else if (event.event().clickCount() >= 3) 747 swallowEvent = handleMousePressEventTripleClick(event); 748 else 749 swallowEvent = handleMousePressEventSingleClick(event); 750 751 m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect 752 || (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled()); 753 754 return swallowEvent; 755} 756 757#if ENABLE(DRAG_SUPPORT) 758bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event) 759{ 760 if (!m_mousePressed) 761 return false; 762 763 if (handleDrag(event, ShouldCheckDragHysteresis)) 764 return true; 765 766 Node* targetNode = event.targetNode(); 767 if (event.event().button() != LeftButton || !targetNode) 768 return false; 769 770 RenderObject* renderer = targetNode->renderer(); 771 if (!renderer) { 772 Element* parent = targetNode->parentOrShadowHostElement(); 773 if (!parent) 774 return false; 775 776 renderer = parent->renderer(); 777 if (!renderer || !renderer->isListBox()) 778 return false; 779 } 780 781#if PLATFORM(COCOA) // FIXME: Why does this assertion fire on other platforms? 782 ASSERT(m_mouseDownMayStartSelect || m_mouseDownMayStartAutoscroll); 783#endif 784 785 m_mouseDownMayStartDrag = false; 786 787 if (m_mouseDownMayStartAutoscroll && !panScrollInProgress()) { 788 m_autoscrollController->startAutoscrollForSelection(renderer); 789 m_mouseDownMayStartAutoscroll = false; 790 } 791 792 if (m_selectionInitiationState != ExtendedSelection) { 793 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent); 794 HitTestResult result(m_mouseDownPos); 795 m_frame.document()->renderView()->hitTest(request, result); 796 797 updateSelectionForMouseDrag(result); 798 } 799 updateSelectionForMouseDrag(event.hitTestResult()); 800 return true; 801} 802 803bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const 804{ 805 // This is a pre-flight check of whether the event might lead to a drag being started. Be careful 806 // that its logic needs to stay in sync with handleMouseMoveEvent() and the way we setMouseDownMayStartDrag 807 // in handleMousePressEvent 808 809 if (!m_frame.contentRenderer() || !m_frame.contentRenderer()->hasLayer()) 810 return false; 811 812 if (event.button() != LeftButton || event.clickCount() != 1) 813 return false; 814 815 FrameView* view = m_frame.view(); 816 if (!view) 817 return false; 818 819 Page* page = m_frame.page(); 820 if (!page) 821 return false; 822 823 updateDragSourceActionsAllowed(); 824 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent); 825 HitTestResult result(view->windowToContents(event.position())); 826 m_frame.contentRenderer()->hitTest(request, result); 827 DragState state; 828 return result.innerElement() && page->dragController().draggableElement(&m_frame, result.innerElement(), result.roundedPointInInnerNodeFrame(), state); 829} 830 831void EventHandler::updateSelectionForMouseDrag() 832{ 833 FrameView* view = m_frame.view(); 834 if (!view) 835 return; 836 RenderView* renderer = m_frame.contentRenderer(); 837 if (!renderer) 838 return; 839 840 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::Move | HitTestRequest::DisallowShadowContent); 841 HitTestResult result(view->windowToContents(m_lastKnownMousePosition)); 842 renderer->hitTest(request, result); 843 updateSelectionForMouseDrag(result); 844} 845 846static VisiblePosition selectionExtentRespectingEditingBoundary(const VisibleSelection& selection, const LayoutPoint& localPoint, Node* targetNode) 847{ 848 LayoutPoint selectionEndPoint = localPoint; 849 Element* editableElement = selection.rootEditableElement(); 850 851 if (!targetNode->renderer()) 852 return VisiblePosition(); 853 854 if (editableElement && !editableElement->contains(targetNode)) { 855 if (!editableElement->renderer()) 856 return VisiblePosition(); 857 858 FloatPoint absolutePoint = targetNode->renderer()->localToAbsolute(FloatPoint(selectionEndPoint)); 859 selectionEndPoint = roundedLayoutPoint(editableElement->renderer()->absoluteToLocal(absolutePoint)); 860 targetNode = editableElement; 861 } 862 863 return targetNode->renderer()->positionForPoint(selectionEndPoint, nullptr); 864} 865 866void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResult) 867{ 868 if (!m_mouseDownMayStartSelect) 869 return; 870 871 Node* target = hitTestResult.targetNode(); 872 if (!target) 873 return; 874 875 VisiblePosition targetPosition = selectionExtentRespectingEditingBoundary(m_frame.selection().selection(), hitTestResult.localPoint(), target); 876 877 // Don't modify the selection if we're not on a node. 878 if (targetPosition.isNull()) 879 return; 880 881 // Restart the selection if this is the first mouse move. This work is usually 882 // done in handleMousePressEvent, but not if the mouse press was on an existing selection. 883 VisibleSelection newSelection = m_frame.selection().selection(); 884 885 // Special case to limit selection to the containing block for SVG text. 886 // FIXME: Isn't there a better non-SVG-specific way to do this? 887 if (Node* selectionBaseNode = newSelection.base().deprecatedNode()) 888 if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer()) 889 if (selectionBaseRenderer->isSVGText()) 890 if (target->renderer()->containingBlock() != selectionBaseRenderer->containingBlock()) 891 return; 892 893 if (m_selectionInitiationState == HaveNotStartedSelection && !dispatchSelectStart(target)) 894 return; 895 896 if (m_selectionInitiationState != ExtendedSelection) { 897 // Always extend selection here because it's caused by a mouse drag 898 m_selectionInitiationState = ExtendedSelection; 899 newSelection = VisibleSelection(targetPosition); 900 } 901 902#if ENABLE(USERSELECT_ALL) 903 Node* rootUserSelectAllForMousePressNode = Position::rootUserSelectAllForNode(m_mousePressNode.get()); 904 if (rootUserSelectAllForMousePressNode && rootUserSelectAllForMousePressNode == Position::rootUserSelectAllForNode(target)) { 905 newSelection.setBase(positionBeforeNode(rootUserSelectAllForMousePressNode).upstream(CanCrossEditingBoundary)); 906 newSelection.setExtent(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary)); 907 } else { 908 // Reset base for user select all when base is inside user-select-all area and extent < base. 909 if (rootUserSelectAllForMousePressNode && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint(), nullptr), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos, nullptr)) < 0) 910 newSelection.setBase(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary)); 911 912 Node* rootUserSelectAllForTarget = Position::rootUserSelectAllForNode(target); 913 if (rootUserSelectAllForTarget && m_mousePressNode->renderer() && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint(), nullptr), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos, nullptr)) < 0) 914 newSelection.setExtent(positionBeforeNode(rootUserSelectAllForTarget).upstream(CanCrossEditingBoundary)); 915 else if (rootUserSelectAllForTarget && m_mousePressNode->renderer()) 916 newSelection.setExtent(positionAfterNode(rootUserSelectAllForTarget).downstream(CanCrossEditingBoundary)); 917 else 918 newSelection.setExtent(targetPosition); 919 } 920#else 921 newSelection.setExtent(targetPosition); 922#endif 923 924 if (m_frame.selection().granularity() != CharacterGranularity) 925 newSelection.expandUsingGranularity(m_frame.selection().granularity()); 926 927 m_frame.selection().setSelectionByMouseIfDifferent(newSelection, m_frame.selection().granularity(), 928 FrameSelection::AdjustEndpointsAtBidiBoundary); 929} 930#endif // ENABLE(DRAG_SUPPORT) 931 932void EventHandler::lostMouseCapture() 933{ 934 m_frame.selection().setCaretBlinkingSuspended(false); 935} 936 937bool EventHandler::handleMouseUp(const MouseEventWithHitTestResults& event) 938{ 939 if (eventLoopHandleMouseUp(event)) 940 return true; 941 942 // If this was the first click in the window, we don't even want to clear the selection. 943 // This case occurs when the user clicks on a draggable element, since we have to process 944 // the mouse down and drag events to see if we might start a drag. For other first clicks 945 // in a window, we just don't acceptFirstMouse, and the whole down-drag-up sequence gets 946 // ignored upstream of this layer. 947 return eventActivatedView(event.event()); 948} 949 950bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event) 951{ 952 if (autoscrollInProgress()) 953 stopAutoscrollTimer(); 954 955 if (handleMouseUp(event)) 956 return true; 957 958 // Used to prevent mouseMoveEvent from initiating a drag before 959 // the mouse is pressed again. 960 m_mousePressed = false; 961 m_capturesDragging = false; 962#if ENABLE(DRAG_SUPPORT) 963 m_mouseDownMayStartDrag = false; 964#endif 965 m_mouseDownMayStartSelect = false; 966 m_mouseDownMayStartAutoscroll = false; 967 m_mouseDownWasInSubframe = false; 968 969 bool handled = false; 970 971 // Clear the selection if the mouse didn't move after the last mouse 972 // press and it's not a context menu click. We do this so when clicking 973 // on the selection, the selection goes away. However, if we are 974 // editing, place the caret. 975 if (m_mouseDownWasSingleClickInSelection && m_selectionInitiationState != ExtendedSelection 976#if ENABLE(DRAG_SUPPORT) 977 && m_dragStartPos == event.event().position() 978#endif 979 && m_frame.selection().isRange() 980 && event.event().button() != RightButton) { 981 VisibleSelection newSelection; 982 Node* node = event.targetNode(); 983 bool caretBrowsing = m_frame.settings().caretBrowsingEnabled(); 984 if (node && node->renderer() && (caretBrowsing || node->hasEditableStyle())) { 985 VisiblePosition pos = node->renderer()->positionForPoint(event.localPoint(), nullptr); 986 newSelection = VisibleSelection(pos); 987 } 988 989 setSelectionIfNeeded(m_frame.selection(), newSelection); 990 991 handled = true; 992 } 993 994 if (event.event().button() == MiddleButton) { 995 // Ignore handled, since we want to paste to where the caret was placed anyway. 996 handled = handlePasteGlobalSelection(event.event()) || handled; 997 } 998 999 return handled; 1000} 1001 1002#if ENABLE(PAN_SCROLLING) 1003 1004void EventHandler::didPanScrollStart() 1005{ 1006 m_autoscrollController->didPanScrollStart(); 1007} 1008 1009void EventHandler::didPanScrollStop() 1010{ 1011 m_autoscrollController->didPanScrollStop(); 1012} 1013 1014void EventHandler::startPanScrolling(RenderElement* renderer) 1015{ 1016#if !PLATFORM(IOS) 1017 if (!renderer->isBox()) 1018 return; 1019 m_autoscrollController->startPanScrolling(toRenderBox(renderer), lastKnownMousePosition()); 1020 invalidateClick(); 1021#endif 1022} 1023 1024#endif // ENABLE(PAN_SCROLLING) 1025 1026RenderBox* EventHandler::autoscrollRenderer() const 1027{ 1028 return m_autoscrollController->autoscrollRenderer(); 1029} 1030 1031void EventHandler::updateAutoscrollRenderer() 1032{ 1033 m_autoscrollController->updateAutoscrollRenderer(); 1034} 1035 1036bool EventHandler::autoscrollInProgress() const 1037{ 1038 return m_autoscrollController->autoscrollInProgress(); 1039} 1040 1041bool EventHandler::panScrollInProgress() const 1042{ 1043 return m_autoscrollController->panScrollInProgress(); 1044} 1045 1046#if ENABLE(DRAG_SUPPORT) 1047DragSourceAction EventHandler::updateDragSourceActionsAllowed() const 1048{ 1049 Page* page = m_frame.page(); 1050 if (!page) 1051 return DragSourceActionNone; 1052 1053 FrameView* view = m_frame.view(); 1054 if (!view) 1055 return DragSourceActionNone; 1056 1057 return page->dragController().delegateDragSourceAction(view->contentsToRootView(m_mouseDownPos)); 1058} 1059#endif // ENABLE(DRAG_SUPPORT) 1060 1061HitTestResult EventHandler::hitTestResultAtPoint(const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType, const LayoutSize& padding) 1062{ 1063 // We always send hitTestResultAtPoint to the main frame if we have one, 1064 // otherwise we might hit areas that are obscured by higher frames. 1065 if (!m_frame.isMainFrame()) { 1066 Frame& mainFrame = m_frame.mainFrame(); 1067 FrameView* frameView = m_frame.view(); 1068 FrameView* mainView = mainFrame.view(); 1069 if (frameView && mainView) { 1070 IntPoint mainFramePoint = mainView->rootViewToContents(frameView->contentsToRootView(roundedIntPoint(point))); 1071 return mainFrame.eventHandler().hitTestResultAtPoint(mainFramePoint, hitType, padding); 1072 } 1073 } 1074 1075 HitTestResult result(point, padding.height(), padding.width(), padding.height(), padding.width()); 1076 1077 if (!m_frame.contentRenderer()) 1078 return result; 1079 1080 m_frame.document()->updateLayout(); 1081 1082 // hitTestResultAtPoint is specifically used to hitTest into all frames, thus it always allows child frame content. 1083 HitTestRequest request(hitType | HitTestRequest::AllowChildFrameContent); 1084 m_frame.contentRenderer()->hitTest(request, result); 1085 if (!request.readOnly()) 1086 m_frame.document()->updateHoverActiveState(request, result.innerElement()); 1087 1088 if (request.disallowsShadowContent()) 1089 result.setToNonShadowAncestor(); 1090 1091 return result; 1092} 1093 1094void EventHandler::stopAutoscrollTimer(bool rendererIsBeingDestroyed) 1095{ 1096 m_autoscrollController->stopAutoscrollTimer(rendererIsBeingDestroyed); 1097} 1098 1099bool EventHandler::scrollOverflow(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode) 1100{ 1101 Node* node = startingNode; 1102 1103 if (!node) 1104 node = m_frame.document()->focusedElement(); 1105 1106 if (!node) 1107 node = m_mousePressNode.get(); 1108 1109 if (node) { 1110 auto r = node->renderer(); 1111 if (r && !r->isListBox() && r->enclosingBox().scroll(direction, granularity)) { 1112 setFrameWasScrolledByUser(); 1113 return true; 1114 } 1115 } 1116 1117 return false; 1118} 1119 1120bool EventHandler::logicalScrollOverflow(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode) 1121{ 1122 Node* node = startingNode; 1123 1124 if (!node) 1125 node = m_frame.document()->focusedElement(); 1126 1127 if (!node) 1128 node = m_mousePressNode.get(); 1129 1130 if (node) { 1131 auto r = node->renderer(); 1132 if (r && !r->isListBox() && r->enclosingBox().logicalScroll(direction, granularity)) { 1133 setFrameWasScrolledByUser(); 1134 return true; 1135 } 1136 } 1137 1138 return false; 1139} 1140 1141bool EventHandler::scrollRecursively(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode) 1142{ 1143 // The layout needs to be up to date to determine if we can scroll. We may be 1144 // here because of an onLoad event, in which case the final layout hasn't been performed yet. 1145 m_frame.document()->updateLayoutIgnorePendingStylesheets(); 1146 if (scrollOverflow(direction, granularity, startingNode)) 1147 return true; 1148 Frame* frame = &m_frame; 1149 FrameView* view = frame->view(); 1150 if (view && view->scroll(direction, granularity)) 1151 return true; 1152 frame = frame->tree().parent(); 1153 if (!frame) 1154 return false; 1155 return frame->eventHandler().scrollRecursively(direction, granularity, m_frame.ownerElement()); 1156} 1157 1158bool EventHandler::logicalScrollRecursively(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode) 1159{ 1160 // The layout needs to be up to date to determine if we can scroll. We may be 1161 // here because of an onLoad event, in which case the final layout hasn't been performed yet. 1162 m_frame.document()->updateLayoutIgnorePendingStylesheets(); 1163 if (logicalScrollOverflow(direction, granularity, startingNode)) 1164 return true; 1165 Frame* frame = &m_frame; 1166 FrameView* view = frame->view(); 1167 1168 bool scrolled = false; 1169#if PLATFORM(COCOA) 1170 // Mac also resets the scroll position in the inline direction. 1171 if (granularity == ScrollByDocument && view && view->logicalScroll(ScrollInlineDirectionBackward, ScrollByDocument)) 1172 scrolled = true; 1173#endif 1174 if (view && view->logicalScroll(direction, granularity)) 1175 scrolled = true; 1176 1177 if (scrolled) 1178 return true; 1179 1180 frame = frame->tree().parent(); 1181 if (!frame) 1182 return false; 1183 1184 return frame->eventHandler().logicalScrollRecursively(direction, granularity, m_frame.ownerElement()); 1185} 1186 1187IntPoint EventHandler::lastKnownMousePosition() const 1188{ 1189 return m_lastKnownMousePosition; 1190} 1191 1192Frame* EventHandler::subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult) 1193{ 1194 if (!hitTestResult.isOverWidget()) 1195 return 0; 1196 return subframeForTargetNode(hitTestResult.targetNode()); 1197} 1198 1199Frame* EventHandler::subframeForTargetNode(Node* node) 1200{ 1201 if (!node) 1202 return 0; 1203 1204 auto renderer = node->renderer(); 1205 if (!renderer || !renderer->isWidget()) 1206 return 0; 1207 1208 Widget* widget = toRenderWidget(renderer)->widget(); 1209 if (!widget || !widget->isFrameView()) 1210 return 0; 1211 1212 return &toFrameView(widget)->frame(); 1213} 1214 1215#if ENABLE(CURSOR_SUPPORT) 1216static bool isSubmitImage(Node* node) 1217{ 1218 return node && isHTMLInputElement(node) && toHTMLInputElement(node)->isImageButton(); 1219} 1220 1221// Returns true if the node's editable block is not current focused for editing 1222static bool nodeIsNotBeingEdited(const Node& node, const Frame& frame) 1223{ 1224 return frame.selection().selection().rootEditableElement() != node.rootEditableElement(); 1225} 1226 1227bool EventHandler::useHandCursor(Node* node, bool isOverLink, bool shiftKey) 1228{ 1229 if (!node) 1230 return false; 1231 1232 bool editable = node->hasEditableStyle(); 1233 bool editableLinkEnabled = false; 1234 1235 // If the link is editable, then we need to check the settings to see whether or not the link should be followed 1236 if (editable) { 1237 switch (m_frame.settings().editableLinkBehavior()) { 1238 default: 1239 case EditableLinkDefaultBehavior: 1240 case EditableLinkAlwaysLive: 1241 editableLinkEnabled = true; 1242 break; 1243 1244 case EditableLinkNeverLive: 1245 editableLinkEnabled = false; 1246 break; 1247 1248 case EditableLinkLiveWhenNotFocused: 1249 editableLinkEnabled = nodeIsNotBeingEdited(*node, m_frame) || shiftKey; 1250 break; 1251 1252 case EditableLinkOnlyLiveWithShiftKey: 1253 editableLinkEnabled = shiftKey; 1254 break; 1255 } 1256 } 1257 1258 return ((isOverLink || isSubmitImage(node)) && (!editable || editableLinkEnabled)); 1259} 1260 1261void EventHandler::cursorUpdateTimerFired(Timer<EventHandler>&) 1262{ 1263 ASSERT(m_frame.document()); 1264 updateCursor(); 1265} 1266 1267void EventHandler::updateCursor() 1268{ 1269 if (m_mousePositionIsUnknown) 1270 return; 1271 1272 FrameView* view = m_frame.view(); 1273 if (!view) 1274 return; 1275 1276 RenderView* renderView = view->renderView(); 1277 if (!renderView) 1278 return; 1279 1280 if (!view->shouldSetCursor()) 1281 return; 1282 1283 bool shiftKey; 1284 bool ctrlKey; 1285 bool altKey; 1286 bool metaKey; 1287 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey); 1288 1289 m_frame.document()->updateLayout(); 1290 1291 HitTestRequest request(HitTestRequest::ReadOnly); 1292 HitTestResult result(view->windowToContents(m_lastKnownMousePosition)); 1293 renderView->hitTest(request, result); 1294 1295 OptionalCursor optionalCursor = selectCursor(result, shiftKey); 1296 if (optionalCursor.isCursorChange()) { 1297 m_currentMouseCursor = optionalCursor.cursor(); 1298 view->setCursor(m_currentMouseCursor); 1299 } 1300} 1301 1302OptionalCursor EventHandler::selectCursor(const HitTestResult& result, bool shiftKey) 1303{ 1304 if (m_resizeLayer && m_resizeLayer->inResizeMode()) 1305 return NoCursorChange; 1306 1307 if (!m_frame.page()) 1308 return NoCursorChange; 1309 1310#if ENABLE(PAN_SCROLLING) 1311 if (m_frame.mainFrame().eventHandler().panScrollInProgress()) 1312 return NoCursorChange; 1313#endif 1314 1315 Node* node = result.targetNode(); 1316 if (!node) 1317 return NoCursorChange; 1318 1319 auto renderer = node->renderer(); 1320 RenderStyle* style = renderer ? &renderer->style() : nullptr; 1321 bool horizontalText = !style || style->isHorizontalWritingMode(); 1322 const Cursor& iBeam = horizontalText ? iBeamCursor() : verticalTextCursor(); 1323 1324#if ENABLE(CURSOR_VISIBILITY) 1325 if (style && style->cursorVisibility() == CursorVisibilityAutoHide) 1326 startAutoHideCursorTimer(); 1327 else 1328 cancelAutoHideCursorTimer(); 1329#endif 1330 1331 if (renderer) { 1332 Cursor overrideCursor; 1333 switch (renderer->getCursor(roundedIntPoint(result.localPoint()), overrideCursor)) { 1334 case SetCursorBasedOnStyle: 1335 break; 1336 case SetCursor: 1337 return overrideCursor; 1338 case DoNotSetCursor: 1339 return NoCursorChange; 1340 } 1341 } 1342 1343 if (style && style->cursors()) { 1344 const CursorList* cursors = style->cursors(); 1345 for (unsigned i = 0; i < cursors->size(); ++i) { 1346 StyleImage* styleImage = (*cursors)[i].image(); 1347 if (!styleImage) 1348 continue; 1349 CachedImage* cachedImage = styleImage->cachedImage(); 1350 if (!cachedImage) 1351 continue; 1352 float scale = styleImage->imageScaleFactor(); 1353 // Get hotspot and convert from logical pixels to physical pixels. 1354 IntPoint hotSpot = (*cursors)[i].hotSpot(); 1355 hotSpot.scale(scale, scale); 1356 FloatSize size = cachedImage->imageForRenderer(renderer)->size(); 1357 if (cachedImage->errorOccurred()) 1358 continue; 1359 // Limit the size of cursors (in UI pixels) so that they cannot be 1360 // used to cover UI elements in chrome. 1361 size.scale(1 / scale); 1362 if (size.width() > maximumCursorSize || size.height() > maximumCursorSize) 1363 continue; 1364 1365 Image* image = cachedImage->imageForRenderer(renderer); 1366#if ENABLE(MOUSE_CURSOR_SCALE) 1367 // Ensure no overflow possible in calculations above. 1368 if (scale < minimumCursorScale) 1369 continue; 1370 return Cursor(image, hotSpot, scale); 1371#else 1372 ASSERT(scale == 1); 1373 return Cursor(image, hotSpot); 1374#endif // ENABLE(MOUSE_CURSOR_SCALE) 1375 } 1376 } 1377 1378 // During selection, use an I-beam regardless of the content beneath the cursor. 1379 // If a drag may be starting or we're capturing mouse events for a particular node, don't treat this as a selection. 1380 if (m_mousePressed 1381 && m_mouseDownMayStartSelect 1382#if ENABLE(DRAG_SUPPORT) 1383 && !m_mouseDownMayStartDrag 1384#endif 1385 && m_frame.selection().isCaretOrRange() 1386 && !m_capturingMouseEventsElement) 1387 return iBeam; 1388 1389 switch (style ? style->cursor() : CURSOR_AUTO) { 1390 case CURSOR_AUTO: { 1391 bool editable = node->hasEditableStyle(); 1392 1393 if (useHandCursor(node, result.isOverLink(), shiftKey)) 1394 return handCursor(); 1395 1396 bool inResizer = false; 1397 if (renderer) { 1398 if (RenderLayer* layer = renderer->enclosingLayer()) { 1399 if (FrameView* view = m_frame.view()) 1400 inResizer = layer->isPointInResizeControl(view->windowToContents(roundedIntPoint(result.localPoint()))); 1401 } 1402 } 1403 1404 if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !result.scrollbar()) 1405 return iBeam; 1406 return pointerCursor(); 1407 } 1408 case CURSOR_CROSS: 1409 return crossCursor(); 1410 case CURSOR_POINTER: 1411 return handCursor(); 1412 case CURSOR_MOVE: 1413 return moveCursor(); 1414 case CURSOR_ALL_SCROLL: 1415 return moveCursor(); 1416 case CURSOR_E_RESIZE: 1417 return eastResizeCursor(); 1418 case CURSOR_W_RESIZE: 1419 return westResizeCursor(); 1420 case CURSOR_N_RESIZE: 1421 return northResizeCursor(); 1422 case CURSOR_S_RESIZE: 1423 return southResizeCursor(); 1424 case CURSOR_NE_RESIZE: 1425 return northEastResizeCursor(); 1426 case CURSOR_SW_RESIZE: 1427 return southWestResizeCursor(); 1428 case CURSOR_NW_RESIZE: 1429 return northWestResizeCursor(); 1430 case CURSOR_SE_RESIZE: 1431 return southEastResizeCursor(); 1432 case CURSOR_NS_RESIZE: 1433 return northSouthResizeCursor(); 1434 case CURSOR_EW_RESIZE: 1435 return eastWestResizeCursor(); 1436 case CURSOR_NESW_RESIZE: 1437 return northEastSouthWestResizeCursor(); 1438 case CURSOR_NWSE_RESIZE: 1439 return northWestSouthEastResizeCursor(); 1440 case CURSOR_COL_RESIZE: 1441 return columnResizeCursor(); 1442 case CURSOR_ROW_RESIZE: 1443 return rowResizeCursor(); 1444 case CURSOR_TEXT: 1445 return iBeamCursor(); 1446 case CURSOR_WAIT: 1447 return waitCursor(); 1448 case CURSOR_HELP: 1449 return helpCursor(); 1450 case CURSOR_VERTICAL_TEXT: 1451 return verticalTextCursor(); 1452 case CURSOR_CELL: 1453 return cellCursor(); 1454 case CURSOR_CONTEXT_MENU: 1455 return contextMenuCursor(); 1456 case CURSOR_PROGRESS: 1457 return progressCursor(); 1458 case CURSOR_NO_DROP: 1459 return noDropCursor(); 1460 case CURSOR_ALIAS: 1461 return aliasCursor(); 1462 case CURSOR_COPY: 1463 return copyCursor(); 1464 case CURSOR_NONE: 1465 return noneCursor(); 1466 case CURSOR_NOT_ALLOWED: 1467 return notAllowedCursor(); 1468 case CURSOR_DEFAULT: 1469 return pointerCursor(); 1470 case CURSOR_WEBKIT_ZOOM_IN: 1471 return zoomInCursor(); 1472 case CURSOR_WEBKIT_ZOOM_OUT: 1473 return zoomOutCursor(); 1474 case CURSOR_WEBKIT_GRAB: 1475 return grabCursor(); 1476 case CURSOR_WEBKIT_GRABBING: 1477 return grabbingCursor(); 1478 } 1479 return pointerCursor(); 1480} 1481#endif // ENABLE(CURSOR_SUPPORT) 1482 1483#if ENABLE(CURSOR_VISIBILITY) 1484void EventHandler::startAutoHideCursorTimer() 1485{ 1486 Page* page = m_frame.page(); 1487 if (!page) 1488 return; 1489 1490 m_autoHideCursorTimer.startOneShot(page->settings().timeWithoutMouseMovementBeforeHidingControls()); 1491 1492#if !ENABLE(IOS_TOUCH_EVENTS) 1493 // The fake mouse move event screws up the auto-hide feature (by resetting the auto-hide timer) 1494 // so cancel any pending fake mouse moves. 1495 if (m_fakeMouseMoveEventTimer.isActive()) 1496 m_fakeMouseMoveEventTimer.stop(); 1497#endif 1498} 1499 1500void EventHandler::cancelAutoHideCursorTimer() 1501{ 1502 if (m_autoHideCursorTimer.isActive()) 1503 m_autoHideCursorTimer.stop(); 1504} 1505 1506void EventHandler::autoHideCursorTimerFired(Timer<EventHandler>& timer) 1507{ 1508 ASSERT_UNUSED(timer, &timer == &m_autoHideCursorTimer); 1509 m_currentMouseCursor = noneCursor(); 1510 FrameView* view = m_frame.view(); 1511 if (view && view->isActive()) 1512 view->setCursor(m_currentMouseCursor); 1513} 1514#endif 1515 1516static LayoutPoint documentPointForWindowPoint(Frame& frame, const IntPoint& windowPoint) 1517{ 1518 FrameView* view = frame.view(); 1519 // FIXME: Is it really OK to use the wrong coordinates here when view is 0? 1520 // Historically the code would just crash; this is clearly no worse than that. 1521 return view ? view->windowToContents(windowPoint) : windowPoint; 1522} 1523 1524bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) 1525{ 1526 RefPtr<FrameView> protector(m_frame.view()); 1527 1528 if (InspectorInstrumentation::handleMousePress(m_frame.page())) { 1529 invalidateClick(); 1530 return true; 1531 } 1532 1533#if ENABLE(TOUCH_EVENTS) 1534 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(mouseEvent); 1535 if (defaultPrevented) 1536 return true; 1537#endif 1538 1539 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture); 1540 1541 // FIXME (bug 68185): this call should be made at another abstraction layer 1542 m_frame.loader().resetMultipleFormSubmissionProtection(); 1543 1544#if !ENABLE(IOS_TOUCH_EVENTS) 1545 cancelFakeMouseMoveEvent(); 1546#endif 1547 m_mousePressed = true; 1548 m_capturesDragging = true; 1549 setLastKnownMousePosition(mouseEvent); 1550 m_mouseDownTimestamp = mouseEvent.timestamp(); 1551#if ENABLE(DRAG_SUPPORT) 1552 m_mouseDownMayStartDrag = false; 1553#endif 1554 m_mouseDownMayStartSelect = false; 1555 m_mouseDownMayStartAutoscroll = false; 1556 if (FrameView* view = m_frame.view()) 1557 m_mouseDownPos = view->windowToContents(mouseEvent.position()); 1558 else { 1559 invalidateClick(); 1560 return false; 1561 } 1562 m_mouseDownWasInSubframe = false; 1563 1564 HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowShadowContent); 1565 // Save the document point we generate in case the window coordinate is invalidated by what happens 1566 // when we dispatch the event. 1567 LayoutPoint documentPoint = documentPointForWindowPoint(m_frame, mouseEvent.position()); 1568 MouseEventWithHitTestResults mev = m_frame.document()->prepareMouseEvent(request, documentPoint, mouseEvent); 1569 1570 if (!mev.targetNode()) { 1571 invalidateClick(); 1572 return false; 1573 } 1574 1575 m_mousePressNode = mev.targetNode(); 1576 1577 RefPtr<Frame> subframe = subframeForHitTestResult(mev); 1578 if (subframe && passMousePressEventToSubframe(mev, subframe.get())) { 1579 // Start capturing future events for this frame. We only do this if we didn't clear 1580 // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop. 1581 m_capturesDragging = subframe->eventHandler().capturesDragging(); 1582 if (m_mousePressed && m_capturesDragging) { 1583 m_capturingMouseEventsElement = subframe->ownerElement(); 1584 m_eventHandlerWillResetCapturingMouseEventsElement = true; 1585 } 1586 invalidateClick(); 1587 return true; 1588 } 1589 1590#if ENABLE(PAN_SCROLLING) 1591 // We store whether pan scrolling is in progress before calling stopAutoscrollTimer() 1592 // because it will set m_autoscrollType to NoAutoscroll on return. 1593 bool isPanScrollInProgress = m_frame.mainFrame().eventHandler().panScrollInProgress(); 1594 stopAutoscrollTimer(); 1595 if (isPanScrollInProgress) { 1596 // We invalidate the click when exiting pan scrolling so that we don't inadvertently navigate 1597 // away from the current page (e.g. the click was on a hyperlink). See <rdar://problem/6095023>. 1598 invalidateClick(); 1599 return true; 1600 } 1601#endif 1602 1603 m_clickCount = mouseEvent.clickCount(); 1604 m_clickNode = mev.targetNode(); 1605 1606 if (!m_clickNode) { 1607 invalidateClick(); 1608 return false; 1609 } 1610 1611 if (FrameView* view = m_frame.view()) { 1612 RenderLayer* layer = m_clickNode->renderer() ? m_clickNode->renderer()->enclosingLayer() : 0; 1613 IntPoint p = view->windowToContents(mouseEvent.position()); 1614 if (layer && layer->isPointInResizeControl(p)) { 1615 layer->setInResizeMode(true); 1616 m_resizeLayer = layer; 1617 m_offsetFromResizeCorner = layer->offsetFromResizeCorner(p); 1618 invalidateClick(); 1619 return true; 1620 } 1621 } 1622 1623 m_frame.selection().setCaretBlinkingSuspended(true); 1624 1625 bool swallowEvent = !dispatchMouseEvent(eventNames().mousedownEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true); 1626 m_capturesDragging = !swallowEvent || mev.scrollbar(); 1627 1628 // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults 1629 // in case the scrollbar widget was destroyed when the mouse event was handled. 1630 if (mev.scrollbar()) { 1631 const bool wasLastScrollBar = mev.scrollbar() == m_lastScrollbarUnderMouse.get(); 1632 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent); 1633 mev = m_frame.document()->prepareMouseEvent(request, documentPoint, mouseEvent); 1634 if (wasLastScrollBar && mev.scrollbar() != m_lastScrollbarUnderMouse.get()) 1635 m_lastScrollbarUnderMouse = 0; 1636 } 1637 1638 if (swallowEvent) { 1639 // scrollbars should get events anyway, even disabled controls might be scrollable 1640 Scrollbar* scrollbar = mev.scrollbar(); 1641 1642 updateLastScrollbarUnderMouse(scrollbar, true); 1643 1644 if (scrollbar) 1645 passMousePressEventToScrollbar(mev, scrollbar); 1646 } else { 1647 // Refetch the event target node if it currently is the shadow node inside an <input> element. 1648 // If a mouse event handler changes the input element type to one that has a widget associated, 1649 // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the 1650 // event target node can't still be the shadow node. 1651 if (mev.targetNode()->isShadowRoot() && isHTMLInputElement(toShadowRoot(mev.targetNode())->hostElement())) { 1652 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent); 1653 mev = m_frame.document()->prepareMouseEvent(request, documentPoint, mouseEvent); 1654 } 1655 1656 FrameView* view = m_frame.view(); 1657 Scrollbar* scrollbar = view ? view->scrollbarAtPoint(mouseEvent.position()) : 0; 1658 if (!scrollbar) 1659 scrollbar = mev.scrollbar(); 1660 1661 updateLastScrollbarUnderMouse(scrollbar, true); 1662 1663 if (scrollbar && passMousePressEventToScrollbar(mev, scrollbar)) 1664 swallowEvent = true; 1665 else 1666 swallowEvent = handleMousePressEvent(mev); 1667 } 1668 1669 return swallowEvent; 1670} 1671 1672// This method only exists for platforms that don't know how to deliver 1673bool EventHandler::handleMouseDoubleClickEvent(const PlatformMouseEvent& mouseEvent) 1674{ 1675 RefPtr<FrameView> protector(m_frame.view()); 1676 1677 m_frame.selection().setCaretBlinkingSuspended(false); 1678 1679 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture); 1680 1681 // We get this instead of a second mouse-up 1682 m_mousePressed = false; 1683 setLastKnownMousePosition(mouseEvent); 1684 1685 HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowShadowContent); 1686 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent); 1687 Frame* subframe = subframeForHitTestResult(mev); 1688 if (m_eventHandlerWillResetCapturingMouseEventsElement) 1689 m_capturingMouseEventsElement = nullptr; 1690 if (subframe && passMousePressEventToSubframe(mev, subframe)) 1691 return true; 1692 1693 m_clickCount = mouseEvent.clickCount(); 1694 bool swallowMouseUpEvent = !dispatchMouseEvent(eventNames().mouseupEvent, mev.targetNode(), true, m_clickCount, mouseEvent, false); 1695 1696 bool swallowClickEvent = mouseEvent.button() != RightButton && mev.targetNode() == m_clickNode && !dispatchMouseEvent(eventNames().clickEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true); 1697 1698 if (m_lastScrollbarUnderMouse) 1699 swallowMouseUpEvent = m_lastScrollbarUnderMouse->mouseUp(mouseEvent); 1700 1701 bool swallowMouseReleaseEvent = !swallowMouseUpEvent && handleMouseReleaseEvent(mev); 1702 1703 invalidateClick(); 1704 1705 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent; 1706} 1707 1708static RenderLayer* layerForNode(Node* node) 1709{ 1710 if (!node) 1711 return 0; 1712 1713 auto renderer = node->renderer(); 1714 if (!renderer) 1715 return 0; 1716 1717 RenderLayer* layer = renderer->enclosingLayer(); 1718 if (!layer) 1719 return 0; 1720 1721 return layer; 1722} 1723 1724bool EventHandler::mouseMoved(const PlatformMouseEvent& event) 1725{ 1726 RefPtr<FrameView> protector(m_frame.view()); 1727 MaximumDurationTracker maxDurationTracker(&m_maxMouseMovedDuration); 1728 1729 HitTestResult hoveredNode = HitTestResult(LayoutPoint()); 1730 bool result = handleMouseMoveEvent(event, &hoveredNode); 1731 1732 Page* page = m_frame.page(); 1733 if (!page) 1734 return result; 1735 1736 if (RenderLayer* layer = layerForNode(hoveredNode.innerNode())) { 1737 if (FrameView* frameView = m_frame.view()) { 1738 if (frameView->containsScrollableArea(layer)) 1739 layer->mouseMovedInContentArea(); 1740 } 1741 } 1742 1743 if (FrameView* frameView = m_frame.view()) 1744 frameView->mouseMovedInContentArea(); 1745 1746 hoveredNode.setToNonShadowAncestor(); 1747 page->chrome().mouseDidMoveOverElement(hoveredNode, event.modifierFlags()); 1748 page->chrome().setToolTip(hoveredNode); 1749 return result; 1750} 1751 1752bool EventHandler::passMouseMovedEventToScrollbars(const PlatformMouseEvent& event) 1753{ 1754 HitTestResult hoveredNode; 1755 return handleMouseMoveEvent(event, &hoveredNode, true); 1756} 1757 1758bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, HitTestResult* hoveredNode, bool onlyUpdateScrollbars) 1759{ 1760#if ENABLE(TOUCH_EVENTS) 1761 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(mouseEvent); 1762 if (defaultPrevented) 1763 return true; 1764#endif 1765 1766 RefPtr<FrameView> protector(m_frame.view()); 1767 1768 setLastKnownMousePosition(mouseEvent); 1769 1770 if (m_hoverTimer.isActive()) 1771 m_hoverTimer.stop(); 1772 1773#if ENABLE(CURSOR_SUPPORT) 1774 m_cursorUpdateTimer.stop(); 1775#endif 1776 1777#if !ENABLE(IOS_TOUCH_EVENTS) 1778 cancelFakeMouseMoveEvent(); 1779#endif 1780 1781 if (m_svgPan) { 1782 toSVGDocument(m_frame.document())->updatePan(m_frame.view()->windowToContents(m_lastKnownMousePosition)); 1783 return true; 1784 } 1785 1786 if (m_frameSetBeingResized) 1787 return !dispatchMouseEvent(eventNames().mousemoveEvent, m_frameSetBeingResized.get(), false, 0, mouseEvent, false); 1788 1789 // On iOS, our scrollbars are managed by UIKit. 1790#if !PLATFORM(IOS) 1791 // Send events right to a scrollbar if the mouse is pressed. 1792 if (m_lastScrollbarUnderMouse && m_mousePressed) 1793 return m_lastScrollbarUnderMouse->mouseMoved(mouseEvent); 1794#endif 1795 1796 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move | HitTestRequest::DisallowShadowContent | HitTestRequest::AllowFrameScrollbars; 1797 if (m_mousePressed) 1798 hitType |= HitTestRequest::Active; 1799 else if (onlyUpdateScrollbars) { 1800 // Mouse events should be treated as "read-only" if we're updating only scrollbars. This 1801 // means that :hover and :active freeze in the state they were in, rather than updating 1802 // for nodes the mouse moves while the window is not key (which will be the case if 1803 // onlyUpdateScrollbars is true). 1804 hitType |= HitTestRequest::ReadOnly; 1805 } 1806 1807#if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS) 1808 // Treat any mouse move events as readonly if the user is currently touching the screen. 1809 if (m_touchPressed) 1810 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly; 1811#endif 1812 HitTestRequest request(hitType); 1813 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent); 1814 if (hoveredNode) 1815 *hoveredNode = mev.hitTestResult(); 1816 1817 if (m_resizeLayer && m_resizeLayer->inResizeMode()) 1818 m_resizeLayer->resize(mouseEvent, m_offsetFromResizeCorner); 1819 else { 1820 Scrollbar* scrollbar = mev.scrollbar(); 1821 updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed); 1822 1823 // On iOS, our scrollbars are managed by UIKit. 1824#if !PLATFORM(IOS) 1825 if (!m_mousePressed && scrollbar) 1826 scrollbar->mouseMoved(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering. 1827#endif 1828 if (onlyUpdateScrollbars) 1829 return true; 1830 } 1831 1832 bool swallowEvent = false; 1833 RefPtr<Frame> newSubframe = m_capturingMouseEventsElement.get() ? subframeForTargetNode(m_capturingMouseEventsElement.get()) : subframeForHitTestResult(mev); 1834 1835 // We want mouseouts to happen first, from the inside out. First send a move event to the last subframe so that it will fire mouseouts. 1836 if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree().isDescendantOf(&m_frame) && m_lastMouseMoveEventSubframe != newSubframe) 1837 passMouseMoveEventToSubframe(mev, m_lastMouseMoveEventSubframe.get()); 1838 1839 if (newSubframe) { 1840 // Update over/out state before passing the event to the subframe. 1841 updateMouseEventTargetNode(mev.targetNode(), mouseEvent, true); 1842 1843 // Event dispatch in updateMouseEventTargetNode may have caused the subframe of the target 1844 // node to be detached from its FrameView, in which case the event should not be passed. 1845 if (newSubframe->view()) 1846 swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(), hoveredNode); 1847#if ENABLE(CURSOR_SUPPORT) 1848 } else { 1849 if (FrameView* view = m_frame.view()) { 1850 OptionalCursor optionalCursor = selectCursor(mev.hitTestResult(), mouseEvent.shiftKey()); 1851 if (optionalCursor.isCursorChange()) { 1852 m_currentMouseCursor = optionalCursor.cursor(); 1853 view->setCursor(m_currentMouseCursor); 1854 } 1855 } 1856#endif 1857 } 1858 1859 m_lastMouseMoveEventSubframe = newSubframe; 1860 1861 if (swallowEvent) 1862 return true; 1863 1864 swallowEvent = !dispatchMouseEvent(eventNames().mousemoveEvent, mev.targetNode(), false, 0, mouseEvent, true); 1865#if ENABLE(DRAG_SUPPORT) 1866 if (!swallowEvent) 1867 swallowEvent = handleMouseDraggedEvent(mev); 1868#endif // ENABLE(DRAG_SUPPORT) 1869 1870 return swallowEvent; 1871} 1872 1873void EventHandler::invalidateClick() 1874{ 1875 m_clickCount = 0; 1876 m_clickNode = 0; 1877} 1878 1879inline static bool mouseIsReleasedOnPressedElement(Node* targetNode, Node* clickNode) 1880{ 1881 if (targetNode == clickNode) 1882 return true; 1883 1884 if (!targetNode) 1885 return false; 1886 1887 ShadowRoot* containingShadowRoot = targetNode->containingShadowRoot(); 1888 if (!containingShadowRoot) 1889 return false; 1890 1891 // FIXME: When an element in UA ShadowDOM (e.g. inner element in <input>) is clicked, 1892 // we assume that the host element is clicked. This is necessary for implementing <input type="range"> etc. 1893 // However, we should not check ShadowRoot type basically. 1894 // https://bugs.webkit.org/show_bug.cgi?id=108047 1895 if (containingShadowRoot->type() != ShadowRoot::UserAgentShadowRoot) 1896 return false; 1897 1898 Node* adjustedTargetNode = targetNode->shadowHost(); 1899 Node* adjustedClickNode = clickNode ? clickNode->shadowHost() : 0; 1900 return adjustedTargetNode == adjustedClickNode; 1901} 1902 1903bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent) 1904{ 1905 RefPtr<FrameView> protector(m_frame.view()); 1906 1907 m_frame.selection().setCaretBlinkingSuspended(false); 1908 1909#if ENABLE(TOUCH_EVENTS) 1910 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(mouseEvent); 1911 if (defaultPrevented) 1912 return true; 1913#endif 1914 1915 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture); 1916 1917#if ENABLE(PAN_SCROLLING) 1918 m_autoscrollController->handleMouseReleaseEvent(mouseEvent); 1919#endif 1920 1921 m_mousePressed = false; 1922 setLastKnownMousePosition(mouseEvent); 1923 1924 if (m_svgPan) { 1925 m_svgPan = false; 1926 toSVGDocument(m_frame.document())->updatePan(m_frame.view()->windowToContents(m_lastKnownMousePosition)); 1927 return true; 1928 } 1929 1930 if (m_frameSetBeingResized) 1931 return !dispatchMouseEvent(eventNames().mouseupEvent, m_frameSetBeingResized.get(), true, m_clickCount, mouseEvent, false); 1932 1933 if (m_lastScrollbarUnderMouse) { 1934 invalidateClick(); 1935 m_lastScrollbarUnderMouse->mouseUp(mouseEvent); 1936 bool cancelable = true; 1937 bool setUnder = false; 1938 return !dispatchMouseEvent(eventNames().mouseupEvent, m_lastElementUnderMouse.get(), cancelable, m_clickCount, mouseEvent, setUnder); 1939 } 1940 1941 HitTestRequest request(HitTestRequest::Release | HitTestRequest::DisallowShadowContent); 1942 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent); 1943 Frame* subframe = m_capturingMouseEventsElement.get() ? subframeForTargetNode(m_capturingMouseEventsElement.get()) : subframeForHitTestResult(mev); 1944 if (m_eventHandlerWillResetCapturingMouseEventsElement) 1945 m_capturingMouseEventsElement = nullptr; 1946 if (subframe && passMouseReleaseEventToSubframe(mev, subframe)) 1947 return true; 1948 1949 bool swallowMouseUpEvent = !dispatchMouseEvent(eventNames().mouseupEvent, mev.targetNode(), true, m_clickCount, mouseEvent, false); 1950 1951 bool contextMenuEvent = mouseEvent.button() == RightButton; 1952 1953 bool swallowClickEvent = m_clickCount > 0 && !contextMenuEvent && mouseIsReleasedOnPressedElement(mev.targetNode(), m_clickNode.get()) && !dispatchMouseEvent(eventNames().clickEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true); 1954 1955 if (m_resizeLayer) { 1956 m_resizeLayer->setInResizeMode(false); 1957 m_resizeLayer = 0; 1958 } 1959 1960 bool swallowMouseReleaseEvent = false; 1961 if (!swallowMouseUpEvent) 1962 swallowMouseReleaseEvent = handleMouseReleaseEvent(mev); 1963 1964 invalidateClick(); 1965 1966 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent; 1967} 1968 1969bool EventHandler::handlePasteGlobalSelection(const PlatformMouseEvent& mouseEvent) 1970{ 1971 // If the event was a middle click, attempt to copy global selection in after 1972 // the newly set caret position. 1973 // 1974 // This code is called from either the mouse up or mouse down handling. There 1975 // is some debate about when the global selection is pasted: 1976 // xterm: pastes on up. 1977 // GTK: pastes on down. 1978 // Qt: pastes on up. 1979 // Firefox: pastes on up. 1980 // Chromium: pastes on up. 1981 // 1982 // There is something of a webcompat angle to this well, as highlighted by 1983 // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on 1984 // down then the text is pasted just before the onclick handler runs and 1985 // clears the text box. So it's important this happens after the event 1986 // handlers have been fired. 1987#if PLATFORM(GTK) 1988 if (mouseEvent.type() != PlatformEvent::MousePressed) 1989 return false; 1990#else 1991 if (mouseEvent.type() != PlatformEvent::MouseReleased) 1992 return false; 1993#endif 1994 1995 if (!m_frame.page()) 1996 return false; 1997 Frame& focusFrame = m_frame.page()->focusController().focusedOrMainFrame(); 1998 // Do not paste here if the focus was moved somewhere else. 1999 if (&m_frame == &focusFrame && m_frame.editor().client()->supportsGlobalSelection()) 2000 return m_frame.editor().command(ASCIILiteral("PasteGlobalSelection")).execute(); 2001 2002 return false; 2003} 2004 2005#if ENABLE(DRAG_SUPPORT) 2006 2007bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Element& dragTarget, const PlatformMouseEvent& event, DataTransfer* dataTransfer) 2008{ 2009 FrameView* view = m_frame.view(); 2010 2011 // FIXME: We might want to dispatch a dragleave even if the view is gone. 2012 if (!view) 2013 return false; 2014 2015 view->disableLayerFlushThrottlingTemporarilyForInteraction(); 2016 RefPtr<MouseEvent> me = MouseEvent::create(eventType, 2017 true, true, event.timestamp(), m_frame.document()->defaultView(), 2018 0, event.globalPosition().x(), event.globalPosition().y(), event.position().x(), event.position().y(), 2019#if ENABLE(POINTER_LOCK) 2020 event.movementDelta().x(), event.movementDelta().y(), 2021#endif 2022 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(), 2023 0, 0, dataTransfer); 2024 2025 dragTarget.dispatchEvent(me.get(), IGNORE_EXCEPTION); 2026 return me->defaultPrevented(); 2027} 2028 2029static bool targetIsFrame(Node* target, Frame*& frame) 2030{ 2031 if (!target) 2032 return false; 2033 2034 if (!target->hasTagName(frameTag) && !target->hasTagName(iframeTag)) 2035 return false; 2036 2037 frame = toHTMLFrameElementBase(target)->contentFrame(); 2038 2039 return true; 2040} 2041 2042static DragOperation convertDropZoneOperationToDragOperation(const String& dragOperation) 2043{ 2044 if (dragOperation == "copy") 2045 return DragOperationCopy; 2046 if (dragOperation == "move") 2047 return DragOperationMove; 2048 if (dragOperation == "link") 2049 return DragOperationLink; 2050 return DragOperationNone; 2051} 2052 2053static String convertDragOperationToDropZoneOperation(DragOperation operation) 2054{ 2055 switch (operation) { 2056 case DragOperationCopy: 2057 return ASCIILiteral("copy"); 2058 case DragOperationMove: 2059 return ASCIILiteral("move"); 2060 case DragOperationLink: 2061 return ASCIILiteral("link"); 2062 default: 2063 return ASCIILiteral("copy"); 2064 } 2065} 2066 2067static bool hasDropZoneType(DataTransfer& dataTransfer, const String& keyword) 2068{ 2069 if (keyword.startsWith("file:")) 2070 return dataTransfer.hasFileOfType(keyword.substring(5)); 2071 2072 if (keyword.startsWith("string:")) 2073 return dataTransfer.hasStringOfType(keyword.substring(7)); 2074 2075 return false; 2076} 2077 2078static bool findDropZone(Node* target, DataTransfer* dataTransfer) 2079{ 2080 Element* element = target->isElementNode() ? toElement(target) : target->parentElement(); 2081 for (; element; element = element->parentElement()) { 2082 bool matched = false; 2083 String dropZoneStr = element->fastGetAttribute(webkitdropzoneAttr); 2084 2085 if (dropZoneStr.isEmpty()) 2086 continue; 2087 2088 dropZoneStr = dropZoneStr.lower(); 2089 2090 SpaceSplitString keywords(dropZoneStr, false); 2091 if (keywords.isEmpty()) 2092 continue; 2093 2094 DragOperation dragOperation = DragOperationNone; 2095 for (unsigned int i = 0; i < keywords.size(); i++) { 2096 DragOperation op = convertDropZoneOperationToDragOperation(keywords[i]); 2097 if (op != DragOperationNone) { 2098 if (dragOperation == DragOperationNone) 2099 dragOperation = op; 2100 } else 2101 matched = matched || hasDropZoneType(*dataTransfer, keywords[i].string()); 2102 2103 if (matched && dragOperation != DragOperationNone) 2104 break; 2105 } 2106 if (matched) { 2107 dataTransfer->setDropEffect(convertDragOperationToDropZoneOperation(dragOperation)); 2108 return true; 2109 } 2110 } 2111 return false; 2112} 2113 2114bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, DataTransfer* dataTransfer) 2115{ 2116 bool accept = false; 2117 2118 if (!m_frame.view()) 2119 return false; 2120 2121 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent); 2122 MouseEventWithHitTestResults mev = prepareMouseEvent(request, event); 2123 2124 RefPtr<Element> newTarget; 2125 if (Node* targetNode = mev.targetNode()) { 2126 // Drag events should never go to non-element nodes (following IE, and proper mouseover/out dispatch) 2127 if (!targetNode->isElementNode()) 2128 newTarget = targetNode->parentOrShadowHostElement(); 2129 else 2130 newTarget = toElement(targetNode); 2131 } 2132 2133 m_autoscrollController->updateDragAndDrop(newTarget.get(), event.position(), event.timestamp()); 2134 2135 if (m_dragTarget != newTarget) { 2136 // FIXME: this ordering was explicitly chosen to match WinIE. However, 2137 // it is sometimes incorrect when dragging within subframes, as seen with 2138 // LayoutTests/fast/events/drag-in-frames.html. 2139 // 2140 // Moreover, this ordering conforms to section 7.9.4 of the HTML 5 spec. <http://dev.w3.org/html5/spec/Overview.html#drag-and-drop-processing-model>. 2141 Frame* targetFrame; 2142 if (targetIsFrame(newTarget.get(), targetFrame)) { 2143 if (targetFrame) 2144 accept = targetFrame->eventHandler().updateDragAndDrop(event, dataTransfer); 2145 } else if (newTarget) { 2146 // As per section 7.9.4 of the HTML 5 spec., we must always fire a drag event before firing a dragenter, dragleave, or dragover event. 2147 if (dragState().source && dragState().shouldDispatchEvents) { 2148 // for now we don't care if event handler cancels default behavior, since there is none 2149 dispatchDragSrcEvent(eventNames().dragEvent, event); 2150 } 2151 accept = dispatchDragEvent(eventNames().dragenterEvent, *newTarget, event, dataTransfer); 2152 if (!accept) 2153 accept = findDropZone(newTarget.get(), dataTransfer); 2154 } 2155 2156 if (targetIsFrame(m_dragTarget.get(), targetFrame)) { 2157 if (targetFrame) 2158 accept = targetFrame->eventHandler().updateDragAndDrop(event, dataTransfer); 2159 } else if (m_dragTarget) 2160 dispatchDragEvent(eventNames().dragleaveEvent, *m_dragTarget, event, dataTransfer); 2161 2162 if (newTarget) { 2163 // We do not explicitly call dispatchDragEvent here because it could ultimately result in the appearance that 2164 // two dragover events fired. So, we mark that we should only fire a dragover event on the next call to this function. 2165 m_shouldOnlyFireDragOverEvent = true; 2166 } 2167 } else { 2168 Frame* targetFrame; 2169 if (targetIsFrame(newTarget.get(), targetFrame)) { 2170 if (targetFrame) 2171 accept = targetFrame->eventHandler().updateDragAndDrop(event, dataTransfer); 2172 } else if (newTarget) { 2173 // Note, when dealing with sub-frames, we may need to fire only a dragover event as a drag event may have been fired earlier. 2174 if (!m_shouldOnlyFireDragOverEvent && dragState().source && dragState().shouldDispatchEvents) { 2175 // for now we don't care if event handler cancels default behavior, since there is none 2176 dispatchDragSrcEvent(eventNames().dragEvent, event); 2177 } 2178 accept = dispatchDragEvent(eventNames().dragoverEvent, *newTarget, event, dataTransfer); 2179 if (!accept) 2180 accept = findDropZone(newTarget.get(), dataTransfer); 2181 m_shouldOnlyFireDragOverEvent = false; 2182 } 2183 } 2184 m_dragTarget = newTarget.release(); 2185 return accept; 2186} 2187 2188void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, DataTransfer* dataTransfer) 2189{ 2190 Frame* targetFrame; 2191 if (targetIsFrame(m_dragTarget.get(), targetFrame)) { 2192 if (targetFrame) 2193 targetFrame->eventHandler().cancelDragAndDrop(event, dataTransfer); 2194 } else if (m_dragTarget) { 2195 if (dragState().source && dragState().shouldDispatchEvents) 2196 dispatchDragSrcEvent(eventNames().dragEvent, event); 2197 dispatchDragEvent(eventNames().dragleaveEvent, *m_dragTarget, event, dataTransfer); 2198 } 2199 clearDragState(); 2200} 2201 2202bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, DataTransfer* dataTransfer) 2203{ 2204 Frame* targetFrame; 2205 bool preventedDefault = false; 2206 if (targetIsFrame(m_dragTarget.get(), targetFrame)) { 2207 if (targetFrame) 2208 preventedDefault = targetFrame->eventHandler().performDragAndDrop(event, dataTransfer); 2209 } else if (m_dragTarget) 2210 preventedDefault = dispatchDragEvent(eventNames().dropEvent, *m_dragTarget, event, dataTransfer); 2211 clearDragState(); 2212 return preventedDefault; 2213} 2214 2215void EventHandler::clearDragState() 2216{ 2217 stopAutoscrollTimer(); 2218 m_dragTarget = nullptr; 2219 m_capturingMouseEventsElement = nullptr; 2220 m_shouldOnlyFireDragOverEvent = false; 2221#if PLATFORM(COCOA) 2222 m_sendingEventToSubview = false; 2223#endif 2224} 2225#endif // ENABLE(DRAG_SUPPORT) 2226 2227void EventHandler::setCapturingMouseEventsElement(PassRefPtr<Element> element) 2228{ 2229 m_capturingMouseEventsElement = element; 2230 m_eventHandlerWillResetCapturingMouseEventsElement = false; 2231} 2232 2233MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mev) 2234{ 2235 ASSERT(m_frame.document()); 2236 return m_frame.document()->prepareMouseEvent(request, documentPointForWindowPoint(m_frame, mev.position()), mev); 2237} 2238 2239static inline SVGElementInstance* instanceAssociatedWithShadowTreeElement(Node* referenceNode) 2240{ 2241 if (!referenceNode || !referenceNode->isSVGElement()) 2242 return 0; 2243 2244 ShadowRoot* shadowRoot = referenceNode->containingShadowRoot(); 2245 if (!shadowRoot) 2246 return 0; 2247 2248 Element* shadowTreeParentElement = shadowRoot->hostElement(); 2249 if (!shadowTreeParentElement || !shadowTreeParentElement->hasTagName(useTag)) 2250 return 0; 2251 2252 return toSVGUseElement(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode); 2253} 2254 2255static RenderElement* nearestCommonHoverAncestor(RenderElement* obj1, RenderElement* obj2) 2256{ 2257 if (!obj1 || !obj2) 2258 return nullptr; 2259 2260 for (RenderElement* currObj1 = obj1; currObj1; currObj1 = currObj1->hoverAncestor()) { 2261 for (RenderElement* currObj2 = obj2; currObj2; currObj2 = currObj2->hoverAncestor()) { 2262 if (currObj1 == currObj2) 2263 return currObj1; 2264 } 2265 } 2266 2267 return nullptr; 2268} 2269 2270static bool hierarchyHasCapturingEventListeners(Element* element, const AtomicString& eventName) 2271{ 2272 for (ContainerNode* curr = element; curr; curr = curr->parentOrShadowHostNode()) { 2273 if (curr->hasCapturingEventListeners(eventName)) 2274 return true; 2275 } 2276 return false; 2277} 2278 2279void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMouseEvent& mouseEvent, bool fireMouseOverOut) 2280{ 2281 Element* targetElement = nullptr; 2282 2283 // If we're capturing, we always go right to that element. 2284 if (m_capturingMouseEventsElement) 2285 targetElement = m_capturingMouseEventsElement.get(); 2286 else if (targetNode) { 2287 // If the target node is a non-element, dispatch on the parent. <rdar://problem/4196646> 2288 if (!targetNode->isElementNode()) 2289 targetElement = targetNode->parentOrShadowHostElement(); 2290 else 2291 targetElement = toElement(targetNode); 2292 } 2293 2294 m_elementUnderMouse = targetElement; 2295 m_instanceUnderMouse = instanceAssociatedWithShadowTreeElement(targetElement); 2296 2297 // <use> shadow tree elements may have been recloned, update node under mouse in any case 2298 if (m_lastInstanceUnderMouse) { 2299 SVGElement* lastCorrespondingElement = m_lastInstanceUnderMouse->correspondingElement(); 2300 SVGElement* lastCorrespondingUseElement = m_lastInstanceUnderMouse->correspondingUseElement(); 2301 2302 if (lastCorrespondingElement && lastCorrespondingUseElement) { 2303 HashSet<SVGElementInstance*> instances = lastCorrespondingElement->instancesForElement(); 2304 2305 // Locate the recloned shadow tree element for our corresponding instance 2306 HashSet<SVGElementInstance*>::iterator end = instances.end(); 2307 for (HashSet<SVGElementInstance*>::iterator it = instances.begin(); it != end; ++it) { 2308 SVGElementInstance* instance = (*it); 2309 ASSERT(instance->correspondingElement() == lastCorrespondingElement); 2310 2311 if (instance == m_lastInstanceUnderMouse) 2312 continue; 2313 2314 if (instance->correspondingUseElement() != lastCorrespondingUseElement) 2315 continue; 2316 2317 SVGElement* shadowTreeElement = instance->shadowTreeElement(); 2318 if (!shadowTreeElement->inDocument() || m_lastElementUnderMouse == shadowTreeElement) 2319 continue; 2320 2321 m_lastElementUnderMouse = shadowTreeElement; 2322 m_lastInstanceUnderMouse = instance; 2323 break; 2324 } 2325 } 2326 } 2327 2328 // Fire mouseout/mouseover if the mouse has shifted to a different node. 2329 if (fireMouseOverOut) { 2330 RenderLayer* layerForLastNode = layerForNode(m_lastElementUnderMouse.get()); 2331 RenderLayer* layerForNodeUnderMouse = layerForNode(m_elementUnderMouse.get()); 2332 Page* page = m_frame.page(); 2333 2334 if (m_lastElementUnderMouse && (!m_elementUnderMouse || &m_elementUnderMouse->document() != m_frame.document())) { 2335 // The mouse has moved between frames. 2336 if (Frame* frame = m_lastElementUnderMouse->document().frame()) { 2337 if (FrameView* frameView = frame->view()) 2338 frameView->mouseExitedContentArea(); 2339 } 2340 } else if (page && (layerForLastNode && (!layerForNodeUnderMouse || layerForNodeUnderMouse != layerForLastNode))) { 2341 // The mouse has moved between layers. 2342 if (Frame* frame = m_lastElementUnderMouse->document().frame()) { 2343 if (FrameView* frameView = frame->view()) { 2344 if (frameView->containsScrollableArea(layerForLastNode)) 2345 layerForLastNode->mouseExitedContentArea(); 2346 } 2347 } 2348 } 2349 2350 if (m_elementUnderMouse && (!m_lastElementUnderMouse || &m_lastElementUnderMouse->document() != m_frame.document())) { 2351 // The mouse has moved between frames. 2352 if (Frame* frame = m_elementUnderMouse->document().frame()) { 2353 if (FrameView* frameView = frame->view()) 2354 frameView->mouseEnteredContentArea(); 2355 } 2356 } else if (page && (layerForNodeUnderMouse && (!layerForLastNode || layerForNodeUnderMouse != layerForLastNode))) { 2357 // The mouse has moved between layers. 2358 if (Frame* frame = m_elementUnderMouse->document().frame()) { 2359 if (FrameView* frameView = frame->view()) { 2360 if (frameView->containsScrollableArea(layerForNodeUnderMouse)) 2361 layerForNodeUnderMouse->mouseEnteredContentArea(); 2362 } 2363 } 2364 } 2365 2366 if (m_lastElementUnderMouse && &m_lastElementUnderMouse->document() != m_frame.document()) { 2367 m_lastElementUnderMouse = nullptr; 2368 m_lastScrollbarUnderMouse = 0; 2369 m_lastInstanceUnderMouse = 0; 2370 } 2371 2372 if (m_lastElementUnderMouse != m_elementUnderMouse) { 2373 // mouseenter and mouseleave events are only dispatched if there is a capturing eventhandler on an ancestor 2374 // or a normal eventhandler on the element itself (they don't bubble). 2375 // This optimization is necessary since these events can cause O(n^2) capturing event-handler checks. 2376 bool hasCapturingMouseEnterListener = hierarchyHasCapturingEventListeners(m_elementUnderMouse.get(), eventNames().mouseenterEvent); 2377 bool hasCapturingMouseLeaveListener = hierarchyHasCapturingEventListeners(m_lastElementUnderMouse.get(), eventNames().mouseleaveEvent); 2378 2379 RenderElement* oldHoverRenderer = m_lastElementUnderMouse ? m_lastElementUnderMouse->renderer() : nullptr; 2380 RenderElement* newHoverRenderer = m_elementUnderMouse ? m_elementUnderMouse->renderer() : nullptr; 2381 RenderElement* ancestor = nearestCommonHoverAncestor(oldHoverRenderer, newHoverRenderer); 2382 2383 Vector<Ref<Element>, 32> leftElementsChain; 2384 if (oldHoverRenderer) { 2385 for (RenderElement* curr = oldHoverRenderer; curr && curr != ancestor; curr = curr->hoverAncestor()) { 2386 if (Element* element = curr->element()) 2387 leftElementsChain.append(*element); 2388 } 2389 } else { 2390 // If the old hovered element is not null but it's renderer is, it was probably detached. 2391 // In this case, the old hovered element (and its ancestors) must be updated, to ensure it's normal style is re-applied. 2392 for (Element* element = m_lastElementUnderMouse.get(); element; element = element->parentElement()) 2393 leftElementsChain.append(*element); 2394 } 2395 2396 Vector<Ref<Element>, 32> enteredElementsChain; 2397 const Element* ancestorElement = ancestor ? ancestor->element() : nullptr; 2398 for (RenderElement* curr = newHoverRenderer; curr; curr = curr->hoverAncestor()) { 2399 if (Element *element = curr->element()) { 2400 if (element == ancestorElement) 2401 break; 2402 enteredElementsChain.append(*element); 2403 } 2404 } 2405 2406 // Send mouseout event to the old node. 2407 if (m_lastElementUnderMouse) 2408 m_lastElementUnderMouse->dispatchMouseEvent(mouseEvent, eventNames().mouseoutEvent, 0, m_elementUnderMouse.get()); 2409 2410 // Send mouseleave to the node hierarchy no longer under the mouse. 2411 for (size_t i = 0; i < leftElementsChain.size(); ++i) { 2412 if (hasCapturingMouseLeaveListener || leftElementsChain[i]->hasEventListeners(eventNames().mouseleaveEvent)) 2413 leftElementsChain[i]->dispatchMouseEvent(mouseEvent, eventNames().mouseleaveEvent, 0, m_elementUnderMouse.get()); 2414 } 2415 2416 // Send mouseover event to the new node. 2417 if (m_elementUnderMouse) 2418 m_elementUnderMouse->dispatchMouseEvent(mouseEvent, eventNames().mouseoverEvent, 0, m_lastElementUnderMouse.get()); 2419 2420 // Send mouseleave event to the nodes hierarchy under the mouse. 2421 for (size_t i = 0, size = enteredElementsChain.size(); i < size; ++i) { 2422 if (hasCapturingMouseEnterListener || enteredElementsChain[i]->hasEventListeners(eventNames().mouseenterEvent)) 2423 enteredElementsChain[i]->dispatchMouseEvent(mouseEvent, eventNames().mouseenterEvent, 0, m_lastElementUnderMouse.get()); 2424 } 2425 } 2426 m_lastElementUnderMouse = m_elementUnderMouse; 2427 m_lastInstanceUnderMouse = instanceAssociatedWithShadowTreeElement(m_elementUnderMouse.get()); 2428 } 2429} 2430 2431bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool /*cancelable*/, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder) 2432{ 2433 if (FrameView* view = m_frame.view()) 2434 view->disableLayerFlushThrottlingTemporarilyForInteraction(); 2435 2436 updateMouseEventTargetNode(targetNode, mouseEvent, setUnder); 2437 2438 bool swallowEvent = false; 2439 2440 if (m_elementUnderMouse) 2441 swallowEvent = !(m_elementUnderMouse->dispatchMouseEvent(mouseEvent, eventType, clickCount)); 2442 2443 if (!swallowEvent && eventType == eventNames().mousedownEvent) { 2444 2445 // If clicking on a frame scrollbar, do not mess up with content focus. 2446 if (FrameView* view = m_frame.view()) { 2447 if (view->scrollbarAtPoint(mouseEvent.position())) 2448 return true; 2449 } 2450 2451 // The layout needs to be up to date to determine if an element is focusable. 2452 m_frame.document()->updateLayoutIgnorePendingStylesheets(); 2453 2454 // Blur current focus node when a link/button is clicked; this 2455 // is expected by some sites that rely on onChange handlers running 2456 // from form fields before the button click is processed. 2457 2458 Element* element = m_elementUnderMouse.get(); 2459 2460 // Walk up the DOM tree to search for an element to focus. 2461 while (element) { 2462 if (element->isMouseFocusable()) { 2463 // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus a 2464 // node on mouse down if it's selected and inside a focused node. It will be 2465 // focused if the user does a mouseup over it, however, because the mouseup 2466 // will set a selection inside it, which will call setFocuseNodeIfNeeded. 2467 if (m_frame.selection().isRange() 2468 && m_frame.selection().toNormalizedRange()->compareNode(element, IGNORE_EXCEPTION) == Range::NODE_INSIDE 2469 && element->isDescendantOf(m_frame.document()->focusedElement())) 2470 return true; 2471 2472 break; 2473 } 2474 element = element->parentOrShadowHostElement(); 2475 } 2476 2477 // Only change the focus when clicking scrollbars if it can transfered to a mouse focusable node. 2478 if ((!element || !element->isMouseFocusable()) && isInsideScrollbar(mouseEvent.position())) 2479 return false; 2480 2481 // If focus shift is blocked, we eat the event. Note we should never clear swallowEvent 2482 // if the page already set it (e.g., by canceling default behavior). 2483 if (Page* page = m_frame.page()) { 2484 if (element && element->isMouseFocusable()) { 2485 if (!page->focusController().setFocusedElement(element, &m_frame)) 2486 swallowEvent = true; 2487 } else if (!element || !element->focused()) { 2488 if (!page->focusController().setFocusedElement(0, &m_frame)) 2489 swallowEvent = true; 2490 } 2491 } 2492 } 2493 2494 return !swallowEvent; 2495} 2496 2497bool EventHandler::isInsideScrollbar(const IntPoint& windowPoint) const 2498{ 2499 if (RenderView* renderView = m_frame.contentRenderer()) { 2500 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent); 2501 HitTestResult result(windowPoint); 2502 renderView->hitTest(request, result); 2503 return result.scrollbar(); 2504 } 2505 2506 return false; 2507} 2508 2509#if !PLATFORM(GTK) 2510 2511bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult&, const PlatformWheelEvent&) const 2512{ 2513 return false; 2514} 2515 2516#endif 2517 2518#if !PLATFORM(MAC) 2519 2520void EventHandler::platformPrepareForWheelEvents(const PlatformWheelEvent&, const HitTestResult&, RefPtr<Element>&, RefPtr<ContainerNode>&, ScrollableArea*&, bool&) 2521{ 2522} 2523 2524void EventHandler::platformRecordWheelEvent(const PlatformWheelEvent& event) 2525{ 2526 m_recentWheelEventDeltaTracker->recordWheelEventDelta(event); 2527} 2528 2529bool EventHandler::platformCompleteWheelEvent(const PlatformWheelEvent& event, Element*, ContainerNode*, ScrollableArea*) 2530{ 2531 // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed. 2532 FrameView* view = m_frame.view(); 2533 2534 bool didHandleEvent = view ? view->wheelEvent(event) : false; 2535 m_isHandlingWheelEvent = false; 2536 return didHandleEvent; 2537} 2538 2539bool EventHandler::platformCompletePlatformWidgetWheelEvent(const PlatformWheelEvent&, const Widget&, ContainerNode*) 2540{ 2541 return true; 2542} 2543 2544#endif 2545 2546bool EventHandler::handleWheelEvent(const PlatformWheelEvent& event) 2547{ 2548 Document* document = m_frame.document(); 2549 if (!document->renderView()) 2550 return false; 2551 2552 RefPtr<FrameView> protector(m_frame.view()); 2553 2554 FrameView* view = m_frame.view(); 2555 if (!view) 2556 return false; 2557 2558 m_isHandlingWheelEvent = true; 2559 setFrameWasScrolledByUser(); 2560 2561 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent); 2562 HitTestResult result(view->windowToContents(event.position())); 2563 document->renderView()->hitTest(request, result); 2564 2565 RefPtr<Element> element = result.innerElement(); 2566 RefPtr<ContainerNode> scrollableContainer; 2567 ScrollableArea* scrollableArea = nullptr; 2568 bool isOverWidget = result.isOverWidget(); 2569 platformPrepareForWheelEvents(event, result, element, scrollableContainer, scrollableArea, isOverWidget); 2570 2571#if PLATFORM(COCOA) 2572 if (event.phase() == PlatformWheelEventPhaseNone && event.momentumPhase() == PlatformWheelEventPhaseNone) 2573#endif 2574 { 2575 m_latchedWheelEventElement = nullptr; 2576 m_previousWheelScrolledElement = nullptr; 2577 } 2578 2579 // FIXME: It should not be necessary to do this mutation here. 2580 // Instead, the handlers should know convert vertical scrolls appropriately. 2581 PlatformWheelEvent adjustedEvent = event; 2582 if (m_baseEventType == PlatformEvent::NoType && shouldTurnVerticalTicksIntoHorizontal(result, event)) 2583 adjustedEvent = event.copyTurningVerticalTicksIntoHorizontalTicks(); 2584 2585 platformRecordWheelEvent(adjustedEvent); 2586 2587 if (element) { 2588 if (isOverWidget) { 2589 RenderElement* target = element->renderer(); 2590 if (target && target->isWidget()) { 2591 Widget* widget = toRenderWidget(target)->widget(); 2592 if (widget && passWheelEventToWidget(event, widget)) { 2593 m_isHandlingWheelEvent = false; 2594 if (scrollableArea) 2595 scrollableArea->setScrolledProgrammatically(false); 2596 if (!widget->platformWidget()) 2597 return true; 2598 return platformCompletePlatformWidgetWheelEvent(event, *widget, scrollableContainer.get()); 2599 } 2600 } 2601 } 2602 2603 if (!element->dispatchWheelEvent(adjustedEvent)) { 2604 m_isHandlingWheelEvent = false; 2605 if (scrollableArea && scrollableArea->isScrolledProgrammatically()) { 2606 // Web developer is controlling scrolling, so don't attempt to latch. 2607 clearLatchedState(); 2608 scrollableArea->setScrolledProgrammatically(false); 2609 } 2610 return true; 2611 } 2612 } 2613 2614 if (scrollableArea) 2615 scrollableArea->setScrolledProgrammatically(false); 2616 2617 return platformCompleteWheelEvent(event, element.get(), scrollableContainer.get(), scrollableArea); 2618} 2619 2620void EventHandler::clearLatchedState() 2621{ 2622 m_latchedWheelEventElement = nullptr; 2623#if PLATFORM(COCOA) 2624 m_latchedScrollableContainer = nullptr; 2625#endif 2626 m_widgetIsLatched = false; 2627 m_previousWheelScrolledElement = nullptr; 2628} 2629 2630void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEvent) 2631{ 2632 if (!startNode || !wheelEvent) 2633 return; 2634 2635 Element* stopElement = m_previousWheelScrolledElement.get(); 2636 ScrollGranularity granularity = wheelGranularityToScrollGranularity(wheelEvent->deltaMode()); 2637 DominantScrollGestureDirection dominantDirection = DominantScrollGestureDirection::None; 2638 2639 // Workaround for scrolling issues <rdar://problem/14758615>. 2640#if PLATFORM(COCOA) 2641 if (m_recentWheelEventDeltaTracker->isTrackingDeltas()) 2642 dominantDirection = m_recentWheelEventDeltaTracker->dominantScrollGestureDirection(); 2643#endif 2644 2645 // Break up into two scrolls if we need to. Diagonal movement on 2646 // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set). 2647 if (dominantDirection != DominantScrollGestureDirection::Vertical && scrollNode(wheelEvent->deltaX(), granularity, ScrollRight, ScrollLeft, startNode, &stopElement, roundedIntPoint(wheelEvent->absoluteLocation()))) 2648 wheelEvent->setDefaultHandled(); 2649 2650 if (dominantDirection != DominantScrollGestureDirection::Horizontal && scrollNode(wheelEvent->deltaY(), granularity, ScrollDown, ScrollUp, startNode, &stopElement, roundedIntPoint(wheelEvent->absoluteLocation()))) 2651 wheelEvent->setDefaultHandled(); 2652 2653 if (!m_latchedWheelEventElement) 2654 m_previousWheelScrolledElement = stopElement; 2655} 2656 2657#if ENABLE(CONTEXT_MENUS) 2658bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event) 2659{ 2660 Document* doc = m_frame.document(); 2661 FrameView* v = m_frame.view(); 2662 if (!v) 2663 return false; 2664 2665 // Clear mouse press state to avoid initiating a drag while context menu is up. 2666 m_mousePressed = false; 2667 bool swallowEvent; 2668 LayoutPoint viewportPos = v->windowToContents(event.position()); 2669 HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowShadowContent); 2670 MouseEventWithHitTestResults mev = doc->prepareMouseEvent(request, viewportPos, event); 2671 2672 if (m_frame.editor().behavior().shouldSelectOnContextualMenuClick() 2673 && !m_frame.selection().contains(viewportPos) 2674 && !mev.scrollbar() 2675 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse. 2676 // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items 2677 // available for text selections. But only if we're above text. 2678 && (m_frame.selection().selection().isContentEditable() || (mev.targetNode() && mev.targetNode()->isTextNode()))) { 2679 m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection 2680 selectClosestWordOrLinkFromMouseEvent(mev); 2681 } 2682 2683 swallowEvent = !dispatchMouseEvent(eventNames().contextmenuEvent, mev.targetNode(), true, 0, event, false); 2684 2685 return swallowEvent; 2686} 2687 2688bool EventHandler::sendContextMenuEventForKey() 2689{ 2690 FrameView* view = m_frame.view(); 2691 if (!view) 2692 return false; 2693 2694 Document* doc = m_frame.document(); 2695 if (!doc) 2696 return false; 2697 2698 // Clear mouse press state to avoid initiating a drag while context menu is up. 2699 m_mousePressed = false; 2700 2701 static const int kContextMenuMargin = 1; 2702 2703#if OS(WINDOWS) && !OS(WINCE) 2704 int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT); 2705#else 2706 int rightAligned = 0; 2707#endif 2708 IntPoint location; 2709 2710 Element* focusedElement = doc->focusedElement(); 2711 const VisibleSelection& selection = m_frame.selection().selection(); 2712 Position start = selection.start(); 2713 2714 if (start.deprecatedNode() && (selection.rootEditableElement() || selection.isRange())) { 2715 RefPtr<Range> selectionRange = selection.toNormalizedRange(); 2716 IntRect firstRect = m_frame.editor().firstRectForRange(selectionRange.get()); 2717 2718 int x = rightAligned ? firstRect.maxX() : firstRect.x(); 2719 // In a multiline edit, firstRect.maxY() would endup on the next line, so -1. 2720 int y = firstRect.maxY() ? firstRect.maxY() - 1 : 0; 2721 location = IntPoint(x, y); 2722 } else if (focusedElement) { 2723 RenderBoxModelObject* box = focusedElement->renderBoxModelObject(); 2724 if (!box) 2725 return false; 2726 IntRect clippedRect = box->pixelSnappedAbsoluteClippedOverflowRect(); 2727 location = IntPoint(clippedRect.x(), clippedRect.maxY() - 1); 2728 } else { 2729 location = IntPoint( 2730 rightAligned ? view->contentsWidth() - kContextMenuMargin : kContextMenuMargin, 2731 kContextMenuMargin); 2732 } 2733 2734 m_frame.view()->setCursor(pointerCursor()); 2735 2736 IntPoint position = view->contentsToRootView(location); 2737 IntPoint globalPosition = view->hostWindow()->rootViewToScreen(IntRect(position, IntSize())).location(); 2738 2739 Node* targetNode = doc->focusedElement(); 2740 if (!targetNode) 2741 targetNode = doc; 2742 2743 // Use the focused node as the target for hover and active. 2744 HitTestResult result(position); 2745 result.setInnerNode(targetNode); 2746 doc->updateHoverActiveState(HitTestRequest::Active | HitTestRequest::DisallowShadowContent, result.innerElement()); 2747 2748 // The contextmenu event is a mouse event even when invoked using the keyboard. 2749 // This is required for web compatibility. 2750 2751#if OS(WINDOWS) 2752 PlatformEvent::Type eventType = PlatformEvent::MouseReleased; 2753#else 2754 PlatformEvent::Type eventType = PlatformEvent::MousePressed; 2755#endif 2756 2757 PlatformMouseEvent mouseEvent(position, globalPosition, RightButton, eventType, 1, false, false, false, false, WTF::currentTime()); 2758 2759 return !dispatchMouseEvent(eventNames().contextmenuEvent, targetNode, true, 0, mouseEvent, false); 2760} 2761#endif // ENABLE(CONTEXT_MENUS) 2762 2763void EventHandler::scheduleHoverStateUpdate() 2764{ 2765 if (!m_hoverTimer.isActive()) 2766 m_hoverTimer.startOneShot(0); 2767} 2768 2769#if ENABLE(CURSOR_SUPPORT) 2770void EventHandler::scheduleCursorUpdate() 2771{ 2772 if (!m_cursorUpdateTimer.isActive()) 2773 m_cursorUpdateTimer.startOneShot(cursorUpdateInterval); 2774} 2775#endif 2776 2777void EventHandler::dispatchFakeMouseMoveEventSoon() 2778{ 2779#if !ENABLE(IOS_TOUCH_EVENTS) 2780 if (m_mousePressed) 2781 return; 2782 2783 if (m_mousePositionIsUnknown) 2784 return; 2785 2786 if (!m_frame.settings().deviceSupportsMouse()) 2787 return; 2788 2789 // If the content has ever taken longer than fakeMouseMoveShortInterval we 2790 // reschedule the timer and use a longer time. This will cause the content 2791 // to receive these moves only after the user is done scrolling, reducing 2792 // pauses during the scroll. 2793 if (m_maxMouseMovedDuration > fakeMouseMoveDurationThreshold) { 2794 if (m_fakeMouseMoveEventTimer.isActive()) 2795 m_fakeMouseMoveEventTimer.stop(); 2796 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveLongInterval); 2797 } else { 2798 if (!m_fakeMouseMoveEventTimer.isActive()) 2799 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveShortInterval); 2800 } 2801#endif 2802} 2803 2804void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad) 2805{ 2806#if ENABLE(IOS_TOUCH_EVENTS) 2807 UNUSED_PARAM(quad); 2808#else 2809 FrameView* view = m_frame.view(); 2810 if (!view) 2811 return; 2812 2813 if (!quad.containsPoint(view->windowToContents(m_lastKnownMousePosition))) 2814 return; 2815 2816 dispatchFakeMouseMoveEventSoon(); 2817#endif 2818} 2819 2820#if !ENABLE(IOS_TOUCH_EVENTS) 2821void EventHandler::cancelFakeMouseMoveEvent() 2822{ 2823 m_fakeMouseMoveEventTimer.stop(); 2824} 2825 2826void EventHandler::fakeMouseMoveEventTimerFired(Timer<EventHandler>& timer) 2827{ 2828 ASSERT_UNUSED(timer, &timer == &m_fakeMouseMoveEventTimer); 2829 ASSERT(!m_mousePressed); 2830 2831 if (!m_frame.settings().deviceSupportsMouse()) 2832 return; 2833 2834 FrameView* view = m_frame.view(); 2835 if (!view) 2836 return; 2837 2838 if (!m_frame.page() || !m_frame.page()->isVisible() || !m_frame.page()->focusController().isActive()) 2839 return; 2840 2841 bool shiftKey; 2842 bool ctrlKey; 2843 bool altKey; 2844 bool metaKey; 2845 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey); 2846 PlatformMouseEvent fakeMouseMoveEvent(m_lastKnownMousePosition, m_lastKnownMouseGlobalPosition, NoButton, PlatformEvent::MouseMoved, 0, shiftKey, ctrlKey, altKey, metaKey, currentTime()); 2847 mouseMoved(fakeMouseMoveEvent); 2848} 2849#endif // !ENABLE(IOS_TOUCH_EVENTS) 2850 2851void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet) 2852{ 2853 m_frameSetBeingResized = frameSet; 2854} 2855 2856void EventHandler::resizeLayerDestroyed() 2857{ 2858 ASSERT(m_resizeLayer); 2859 m_resizeLayer = 0; 2860} 2861 2862void EventHandler::hoverTimerFired(Timer<EventHandler>&) 2863{ 2864 m_hoverTimer.stop(); 2865 2866 ASSERT(m_frame.document()); 2867 2868 if (RenderView* renderer = m_frame.contentRenderer()) { 2869 if (FrameView* view = m_frame.view()) { 2870 HitTestRequest request(HitTestRequest::Move | HitTestRequest::DisallowShadowContent); 2871 HitTestResult result(view->windowToContents(m_lastKnownMousePosition)); 2872 renderer->hitTest(request, result); 2873 m_frame.document()->updateHoverActiveState(request, result.innerElement()); 2874 } 2875 } 2876} 2877 2878bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt) 2879{ 2880 // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do. 2881 // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and 2882 // lower case variants are present in a document, the correct element is matched based on Shift key state. 2883 // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively. 2884 ASSERT(!(accessKeyModifiers() & PlatformEvent::ShiftKey)); 2885 if ((evt.modifiers() & ~PlatformEvent::ShiftKey) != accessKeyModifiers()) 2886 return false; 2887 String key = evt.unmodifiedText(); 2888 Element* elem = m_frame.document()->getElementByAccessKey(key.lower()); 2889 if (!elem) 2890 return false; 2891 elem->accessKeyAction(false); 2892 return true; 2893} 2894 2895#if !PLATFORM(MAC) 2896bool EventHandler::needsKeyboardEventDisambiguationQuirks() const 2897{ 2898 return false; 2899} 2900#endif 2901 2902#if ENABLE(FULLSCREEN_API) 2903bool EventHandler::isKeyEventAllowedInFullScreen(const PlatformKeyboardEvent& keyEvent) const 2904{ 2905 Document* document = m_frame.document(); 2906 if (document->webkitFullScreenKeyboardInputAllowed()) 2907 return true; 2908 2909 if (keyEvent.type() == PlatformKeyboardEvent::Char) { 2910 if (keyEvent.text().length() != 1) 2911 return false; 2912 UChar character = keyEvent.text()[0]; 2913 return character == ' '; 2914 } 2915 2916 int keyCode = keyEvent.windowsVirtualKeyCode(); 2917 return (keyCode >= VK_BACK && keyCode <= VK_CAPITAL) 2918 || (keyCode >= VK_SPACE && keyCode <= VK_DELETE) 2919 || (keyCode >= VK_OEM_1 && keyCode <= VK_OEM_PLUS) 2920 || (keyCode >= VK_MULTIPLY && keyCode <= VK_OEM_8); 2921} 2922#endif 2923 2924bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent) 2925{ 2926 RefPtr<FrameView> protector(m_frame.view()); 2927 2928#if ENABLE(FULLSCREEN_API) 2929 if (m_frame.document()->webkitIsFullScreen() && !isKeyEventAllowedInFullScreen(initialKeyEvent)) 2930 return false; 2931#endif 2932 2933 if (initialKeyEvent.windowsVirtualKeyCode() == VK_CAPITAL) 2934 capsLockStateMayHaveChanged(); 2935 2936#if ENABLE(PAN_SCROLLING) 2937 if (m_frame.mainFrame().eventHandler().panScrollInProgress()) { 2938 // If a key is pressed while the panScroll is in progress then we want to stop 2939 if (initialKeyEvent.type() == PlatformEvent::KeyDown || initialKeyEvent.type() == PlatformEvent::RawKeyDown) 2940 stopAutoscrollTimer(); 2941 2942 // If we were in panscroll mode, we swallow the key event 2943 return true; 2944 } 2945#endif 2946 2947 // Check for cases where we are too early for events -- possible unmatched key up 2948 // from pressing return in the location bar. 2949 RefPtr<Element> element = eventTargetElementForDocument(m_frame.document()); 2950 if (!element) 2951 return false; 2952 2953 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture); 2954 UserTypingGestureIndicator typingGestureIndicator(m_frame); 2955 2956 if (FrameView* view = m_frame.view()) 2957 view->disableLayerFlushThrottlingTemporarilyForInteraction(); 2958 2959 // FIXME (bug 68185): this call should be made at another abstraction layer 2960 m_frame.loader().resetMultipleFormSubmissionProtection(); 2961 2962 // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match. 2963 // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict 2964 // with access keys. Then we dispatch keydown, but suppress its default handling. 2965 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages. 2966 // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events. 2967 bool matchedAnAccessKey = false; 2968 if (initialKeyEvent.type() == PlatformEvent::KeyDown) 2969 matchedAnAccessKey = handleAccessKey(initialKeyEvent); 2970 2971 // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch. 2972 if (initialKeyEvent.type() == PlatformEvent::KeyUp || initialKeyEvent.type() == PlatformEvent::Char) 2973 return !element->dispatchKeyEvent(initialKeyEvent); 2974 2975 bool backwardCompatibilityMode = needsKeyboardEventDisambiguationQuirks(); 2976 2977 PlatformKeyboardEvent keyDownEvent = initialKeyEvent; 2978 if (keyDownEvent.type() != PlatformEvent::RawKeyDown) 2979 keyDownEvent.disambiguateKeyDownEvent(PlatformEvent::RawKeyDown, backwardCompatibilityMode); 2980 RefPtr<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame.document()->defaultView()); 2981 if (matchedAnAccessKey) 2982 keydown->setDefaultPrevented(true); 2983 keydown->setTarget(element); 2984 2985 if (initialKeyEvent.type() == PlatformEvent::RawKeyDown) { 2986 element->dispatchEvent(keydown, IGNORE_EXCEPTION); 2987 // If frame changed as a result of keydown dispatch, then return true to avoid sending a subsequent keypress message to the new frame. 2988 bool changedFocusedFrame = m_frame.page() && &m_frame != &m_frame.page()->focusController().focusedOrMainFrame(); 2989 return keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame; 2990 } 2991 2992 // Run input method in advance of DOM event handling. This may result in the IM 2993 // modifying the page prior the keydown event, but this behaviour is necessary 2994 // in order to match IE: 2995 // 1. preventing default handling of keydown and keypress events has no effect on IM input; 2996 // 2. if an input method handles the event, its keyCode is set to 229 in keydown event. 2997 m_frame.editor().handleInputMethodKeydown(keydown.get()); 2998 2999 bool handledByInputMethod = keydown->defaultHandled(); 3000 3001 if (handledByInputMethod) { 3002 keyDownEvent.setWindowsVirtualKeyCode(CompositionEventKeyCode); 3003 keydown = KeyboardEvent::create(keyDownEvent, m_frame.document()->defaultView()); 3004 keydown->setTarget(element); 3005 keydown->setDefaultHandled(); 3006 } 3007 3008 element->dispatchEvent(keydown, IGNORE_EXCEPTION); 3009 // If frame changed as a result of keydown dispatch, then return early to avoid sending a subsequent keypress message to the new frame. 3010 bool changedFocusedFrame = m_frame.page() && &m_frame != &m_frame.page()->focusController().focusedOrMainFrame(); 3011 bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame; 3012 if (handledByInputMethod || (keydownResult && !backwardCompatibilityMode)) 3013 return keydownResult; 3014 3015 // Focus may have changed during keydown handling, so refetch element. 3016 // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original element. 3017 if (!keydownResult) { 3018 element = eventTargetElementForDocument(m_frame.document()); 3019 if (!element) 3020 return false; 3021 } 3022 3023 PlatformKeyboardEvent keyPressEvent = initialKeyEvent; 3024 keyPressEvent.disambiguateKeyDownEvent(PlatformEvent::Char, backwardCompatibilityMode); 3025 if (keyPressEvent.text().isEmpty()) 3026 return keydownResult; 3027 RefPtr<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_frame.document()->defaultView()); 3028 keypress->setTarget(element); 3029 if (keydownResult) 3030 keypress->setDefaultPrevented(true); 3031#if PLATFORM(COCOA) 3032 keypress->keypressCommands() = keydown->keypressCommands(); 3033#endif 3034 element->dispatchEvent(keypress, IGNORE_EXCEPTION); 3035 3036 return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled(); 3037} 3038 3039static FocusDirection focusDirectionForKey(const AtomicString& keyIdentifier) 3040{ 3041 DEPRECATED_DEFINE_STATIC_LOCAL(AtomicString, Down, ("Down", AtomicString::ConstructFromLiteral)); 3042 DEPRECATED_DEFINE_STATIC_LOCAL(AtomicString, Up, ("Up", AtomicString::ConstructFromLiteral)); 3043 DEPRECATED_DEFINE_STATIC_LOCAL(AtomicString, Left, ("Left", AtomicString::ConstructFromLiteral)); 3044 DEPRECATED_DEFINE_STATIC_LOCAL(AtomicString, Right, ("Right", AtomicString::ConstructFromLiteral)); 3045 3046 FocusDirection retVal = FocusDirectionNone; 3047 3048 if (keyIdentifier == Down) 3049 retVal = FocusDirectionDown; 3050 else if (keyIdentifier == Up) 3051 retVal = FocusDirectionUp; 3052 else if (keyIdentifier == Left) 3053 retVal = FocusDirectionLeft; 3054 else if (keyIdentifier == Right) 3055 retVal = FocusDirectionRight; 3056 3057 return retVal; 3058} 3059 3060static void setInitialKeyboardSelection(Frame& frame, SelectionDirection direction) 3061{ 3062 Document* document = frame.document(); 3063 if (!document) 3064 return; 3065 3066 FrameSelection& selection = frame.selection(); 3067 3068 if (!selection.isNone()) 3069 return; 3070 3071 Element* focusedElement = document->focusedElement(); 3072 VisiblePosition visiblePosition; 3073 3074 switch (direction) { 3075 case DirectionBackward: 3076 case DirectionLeft: 3077 if (focusedElement) 3078 visiblePosition = VisiblePosition(positionBeforeNode(focusedElement)); 3079 else 3080 visiblePosition = endOfDocument(document); 3081 break; 3082 case DirectionForward: 3083 case DirectionRight: 3084 if (focusedElement) 3085 visiblePosition = VisiblePosition(positionAfterNode(focusedElement)); 3086 else 3087 visiblePosition = startOfDocument(document); 3088 break; 3089 } 3090 3091 selection.setSelection(visiblePosition, FrameSelection::defaultSetSelectionOptions(UserTriggered)); 3092} 3093 3094static void handleKeyboardSelectionMovement(Frame& frame, KeyboardEvent* event) 3095{ 3096 if (!event) 3097 return; 3098 3099 FrameSelection& selection = frame.selection(); 3100 3101 bool isCommanded = event->getModifierState("Meta"); 3102 bool isOptioned = event->getModifierState("Alt"); 3103 bool isSelection = !selection.isNone(); 3104 3105 FrameSelection::EAlteration alternation = event->getModifierState("Shift") ? FrameSelection::AlterationExtend : FrameSelection::AlterationMove; 3106 SelectionDirection direction = DirectionForward; 3107 TextGranularity granularity = CharacterGranularity; 3108 3109 switch (focusDirectionForKey(event->keyIdentifier())) { 3110 case FocusDirectionNone: 3111 return; 3112 case FocusDirectionForward: 3113 case FocusDirectionBackward: 3114 ASSERT_NOT_REACHED(); 3115 return; 3116 case FocusDirectionUp: 3117 direction = DirectionBackward; 3118 granularity = isCommanded ? DocumentBoundary : LineGranularity; 3119 break; 3120 case FocusDirectionDown: 3121 direction = DirectionForward; 3122 granularity = isCommanded ? DocumentBoundary : LineGranularity; 3123 break; 3124 case FocusDirectionLeft: 3125 direction = DirectionLeft; 3126 granularity = (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity; 3127 break; 3128 case FocusDirectionRight: 3129 direction = DirectionRight; 3130 granularity = (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity; 3131 break; 3132 } 3133 3134 if (isSelection) 3135 selection.modify(alternation, direction, granularity, UserTriggered); 3136 else 3137 setInitialKeyboardSelection(frame, direction); 3138 3139 event->setDefaultHandled(); 3140} 3141 3142void EventHandler::handleKeyboardSelectionMovementForAccessibility(KeyboardEvent* event) 3143{ 3144 if (event->type() == eventNames().keydownEvent) { 3145 if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled()) 3146 handleKeyboardSelectionMovement(m_frame, event); 3147 } 3148} 3149 3150void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event) 3151{ 3152 if (event->type() == eventNames().keydownEvent) { 3153 m_frame.editor().handleKeyboardEvent(event); 3154 if (event->defaultHandled()) 3155 return; 3156 if (event->keyIdentifier() == "U+0009") 3157 defaultTabEventHandler(event); 3158 else if (event->keyIdentifier() == "U+0008") 3159 defaultBackspaceEventHandler(event); 3160 else { 3161 FocusDirection direction = focusDirectionForKey(event->keyIdentifier()); 3162 if (direction != FocusDirectionNone) 3163 defaultArrowEventHandler(direction, event); 3164 } 3165 3166 handleKeyboardSelectionMovementForAccessibility(event); 3167 } 3168 if (event->type() == eventNames().keypressEvent) { 3169 m_frame.editor().handleKeyboardEvent(event); 3170 if (event->defaultHandled()) 3171 return; 3172 if (event->charCode() == ' ') 3173 defaultSpaceEventHandler(event); 3174 } 3175} 3176 3177#if ENABLE(DRAG_SUPPORT) 3178bool EventHandler::dragHysteresisExceeded(const IntPoint& floatDragViewportLocation) const 3179{ 3180 FloatPoint dragViewportLocation(floatDragViewportLocation.x(), floatDragViewportLocation.y()); 3181 return dragHysteresisExceeded(dragViewportLocation); 3182} 3183 3184bool EventHandler::dragHysteresisExceeded(const FloatPoint& dragViewportLocation) const 3185{ 3186 FrameView* view = m_frame.view(); 3187 if (!view) 3188 return false; 3189 IntPoint dragLocation = view->windowToContents(flooredIntPoint(dragViewportLocation)); 3190 IntSize delta = dragLocation - m_mouseDownPos; 3191 3192 int threshold = GeneralDragHysteresis; 3193 switch (dragState().type) { 3194 case DragSourceActionSelection: 3195 threshold = TextDragHysteresis; 3196 break; 3197 case DragSourceActionImage: 3198 threshold = ImageDragHysteresis; 3199 break; 3200 case DragSourceActionLink: 3201 threshold = LinkDragHysteresis; 3202 break; 3203 case DragSourceActionDHTML: 3204 break; 3205 case DragSourceActionNone: 3206 case DragSourceActionAny: 3207 ASSERT_NOT_REACHED(); 3208 } 3209 3210 return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold; 3211} 3212 3213void EventHandler::freeDataTransfer() 3214{ 3215 if (!dragState().dataTransfer) 3216 return; 3217 dragState().dataTransfer->setAccessPolicy(DataTransferAccessPolicy::Numb); 3218 dragState().dataTransfer = 0; 3219} 3220 3221void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation) 3222{ 3223 // Send a hit test request so that RenderLayer gets a chance to update the :hover and :active pseudoclasses. 3224 HitTestRequest request(HitTestRequest::Release | HitTestRequest::DisallowShadowContent); 3225 prepareMouseEvent(request, event); 3226 3227 if (dragState().source && dragState().shouldDispatchEvents) { 3228 dragState().dataTransfer->setDestinationOperation(operation); 3229 // For now we don't care if event handler cancels default behavior, since there is no default behavior. 3230 dispatchDragSrcEvent(eventNames().dragendEvent, event); 3231 } 3232 freeDataTransfer(); 3233 dragState().source = 0; 3234 // In case the drag was ended due to an escape key press we need to ensure 3235 // that consecutive mousemove events don't reinitiate the drag and drop. 3236 m_mouseDownMayStartDrag = false; 3237} 3238 3239void EventHandler::updateDragStateAfterEditDragIfNeeded(Element* rootEditableElement) 3240{ 3241 // If inserting the dragged contents removed the drag source, we still want to fire dragend at the root editable element. 3242 if (dragState().source && !dragState().source->inDocument()) 3243 dragState().source = rootEditableElement; 3244} 3245 3246// Return value indicates if we should continue "default processing", i.e., whether event handler canceled. 3247bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event) 3248{ 3249 return !dispatchDragEvent(eventType, *dragState().source, event, dragState().dataTransfer.get()); 3250} 3251 3252static bool ExactlyOneBitSet(DragSourceAction n) 3253{ 3254 return n && !(n & (n - 1)); 3255} 3256 3257bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDragHysteresis checkDragHysteresis) 3258{ 3259 if (event.event().button() != LeftButton || event.event().type() != PlatformEvent::MouseMoved) { 3260 // If we allowed the other side of the bridge to handle a drag 3261 // last time, then m_mousePressed might still be set. So we 3262 // clear it now to make sure the next move after a drag 3263 // doesn't look like a drag. 3264 m_mousePressed = false; 3265 return false; 3266 } 3267 3268 if (eventLoopHandleMouseDragged(event)) 3269 return true; 3270 3271 // Careful that the drag starting logic stays in sync with eventMayStartDrag() 3272 3273 if (m_mouseDownMayStartDrag && !dragState().source) { 3274 dragState().shouldDispatchEvents = (updateDragSourceActionsAllowed() & DragSourceActionDHTML); 3275 3276 // try to find an element that wants to be dragged 3277 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent); 3278 HitTestResult result(m_mouseDownPos); 3279 m_frame.contentRenderer()->hitTest(request, result); 3280 if (m_frame.page()) 3281 dragState().source = m_frame.page()->dragController().draggableElement(&m_frame, result.innerElement(), m_mouseDownPos, dragState()); 3282 3283 if (!dragState().source) 3284 m_mouseDownMayStartDrag = false; // no element is draggable 3285 else 3286 m_dragMayStartSelectionInstead = (dragState().type & DragSourceActionSelection); 3287 } 3288 3289 // For drags starting in the selection, the user must wait between the mousedown and mousedrag, 3290 // or else we bail on the dragging stuff and allow selection to occur 3291 if (m_mouseDownMayStartDrag && m_dragMayStartSelectionInstead && (dragState().type & DragSourceActionSelection) && event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay) { 3292 ASSERT(event.event().type() == PlatformEvent::MouseMoved); 3293 if ((dragState().type & DragSourceActionImage)) { 3294 // ... unless the mouse is over an image, then we start dragging just the image 3295 dragState().type = DragSourceActionImage; 3296 } else if (!(dragState().type & (DragSourceActionDHTML | DragSourceActionLink))) { 3297 // ... but only bail if we're not over an unselectable element. 3298 m_mouseDownMayStartDrag = false; 3299 dragState().source = 0; 3300 // ... but if this was the first click in the window, we don't even want to start selection 3301 if (eventActivatedView(event.event())) 3302 m_mouseDownMayStartSelect = false; 3303 } else { 3304 // Prevent the following case from occuring: 3305 // 1. User starts a drag immediately after mouse down over an unselectable element. 3306 // 2. We enter this block and decided that since we're over an unselectable element, don't cancel the drag. 3307 // 3. The drag gets resolved as a potential selection drag below /but/ we haven't exceeded the drag hysteresis yet. 3308 // 4. We enter this block again, and since it's now marked as a selection drag, we cancel the drag. 3309 m_dragMayStartSelectionInstead = false; 3310 } 3311 } 3312 3313 if (!m_mouseDownMayStartDrag) 3314 return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll; 3315 3316 if (!ExactlyOneBitSet(dragState().type)) { 3317 ASSERT((dragState().type & DragSourceActionSelection)); 3318 ASSERT((dragState().type & ~DragSourceActionSelection) == DragSourceActionDHTML 3319 || (dragState().type & ~DragSourceActionSelection) == DragSourceActionImage 3320 || (dragState().type & ~DragSourceActionSelection) == DragSourceActionLink); 3321 dragState().type = DragSourceActionSelection; 3322 } 3323 3324 // We are starting a text/image/url drag, so the cursor should be an arrow 3325 if (FrameView* view = m_frame.view()) { 3326 // FIXME <rdar://7577595>: Custom cursors aren't supported during drag and drop (default to pointer). 3327 view->setCursor(pointerCursor()); 3328 } 3329 3330 if (checkDragHysteresis == ShouldCheckDragHysteresis && !dragHysteresisExceeded(event.event().position())) 3331 return true; 3332 3333 // Once we're past the hysteresis point, we don't want to treat this gesture as a click 3334 invalidateClick(); 3335 3336 DragOperation srcOp = DragOperationNone; 3337 3338 // This does work only if we missed a dragEnd. Do it anyway, just to make sure the old dataTransfer gets numbed. 3339 freeDataTransfer(); 3340 3341 dragState().dataTransfer = createDraggingDataTransfer(); 3342 3343 if (dragState().shouldDispatchEvents) { 3344 // Check to see if the is a DOM based drag. If it is, get the DOM specified drag image and offset. 3345 if (dragState().type == DragSourceActionDHTML) { 3346 if (RenderObject* renderer = dragState().source->renderer()) { 3347 // FIXME: This doesn't work correctly with transforms. 3348 FloatPoint absPos = renderer->localToAbsolute(); 3349 IntSize delta = m_mouseDownPos - roundedIntPoint(absPos); 3350 dragState().dataTransfer->setDragImage(dragState().source.get(), delta.width(), delta.height()); 3351 } else { 3352 // The renderer has disappeared, this can happen if the onStartDrag handler has hidden 3353 // the element in some way. In this case we just kill the drag. 3354 m_mouseDownMayStartDrag = false; 3355 goto cleanupDrag; 3356 } 3357 } 3358 3359 m_mouseDownMayStartDrag = dispatchDragSrcEvent(eventNames().dragstartEvent, m_mouseDown) 3360 && !m_frame.selection().selection().isInPasswordField(); 3361 3362 // Invalidate dataTransfer here against anymore pasteboard writing for security. The drag 3363 // image can still be changed as we drag, but not the pasteboard data. 3364 dragState().dataTransfer->setAccessPolicy(DataTransferAccessPolicy::ImageWritable); 3365 3366 if (m_mouseDownMayStartDrag) { 3367 // Gather values from DHTML element, if it set any. 3368 srcOp = dragState().dataTransfer->sourceOperation(); 3369 3370 // Yuck, a draggedImage:moveTo: message can be fired as a result of kicking off the 3371 // drag with dragImage! Because of that dumb reentrancy, we may think we've not 3372 // started the drag when that happens. So we have to assume it's started before we kick it off. 3373 dragState().dataTransfer->setDragHasStarted(); 3374 } 3375 } 3376 3377 if (m_mouseDownMayStartDrag) { 3378 Page* page = m_frame.page(); 3379 m_didStartDrag = page && page->dragController().startDrag(m_frame, dragState(), srcOp, event.event(), m_mouseDownPos); 3380 // In WebKit2 we could re-enter this code and start another drag. 3381 // On OS X this causes problems with the ownership of the pasteboard and the promised types. 3382 if (m_didStartDrag) { 3383 m_mouseDownMayStartDrag = false; 3384 return true; 3385 } 3386 if (dragState().source && dragState().shouldDispatchEvents) { 3387 // Drag was canned at the last minute. We owe dragSource a dragend event. 3388 dispatchDragSrcEvent(eventNames().dragendEvent, event.event()); 3389 m_mouseDownMayStartDrag = false; 3390 } 3391 } 3392 3393cleanupDrag: 3394 if (!m_mouseDownMayStartDrag) { 3395 // Something failed to start the drag, clean up. 3396 freeDataTransfer(); 3397 dragState().source = 0; 3398 } 3399 3400 // No more default handling (like selection), whether we're past the hysteresis bounds or not 3401 return true; 3402} 3403#endif // ENABLE(DRAG_SUPPORT) 3404 3405bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, TextEventInputType inputType) 3406{ 3407 // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline), 3408 // and avoid dispatching text input events from keydown default handlers. 3409 ASSERT(!underlyingEvent || !underlyingEvent->isKeyboardEvent() || toKeyboardEvent(underlyingEvent)->type() == eventNames().keypressEvent); 3410 3411 EventTarget* target; 3412 if (underlyingEvent) 3413 target = underlyingEvent->target(); 3414 else 3415 target = eventTargetElementForDocument(m_frame.document()); 3416 if (!target) 3417 return false; 3418 3419 if (FrameView* view = m_frame.view()) 3420 view->disableLayerFlushThrottlingTemporarilyForInteraction(); 3421 3422 RefPtr<TextEvent> event = TextEvent::create(m_frame.document()->domWindow(), text, inputType); 3423 event->setUnderlyingEvent(underlyingEvent); 3424 3425 target->dispatchEvent(event, IGNORE_EXCEPTION); 3426 return event->defaultHandled(); 3427} 3428 3429bool EventHandler::isKeyboardOptionTab(KeyboardEvent* event) 3430{ 3431 return event 3432 && (event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent) 3433 && event->altKey() 3434 && event->keyIdentifier() == "U+0009"; 3435} 3436 3437bool EventHandler::eventInvertsTabsToLinksClientCallResult(KeyboardEvent* event) 3438{ 3439#if PLATFORM(COCOA) || PLATFORM(EFL) 3440 return EventHandler::isKeyboardOptionTab(event); 3441#else 3442 UNUSED_PARAM(event); 3443 return false; 3444#endif 3445} 3446 3447bool EventHandler::tabsToLinks(KeyboardEvent* event) const 3448{ 3449 // FIXME: This function needs a better name. It can be called for keypresses other than Tab when spatial navigation is enabled. 3450 3451 Page* page = m_frame.page(); 3452 if (!page) 3453 return false; 3454 3455 bool tabsToLinksClientCallResult = page->chrome().client().keyboardUIMode() & KeyboardAccessTabsToLinks; 3456 return eventInvertsTabsToLinksClientCallResult(event) ? !tabsToLinksClientCallResult : tabsToLinksClientCallResult; 3457} 3458 3459void EventHandler::defaultTextInputEventHandler(TextEvent* event) 3460{ 3461 if (m_frame.editor().handleTextEvent(event)) 3462 event->setDefaultHandled(); 3463} 3464 3465 3466void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event) 3467{ 3468 ASSERT(event->type() == eventNames().keypressEvent); 3469 3470 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey()) 3471 return; 3472 3473 ScrollLogicalDirection direction = event->shiftKey() ? ScrollBlockDirectionBackward : ScrollBlockDirectionForward; 3474 if (logicalScrollOverflow(direction, ScrollByPage)) { 3475 event->setDefaultHandled(); 3476 return; 3477 } 3478 3479 FrameView* view = m_frame.view(); 3480 if (!view) 3481 return; 3482 3483 if (view->logicalScroll(direction, ScrollByPage)) 3484 event->setDefaultHandled(); 3485} 3486 3487void EventHandler::defaultBackspaceEventHandler(KeyboardEvent* event) 3488{ 3489 ASSERT(event->type() == eventNames().keydownEvent); 3490 3491 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey()) 3492 return; 3493 3494 if (!m_frame.editor().behavior().shouldNavigateBackOnBackspace()) 3495 return; 3496 3497 Page* page = m_frame.page(); 3498 if (!page) 3499 return; 3500 3501 if (!m_frame.settings().backspaceKeyNavigationEnabled()) 3502 return; 3503 3504 bool handledEvent = false; 3505 3506 if (event->shiftKey()) 3507 handledEvent = page->backForward().goForward(); 3508 else 3509 handledEvent = page->backForward().goBack(); 3510 3511 if (handledEvent) 3512 event->setDefaultHandled(); 3513} 3514 3515 3516void EventHandler::defaultArrowEventHandler(FocusDirection focusDirection, KeyboardEvent* event) 3517{ 3518 ASSERT(event->type() == eventNames().keydownEvent); 3519 3520 if (event->ctrlKey() || event->metaKey() || event->altGraphKey() || event->shiftKey()) 3521 return; 3522 3523 Page* page = m_frame.page(); 3524 if (!page) 3525 return; 3526 3527 if (!isSpatialNavigationEnabled(&m_frame)) 3528 return; 3529 3530 // Arrows and other possible directional navigation keys can be used in design 3531 // mode editing. 3532 if (m_frame.document()->inDesignMode()) 3533 return; 3534 3535 if (page->focusController().advanceFocus(focusDirection, event)) 3536 event->setDefaultHandled(); 3537} 3538 3539void EventHandler::defaultTabEventHandler(KeyboardEvent* event) 3540{ 3541 ASSERT(event->type() == eventNames().keydownEvent); 3542 3543 // We should only advance focus on tabs if no special modifier keys are held down. 3544 if (event->ctrlKey() || event->metaKey() || event->altGraphKey()) 3545 return; 3546 3547 Page* page = m_frame.page(); 3548 if (!page) 3549 return; 3550 if (!page->tabKeyCyclesThroughElements()) 3551 return; 3552 3553 FocusDirection focusDirection = event->shiftKey() ? FocusDirectionBackward : FocusDirectionForward; 3554 3555 // Tabs can be used in design mode editing. 3556 if (m_frame.document()->inDesignMode()) 3557 return; 3558 3559 if (page->focusController().advanceFocus(focusDirection, event)) 3560 event->setDefaultHandled(); 3561} 3562 3563void EventHandler::capsLockStateMayHaveChanged() 3564{ 3565 Document* d = m_frame.document(); 3566 if (Element* element = d->focusedElement()) { 3567 if (RenderObject* r = element->renderer()) { 3568 if (r->isTextField()) 3569 toRenderTextControlSingleLine(r)->capsLockStateMayHaveChanged(); 3570 } 3571 } 3572} 3573 3574void EventHandler::sendScrollEvent() 3575{ 3576 setFrameWasScrolledByUser(); 3577 if (m_frame.view() && m_frame.document()) 3578 m_frame.document()->eventQueue().enqueueOrDispatchScrollEvent(*m_frame.document()); 3579} 3580 3581void EventHandler::setFrameWasScrolledByUser() 3582{ 3583 FrameView* v = m_frame.view(); 3584 if (v) 3585 v->setWasScrolledByUser(true); 3586} 3587 3588bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& mev, Scrollbar* scrollbar) 3589{ 3590 if (!scrollbar || !scrollbar->enabled()) 3591 return false; 3592 setFrameWasScrolledByUser(); 3593 return scrollbar->mouseDown(mev.event()); 3594} 3595 3596// If scrollbar (under mouse) is different from last, send a mouse exited. Set 3597// last to scrollbar if setLast is true; else set last to 0. 3598void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setLast) 3599{ 3600 if (m_lastScrollbarUnderMouse != scrollbar) { 3601 // Send mouse exited to the old scrollbar. 3602 if (m_lastScrollbarUnderMouse) 3603 m_lastScrollbarUnderMouse->mouseExited(); 3604 3605 // Send mouse entered if we're setting a new scrollbar. 3606 if (scrollbar && setLast) 3607 scrollbar->mouseEntered(); 3608 3609 m_lastScrollbarUnderMouse = setLast ? scrollbar : 0; 3610 } 3611} 3612 3613#if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS) 3614static const AtomicString& eventNameForTouchPointState(PlatformTouchPoint::State state) 3615{ 3616 switch (state) { 3617 case PlatformTouchPoint::TouchReleased: 3618 return eventNames().touchendEvent; 3619 case PlatformTouchPoint::TouchCancelled: 3620 return eventNames().touchcancelEvent; 3621 case PlatformTouchPoint::TouchPressed: 3622 return eventNames().touchstartEvent; 3623 case PlatformTouchPoint::TouchMoved: 3624 return eventNames().touchmoveEvent; 3625 case PlatformTouchPoint::TouchStationary: 3626 // TouchStationary state is not converted to touch events, so fall through to assert. 3627 default: 3628 ASSERT_NOT_REACHED(); 3629 return emptyAtom; 3630 } 3631} 3632 3633static HitTestResult hitTestResultInFrame(Frame* frame, const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType) 3634{ 3635 HitTestResult result(point); 3636 3637 if (!frame || !frame->contentRenderer()) 3638 return result; 3639 if (frame->view()) { 3640 IntRect rect = frame->view()->visibleContentRect(); 3641 if (!rect.contains(roundedIntPoint(point))) 3642 return result; 3643 } 3644 frame->contentRenderer()->hitTest(HitTestRequest(hitType), result); 3645 return result; 3646} 3647 3648bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) 3649{ 3650 // First build up the lists to use for the 'touches', 'targetTouches' and 'changedTouches' attributes 3651 // in the JS event. See http://www.sitepen.com/blog/2008/07/10/touching-and-gesturing-on-the-iphone/ 3652 // for an overview of how these lists fit together. 3653 3654 // Holds the complete set of touches on the screen and will be used as the 'touches' list in the JS event. 3655 RefPtr<TouchList> touches = TouchList::create(); 3656 3657 // A different view on the 'touches' list above, filtered and grouped by event target. Used for the 3658 // 'targetTouches' list in the JS event. 3659 typedef HashMap<EventTarget*, RefPtr<TouchList>> TargetTouchesMap; 3660 TargetTouchesMap touchesByTarget; 3661 3662 // Array of touches per state, used to assemble the 'changedTouches' list in the JS event. 3663 typedef HashSet<RefPtr<EventTarget>> EventTargetSet; 3664 struct { 3665 // The touches corresponding to the particular change state this struct instance represents. 3666 RefPtr<TouchList> m_touches; 3667 // Set of targets involved in m_touches. 3668 EventTargetSet m_targets; 3669 } changedTouches[PlatformTouchPoint::TouchStateEnd]; 3670 3671 const Vector<PlatformTouchPoint>& points = event.touchPoints(); 3672 3673 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture); 3674 3675 unsigned i; 3676 bool freshTouchEvents = true; 3677 bool allTouchReleased = true; 3678 for (i = 0; i < points.size(); ++i) { 3679 const PlatformTouchPoint& point = points[i]; 3680 if (point.state() != PlatformTouchPoint::TouchPressed) 3681 freshTouchEvents = false; 3682 if (point.state() != PlatformTouchPoint::TouchReleased && point.state() != PlatformTouchPoint::TouchCancelled) 3683 allTouchReleased = false; 3684 } 3685 3686 for (i = 0; i < points.size(); ++i) { 3687 const PlatformTouchPoint& point = points[i]; 3688 PlatformTouchPoint::State pointState = point.state(); 3689 LayoutPoint pagePoint = documentPointForWindowPoint(m_frame, point.pos()); 3690 3691 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEvent; 3692 // The HitTestRequest types used for mouse events map quite adequately 3693 // to touch events. Note that in addition to meaning that the hit test 3694 // should affect the active state of the current node if necessary, 3695 // HitTestRequest::Active signifies that the hit test is taking place 3696 // with the mouse (or finger in this case) being pressed. 3697 switch (pointState) { 3698 case PlatformTouchPoint::TouchPressed: 3699 hitType |= HitTestRequest::Active; 3700 break; 3701 case PlatformTouchPoint::TouchMoved: 3702 hitType |= HitTestRequest::Active | HitTestRequest::Move | HitTestRequest::ReadOnly; 3703 break; 3704 case PlatformTouchPoint::TouchReleased: 3705 case PlatformTouchPoint::TouchCancelled: 3706 hitType |= HitTestRequest::Release; 3707 break; 3708 case PlatformTouchPoint::TouchStationary: 3709 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly; 3710 break; 3711 default: 3712 ASSERT_NOT_REACHED(); 3713 break; 3714 } 3715 3716 if (shouldGesturesTriggerActive()) 3717 hitType |= HitTestRequest::ReadOnly; 3718 3719 // Increment the platform touch id by 1 to avoid storing a key of 0 in the hashmap. 3720 unsigned touchPointTargetKey = point.id() + 1; 3721 RefPtr<EventTarget> touchTarget; 3722 if (pointState == PlatformTouchPoint::TouchPressed) { 3723 HitTestResult result; 3724 if (freshTouchEvents) { 3725 result = hitTestResultAtPoint(pagePoint, hitType); 3726 m_originatingTouchPointTargetKey = touchPointTargetKey; 3727 } else if (m_originatingTouchPointDocument.get() && m_originatingTouchPointDocument->frame()) { 3728 LayoutPoint pagePointInOriginatingDocument = documentPointForWindowPoint(*m_originatingTouchPointDocument->frame(), point.pos()); 3729 result = hitTestResultInFrame(m_originatingTouchPointDocument->frame(), pagePointInOriginatingDocument, hitType); 3730 if (!result.innerNode()) 3731 continue; 3732 } else 3733 continue; 3734 3735 // FIXME: This code should use Element* instead of Node*. 3736 Node* node = result.innerElement(); 3737 ASSERT(node); 3738 3739 if (InspectorInstrumentation::handleTouchEvent(m_frame.page(), node)) 3740 return true; 3741 3742 Document& doc = node->document(); 3743 // Record the originating touch document even if it does not have a touch listener. 3744 if (freshTouchEvents) { 3745 m_originatingTouchPointDocument = &doc; 3746 freshTouchEvents = false; 3747 } 3748 if (!doc.hasTouchEventHandlers()) 3749 continue; 3750 m_originatingTouchPointTargets.set(touchPointTargetKey, node); 3751 touchTarget = node; 3752 } else if (pointState == PlatformTouchPoint::TouchReleased || pointState == PlatformTouchPoint::TouchCancelled) { 3753 // No need to perform a hit-test since we only need to unset :hover and :active states. 3754 if (!shouldGesturesTriggerActive() && allTouchReleased) 3755 m_frame.document()->updateHoverActiveState(hitType, 0); 3756 if (touchPointTargetKey == m_originatingTouchPointTargetKey) 3757 m_originatingTouchPointTargetKey = 0; 3758 3759 // The target should be the original target for this touch, so get it from the hashmap. As it's a release or cancel 3760 // we also remove it from the map. 3761 touchTarget = m_originatingTouchPointTargets.take(touchPointTargetKey); 3762 } else 3763 // No hittest is performed on move or stationary, since the target is not allowed to change anyway. 3764 touchTarget = m_originatingTouchPointTargets.get(touchPointTargetKey); 3765 3766 if (!touchTarget.get()) 3767 continue; 3768 Document& doc = touchTarget->toNode()->document(); 3769 if (!doc.hasTouchEventHandlers()) 3770 continue; 3771 Frame* targetFrame = doc.frame(); 3772 if (!targetFrame) 3773 continue; 3774 3775 if (&m_frame != targetFrame) { 3776 // pagePoint should always be relative to the target elements containing frame. 3777 pagePoint = documentPointForWindowPoint(*targetFrame, point.pos()); 3778 } 3779 3780 float scaleFactor = targetFrame->pageZoomFactor() * targetFrame->frameScaleFactor(); 3781 3782 int adjustedPageX = lroundf(pagePoint.x() / scaleFactor); 3783 int adjustedPageY = lroundf(pagePoint.y() / scaleFactor); 3784 3785 RefPtr<Touch> touch = Touch::create(targetFrame, touchTarget.get(), point.id(), 3786 point.screenPos().x(), point.screenPos().y(), 3787 adjustedPageX, adjustedPageY, 3788 point.radiusX(), point.radiusY(), point.rotationAngle(), point.force()); 3789 3790 // Ensure this target's touch list exists, even if it ends up empty, so it can always be passed to TouchEvent::Create below. 3791 TargetTouchesMap::iterator targetTouchesIterator = touchesByTarget.find(touchTarget.get()); 3792 if (targetTouchesIterator == touchesByTarget.end()) 3793 targetTouchesIterator = touchesByTarget.set(touchTarget.get(), TouchList::create()).iterator; 3794 3795 // touches and targetTouches should only contain information about touches still on the screen, so if this point is 3796 // released or cancelled it will only appear in the changedTouches list. 3797 if (pointState != PlatformTouchPoint::TouchReleased && pointState != PlatformTouchPoint::TouchCancelled) { 3798 touches->append(touch); 3799 targetTouchesIterator->value->append(touch); 3800 } 3801 3802 // Now build up the correct list for changedTouches. 3803 // Note that any touches that are in the TouchStationary state (e.g. if 3804 // the user had several points touched but did not move them all) should 3805 // never be in the changedTouches list so we do not handle them explicitly here. 3806 // See https://bugs.webkit.org/show_bug.cgi?id=37609 for further discussion 3807 // about the TouchStationary state. 3808 if (pointState != PlatformTouchPoint::TouchStationary) { 3809 ASSERT(pointState < PlatformTouchPoint::TouchStateEnd); 3810 if (!changedTouches[pointState].m_touches) 3811 changedTouches[pointState].m_touches = TouchList::create(); 3812 changedTouches[pointState].m_touches->append(touch); 3813 changedTouches[pointState].m_targets.add(touchTarget); 3814 } 3815 } 3816 m_touchPressed = touches->length() > 0; 3817 if (allTouchReleased) 3818 m_originatingTouchPointDocument.clear(); 3819 3820 // Now iterate the changedTouches list and m_targets within it, sending events to the targets as required. 3821 bool swallowedEvent = false; 3822 RefPtr<TouchList> emptyList = TouchList::create(); 3823 for (unsigned state = 0; state != PlatformTouchPoint::TouchStateEnd; ++state) { 3824 if (!changedTouches[state].m_touches) 3825 continue; 3826 3827 // When sending a touch cancel event, use empty touches and targetTouches lists. 3828 bool isTouchCancelEvent = (state == PlatformTouchPoint::TouchCancelled); 3829 RefPtr<TouchList>& effectiveTouches(isTouchCancelEvent ? emptyList : touches); 3830 const AtomicString& stateName(eventNameForTouchPointState(static_cast<PlatformTouchPoint::State>(state))); 3831 const EventTargetSet& targetsForState = changedTouches[state].m_targets; 3832 3833 for (EventTargetSet::const_iterator it = targetsForState.begin(); it != targetsForState.end(); ++it) { 3834 EventTarget* touchEventTarget = it->get(); 3835 RefPtr<TouchList> targetTouches(isTouchCancelEvent ? emptyList : touchesByTarget.get(touchEventTarget)); 3836 ASSERT(targetTouches); 3837 3838 RefPtr<TouchEvent> touchEvent = 3839 TouchEvent::create(effectiveTouches.get(), targetTouches.get(), changedTouches[state].m_touches.get(), 3840 stateName, touchEventTarget->toNode()->document().defaultView(), 3841 0, 0, 0, 0, event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey()); 3842 touchEventTarget->toNode()->dispatchTouchEvent(touchEvent.get()); 3843 swallowedEvent = swallowedEvent || touchEvent->defaultPrevented() || touchEvent->defaultHandled(); 3844 } 3845 } 3846 3847 return swallowedEvent; 3848} 3849#endif // ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS) 3850 3851#if ENABLE(TOUCH_EVENTS) 3852bool EventHandler::dispatchSyntheticTouchEventIfEnabled(const PlatformMouseEvent& event) 3853{ 3854#if ENABLE(IOS_TOUCH_EVENTS) 3855 UNUSED_PARAM(event); 3856 return false; 3857#else 3858 if (!m_frame.settings().isTouchEventEmulationEnabled()) 3859 return false; 3860 3861 PlatformEvent::Type eventType = event.type(); 3862 if (eventType != PlatformEvent::MouseMoved && eventType != PlatformEvent::MousePressed && eventType != PlatformEvent::MouseReleased) 3863 return false; 3864 3865 HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowShadowContent); 3866 MouseEventWithHitTestResults mev = prepareMouseEvent(request, event); 3867 if (mev.scrollbar() || subframeForHitTestResult(mev)) 3868 return false; 3869 3870 // The order is important. This check should follow the subframe test: http://webkit.org/b/111292. 3871 if (eventType == PlatformEvent::MouseMoved && !m_touchPressed) 3872 return true; 3873 3874 SyntheticSingleTouchEvent touchEvent(event); 3875 return handleTouchEvent(touchEvent); 3876#endif 3877} 3878#endif // ENABLE(TOUCH_EVENTS) 3879 3880void EventHandler::setLastKnownMousePosition(const PlatformMouseEvent& event) 3881{ 3882 m_mousePositionIsUnknown = false; 3883 m_lastKnownMousePosition = event.position(); 3884 m_lastKnownMouseGlobalPosition = event.globalPosition(); 3885} 3886 3887} // namespace WebCore 3888