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