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