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