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