EventHandler.cpp revision 63f95120ca90887045131d7ecf183e171d5dbe5d
1/* 2 * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. 3 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "config.h" 28#include "EventHandler.h" 29 30#include "AXObjectCache.h" 31#include "CachedImage.h" 32#include "Chrome.h" 33#include "ChromeClient.h" 34#include "Cursor.h" 35#include "Document.h" 36#include "DragController.h" 37#include "Editor.h" 38#include "EventNames.h" 39#include "FloatPoint.h" 40#include "FloatRect.h" 41#include "FocusController.h" 42#include "Frame.h" 43#include "FrameLoader.h" 44#include "FrameTree.h" 45#include "FrameView.h" 46#include "HTMLFrameElementBase.h" 47#include "HTMLFrameSetElement.h" 48#include "HTMLInputElement.h" 49#include "HTMLNames.h" 50#include "HitTestRequest.h" 51#include "HitTestResult.h" 52#include "Image.h" 53#include "InspectorController.h" 54#include "KeyboardEvent.h" 55#include "MouseEvent.h" 56#include "MouseEventWithHitTestResults.h" 57#include "Page.h" 58#include "PlatformKeyboardEvent.h" 59#include "PlatformWheelEvent.h" 60#include "PluginView.h" 61#include "RenderFrameSet.h" 62#include "RenderTextControlSingleLine.h" 63#include "RenderView.h" 64#include "RenderWidget.h" 65#include "Scrollbar.h" 66#include "SelectionController.h" 67#include "Settings.h" 68#include "TextEvent.h" 69#include "htmlediting.h" // for comparePositions() 70#include <wtf/StdLibExtras.h> 71 72#if ENABLE(SVG) 73#include "SVGDocument.h" 74#include "SVGElementInstance.h" 75#include "SVGNames.h" 76#include "SVGUseElement.h" 77#endif 78 79#if ENABLE(TOUCH_EVENTS) 80#include "PlatformTouchEvent.h" 81#include "TouchEvent.h" 82#endif 83 84#if defined(ANDROID_PLUGINS) 85#include "WebViewCore.h" 86#endif 87 88namespace WebCore { 89 90using namespace HTMLNames; 91 92#if ENABLE(DRAG_SUPPORT) 93// The link drag hysteresis is much larger than the others because there 94// needs to be enough space to cancel the link press without starting a link drag, 95// and because dragging links is rare. 96const int LinkDragHysteresis = 40; 97const int ImageDragHysteresis = 5; 98const int TextDragHysteresis = 3; 99const int GeneralDragHysteresis = 3; 100#endif // ENABLE(DRAG_SUPPORT) 101 102// Match key code of composition keydown event on windows. 103// IE sends VK_PROCESSKEY which has value 229; 104const int CompositionEventKeyCode = 229; 105 106#if ENABLE(SVG) 107using namespace SVGNames; 108#endif 109 110// When the autoscroll or the panScroll is triggered when do the scroll every 0.05s to make it smooth 111const double autoscrollInterval = 0.05; 112 113static Frame* subframeForHitTestResult(const MouseEventWithHitTestResults&); 114 115static inline void scrollAndAcceptEvent(float delta, ScrollDirection positiveDirection, ScrollDirection negativeDirection, PlatformWheelEvent& e, Node* node, Node** stopNode) 116{ 117 if (!delta) 118 return; 119 120 // Find the nearest enclosing box. 121 RenderBox* enclosingBox = node->renderer()->enclosingBox(); 122 123 if (e.granularity() == ScrollByPageWheelEvent) { 124 if (enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPage, 1, stopNode)) 125 e.accept(); 126 return; 127 } 128 129 float pixelsToScroll = delta > 0 ? delta : -delta; 130 if (enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPixel, pixelsToScroll, stopNode)) 131 e.accept(); 132} 133 134#if !PLATFORM(MAC) || ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) 135 136inline bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&) 137{ 138 return false; 139} 140 141#if ENABLE(DRAG_SUPPORT) 142inline bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&) 143{ 144 return false; 145} 146#endif 147 148#endif 149 150EventHandler::EventHandler(Frame* frame) 151 : m_frame(frame) 152 , m_mousePressed(false) 153 , m_capturesDragging(false) 154 , m_mouseDownMayStartSelect(false) 155#if ENABLE(DRAG_SUPPORT) 156 , m_mouseDownMayStartDrag(false) 157#endif 158 , m_mouseDownWasSingleClickInSelection(false) 159 , m_beganSelectingText(false) 160 , m_panScrollInProgress(false) 161 , m_panScrollButtonPressed(false) 162 , m_springLoadedPanScrollInProgress(false) 163 , m_hoverTimer(this, &EventHandler::hoverTimerFired) 164 , m_autoscrollTimer(this, &EventHandler::autoscrollTimerFired) 165 , m_autoscrollRenderer(0) 166 , m_autoscrollInProgress(false) 167 , m_mouseDownMayStartAutoscroll(false) 168 , m_mouseDownWasInSubframe(false) 169#if ENABLE(SVG) 170 , m_svgPan(false) 171#endif 172 , m_resizeLayer(0) 173 , m_capturingMouseEventsNode(0) 174 , m_clickCount(0) 175 , m_mouseDownTimestamp(0) 176 , m_useLatchedWheelEventNode(false) 177 , m_widgetIsLatched(false) 178#if PLATFORM(MAC) && !ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) 179 , m_mouseDownView(nil) 180 , m_sendingEventToSubview(false) 181 , m_activationEventNumber(0) 182#endif 183{ 184} 185 186EventHandler::~EventHandler() 187{ 188} 189 190#if ENABLE(DRAG_SUPPORT) 191EventHandler::EventHandlerDragState& EventHandler::dragState() 192{ 193 DEFINE_STATIC_LOCAL(EventHandlerDragState, state, ()); 194 return state; 195} 196#endif // ENABLE(DRAG_SUPPORT) 197 198void EventHandler::clear() 199{ 200 m_hoverTimer.stop(); 201 m_resizeLayer = 0; 202 m_nodeUnderMouse = 0; 203 m_lastNodeUnderMouse = 0; 204#if ENABLE(SVG) 205 m_instanceUnderMouse = 0; 206 m_lastInstanceUnderMouse = 0; 207#endif 208 m_lastMouseMoveEventSubframe = 0; 209 m_lastScrollbarUnderMouse = 0; 210 m_clickCount = 0; 211 m_clickNode = 0; 212#if ENABLE(TOUCH_EVENTS) 213 m_touchEventTarget = 0; 214#endif 215 m_frameSetBeingResized = 0; 216#if ENABLE(DRAG_SUPPORT) 217 m_dragTarget = 0; 218 m_shouldOnlyFireDragOverEvent = false; 219#endif 220 m_currentMousePosition = IntPoint(); 221 m_mousePressNode = 0; 222 m_mousePressed = false; 223 m_capturesDragging = false; 224 m_capturingMouseEventsNode = 0; 225 m_latchedWheelEventNode = 0; 226 m_previousWheelScrolledNode = 0; 227} 228 229void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result) 230{ 231 Node* innerNode = result.targetNode(); 232 VisibleSelection newSelection; 233 234 if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) { 235 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint())); 236 if (pos.isNotNull()) { 237 newSelection = VisibleSelection(pos); 238 newSelection.expandUsingGranularity(WordGranularity); 239 } 240 241 if (newSelection.isRange()) { 242 m_frame->setSelectionGranularity(WordGranularity); 243 m_beganSelectingText = true; 244 if (result.event().clickCount() == 2 && m_frame->editor()->isSelectTrailingWhitespaceEnabled()) 245 newSelection.appendTrailingWhitespace(); 246 } 247 248 if (m_frame->shouldChangeSelection(newSelection)) 249 m_frame->selection()->setSelection(newSelection); 250 } 251} 252 253void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result) 254{ 255 if (!result.hitTestResult().isLiveLink()) 256 return selectClosestWordFromMouseEvent(result); 257 258 Node* innerNode = result.targetNode(); 259 260 if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) { 261 VisibleSelection newSelection; 262 Element* URLElement = result.hitTestResult().URLElement(); 263 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint())); 264 if (pos.isNotNull() && pos.deepEquivalent().node()->isDescendantOf(URLElement)) 265 newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement); 266 267 if (newSelection.isRange()) { 268 m_frame->setSelectionGranularity(WordGranularity); 269 m_beganSelectingText = true; 270 } 271 272 if (m_frame->shouldChangeSelection(newSelection)) 273 m_frame->selection()->setSelection(newSelection); 274 } 275} 276 277bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event) 278{ 279 if (event.event().button() != LeftButton) 280 return false; 281 282 if (m_frame->selection()->isRange()) 283 // A double-click when range is already selected 284 // should not change the selection. So, do not call 285 // selectClosestWordFromMouseEvent, but do set 286 // m_beganSelectingText to prevent handleMouseReleaseEvent 287 // from setting caret selection. 288 m_beganSelectingText = true; 289 else 290 selectClosestWordFromMouseEvent(event); 291 292 return true; 293} 294 295bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event) 296{ 297 if (event.event().button() != LeftButton) 298 return false; 299 300 Node* innerNode = event.targetNode(); 301 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect)) 302 return false; 303 304 VisibleSelection newSelection; 305 VisiblePosition pos(innerNode->renderer()->positionForPoint(event.localPoint())); 306 if (pos.isNotNull()) { 307 newSelection = VisibleSelection(pos); 308 newSelection.expandUsingGranularity(ParagraphGranularity); 309 } 310 if (newSelection.isRange()) { 311 m_frame->setSelectionGranularity(ParagraphGranularity); 312 m_beganSelectingText = true; 313 } 314 315 if (m_frame->shouldChangeSelection(newSelection)) 316 m_frame->selection()->setSelection(newSelection); 317 318 return true; 319} 320 321bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event) 322{ 323 Node* innerNode = event.targetNode(); 324 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect)) 325 return false; 326 327 // Extend the selection if the Shift key is down, unless the click is in a link. 328 bool extendSelection = event.event().shiftKey() && !event.isOverLink(); 329 330 // Don't restart the selection when the mouse is pressed on an 331 // existing selection so we can allow for text dragging. 332 if (FrameView* view = m_frame->view()) { 333 IntPoint vPoint = view->windowToContents(event.event().pos()); 334 if (!extendSelection && m_frame->selection()->contains(vPoint)) { 335 m_mouseDownWasSingleClickInSelection = true; 336 return false; 337 } 338 } 339 340 VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(event.localPoint())); 341 if (visiblePos.isNull()) 342 visiblePos = VisiblePosition(innerNode, 0, DOWNSTREAM); 343 Position pos = visiblePos.deepEquivalent(); 344 345 VisibleSelection newSelection = m_frame->selection()->selection(); 346 if (extendSelection && newSelection.isCaretOrRange()) { 347 m_frame->selection()->setLastChangeWasHorizontalExtension(false); 348 349 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection 350 // was created right-to-left 351 Position start = newSelection.start(); 352 Position end = newSelection.end(); 353 if (comparePositions(pos, start) <= 0) 354 newSelection = VisibleSelection(pos, end); 355 else 356 newSelection = VisibleSelection(start, pos); 357 358 if (m_frame->selectionGranularity() != CharacterGranularity) 359 newSelection.expandUsingGranularity(m_frame->selectionGranularity()); 360 m_beganSelectingText = true; 361 } else { 362 newSelection = VisibleSelection(visiblePos); 363 m_frame->setSelectionGranularity(CharacterGranularity); 364 } 365 366 if (m_frame->shouldChangeSelection(newSelection)) 367 m_frame->selection()->setSelection(newSelection); 368 369 return true; 370} 371 372bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event) 373{ 374#if ENABLE(DRAG_SUPPORT) 375 // Reset drag state. 376 dragState().m_dragSrc = 0; 377#endif 378 379 if (ScrollView* scrollView = m_frame->view()) { 380 if (scrollView->isPointInScrollbarCorner(event.event().pos())) 381 return false; 382 } 383 384 bool singleClick = event.event().clickCount() <= 1; 385 386 // If we got the event back, that must mean it wasn't prevented, 387 // so it's allowed to start a drag or selection. 388 m_mouseDownMayStartSelect = canMouseDownStartSelect(event.targetNode()); 389 390#if ENABLE(DRAG_SUPPORT) 391 // Careful that the drag starting logic stays in sync with eventMayStartDrag() 392 m_mouseDownMayStartDrag = singleClick; 393#endif 394 395 m_mouseDownWasSingleClickInSelection = false; 396 397 m_mouseDown = event.event(); 398 399 if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event)) 400 return true; 401 402#if ENABLE(SVG) 403 if (m_frame->document()->isSVGDocument() && 404 static_cast<SVGDocument*>(m_frame->document())->zoomAndPanEnabled()) { 405 if (event.event().shiftKey() && singleClick) { 406 m_svgPan = true; 407 static_cast<SVGDocument*>(m_frame->document())->startPan(event.event().pos()); 408 return true; 409 } 410 } 411#endif 412 413 // We don't do this at the start of mouse down handling, 414 // because we don't want to do it until we know we didn't hit a widget. 415 if (singleClick) 416 focusDocumentView(); 417 418 Node* innerNode = event.targetNode(); 419 420 m_mousePressNode = innerNode; 421#if ENABLE(DRAG_SUPPORT) 422 m_dragStartPos = event.event().pos(); 423#endif 424 425 bool swallowEvent = false; 426 m_frame->selection()->setCaretBlinkingSuspended(true); 427 m_mousePressed = true; 428 m_beganSelectingText = false; 429 430 if (event.event().clickCount() == 2) 431 swallowEvent = handleMousePressEventDoubleClick(event); 432 else if (event.event().clickCount() >= 3) 433 swallowEvent = handleMousePressEventTripleClick(event); 434 else 435 swallowEvent = handleMousePressEventSingleClick(event); 436 437 m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect || 438 (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled(true)); 439 440 return swallowEvent; 441} 442 443#if ENABLE(DRAG_SUPPORT) 444bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event) 445{ 446 if (handleDrag(event)) 447 return true; 448 449 if (!m_mousePressed) 450 return false; 451 452 Node* targetNode = event.targetNode(); 453 if (event.event().button() != LeftButton || !targetNode || !targetNode->renderer()) 454 return false; 455 456#if PLATFORM(MAC) // FIXME: Why does this assertion fire on other platforms? 457 ASSERT(m_mouseDownMayStartSelect || m_mouseDownMayStartAutoscroll); 458#endif 459 460 m_mouseDownMayStartDrag = false; 461 462 if (m_mouseDownMayStartAutoscroll && !m_panScrollInProgress) { 463 // If the selection is contained in a layer that can scroll, that layer should handle the autoscroll 464 // Otherwise, let the bridge handle it so the view can scroll itself. 465 RenderObject* renderer = targetNode->renderer(); 466 while (renderer && (!renderer->isBox() || !toRenderBox(renderer)->canBeScrolledAndHasScrollableArea())) { 467 if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement()) 468 renderer = renderer->document()->ownerElement()->renderer(); 469 else 470 renderer = renderer->parent(); 471 } 472 473 if (renderer) { 474 m_autoscrollInProgress = true; 475 handleAutoscroll(renderer); 476 } 477 478 m_mouseDownMayStartAutoscroll = false; 479 } 480 481 updateSelectionForMouseDrag(targetNode, event.localPoint()); 482 return true; 483} 484 485bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const 486{ 487 // This is a pre-flight check of whether the event might lead to a drag being started. Be careful 488 // that its logic needs to stay in sync with handleMouseMoveEvent() and the way we setMouseDownMayStartDrag 489 // in handleMousePressEvent 490 491 if (!m_frame->contentRenderer() || !m_frame->contentRenderer()->hasLayer()) 492 return false; 493 494 if (event.button() != LeftButton || event.clickCount() != 1) 495 return false; 496 497 bool DHTMLFlag; 498 bool UAFlag; 499 allowDHTMLDrag(DHTMLFlag, UAFlag); 500 if (!DHTMLFlag && !UAFlag) 501 return false; 502 503 FrameView* view = m_frame->view(); 504 if (!view) 505 return false; 506 507 HitTestRequest request(HitTestRequest::ReadOnly); 508 HitTestResult result(view->windowToContents(event.pos())); 509 m_frame->contentRenderer()->layer()->hitTest(request, result); 510 bool srcIsDHTML; 511 return result.innerNode() && result.innerNode()->renderer()->draggableNode(DHTMLFlag, UAFlag, result.point().x(), result.point().y(), srcIsDHTML); 512} 513 514void EventHandler::updateSelectionForMouseDrag() 515{ 516 FrameView* view = m_frame->view(); 517 if (!view) 518 return; 519 RenderView* renderer = m_frame->contentRenderer(); 520 if (!renderer) 521 return; 522 RenderLayer* layer = renderer->layer(); 523 if (!layer) 524 return; 525 526 HitTestRequest request(HitTestRequest::ReadOnly | 527 HitTestRequest::Active | 528 HitTestRequest::MouseMove); 529 HitTestResult result(view->windowToContents(m_currentMousePosition)); 530 layer->hitTest(request, result); 531 updateSelectionForMouseDrag(result.innerNode(), result.localPoint()); 532} 533 534void EventHandler::updateSelectionForMouseDrag(Node* targetNode, const IntPoint& localPoint) 535{ 536 if (!m_mouseDownMayStartSelect) 537 return; 538 539 if (!targetNode) 540 return; 541 542 RenderObject* targetRenderer = targetNode->renderer(); 543 if (!targetRenderer) 544 return; 545 546 if (!canMouseDragExtendSelect(targetNode)) 547 return; 548 549 VisiblePosition targetPosition(targetRenderer->positionForPoint(localPoint)); 550 551 // Don't modify the selection if we're not on a node. 552 if (targetPosition.isNull()) 553 return; 554 555 // Restart the selection if this is the first mouse move. This work is usually 556 // done in handleMousePressEvent, but not if the mouse press was on an existing selection. 557 VisibleSelection newSelection = m_frame->selection()->selection(); 558 559#if ENABLE(SVG) 560 // Special case to limit selection to the containing block for SVG text. 561 // FIXME: Isn't there a better non-SVG-specific way to do this? 562 if (Node* selectionBaseNode = newSelection.base().node()) 563 if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer()) 564 if (selectionBaseRenderer->isSVGText()) 565 if (targetNode->renderer()->containingBlock() != selectionBaseRenderer->containingBlock()) 566 return; 567#endif 568 569 if (!m_beganSelectingText) { 570 m_beganSelectingText = true; 571 newSelection = VisibleSelection(targetPosition); 572 } 573 574 newSelection.setExtent(targetPosition); 575 if (m_frame->selectionGranularity() != CharacterGranularity) 576 newSelection.expandUsingGranularity(m_frame->selectionGranularity()); 577 578 if (m_frame->shouldChangeSelection(newSelection)) { 579 m_frame->selection()->setLastChangeWasHorizontalExtension(false); 580 m_frame->selection()->setSelection(newSelection); 581 } 582} 583#endif // ENABLE(DRAG_SUPPORT) 584 585bool EventHandler::handleMouseUp(const MouseEventWithHitTestResults& event) 586{ 587 if (eventLoopHandleMouseUp(event)) 588 return true; 589 590 // If this was the first click in the window, we don't even want to clear the selection. 591 // This case occurs when the user clicks on a draggable element, since we have to process 592 // the mouse down and drag events to see if we might start a drag. For other first clicks 593 // in a window, we just don't acceptFirstMouse, and the whole down-drag-up sequence gets 594 // ignored upstream of this layer. 595 return eventActivatedView(event.event()); 596} 597 598bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event) 599{ 600 if (m_autoscrollInProgress) 601 stopAutoscrollTimer(); 602 603 if (handleMouseUp(event)) 604 return true; 605 606 // Used to prevent mouseMoveEvent from initiating a drag before 607 // the mouse is pressed again. 608 m_frame->selection()->setCaretBlinkingSuspended(false); 609 m_mousePressed = false; 610 m_capturesDragging = false; 611#if ENABLE(DRAG_SUPPORT) 612 m_mouseDownMayStartDrag = false; 613#endif 614 m_mouseDownMayStartSelect = false; 615 m_mouseDownMayStartAutoscroll = false; 616 m_mouseDownWasInSubframe = false; 617 618 bool handled = false; 619 620 // Clear the selection if the mouse didn't move after the last mouse 621 // press and it's not a context menu click. We do this so when clicking 622 // on the selection, the selection goes away. However, if we are 623 // editing, place the caret. 624 if (m_mouseDownWasSingleClickInSelection && !m_beganSelectingText 625#if ENABLE(DRAG_SUPPORT) 626 && m_dragStartPos == event.event().pos() 627#endif 628 && m_frame->selection()->isRange() 629 && event.event().button() != RightButton) { 630 VisibleSelection newSelection; 631 Node *node = event.targetNode(); 632 bool caretBrowsing = m_frame->settings()->caretBrowsingEnabled(); 633 if (node && (caretBrowsing || node->isContentEditable()) && node->renderer()) { 634 VisiblePosition pos = node->renderer()->positionForPoint(event.localPoint()); 635 newSelection = VisibleSelection(pos); 636 } 637 if (m_frame->shouldChangeSelection(newSelection)) 638 m_frame->selection()->setSelection(newSelection); 639 640 handled = true; 641 } 642 643 m_frame->notifyRendererOfSelectionChange(true); 644 645 m_frame->selection()->selectFrameElementInParentIfFullySelected(); 646 647 return handled; 648} 649 650void EventHandler::handleAutoscroll(RenderObject* renderer) 651{ 652 // We don't want to trigger the autoscroll or the panScroll if it's already active 653 if (m_autoscrollTimer.isActive()) 654 return; 655 656 setAutoscrollRenderer(renderer); 657 658#if ENABLE(PAN_SCROLLING) 659 if (m_panScrollInProgress) { 660 m_panScrollStartPos = currentMousePosition(); 661 if (FrameView* view = m_frame->view()) 662 view->addPanScrollIcon(m_panScrollStartPos); 663 // If we're not in the top frame we notify it that we doing a panScroll. 664 if (Page* page = m_frame->page()) { 665 Frame* mainFrame = page->mainFrame(); 666 if (m_frame != mainFrame) 667 mainFrame->eventHandler()->setPanScrollInProgress(true); 668 } 669 } 670#endif 671 672 startAutoscrollTimer(); 673} 674 675void EventHandler::autoscrollTimerFired(Timer<EventHandler>*) 676{ 677 RenderObject* r = autoscrollRenderer(); 678 if (!r || !r->isBox()) { 679 stopAutoscrollTimer(); 680 return; 681 } 682 683 if (m_autoscrollInProgress) { 684 if (!m_mousePressed) { 685 stopAutoscrollTimer(); 686 return; 687 } 688 toRenderBox(r)->autoscroll(); 689 } else { 690 // we verify that the main frame hasn't received the order to stop the panScroll 691 if (Page* page = m_frame->page()) { 692 if (!page->mainFrame()->eventHandler()->panScrollInProgress()) { 693 stopAutoscrollTimer(); 694 return; 695 } 696 } 697#if ENABLE(PAN_SCROLLING) 698 updatePanScrollState(); 699 toRenderBox(r)->panScroll(m_panScrollStartPos); 700#endif 701 } 702} 703 704#if ENABLE(PAN_SCROLLING) 705 706void EventHandler::startPanScrolling(RenderObject* renderer) 707{ 708 m_panScrollInProgress = true; 709 m_panScrollButtonPressed = true; 710 handleAutoscroll(renderer); 711 invalidateClick(); 712} 713 714void EventHandler::updatePanScrollState() 715{ 716 FrameView* view = m_frame->view(); 717 if (!view) 718 return; 719 720 // At the original click location we draw a 4 arrowed icon. Over this icon there won't be any scroll 721 // So we don't want to change the cursor over this area 722 bool east = m_panScrollStartPos.x() < (m_currentMousePosition.x() - ScrollView::noPanScrollRadius); 723 bool west = m_panScrollStartPos.x() > (m_currentMousePosition.x() + ScrollView::noPanScrollRadius); 724 bool north = m_panScrollStartPos.y() > (m_currentMousePosition.y() + ScrollView::noPanScrollRadius); 725 bool south = m_panScrollStartPos.y() < (m_currentMousePosition.y() - ScrollView::noPanScrollRadius); 726 727 if ((east || west || north || south) && m_panScrollButtonPressed) 728 m_springLoadedPanScrollInProgress = true; 729 730 if (north) { 731 if (east) 732 view->setCursor(northEastPanningCursor()); 733 else if (west) 734 view->setCursor(northWestPanningCursor()); 735 else 736 view->setCursor(northPanningCursor()); 737 } else if (south) { 738 if (east) 739 view->setCursor(southEastPanningCursor()); 740 else if (west) 741 view->setCursor(southWestPanningCursor()); 742 else 743 view->setCursor(southPanningCursor()); 744 } else if (east) 745 view->setCursor(eastPanningCursor()); 746 else if (west) 747 view->setCursor(westPanningCursor()); 748 else 749 view->setCursor(middlePanningCursor()); 750} 751 752#endif // ENABLE(PAN_SCROLLING) 753 754RenderObject* EventHandler::autoscrollRenderer() const 755{ 756 return m_autoscrollRenderer; 757} 758 759void EventHandler::updateAutoscrollRenderer() 760{ 761 if (!m_autoscrollRenderer) 762 return; 763 764 HitTestResult hitTest = hitTestResultAtPoint(m_panScrollStartPos, true); 765 766 if (Node* nodeAtPoint = hitTest.innerNode()) 767 m_autoscrollRenderer = nodeAtPoint->renderer(); 768 769 while (m_autoscrollRenderer && (!m_autoscrollRenderer->isBox() || !toRenderBox(m_autoscrollRenderer)->canBeScrolledAndHasScrollableArea())) 770 m_autoscrollRenderer = m_autoscrollRenderer->parent(); 771} 772 773void EventHandler::setAutoscrollRenderer(RenderObject* renderer) 774{ 775 m_autoscrollRenderer = renderer; 776} 777 778#if ENABLE(DRAG_SUPPORT) 779void EventHandler::allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const 780{ 781 flagDHTML = false; 782 flagUA = false; 783 784 if (!m_frame) 785 return; 786 787 Page* page = m_frame->page(); 788 if (!page) 789 return; 790 791 FrameView* view = m_frame->view(); 792 if (!view) 793 return; 794 795 unsigned mask = page->dragController()->delegateDragSourceAction(view->contentsToWindow(m_mouseDownPos)); 796 flagDHTML = (mask & DragSourceActionDHTML) != DragSourceActionNone; 797 flagUA = ((mask & DragSourceActionImage) || (mask & DragSourceActionLink) || (mask & DragSourceActionSelection)); 798} 799#endif // ENABLE(DRAG_SUPPORT) 800 801HitTestResult EventHandler::hitTestResultAtPoint(const IntPoint& point, bool allowShadowContent, bool ignoreClipping, HitTestScrollbars testScrollbars) 802{ 803 HitTestResult result(point); 804 if (!m_frame->contentRenderer()) 805 return result; 806 int hitType = HitTestRequest::ReadOnly | HitTestRequest::Active; 807 if (ignoreClipping) 808 hitType |= HitTestRequest::IgnoreClipping; 809 m_frame->contentRenderer()->layer()->hitTest(HitTestRequest(hitType), result); 810 811 while (true) { 812 Node* n = result.innerNode(); 813 if (!result.isOverWidget() || !n || !n->renderer() || !n->renderer()->isWidget()) 814 break; 815 RenderWidget* renderWidget = toRenderWidget(n->renderer()); 816 Widget* widget = renderWidget->widget(); 817 if (!widget || !widget->isFrameView()) 818 break; 819 Frame* frame = static_cast<HTMLFrameElementBase*>(n)->contentFrame(); 820 if (!frame || !frame->contentRenderer()) 821 break; 822 FrameView* view = static_cast<FrameView*>(widget); 823 IntPoint widgetPoint(result.localPoint().x() + view->scrollX() - renderWidget->borderLeft() - renderWidget->paddingLeft(), 824 result.localPoint().y() + view->scrollY() - renderWidget->borderTop() - renderWidget->paddingTop()); 825 HitTestResult widgetHitTestResult(widgetPoint); 826 frame->contentRenderer()->layer()->hitTest(HitTestRequest(hitType), widgetHitTestResult); 827 result = widgetHitTestResult; 828 829 if (testScrollbars == ShouldHitTestScrollbars) { 830 Scrollbar* eventScrollbar = view->scrollbarAtPoint(point); 831 if (eventScrollbar) 832 result.setScrollbar(eventScrollbar); 833 } 834 } 835 836 // If our HitTestResult is not visible, then we started hit testing too far down the frame chain. 837 // Another hit test at the main frame level should get us the correct visible result. 838 Frame* resultFrame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document()->frame() : 0; 839 if (Page* page = m_frame->page()) { 840 Frame* mainFrame = page->mainFrame(); 841 if (m_frame != mainFrame && resultFrame && resultFrame != mainFrame && !resultFrame->editor()->insideVisibleArea(result.point())) { 842 FrameView* resultView = resultFrame->view(); 843 FrameView* mainView = mainFrame->view(); 844 if (resultView && mainView) { 845 IntPoint windowPoint = resultView->contentsToWindow(result.point()); 846 IntPoint mainFramePoint = mainView->windowToContents(windowPoint); 847 result = mainFrame->eventHandler()->hitTestResultAtPoint(mainFramePoint, allowShadowContent, ignoreClipping); 848 } 849 } 850 } 851 852 if (!allowShadowContent) 853 result.setToNonShadowAncestor(); 854 855 return result; 856} 857 858 859void EventHandler::startAutoscrollTimer() 860{ 861 m_autoscrollTimer.startRepeating(autoscrollInterval); 862} 863 864void EventHandler::stopAutoscrollTimer(bool rendererIsBeingDestroyed) 865{ 866 if (m_autoscrollInProgress) { 867 if (m_mouseDownWasInSubframe) { 868 if (Frame* subframe = subframeForTargetNode(m_mousePressNode.get())) 869 subframe->eventHandler()->stopAutoscrollTimer(rendererIsBeingDestroyed); 870 return; 871 } 872 } 873 874 if (autoscrollRenderer()) { 875 if (!rendererIsBeingDestroyed && (m_autoscrollInProgress || m_panScrollInProgress)) 876 toRenderBox(autoscrollRenderer())->stopAutoscroll(); 877#if ENABLE(PAN_SCROLLING) 878 if (m_panScrollInProgress) { 879 if (FrameView* view = m_frame->view()) { 880 view->removePanScrollIcon(); 881 view->setCursor(pointerCursor()); 882 } 883 } 884#endif 885 886 setAutoscrollRenderer(0); 887 } 888 889 m_autoscrollTimer.stop(); 890 891 m_panScrollInProgress = false; 892 m_springLoadedPanScrollInProgress = false; 893 894 // If we're not in the top frame we notify it that we are not doing a panScroll any more. 895 if (Page* page = m_frame->page()) { 896 Frame* mainFrame = page->mainFrame(); 897 if (m_frame != mainFrame) 898 mainFrame->eventHandler()->setPanScrollInProgress(false); 899 } 900 901 m_autoscrollInProgress = false; 902} 903 904Node* EventHandler::mousePressNode() const 905{ 906 return m_mousePressNode.get(); 907} 908 909void EventHandler::setMousePressNode(PassRefPtr<Node> node) 910{ 911 m_mousePressNode = node; 912} 913 914bool EventHandler::scrollOverflow(ScrollDirection direction, ScrollGranularity granularity) 915{ 916 Node* node = m_frame->document()->focusedNode(); 917 if (!node) 918 node = m_mousePressNode.get(); 919 920 if (node) { 921 RenderObject* r = node->renderer(); 922 if (r && !r->isListBox() && r->enclosingBox()->scroll(direction, granularity)) { 923 setFrameWasScrolledByUser(); 924 return true; 925 } 926 } 927 928 return false; 929} 930 931bool EventHandler::scrollRecursively(ScrollDirection direction, ScrollGranularity granularity) 932{ 933 bool handled = scrollOverflow(direction, granularity); 934 if (!handled) { 935 Frame* frame = m_frame; 936 do { 937 FrameView* view = frame->view(); 938 handled = view ? view->scroll(direction, granularity) : false; 939 frame = frame->tree()->parent(); 940 } while (!handled && frame); 941 } 942 943 return handled; 944} 945 946IntPoint EventHandler::currentMousePosition() const 947{ 948 return m_currentMousePosition; 949} 950 951Frame* subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult) 952{ 953 if (!hitTestResult.isOverWidget()) 954 return 0; 955 return EventHandler::subframeForTargetNode(hitTestResult.targetNode()); 956} 957 958Frame* EventHandler::subframeForTargetNode(Node* node) 959{ 960 if (!node) 961 return 0; 962 963 RenderObject* renderer = node->renderer(); 964 if (!renderer || !renderer->isWidget()) 965 return 0; 966 967 Widget* widget = toRenderWidget(renderer)->widget(); 968 if (!widget || !widget->isFrameView()) 969 return 0; 970 971 return static_cast<FrameView*>(widget)->frame(); 972} 973 974static bool isSubmitImage(Node* node) 975{ 976 return node && node->hasTagName(inputTag) 977 && static_cast<HTMLInputElement*>(node)->inputType() == HTMLInputElement::IMAGE; 978} 979 980// Returns true if the node's editable block is not current focused for editing 981static bool nodeIsNotBeingEdited(Node* node, Frame* frame) 982{ 983 return frame->selection()->rootEditableElement() != node->rootEditableElement(); 984} 985 986Cursor EventHandler::selectCursor(const MouseEventWithHitTestResults& event, Scrollbar* scrollbar) 987{ 988 // During selection, use an I-beam no matter what we're over. 989 // If you're capturing mouse events for a particular node, don't treat this as a selection. 990 if (m_mousePressed && m_mouseDownMayStartSelect && m_frame->selection()->isCaretOrRange() && !m_capturingMouseEventsNode) 991 return iBeamCursor(); 992 993 Node* node = event.targetNode(); 994 RenderObject* renderer = node ? node->renderer() : 0; 995 RenderStyle* style = renderer ? renderer->style() : 0; 996 997 if (renderer && renderer->isFrameSet()) { 998 RenderFrameSet* frameSetRenderer = toRenderFrameSet(renderer); 999 if (frameSetRenderer->canResizeRow(event.localPoint())) 1000 return rowResizeCursor(); 1001 if (frameSetRenderer->canResizeColumn(event.localPoint())) 1002 return columnResizeCursor(); 1003 } 1004 1005 if (style && style->cursors()) { 1006 const CursorList* cursors = style->cursors(); 1007 for (unsigned i = 0; i < cursors->size(); ++i) { 1008 CachedImage* cimage = (*cursors)[i].cursorImage.get(); 1009 IntPoint hotSpot = (*cursors)[i].hotSpot; 1010 if (!cimage) 1011 continue; 1012 // Limit the size of cursors so that they cannot be used to cover UI elements in chrome. 1013 IntSize size = cimage->image()->size(); 1014 if (size.width() > 128 || size.height() > 128) 1015 continue; 1016 // Do not let the hotspot be outside the bounds of the image. 1017 if (hotSpot.x() < 0 || hotSpot.y() < 0 || hotSpot.x() > size.width() || hotSpot.y() > size.height()) 1018 continue; 1019 if (cimage->image()->isNull()) 1020 break; 1021 if (!cimage->errorOccurred()) 1022 return Cursor(cimage->image(), hotSpot); 1023 } 1024 } 1025 1026 switch (style ? style->cursor() : CURSOR_AUTO) { 1027 case CURSOR_AUTO: { 1028 bool editable = (node && node->isContentEditable()); 1029 bool editableLinkEnabled = false; 1030 1031 // If the link is editable, then we need to check the settings to see whether or not the link should be followed 1032 if (editable) { 1033 ASSERT(m_frame->settings()); 1034 switch (m_frame->settings()->editableLinkBehavior()) { 1035 default: 1036 case EditableLinkDefaultBehavior: 1037 case EditableLinkAlwaysLive: 1038 editableLinkEnabled = true; 1039 break; 1040 1041 case EditableLinkNeverLive: 1042 editableLinkEnabled = false; 1043 break; 1044 1045 case EditableLinkLiveWhenNotFocused: 1046 editableLinkEnabled = nodeIsNotBeingEdited(node, m_frame) || event.event().shiftKey(); 1047 break; 1048 1049 case EditableLinkOnlyLiveWithShiftKey: 1050 editableLinkEnabled = event.event().shiftKey(); 1051 break; 1052 } 1053 } 1054 1055 if ((event.isOverLink() || isSubmitImage(node)) && (!editable || editableLinkEnabled)) 1056 return handCursor(); 1057 bool inResizer = false; 1058 if (renderer) { 1059 if (RenderLayer* layer = renderer->enclosingLayer()) { 1060 if (FrameView* view = m_frame->view()) 1061 inResizer = layer->isPointInResizeControl(view->windowToContents(event.event().pos())); 1062 } 1063 } 1064 if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !scrollbar) 1065 return iBeamCursor(); 1066 return pointerCursor(); 1067 } 1068 case CURSOR_CROSS: 1069 return crossCursor(); 1070 case CURSOR_POINTER: 1071 return handCursor(); 1072 case CURSOR_MOVE: 1073 return moveCursor(); 1074 case CURSOR_ALL_SCROLL: 1075 return moveCursor(); 1076 case CURSOR_E_RESIZE: 1077 return eastResizeCursor(); 1078 case CURSOR_W_RESIZE: 1079 return westResizeCursor(); 1080 case CURSOR_N_RESIZE: 1081 return northResizeCursor(); 1082 case CURSOR_S_RESIZE: 1083 return southResizeCursor(); 1084 case CURSOR_NE_RESIZE: 1085 return northEastResizeCursor(); 1086 case CURSOR_SW_RESIZE: 1087 return southWestResizeCursor(); 1088 case CURSOR_NW_RESIZE: 1089 return northWestResizeCursor(); 1090 case CURSOR_SE_RESIZE: 1091 return southEastResizeCursor(); 1092 case CURSOR_NS_RESIZE: 1093 return northSouthResizeCursor(); 1094 case CURSOR_EW_RESIZE: 1095 return eastWestResizeCursor(); 1096 case CURSOR_NESW_RESIZE: 1097 return northEastSouthWestResizeCursor(); 1098 case CURSOR_NWSE_RESIZE: 1099 return northWestSouthEastResizeCursor(); 1100 case CURSOR_COL_RESIZE: 1101 return columnResizeCursor(); 1102 case CURSOR_ROW_RESIZE: 1103 return rowResizeCursor(); 1104 case CURSOR_TEXT: 1105 return iBeamCursor(); 1106 case CURSOR_WAIT: 1107 return waitCursor(); 1108 case CURSOR_HELP: 1109 return helpCursor(); 1110 case CURSOR_VERTICAL_TEXT: 1111 return verticalTextCursor(); 1112 case CURSOR_CELL: 1113 return cellCursor(); 1114 case CURSOR_CONTEXT_MENU: 1115 return contextMenuCursor(); 1116 case CURSOR_PROGRESS: 1117 return progressCursor(); 1118 case CURSOR_NO_DROP: 1119 return noDropCursor(); 1120 case CURSOR_ALIAS: 1121 return aliasCursor(); 1122 case CURSOR_COPY: 1123 return copyCursor(); 1124 case CURSOR_NONE: 1125 return noneCursor(); 1126 case CURSOR_NOT_ALLOWED: 1127 return notAllowedCursor(); 1128 case CURSOR_DEFAULT: 1129 return pointerCursor(); 1130 case CURSOR_WEBKIT_ZOOM_IN: 1131 return zoomInCursor(); 1132 case CURSOR_WEBKIT_ZOOM_OUT: 1133 return zoomOutCursor(); 1134 case CURSOR_WEBKIT_GRAB: 1135 return grabCursor(); 1136 case CURSOR_WEBKIT_GRABBING: 1137 return grabbingCursor(); 1138 } 1139 return pointerCursor(); 1140} 1141 1142static IntPoint documentPointForWindowPoint(Frame* frame, const IntPoint& windowPoint) 1143{ 1144 FrameView* view = frame->view(); 1145 // FIXME: Is it really OK to use the wrong coordinates here when view is 0? 1146 // Historically the code would just crash; this is clearly no worse than that. 1147 return view ? view->windowToContents(windowPoint) : windowPoint; 1148} 1149 1150bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) 1151{ 1152 RefPtr<FrameView> protector(m_frame->view()); 1153 1154 m_mousePressed = true; 1155 m_capturesDragging = true; 1156 m_currentMousePosition = mouseEvent.pos(); 1157 m_mouseDownTimestamp = mouseEvent.timestamp(); 1158#if ENABLE(DRAG_SUPPORT) 1159 m_mouseDownMayStartDrag = false; 1160#endif 1161 m_mouseDownMayStartSelect = false; 1162 m_mouseDownMayStartAutoscroll = false; 1163 if (FrameView* view = m_frame->view()) 1164 m_mouseDownPos = view->windowToContents(mouseEvent.pos()); 1165 else { 1166 invalidateClick(); 1167 return false; 1168 } 1169 m_mouseDownWasInSubframe = false; 1170 1171 HitTestRequest request(HitTestRequest::Active); 1172 // Save the document point we generate in case the window coordinate is invalidated by what happens 1173 // when we dispatch the event. 1174 IntPoint documentPoint = documentPointForWindowPoint(m_frame, mouseEvent.pos()); 1175 MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent); 1176 1177 if (!mev.targetNode()) { 1178 invalidateClick(); 1179 return false; 1180 } 1181 1182 m_mousePressNode = mev.targetNode(); 1183 1184#if ENABLE(INSPECTOR) 1185 if (Page* page = m_frame->page()) { 1186 InspectorController* inspector = page->inspectorController(); 1187 if (inspector && inspector->enabled() && inspector->searchingForNodeInPage()) { 1188 inspector->handleMousePressOnNode(m_mousePressNode.get()); 1189 invalidateClick(); 1190 return true; 1191 } 1192 } 1193#endif 1194 1195 Frame* subframe = subframeForHitTestResult(mev); 1196 if (subframe && passMousePressEventToSubframe(mev, subframe)) { 1197 // Start capturing future events for this frame. We only do this if we didn't clear 1198 // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop. 1199 m_capturesDragging = subframe->eventHandler()->capturesDragging(); 1200 if (m_mousePressed && m_capturesDragging) 1201 m_capturingMouseEventsNode = mev.targetNode(); 1202 invalidateClick(); 1203 return true; 1204 } 1205 1206#if ENABLE(PAN_SCROLLING) 1207 Page* page = m_frame->page(); 1208 if (page && page->mainFrame()->eventHandler()->panScrollInProgress() || m_autoscrollInProgress) { 1209 stopAutoscrollTimer(); 1210 invalidateClick(); 1211 return true; 1212 } 1213#endif 1214 1215 m_clickCount = mouseEvent.clickCount(); 1216 m_clickNode = mev.targetNode(); 1217 1218 if (FrameView* view = m_frame->view()) { 1219 RenderLayer* layer = m_clickNode->renderer() ? m_clickNode->renderer()->enclosingLayer() : 0; 1220 IntPoint p = view->windowToContents(mouseEvent.pos()); 1221 if (layer && layer->isPointInResizeControl(p)) { 1222 layer->setInResizeMode(true); 1223 m_resizeLayer = layer; 1224 m_offsetFromResizeCorner = layer->offsetFromResizeCorner(p); 1225 invalidateClick(); 1226 return true; 1227 } 1228 } 1229 1230 bool swallowEvent = dispatchMouseEvent(eventNames().mousedownEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true); 1231 m_capturesDragging = !swallowEvent; 1232 1233 // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults 1234 // in case the scrollbar widget was destroyed when the mouse event was handled. 1235 if (mev.scrollbar()) { 1236 const bool wasLastScrollBar = mev.scrollbar() == m_lastScrollbarUnderMouse.get(); 1237 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active); 1238 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent); 1239 if (wasLastScrollBar && mev.scrollbar() != m_lastScrollbarUnderMouse.get()) 1240 m_lastScrollbarUnderMouse = 0; 1241 } 1242 1243 if (swallowEvent) { 1244 // scrollbars should get events anyway, even disabled controls might be scrollable 1245 Scrollbar* scrollbar = mev.scrollbar(); 1246 1247 updateLastScrollbarUnderMouse(scrollbar, true); 1248 1249 if (scrollbar) 1250 passMousePressEventToScrollbar(mev, scrollbar); 1251 } else { 1252 // Refetch the event target node if it currently is the shadow node inside an <input> element. 1253 // If a mouse event handler changes the input element type to one that has a widget associated, 1254 // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the 1255 // event target node can't still be the shadow node. 1256 if (mev.targetNode()->isShadowNode() && mev.targetNode()->shadowParentNode()->hasTagName(inputTag)) { 1257 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active); 1258 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent); 1259 } 1260 1261 FrameView* view = m_frame->view(); 1262 Scrollbar* scrollbar = view ? view->scrollbarAtPoint(mouseEvent.pos()) : 0; 1263 if (!scrollbar) 1264 scrollbar = mev.scrollbar(); 1265 1266 updateLastScrollbarUnderMouse(scrollbar, true); 1267 1268 if (scrollbar && passMousePressEventToScrollbar(mev, scrollbar)) 1269 swallowEvent = true; 1270 else 1271 swallowEvent = handleMousePressEvent(mev); 1272 } 1273 1274 return swallowEvent; 1275} 1276 1277// This method only exists for platforms that don't know how to deliver 1278bool EventHandler::handleMouseDoubleClickEvent(const PlatformMouseEvent& mouseEvent) 1279{ 1280 RefPtr<FrameView> protector(m_frame->view()); 1281 1282 // We get this instead of a second mouse-up 1283 m_mousePressed = false; 1284 m_currentMousePosition = mouseEvent.pos(); 1285 1286 HitTestRequest request(HitTestRequest::Active); 1287 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent); 1288 Frame* subframe = subframeForHitTestResult(mev); 1289 if (subframe && passMousePressEventToSubframe(mev, subframe)) { 1290 m_capturingMouseEventsNode = 0; 1291 return true; 1292 } 1293 1294 m_clickCount = mouseEvent.clickCount(); 1295 bool swallowMouseUpEvent = dispatchMouseEvent(eventNames().mouseupEvent, mev.targetNode(), true, m_clickCount, mouseEvent, false); 1296 1297 bool swallowClickEvent = false; 1298 // Don't ever dispatch click events for right clicks 1299 if (mouseEvent.button() != RightButton && mev.targetNode() == m_clickNode) 1300 swallowClickEvent = dispatchMouseEvent(eventNames().clickEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true); 1301 1302 if (m_lastScrollbarUnderMouse) 1303 swallowMouseUpEvent = m_lastScrollbarUnderMouse->mouseUp(); 1304 1305 bool swallowMouseReleaseEvent = false; 1306 if (!swallowMouseUpEvent) 1307 swallowMouseReleaseEvent = handleMouseReleaseEvent(mev); 1308 1309 invalidateClick(); 1310 1311 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent; 1312} 1313 1314bool EventHandler::mouseMoved(const PlatformMouseEvent& event) 1315{ 1316 HitTestResult hoveredNode = HitTestResult(IntPoint()); 1317 bool result = handleMouseMoveEvent(event, &hoveredNode); 1318 1319 Page* page = m_frame->page(); 1320 if (!page) 1321 return result; 1322 1323 hoveredNode.setToNonShadowAncestor(); 1324 page->chrome()->mouseDidMoveOverElement(hoveredNode, event.modifierFlags()); 1325 page->chrome()->setToolTip(hoveredNode); 1326 return result; 1327} 1328 1329bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, HitTestResult* hoveredNode) 1330{ 1331 // in Radar 3703768 we saw frequent crashes apparently due to the 1332 // part being null here, which seems impossible, so check for nil 1333 // but also assert so that we can try to figure this out in debug 1334 // builds, if it happens. 1335 ASSERT(m_frame); 1336 if (!m_frame) 1337 return false; 1338 1339 RefPtr<FrameView> protector(m_frame->view()); 1340 m_currentMousePosition = mouseEvent.pos(); 1341 1342 if (m_hoverTimer.isActive()) 1343 m_hoverTimer.stop(); 1344 1345#if ENABLE(SVG) 1346 if (m_svgPan) { 1347 static_cast<SVGDocument*>(m_frame->document())->updatePan(m_currentMousePosition); 1348 return true; 1349 } 1350#endif 1351 1352 if (m_frameSetBeingResized) 1353 return dispatchMouseEvent(eventNames().mousemoveEvent, m_frameSetBeingResized.get(), false, 0, mouseEvent, false); 1354 1355 // Send events right to a scrollbar if the mouse is pressed. 1356 if (m_lastScrollbarUnderMouse && m_mousePressed) 1357 return m_lastScrollbarUnderMouse->mouseMoved(mouseEvent); 1358 1359 // Treat mouse move events while the mouse is pressed as "read-only" in prepareMouseEvent 1360 // if we are allowed to select. 1361 // This means that :hover and :active freeze in the state they were in when the mouse 1362 // was pressed, rather than updating for nodes the mouse moves over as you hold the mouse down. 1363 int hitType = HitTestRequest::MouseMove; 1364 if (m_mousePressed && m_mouseDownMayStartSelect) 1365 hitType |= HitTestRequest::ReadOnly; 1366 if (m_mousePressed) 1367 hitType |= HitTestRequest::Active; 1368 HitTestRequest request(hitType); 1369 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent); 1370 if (hoveredNode) 1371 *hoveredNode = mev.hitTestResult(); 1372 1373 Scrollbar* scrollbar = 0; 1374 1375 if (m_resizeLayer && m_resizeLayer->inResizeMode()) 1376 m_resizeLayer->resize(mouseEvent, m_offsetFromResizeCorner); 1377 else { 1378 if (FrameView* view = m_frame->view()) 1379 scrollbar = view->scrollbarAtPoint(mouseEvent.pos()); 1380 1381 if (!scrollbar) 1382 scrollbar = mev.scrollbar(); 1383 1384 updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed); 1385 } 1386 1387 bool swallowEvent = false; 1388 RefPtr<Frame> newSubframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev); 1389 1390 // 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. 1391 if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree()->isDescendantOf(m_frame) && m_lastMouseMoveEventSubframe != newSubframe) 1392 passMouseMoveEventToSubframe(mev, m_lastMouseMoveEventSubframe.get()); 1393 1394 if (newSubframe) { 1395 // Update over/out state before passing the event to the subframe. 1396 updateMouseEventTargetNode(mev.targetNode(), mouseEvent, true); 1397 1398 // Event dispatch in updateMouseEventTargetNode may have caused the subframe of the target 1399 // node to be detached from its FrameView, in which case the event should not be passed. 1400 if (newSubframe->view()) 1401 swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(), hoveredNode); 1402 } else { 1403 if (scrollbar && !m_mousePressed) 1404 scrollbar->mouseMoved(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering. 1405 if (Page* page = m_frame->page()) { 1406 if ((!m_resizeLayer || !m_resizeLayer->inResizeMode()) && !page->mainFrame()->eventHandler()->panScrollInProgress()) { 1407 if (FrameView* view = m_frame->view()) 1408 view->setCursor(selectCursor(mev, scrollbar)); 1409 } 1410 } 1411 } 1412 1413 m_lastMouseMoveEventSubframe = newSubframe; 1414 1415 if (swallowEvent) 1416 return true; 1417 1418 swallowEvent = dispatchMouseEvent(eventNames().mousemoveEvent, mev.targetNode(), false, 0, mouseEvent, true); 1419#if ENABLE(DRAG_SUPPORT) 1420 if (!swallowEvent) 1421 swallowEvent = handleMouseDraggedEvent(mev); 1422#endif // ENABLE(DRAG_SUPPORT) 1423 1424 return swallowEvent; 1425} 1426 1427void EventHandler::invalidateClick() 1428{ 1429 m_clickCount = 0; 1430 m_clickNode = 0; 1431} 1432 1433bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent) 1434{ 1435 RefPtr<FrameView> protector(m_frame->view()); 1436 1437#if ENABLE(PAN_SCROLLING) 1438 if (mouseEvent.button() == MiddleButton) 1439 m_panScrollButtonPressed = false; 1440 if (m_springLoadedPanScrollInProgress) 1441 stopAutoscrollTimer(); 1442#endif 1443 1444 m_mousePressed = false; 1445 m_currentMousePosition = mouseEvent.pos(); 1446 1447#if ENABLE(SVG) 1448 if (m_svgPan) { 1449 m_svgPan = false; 1450 static_cast<SVGDocument*>(m_frame->document())->updatePan(m_currentMousePosition); 1451 return true; 1452 } 1453#endif 1454 1455 if (m_frameSetBeingResized) 1456 return dispatchMouseEvent(eventNames().mouseupEvent, m_frameSetBeingResized.get(), true, m_clickCount, mouseEvent, false); 1457 1458 if (m_lastScrollbarUnderMouse) { 1459 invalidateClick(); 1460 return m_lastScrollbarUnderMouse->mouseUp(); 1461 } 1462 1463 HitTestRequest request(HitTestRequest::MouseUp); 1464 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent); 1465 Frame* subframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev); 1466 if (subframe && passMouseReleaseEventToSubframe(mev, subframe)) { 1467 m_capturingMouseEventsNode = 0; 1468 return true; 1469 } 1470 1471 bool swallowMouseUpEvent = dispatchMouseEvent(eventNames().mouseupEvent, mev.targetNode(), true, m_clickCount, mouseEvent, false); 1472 1473 // Don't ever dispatch click events for right clicks 1474 bool swallowClickEvent = false; 1475 if (m_clickCount > 0 && mouseEvent.button() != RightButton && mev.targetNode() == m_clickNode) 1476 swallowClickEvent = dispatchMouseEvent(eventNames().clickEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true); 1477 1478 if (m_resizeLayer) { 1479 m_resizeLayer->setInResizeMode(false); 1480 m_resizeLayer = 0; 1481 } 1482 1483 bool swallowMouseReleaseEvent = false; 1484 if (!swallowMouseUpEvent) 1485 swallowMouseReleaseEvent = handleMouseReleaseEvent(mev); 1486 1487 invalidateClick(); 1488 1489 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent; 1490} 1491 1492#if ENABLE(DRAG_SUPPORT) 1493bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTarget, const PlatformMouseEvent& event, Clipboard* clipboard) 1494{ 1495 FrameView* view = m_frame->view(); 1496 1497 // FIXME: We might want to dispatch a dragleave even if the view is gone. 1498 if (!view) 1499 return false; 1500 1501 view->resetDeferredRepaintDelay(); 1502 IntPoint contentsPos = view->windowToContents(event.pos()); 1503 1504 RefPtr<MouseEvent> me = MouseEvent::create(eventType, 1505 true, true, m_frame->document()->defaultView(), 1506 0, event.globalX(), event.globalY(), contentsPos.x(), contentsPos.y(), 1507 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(), 1508 0, 0, clipboard); 1509 1510 ExceptionCode ec; 1511 dragTarget->dispatchEvent(me.get(), ec); 1512 return me->defaultPrevented(); 1513} 1514 1515bool EventHandler::canHandleDragAndDropForTarget(DragAndDropHandleType type, Node* target, const PlatformMouseEvent& event, Clipboard* clipboard, bool* accepted) 1516{ 1517 bool canHandle = false; 1518 bool wasAccepted = false; 1519 1520 if (target->hasTagName(frameTag) || target->hasTagName(iframeTag)) { 1521 Frame* frame = static_cast<HTMLFrameElementBase*>(target)->contentFrame(); 1522 if (frame) { 1523 switch (type) { 1524 case UpdateDragAndDrop: 1525 wasAccepted = frame->eventHandler()->updateDragAndDrop(event, clipboard); 1526 break; 1527 case CancelDragAndDrop: 1528 frame->eventHandler()->cancelDragAndDrop(event, clipboard); 1529 break; 1530 case PerformDragAndDrop: 1531 wasAccepted = frame->eventHandler()->performDragAndDrop(event, clipboard); 1532 break; 1533 } 1534 } 1535 } else 1536 canHandle = true; 1537 1538 if (accepted) 1539 *accepted = wasAccepted; 1540 1541 return canHandle; 1542} 1543 1544bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard) 1545{ 1546 bool accept = false; 1547 1548 if (!m_frame->view()) 1549 return false; 1550 1551 HitTestRequest request(HitTestRequest::ReadOnly); 1552 MouseEventWithHitTestResults mev = prepareMouseEvent(request, event); 1553 1554 // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch) 1555 Node* newTarget = mev.targetNode(); 1556 if (newTarget && newTarget->isTextNode()) 1557 newTarget = newTarget->parentNode(); 1558 if (newTarget) 1559 newTarget = newTarget->shadowAncestorNode(); 1560 1561 if (m_dragTarget != newTarget) { 1562 // FIXME: this ordering was explicitly chosen to match WinIE. However, 1563 // it is sometimes incorrect when dragging within subframes, as seen with 1564 // LayoutTests/fast/events/drag-in-frames.html. 1565 // 1566 // 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>. 1567 if (newTarget && canHandleDragAndDropForTarget(UpdateDragAndDrop, newTarget, event, clipboard, &accept)) { 1568 // 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. 1569 if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) { 1570 // for now we don't care if event handler cancels default behavior, since there is none 1571 dispatchDragSrcEvent(eventNames().dragEvent, event); 1572 } 1573 accept = dispatchDragEvent(eventNames().dragenterEvent, newTarget, event, clipboard); 1574 } 1575 1576 if (m_dragTarget && canHandleDragAndDropForTarget(UpdateDragAndDrop, m_dragTarget.get(), event, clipboard, &accept)) 1577 dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard); 1578 1579 if (newTarget) { 1580 // We do not explicitly call dispatchDragEvent here because it could ultimately result in the appearance that 1581 // two dragover events fired. So, we mark that we should only fire a dragover event on the next call to this function. 1582 m_shouldOnlyFireDragOverEvent = true; 1583 } 1584 } else { 1585 if (newTarget && canHandleDragAndDropForTarget(UpdateDragAndDrop, newTarget, event, clipboard, &accept)) { 1586 // Note, when dealing with sub-frames, we may need to fire only a dragover event as a drag event may have been fired earlier. 1587 if (!m_shouldOnlyFireDragOverEvent && dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) { 1588 // for now we don't care if event handler cancels default behavior, since there is none 1589 dispatchDragSrcEvent(eventNames().dragEvent, event); 1590 } 1591 accept = dispatchDragEvent(eventNames().dragoverEvent, newTarget, event, clipboard); 1592 m_shouldOnlyFireDragOverEvent = false; 1593 } 1594 } 1595 m_dragTarget = newTarget; 1596 1597 return accept; 1598} 1599 1600void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard) 1601{ 1602 if (m_dragTarget && canHandleDragAndDropForTarget(CancelDragAndDrop, m_dragTarget.get(), event, clipboard)) { 1603 if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) 1604 dispatchDragSrcEvent(eventNames().dragEvent, event); 1605 dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard); 1606 } 1607 clearDragState(); 1608} 1609 1610bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard) 1611{ 1612 bool accept = false; 1613 if (m_dragTarget && canHandleDragAndDropForTarget(PerformDragAndDrop, m_dragTarget.get(), event, clipboard, &accept)) 1614 dispatchDragEvent(eventNames().dropEvent, m_dragTarget.get(), event, clipboard); 1615 clearDragState(); 1616 return accept; 1617} 1618 1619void EventHandler::clearDragState() 1620{ 1621 m_dragTarget = 0; 1622 m_capturingMouseEventsNode = 0; 1623 m_shouldOnlyFireDragOverEvent = false; 1624#if PLATFORM(MAC) && !ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) 1625 m_sendingEventToSubview = false; 1626#endif 1627} 1628#endif // ENABLE(DRAG_SUPPORT) 1629 1630void EventHandler::setCapturingMouseEventsNode(PassRefPtr<Node> n) 1631{ 1632 m_capturingMouseEventsNode = n; 1633} 1634 1635MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mev) 1636{ 1637 ASSERT(m_frame); 1638 ASSERT(m_frame->document()); 1639 1640 return m_frame->document()->prepareMouseEvent(request, documentPointForWindowPoint(m_frame, mev.pos()), mev); 1641} 1642 1643#if ENABLE(SVG) 1644static inline SVGElementInstance* instanceAssociatedWithShadowTreeElement(Node* referenceNode) 1645{ 1646 if (!referenceNode || !referenceNode->isSVGElement()) 1647 return 0; 1648 1649 Node* shadowTreeElement = referenceNode->shadowTreeRootNode(); 1650 if (!shadowTreeElement) 1651 return 0; 1652 1653 Node* shadowTreeParentElement = shadowTreeElement->shadowParentNode(); 1654 if (!shadowTreeParentElement) 1655 return 0; 1656 1657 ASSERT(shadowTreeParentElement->hasTagName(useTag)); 1658 return static_cast<SVGUseElement*>(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode); 1659} 1660#endif 1661 1662void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMouseEvent& mouseEvent, bool fireMouseOverOut) 1663{ 1664 Node* result = targetNode; 1665 1666 // If we're capturing, we always go right to that node. 1667 if (m_capturingMouseEventsNode) 1668 result = m_capturingMouseEventsNode.get(); 1669 else { 1670 // If the target node is a text node, dispatch on the parent node - rdar://4196646 1671 if (result && result->isTextNode()) 1672 result = result->parentNode(); 1673 if (result) 1674 result = result->shadowAncestorNode(); 1675 } 1676 m_nodeUnderMouse = result; 1677#if ENABLE(SVG) 1678 m_instanceUnderMouse = instanceAssociatedWithShadowTreeElement(result); 1679 1680 // <use> shadow tree elements may have been recloned, update node under mouse in any case 1681 if (m_lastInstanceUnderMouse) { 1682 SVGElement* lastCorrespondingElement = m_lastInstanceUnderMouse->correspondingElement(); 1683 SVGElement* lastCorrespondingUseElement = m_lastInstanceUnderMouse->correspondingUseElement(); 1684 1685 if (lastCorrespondingElement && lastCorrespondingUseElement) { 1686 HashSet<SVGElementInstance*> instances = lastCorrespondingElement->instancesForElement(); 1687 1688 // Locate the recloned shadow tree element for our corresponding instance 1689 HashSet<SVGElementInstance*>::iterator end = instances.end(); 1690 for (HashSet<SVGElementInstance*>::iterator it = instances.begin(); it != end; ++it) { 1691 SVGElementInstance* instance = (*it); 1692 ASSERT(instance->correspondingElement() == lastCorrespondingElement); 1693 1694 if (instance == m_lastInstanceUnderMouse) 1695 continue; 1696 1697 if (instance->correspondingUseElement() != lastCorrespondingUseElement) 1698 continue; 1699 1700 SVGElement* shadowTreeElement = instance->shadowTreeElement(); 1701 if (!shadowTreeElement->inDocument() || m_lastNodeUnderMouse == shadowTreeElement) 1702 continue; 1703 1704 m_lastNodeUnderMouse = shadowTreeElement; 1705 m_lastInstanceUnderMouse = instance; 1706 break; 1707 } 1708 } 1709 } 1710#endif 1711 1712 // Fire mouseout/mouseover if the mouse has shifted to a different node. 1713 if (fireMouseOverOut) { 1714 if (m_lastNodeUnderMouse && m_lastNodeUnderMouse->document() != m_frame->document()) { 1715 m_lastNodeUnderMouse = 0; 1716 m_lastScrollbarUnderMouse = 0; 1717#if ENABLE(SVG) 1718 m_lastInstanceUnderMouse = 0; 1719#endif 1720 } 1721 1722 if (m_lastNodeUnderMouse != m_nodeUnderMouse) { 1723 // send mouseout event to the old node 1724 if (m_lastNodeUnderMouse) 1725 m_lastNodeUnderMouse->dispatchMouseEvent(mouseEvent, eventNames().mouseoutEvent, 0, m_nodeUnderMouse.get()); 1726 // send mouseover event to the new node 1727 if (m_nodeUnderMouse) 1728 m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventNames().mouseoverEvent, 0, m_lastNodeUnderMouse.get()); 1729 } 1730 m_lastNodeUnderMouse = m_nodeUnderMouse; 1731#if ENABLE(SVG) 1732 m_lastInstanceUnderMouse = instanceAssociatedWithShadowTreeElement(m_nodeUnderMouse.get()); 1733#endif 1734 } 1735} 1736 1737bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool /*cancelable*/, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder) 1738{ 1739 if (FrameView* view = m_frame->view()) 1740 view->resetDeferredRepaintDelay(); 1741 1742 updateMouseEventTargetNode(targetNode, mouseEvent, setUnder); 1743 1744 bool swallowEvent = false; 1745 1746 if (m_nodeUnderMouse) 1747 swallowEvent = m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventType, clickCount); 1748 1749 if (!swallowEvent && eventType == eventNames().mousedownEvent) { 1750 // The layout needs to be up to date to determine if an element is focusable. 1751 m_frame->document()->updateLayoutIgnorePendingStylesheets(); 1752 1753 // Blur current focus node when a link/button is clicked; this 1754 // is expected by some sites that rely on onChange handlers running 1755 // from form fields before the button click is processed. 1756 Node* node = m_nodeUnderMouse.get(); 1757 RenderObject* renderer = node ? node->renderer() : 0; 1758 1759 // Walk up the render tree to search for a node to focus. 1760 // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields. 1761 while (renderer) { 1762 node = renderer->node(); 1763 if (node && node->isFocusable()) { 1764 // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus a 1765 // node on mouse down if it's selected and inside a focused node. It will be 1766 // focused if the user does a mouseup over it, however, because the mouseup 1767 // will set a selection inside it, which will call setFocuseNodeIfNeeded. 1768 ExceptionCode ec = 0; 1769 Node* n = node->isShadowNode() ? node->shadowParentNode() : node; 1770 if (m_frame->selection()->isRange() && 1771 m_frame->selection()->toNormalizedRange()->compareNode(n, ec) == Range::NODE_INSIDE && 1772 n->isDescendantOf(m_frame->document()->focusedNode())) 1773 return false; 1774 1775 break; 1776 } 1777 1778 renderer = renderer->parent(); 1779 } 1780 1781 // If focus shift is blocked, we eat the event. Note we should never clear swallowEvent 1782 // if the page already set it (e.g., by canceling default behavior). 1783 if (Page* page = m_frame->page()) { 1784 if (node && node->isMouseFocusable()) { 1785 if (!page->focusController()->setFocusedNode(node, m_frame)) 1786 swallowEvent = true; 1787 } else if (!node || !node->focused()) { 1788 if (!page->focusController()->setFocusedNode(0, m_frame)) 1789 swallowEvent = true; 1790 } 1791 } 1792 } 1793 1794 return swallowEvent; 1795} 1796 1797#if !PLATFORM(GTK) && !(PLATFORM(CHROMIUM) && OS(LINUX)) 1798bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult&) const 1799{ 1800 return false; 1801} 1802#endif 1803 1804bool EventHandler::handleWheelEvent(PlatformWheelEvent& e) 1805{ 1806 Document* doc = m_frame->document(); 1807 1808 RenderObject* docRenderer = doc->renderer(); 1809 if (!docRenderer) 1810 return false; 1811 1812 RefPtr<FrameView> protector(m_frame->view()); 1813 1814 FrameView* view = m_frame->view(); 1815 if (!view) 1816 return false; 1817 setFrameWasScrolledByUser(); 1818 IntPoint vPoint = view->windowToContents(e.pos()); 1819 1820 Node* node; 1821 bool isOverWidget; 1822 bool didSetLatchedNode = false; 1823 1824 HitTestRequest request(HitTestRequest::ReadOnly); 1825 HitTestResult result(vPoint); 1826 doc->renderView()->layer()->hitTest(request, result); 1827 1828 if (m_useLatchedWheelEventNode) { 1829 if (!m_latchedWheelEventNode) { 1830 m_latchedWheelEventNode = result.innerNode(); 1831 m_widgetIsLatched = result.isOverWidget(); 1832 didSetLatchedNode = true; 1833 } 1834 1835 node = m_latchedWheelEventNode.get(); 1836 isOverWidget = m_widgetIsLatched; 1837 } else { 1838 if (m_latchedWheelEventNode) 1839 m_latchedWheelEventNode = 0; 1840 if (m_previousWheelScrolledNode) 1841 m_previousWheelScrolledNode = 0; 1842 1843 node = result.innerNode(); 1844 isOverWidget = result.isOverWidget(); 1845 } 1846 1847 if (shouldTurnVerticalTicksIntoHorizontal(result)) 1848 e.turnVerticalTicksIntoHorizontal(); 1849 1850 if (node) { 1851 // Figure out which view to send the event to. 1852 RenderObject* target = node->renderer(); 1853 1854 if (isOverWidget && target && target->isWidget()) { 1855 Widget* widget = toRenderWidget(target)->widget(); 1856 if (widget && passWheelEventToWidget(e, widget)) { 1857 e.accept(); 1858 return true; 1859 } 1860 } 1861 1862 node = node->shadowAncestorNode(); 1863 node->dispatchWheelEvent(e); 1864 if (e.isAccepted()) 1865 return true; 1866 1867 // If we don't have a renderer, send the wheel event to the first node we find with a renderer. 1868 // This is needed for <option> and <optgroup> elements so that <select>s get a wheel scroll. 1869 while (node && !node->renderer()) 1870 node = node->parent(); 1871 1872 if (node && node->renderer()) { 1873 // Just break up into two scrolls if we need to. Diagonal movement on 1874 // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set). 1875 Node* stopNode = m_previousWheelScrolledNode.get(); 1876 scrollAndAcceptEvent(e.deltaX(), ScrollLeft, ScrollRight, e, node, &stopNode); 1877 scrollAndAcceptEvent(e.deltaY(), ScrollUp, ScrollDown, e, node, &stopNode); 1878 if (!m_useLatchedWheelEventNode) 1879 m_previousWheelScrolledNode = stopNode; 1880 } 1881 } 1882 1883 if (e.isAccepted()) 1884 return true; 1885 1886 view = m_frame->view(); 1887 if (!view) 1888 return false; 1889 1890 view->wheelEvent(e); 1891 return e.isAccepted(); 1892} 1893 1894#if ENABLE(CONTEXT_MENUS) 1895bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event) 1896{ 1897 Document* doc = m_frame->document(); 1898 FrameView* v = m_frame->view(); 1899 if (!v) 1900 return false; 1901 1902 bool swallowEvent; 1903 IntPoint viewportPos = v->windowToContents(event.pos()); 1904 HitTestRequest request(HitTestRequest::Active); 1905 MouseEventWithHitTestResults mev = doc->prepareMouseEvent(request, viewportPos, event); 1906 1907 // Context menu events shouldn't select text in GTK+ applications or in Chromium. 1908 // FIXME: This should probably be configurable by embedders. Consider making it a WebPreferences setting. 1909 // See: https://bugs.webkit.org/show_bug.cgi?id=15279 1910#if !PLATFORM(GTK) && !PLATFORM(CHROMIUM) 1911 if (!m_frame->selection()->contains(viewportPos) && 1912 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse. 1913 // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items 1914 // available for text selections. But only if we're above text. 1915 (m_frame->selection()->isContentEditable() || (mev.targetNode() && mev.targetNode()->isTextNode()))) { 1916 m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection 1917 selectClosestWordOrLinkFromMouseEvent(mev); 1918 } 1919#endif 1920 1921 swallowEvent = dispatchMouseEvent(eventNames().contextmenuEvent, mev.targetNode(), true, 0, event, true); 1922 1923 return swallowEvent; 1924} 1925#endif // ENABLE(CONTEXT_MENUS) 1926 1927void EventHandler::scheduleHoverStateUpdate() 1928{ 1929 if (!m_hoverTimer.isActive()) 1930 m_hoverTimer.startOneShot(0); 1931} 1932 1933// Whether or not a mouse down can begin the creation of a selection. Fires the selectStart event. 1934bool EventHandler::canMouseDownStartSelect(Node* node) 1935{ 1936 if (!node || !node->renderer()) 1937 return true; 1938 1939 // Some controls and images can't start a select on a mouse down. 1940 if (!node->canStartSelection()) 1941 return false; 1942 1943 for (RenderObject* curr = node->renderer(); curr; curr = curr->parent()) { 1944 if (Node* node = curr->node()) 1945 return node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true)); 1946 } 1947 1948 return true; 1949} 1950 1951#if ENABLE(DRAG_SUPPORT) 1952bool EventHandler::canMouseDragExtendSelect(Node* node) 1953{ 1954 if (!node || !node->renderer()) 1955 return true; 1956 1957 for (RenderObject* curr = node->renderer(); curr; curr = curr->parent()) { 1958 if (Node* node = curr->node()) 1959 return node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true)); 1960 } 1961 1962 return true; 1963} 1964#endif // ENABLE(DRAG_SUPPORT) 1965 1966void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet) 1967{ 1968 m_frameSetBeingResized = frameSet; 1969} 1970 1971void EventHandler::resizeLayerDestroyed() 1972{ 1973 ASSERT(m_resizeLayer); 1974 m_resizeLayer = 0; 1975} 1976 1977void EventHandler::hoverTimerFired(Timer<EventHandler>*) 1978{ 1979 m_hoverTimer.stop(); 1980 1981 ASSERT(m_frame); 1982 ASSERT(m_frame->document()); 1983 1984 if (RenderView* renderer = m_frame->contentRenderer()) { 1985 if (FrameView* view = m_frame->view()) { 1986 HitTestRequest request(HitTestRequest::MouseMove); 1987 HitTestResult result(view->windowToContents(m_currentMousePosition)); 1988 renderer->layer()->hitTest(request, result); 1989 m_frame->document()->updateStyleIfNeeded(); 1990 } 1991 } 1992} 1993 1994static Node* eventTargetNodeForDocument(Document* doc) 1995{ 1996 if (!doc) 1997 return 0; 1998 Node* node = doc->focusedNode(); 1999 2000#if defined(ANDROID_PLUGINS) 2001 if (!node && doc->frame() && doc->frame()->view()) 2002 node = android::WebViewCore::getWebViewCore(doc->frame()->view()) 2003 ->cursorNodeIsPlugin(); 2004#endif 2005 2006 if (!node && doc->isHTMLDocument()) 2007 node = doc->body(); 2008 if (!node) 2009 node = doc->documentElement(); 2010 return node; 2011} 2012 2013bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt) 2014{ 2015 // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do. 2016 // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and 2017 // lower case variants are present in a document, the correct element is matched based on Shift key state. 2018 // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively. 2019 ASSERT(!(accessKeyModifiers() & PlatformKeyboardEvent::ShiftKey)); 2020 if ((evt.modifiers() & ~PlatformKeyboardEvent::ShiftKey) != accessKeyModifiers()) 2021 return false; 2022 String key = evt.unmodifiedText(); 2023 Element* elem = m_frame->document()->getElementByAccessKey(key.lower()); 2024 if (!elem) 2025 return false; 2026 elem->accessKeyAction(false); 2027 return true; 2028} 2029 2030#if !PLATFORM(MAC) 2031bool EventHandler::needsKeyboardEventDisambiguationQuirks() const 2032{ 2033 return false; 2034} 2035#endif 2036 2037bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent) 2038{ 2039#if ENABLE(PAN_SCROLLING) 2040 if (Page* page = m_frame->page()) { 2041 if (page->mainFrame()->eventHandler()->panScrollInProgress() || m_autoscrollInProgress) { 2042 // If a key is pressed while the autoscroll/panScroll is in progress then we want to stop 2043 if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyDown || initialKeyEvent.type() == PlatformKeyboardEvent::RawKeyDown) 2044 stopAutoscrollTimer(); 2045 2046 // If we were in autoscroll/panscroll mode, we swallow the key event 2047 return true; 2048 } 2049 } 2050#endif 2051 2052 // Check for cases where we are too early for events -- possible unmatched key up 2053 // from pressing return in the location bar. 2054 RefPtr<Node> node = eventTargetNodeForDocument(m_frame->document()); 2055 if (!node) 2056 return false; 2057 2058 if (FrameView* view = m_frame->view()) 2059 view->resetDeferredRepaintDelay(); 2060 2061 // FIXME: what is this doing here, in keyboard event handler? 2062 m_frame->loader()->resetMultipleFormSubmissionProtection(); 2063 2064 // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match. 2065 // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict 2066 // with access keys. Then we dispatch keydown, but suppress its default handling. 2067 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages. 2068 // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events. 2069 bool matchedAnAccessKey = false; 2070 if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyDown) 2071 matchedAnAccessKey = handleAccessKey(initialKeyEvent); 2072 2073 // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch. 2074 if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyUp || initialKeyEvent.type() == PlatformKeyboardEvent::Char) 2075 return !node->dispatchKeyEvent(initialKeyEvent); 2076 2077 bool backwardCompatibilityMode = needsKeyboardEventDisambiguationQuirks(); 2078 2079 ExceptionCode ec; 2080 PlatformKeyboardEvent keyDownEvent = initialKeyEvent; 2081 if (keyDownEvent.type() != PlatformKeyboardEvent::RawKeyDown) 2082 keyDownEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::RawKeyDown, backwardCompatibilityMode); 2083 RefPtr<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView()); 2084 if (matchedAnAccessKey) 2085 keydown->setDefaultPrevented(true); 2086 keydown->setTarget(node); 2087 2088 if (initialKeyEvent.type() == PlatformKeyboardEvent::RawKeyDown) { 2089 node->dispatchEvent(keydown, ec); 2090 return keydown->defaultHandled() || keydown->defaultPrevented(); 2091 } 2092 2093 // Run input method in advance of DOM event handling. This may result in the IM 2094 // modifying the page prior the keydown event, but this behaviour is necessary 2095 // in order to match IE: 2096 // 1. preventing default handling of keydown and keypress events has no effect on IM input; 2097 // 2. if an input method handles the event, its keyCode is set to 229 in keydown event. 2098 m_frame->editor()->handleInputMethodKeydown(keydown.get()); 2099 2100 bool handledByInputMethod = keydown->defaultHandled(); 2101 2102 if (handledByInputMethod) { 2103 keyDownEvent.setWindowsVirtualKeyCode(CompositionEventKeyCode); 2104 keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView()); 2105 keydown->setTarget(node); 2106 keydown->setDefaultHandled(); 2107 } 2108 2109 node->dispatchEvent(keydown, ec); 2110 bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented(); 2111 if (handledByInputMethod || (keydownResult && !backwardCompatibilityMode)) 2112 return keydownResult; 2113 2114 // Focus may have changed during keydown handling, so refetch node. 2115 // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original node. 2116 if (!keydownResult) { 2117 node = eventTargetNodeForDocument(m_frame->document()); 2118 if (!node) 2119 return false; 2120 } 2121 2122 PlatformKeyboardEvent keyPressEvent = initialKeyEvent; 2123 keyPressEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::Char, backwardCompatibilityMode); 2124 if (keyPressEvent.text().isEmpty()) 2125 return keydownResult; 2126 RefPtr<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_frame->document()->defaultView()); 2127 keypress->setTarget(node); 2128 if (keydownResult) 2129 keypress->setDefaultPrevented(true); 2130#if PLATFORM(MAC) 2131 keypress->keypressCommands() = keydown->keypressCommands(); 2132#endif 2133 node->dispatchEvent(keypress, ec); 2134 2135 return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled(); 2136} 2137 2138void EventHandler::handleKeyboardSelectionMovement(KeyboardEvent* event) 2139{ 2140 if (!event) 2141 return; 2142 2143 String key = event->keyIdentifier(); 2144 bool isShifted = event->getModifierState("Shift"); 2145 bool isOptioned = event->getModifierState("Alt"); 2146 bool isCommanded = event->getModifierState("Meta"); 2147 2148 if (key == "Up") { 2149 m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::BACKWARD, (isCommanded) ? DocumentBoundary : LineGranularity, true); 2150 event->setDefaultHandled(); 2151 } 2152 else if (key == "Down") { 2153 m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::FORWARD, (isCommanded) ? DocumentBoundary : LineGranularity, true); 2154 event->setDefaultHandled(); 2155 } 2156 else if (key == "Left") { 2157 m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::LEFT, (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity, true); 2158 event->setDefaultHandled(); 2159 } 2160 else if (key == "Right") { 2161 m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::RIGHT, (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity, true); 2162 event->setDefaultHandled(); 2163 } 2164} 2165 2166void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event) 2167{ 2168 if (event->type() == eventNames().keydownEvent) { 2169 m_frame->editor()->handleKeyboardEvent(event); 2170 if (event->defaultHandled()) 2171 return; 2172 if (event->keyIdentifier() == "U+0009") 2173 defaultTabEventHandler(event); 2174 2175 // provides KB navigation and selection for enhanced accessibility users 2176 if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled()) 2177 handleKeyboardSelectionMovement(event); 2178 } 2179 if (event->type() == eventNames().keypressEvent) { 2180 m_frame->editor()->handleKeyboardEvent(event); 2181 if (event->defaultHandled()) 2182 return; 2183 if (event->charCode() == ' ') 2184 defaultSpaceEventHandler(event); 2185 } 2186} 2187 2188#if ENABLE(DRAG_SUPPORT) 2189bool EventHandler::dragHysteresisExceeded(const FloatPoint& floatDragViewportLocation) const 2190{ 2191 IntPoint dragViewportLocation((int)floatDragViewportLocation.x(), (int)floatDragViewportLocation.y()); 2192 return dragHysteresisExceeded(dragViewportLocation); 2193} 2194 2195bool EventHandler::dragHysteresisExceeded(const IntPoint& dragViewportLocation) const 2196{ 2197 FrameView* view = m_frame->view(); 2198 if (!view) 2199 return false; 2200 IntPoint dragLocation = view->windowToContents(dragViewportLocation); 2201 IntSize delta = dragLocation - m_mouseDownPos; 2202 2203 int threshold = GeneralDragHysteresis; 2204 if (dragState().m_dragSrcIsImage) 2205 threshold = ImageDragHysteresis; 2206 else if (dragState().m_dragSrcIsLink) 2207 threshold = LinkDragHysteresis; 2208 else if (dragState().m_dragSrcInSelection) 2209 threshold = TextDragHysteresis; 2210 2211 return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold; 2212} 2213 2214void EventHandler::freeClipboard() 2215{ 2216 if (dragState().m_dragClipboard) 2217 dragState().m_dragClipboard->setAccessPolicy(ClipboardNumb); 2218} 2219 2220bool EventHandler::shouldDragAutoNode(Node* node, const IntPoint& point) const 2221{ 2222 if (!node || !m_frame->view()) 2223 return false; 2224 Page* page = m_frame->page(); 2225 return page && page->dragController()->mayStartDragAtEventLocation(m_frame, point); 2226} 2227 2228void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation) 2229{ 2230 if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) { 2231 dragState().m_dragClipboard->setDestinationOperation(operation); 2232 // for now we don't care if event handler cancels default behavior, since there is none 2233 dispatchDragSrcEvent(eventNames().dragendEvent, event); 2234 } 2235 freeClipboard(); 2236 dragState().m_dragSrc = 0; 2237 // In case the drag was ended due to an escape key press we need to ensure 2238 // that consecutive mousemove events don't reinitiate the drag and drop. 2239 m_mouseDownMayStartDrag = false; 2240} 2241 2242// returns if we should continue "default processing", i.e., whether eventhandler canceled 2243bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event) 2244{ 2245 return !dispatchDragEvent(eventType, dragState().m_dragSrc.get(), event, dragState().m_dragClipboard.get()); 2246} 2247 2248bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event) 2249{ 2250 if (event.event().button() != LeftButton || event.event().eventType() != MouseEventMoved) { 2251 // If we allowed the other side of the bridge to handle a drag 2252 // last time, then m_mousePressed might still be set. So we 2253 // clear it now to make sure the next move after a drag 2254 // doesn't look like a drag. 2255 m_mousePressed = false; 2256 return false; 2257 } 2258 2259 if (eventLoopHandleMouseDragged(event)) 2260 return true; 2261 2262 // Careful that the drag starting logic stays in sync with eventMayStartDrag() 2263 2264 if (m_mouseDownMayStartDrag && !dragState().m_dragSrc) { 2265 allowDHTMLDrag(dragState().m_dragSrcMayBeDHTML, dragState().m_dragSrcMayBeUA); 2266 if (!dragState().m_dragSrcMayBeDHTML && !dragState().m_dragSrcMayBeUA) 2267 m_mouseDownMayStartDrag = false; // no element is draggable 2268 } 2269 2270 if (m_mouseDownMayStartDrag && !dragState().m_dragSrc) { 2271 // try to find an element that wants to be dragged 2272 HitTestRequest request(HitTestRequest::ReadOnly); 2273 HitTestResult result(m_mouseDownPos); 2274 m_frame->contentRenderer()->layer()->hitTest(request, result); 2275 Node* node = result.innerNode(); 2276 if (node && node->renderer()) 2277 dragState().m_dragSrc = node->renderer()->draggableNode(dragState().m_dragSrcMayBeDHTML, dragState().m_dragSrcMayBeUA, 2278 m_mouseDownPos.x(), m_mouseDownPos.y(), dragState().m_dragSrcIsDHTML); 2279 else 2280 dragState().m_dragSrc = 0; 2281 2282 if (!dragState().m_dragSrc) 2283 m_mouseDownMayStartDrag = false; // no element is draggable 2284 else { 2285 // remember some facts about this source, while we have a HitTestResult handy 2286 node = result.URLElement(); 2287 dragState().m_dragSrcIsLink = node && node->isLink(); 2288 2289 node = result.innerNonSharedNode(); 2290 dragState().m_dragSrcIsImage = node && node->renderer() && node->renderer()->isImage(); 2291 2292 dragState().m_dragSrcInSelection = m_frame->selection()->contains(m_mouseDownPos); 2293 } 2294 } 2295 2296 // For drags starting in the selection, the user must wait between the mousedown and mousedrag, 2297 // or else we bail on the dragging stuff and allow selection to occur 2298 if (m_mouseDownMayStartDrag && !dragState().m_dragSrcIsImage && dragState().m_dragSrcInSelection && event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay) { 2299 m_mouseDownMayStartDrag = false; 2300 dragState().m_dragSrc = 0; 2301 // ...but if this was the first click in the window, we don't even want to start selection 2302 if (eventActivatedView(event.event())) 2303 m_mouseDownMayStartSelect = false; 2304 } 2305 2306 if (!m_mouseDownMayStartDrag) 2307 return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll; 2308 2309 // We are starting a text/image/url drag, so the cursor should be an arrow 2310 if (FrameView* view = m_frame->view()) { 2311 // FIXME <rdar://7577595>: Custom cursors aren't supported during drag and drop (default to pointer). 2312 view->setCursor(pointerCursor()); 2313 } 2314 2315 if (!dragHysteresisExceeded(event.event().pos())) 2316 return true; 2317 2318 // Once we're past the hysteresis point, we don't want to treat this gesture as a click 2319 invalidateClick(); 2320 2321 DragOperation srcOp = DragOperationNone; 2322 2323 freeClipboard(); // would only happen if we missed a dragEnd. Do it anyway, just 2324 // to make sure it gets numbified 2325 dragState().m_dragClipboard = createDraggingClipboard(); 2326 2327 if (dragState().m_dragSrcMayBeDHTML) { 2328 // Check to see if the is a DOM based drag, if it is get the DOM specified drag 2329 // image and offset 2330 if (dragState().m_dragSrcIsDHTML) { 2331 if (RenderObject* renderer = dragState().m_dragSrc->renderer()) { 2332 // FIXME: This doesn't work correctly with transforms. 2333 FloatPoint absPos = renderer->localToAbsolute(); 2334 IntSize delta = m_mouseDownPos - roundedIntPoint(absPos); 2335 dragState().m_dragClipboard->setDragImageElement(dragState().m_dragSrc.get(), IntPoint() + delta); 2336 } else { 2337 // The renderer has disappeared, this can happen if the onStartDrag handler has hidden 2338 // the element in some way. In this case we just kill the drag. 2339 m_mouseDownMayStartDrag = false; 2340 goto cleanupDrag; 2341 } 2342 } 2343 2344 m_mouseDownMayStartDrag = dispatchDragSrcEvent(eventNames().dragstartEvent, m_mouseDown) 2345 && !m_frame->selection()->isInPasswordField(); 2346 2347 // Invalidate clipboard here against anymore pasteboard writing for security. The drag 2348 // image can still be changed as we drag, but not the pasteboard data. 2349 dragState().m_dragClipboard->setAccessPolicy(ClipboardImageWritable); 2350 2351 if (m_mouseDownMayStartDrag) { 2352 // gather values from DHTML element, if it set any 2353 srcOp = dragState().m_dragClipboard->sourceOperation(); 2354 2355 // Yuck, a draggedImage:moveTo: message can be fired as a result of kicking off the 2356 // drag with dragImage! Because of that dumb reentrancy, we may think we've not 2357 // started the drag when that happens. So we have to assume it's started before we 2358 // kick it off. 2359 dragState().m_dragClipboard->setDragHasStarted(); 2360 } 2361 } 2362 2363 if (m_mouseDownMayStartDrag) { 2364 Page* page = m_frame->page(); 2365 DragController* dragController = page ? page->dragController() : 0; 2366 bool startedDrag = dragController && dragController->startDrag(m_frame, dragState().m_dragClipboard.get(), srcOp, event.event(), m_mouseDownPos, dragState().m_dragSrcIsDHTML); 2367 if (!startedDrag && dragState().m_dragSrcMayBeDHTML) { 2368 // Drag was canned at the last minute - we owe m_dragSrc a DRAGEND event 2369 dispatchDragSrcEvent(eventNames().dragendEvent, event.event()); 2370 m_mouseDownMayStartDrag = false; 2371 } 2372 } 2373 2374cleanupDrag: 2375 if (!m_mouseDownMayStartDrag) { 2376 // something failed to start the drag, cleanup 2377 freeClipboard(); 2378 dragState().m_dragSrc = 0; 2379 } 2380 2381 // No more default handling (like selection), whether we're past the hysteresis bounds or not 2382 return true; 2383} 2384#endif // ENABLE(DRAG_SUPPORT) 2385 2386bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, bool isLineBreak, bool isBackTab) 2387{ 2388 // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline), 2389 // and avoid dispatching text input events from keydown default handlers. 2390 ASSERT(!underlyingEvent || !underlyingEvent->isKeyboardEvent() || static_cast<KeyboardEvent*>(underlyingEvent)->type() == eventNames().keypressEvent); 2391 2392 if (!m_frame) 2393 return false; 2394 2395 EventTarget* target; 2396 if (underlyingEvent) 2397 target = underlyingEvent->target(); 2398 else 2399 target = eventTargetNodeForDocument(m_frame->document()); 2400 if (!target) 2401 return false; 2402 2403 if (FrameView* view = m_frame->view()) 2404 view->resetDeferredRepaintDelay(); 2405 2406 RefPtr<TextEvent> event = TextEvent::create(m_frame->domWindow(), text); 2407 event->setUnderlyingEvent(underlyingEvent); 2408 event->setIsLineBreak(isLineBreak); 2409 event->setIsBackTab(isBackTab); 2410 ExceptionCode ec; 2411 target->dispatchEvent(event, ec); 2412 return event->defaultHandled(); 2413} 2414 2415 2416#if !PLATFORM(MAC) && !PLATFORM(QT) && !PLATFORM(HAIKU) 2417bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent*) const 2418{ 2419 return false; 2420} 2421#endif 2422 2423bool EventHandler::tabsToLinks(KeyboardEvent* event) const 2424{ 2425 Page* page = m_frame->page(); 2426 if (!page) 2427 return false; 2428 2429 if (page->chrome()->client()->tabsToLinks()) 2430 return !invertSenseOfTabsToLinks(event); 2431 2432 return invertSenseOfTabsToLinks(event); 2433} 2434 2435void EventHandler::defaultTextInputEventHandler(TextEvent* event) 2436{ 2437 String data = event->data(); 2438 if (data == "\n") { 2439 if (event->isLineBreak()) { 2440 if (m_frame->editor()->insertLineBreak()) 2441 event->setDefaultHandled(); 2442 } else { 2443 if (m_frame->editor()->insertParagraphSeparator()) 2444 event->setDefaultHandled(); 2445 } 2446 } else { 2447 if (m_frame->editor()->insertTextWithoutSendingTextEvent(data, false, event)) 2448 event->setDefaultHandled(); 2449 } 2450} 2451 2452#if PLATFORM(QT) || PLATFORM(MAC) || PLATFORM(ANDROID) 2453 2454// These two platforms handle the space event in the platform-specific WebKit code. 2455// Eventually it would be good to eliminate that and use the code here instead, but 2456// the Qt version is inside an ifdef and the Mac version has some extra behavior 2457// so we can't unify everything yet. 2458void EventHandler::defaultSpaceEventHandler(KeyboardEvent*) 2459{ 2460} 2461 2462#else 2463 2464void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event) 2465{ 2466 ScrollDirection direction = event->shiftKey() ? ScrollUp : ScrollDown; 2467 if (scrollOverflow(direction, ScrollByPage)) { 2468 event->setDefaultHandled(); 2469 return; 2470 } 2471 2472 FrameView* view = m_frame->view(); 2473 if (!view) 2474 return; 2475 2476 if (view->scroll(direction, ScrollByPage)) 2477 event->setDefaultHandled(); 2478} 2479 2480#endif 2481 2482void EventHandler::defaultTabEventHandler(KeyboardEvent* event) 2483{ 2484 // We should only advance focus on tabs if no special modifier keys are held down. 2485 if (event->ctrlKey() || event->metaKey() || event->altGraphKey()) 2486 return; 2487 2488 Page* page = m_frame->page(); 2489 if (!page) 2490 return; 2491 if (!page->tabKeyCyclesThroughElements()) 2492 return; 2493 2494 FocusDirection focusDirection = event->shiftKey() ? FocusDirectionBackward : FocusDirectionForward; 2495 2496 // Tabs can be used in design mode editing. 2497 if (m_frame->document()->inDesignMode()) 2498 return; 2499 2500 if (page->focusController()->advanceFocus(focusDirection, event)) 2501 event->setDefaultHandled(); 2502} 2503 2504void EventHandler::capsLockStateMayHaveChanged() 2505{ 2506 Document* d = m_frame->document(); 2507 if (Node* node = d->focusedNode()) { 2508 if (RenderObject* r = node->renderer()) { 2509 if (r->isTextField()) 2510 toRenderTextControlSingleLine(r)->capsLockStateMayHaveChanged(); 2511 } 2512 } 2513} 2514 2515void EventHandler::sendResizeEvent() 2516{ 2517 m_frame->document()->dispatchWindowEvent(Event::create(eventNames().resizeEvent, false, false)); 2518} 2519 2520void EventHandler::sendScrollEvent() 2521{ 2522 setFrameWasScrolledByUser(); 2523 if (m_frame->view()) 2524 m_frame->document()->dispatchEvent(Event::create(eventNames().scrollEvent, true, false)); 2525} 2526 2527void EventHandler::setFrameWasScrolledByUser() 2528{ 2529 FrameView* v = m_frame->view(); 2530 if (v) 2531 v->setWasScrolledByUser(true); 2532} 2533 2534bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& mev, Scrollbar* scrollbar) 2535{ 2536 if (!scrollbar || !scrollbar->enabled()) 2537 return false; 2538 setFrameWasScrolledByUser(); 2539 return scrollbar->mouseDown(mev.event()); 2540} 2541 2542// If scrollbar (under mouse) is different from last, send a mouse exited. Set 2543// last to scrollbar if setLast is true; else set last to 0. 2544void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setLast) 2545{ 2546 if (m_lastScrollbarUnderMouse != scrollbar) { 2547 // Send mouse exited to the old scrollbar. 2548 if (m_lastScrollbarUnderMouse) 2549 m_lastScrollbarUnderMouse->mouseExited(); 2550 m_lastScrollbarUnderMouse = setLast ? scrollbar : 0; 2551 } 2552} 2553 2554#if ENABLE(TOUCH_EVENTS) 2555#if PLATFORM(ANDROID) 2556// TODO(benm): On Android we return an int back to Java to signify whether the default actions 2557// for longpress/doubletap in the Browser should be prevented. I think that before upstreaming 2558// to webkit.org we can refactor the Java side to not require this. 2559int EventHandler::handleTouchEvent(const PlatformTouchEvent& event) 2560#else 2561bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) 2562#endif 2563{ 2564 RefPtr<TouchList> touches = TouchList::create(); 2565 RefPtr<TouchList> pressedTouches = TouchList::create(); 2566 RefPtr<TouchList> releasedTouches = TouchList::create(); 2567 RefPtr<TouchList> movedTouches = TouchList::create(); 2568 RefPtr<TouchList> targetTouches = TouchList::create(); 2569 RefPtr<TouchList> cancelTouches = TouchList::create(); 2570 RefPtr<TouchList> stationaryTouches = TouchList::create(); 2571 2572 const Vector<PlatformTouchPoint>& points = event.touchPoints(); 2573 AtomicString* eventName = 0; 2574 2575 for (int i = 0; i < points.size(); ++i) { 2576 const PlatformTouchPoint& point = points[i]; 2577 IntPoint pagePoint = documentPointForWindowPoint(m_frame, point.pos()); 2578 HitTestResult result = hitTestResultAtPoint(pagePoint, /*allowShadowContent*/ false); 2579 Node* target = result.innerNode(); 2580 2581 // Touch events should not go to text nodes 2582 if (target && target->isTextNode()) 2583 target = target->parentNode(); 2584 2585 Document* doc = target->document(); 2586 if (!doc) 2587 continue; 2588 if (!doc->hasListenerType(Document::TOUCH_LISTENER)) 2589 continue; 2590 2591 if (m_frame != doc->frame()) { 2592 // pagePoint should always be relative to the target elements containing frame. 2593 pagePoint = documentPointForWindowPoint(doc->frame(), point.pos()); 2594 } 2595 2596 int adjustedPageX = lroundf(pagePoint.x() / m_frame->pageZoomFactor()); 2597 int adjustedPageY = lroundf(pagePoint.y() / m_frame->pageZoomFactor()); 2598 2599 // ANDROID 2600 // The touch event should act on the originating touch target, not the current target 2601 // TODO: Upstream this fix to webkit.org (see webkit bug 34585) 2602 int touchPointId = point.id(); 2603 EventTarget* touchTarget = 0; 2604 if (point.state() == PlatformTouchPoint::TouchPressed) { 2605 m_originatingTouchPointTargets.set(touchPointId, target); 2606 touchTarget = target; 2607 } else 2608 touchTarget = m_originatingTouchPointTargets.get(touchPointId).get(); 2609 2610 ASSERT(touchTarget); 2611 2612 RefPtr<Touch> touch = Touch::create(doc->frame(), touchTarget, touchPointId, 2613 point.screenPos().x(), point.screenPos().y(), 2614 adjustedPageX, adjustedPageY); 2615 2616 // touches should contain information about every touch currently on the screen. 2617 if (point.state() != PlatformTouchPoint::TouchReleased) 2618 touches->append(touch); 2619 2620 // If it's a stationary touch, we don't want to process it further at the moment. 2621 // We may add it to targetTouches later. 2622 if (point.state() == PlatformTouchPoint::TouchStationary) { 2623 stationaryTouches->append(touch); 2624 continue; 2625 } 2626 2627 if ((event.type() == TouchStart 2628#if PLATFORM(ANDROID) 2629 || event.type() == TouchDoubleTap 2630 || event.type() == TouchLongPress 2631#endif 2632 ) && !i) { 2633 m_touchEventTarget = target; 2634 m_firstTouchScreenPos = point.screenPos(); 2635 m_firstTouchPagePos = pagePoint; 2636 } 2637 2638 // Check to see if this should be added to targetTouches. 2639 // If we've got here then the touch is not stationary. If it's a release, it's no longer 2640 // a touch on the screen so we don't want it in targetTouches. The first touch that gets 2641 // to here defines the 'target' the touchTarget list uses. This seems arbitrary (much like 2642 // checking !i to set m_touchEventTarget above?) but seems to yield compatible behaviour. 2643 // 2644 // FIXME: Is this really the correct semantics for the touchTargets list? The touch event 2645 // spec is not clear to me. 2646 if (point.state() != PlatformTouchPoint::TouchReleased) { 2647 if (targetTouches->length() == 0) 2648 targetTouches->append(touch); 2649 else { 2650 if (touch->target() == targetTouches->item(0)->target()) 2651 targetTouches->append(touch); 2652 } 2653 } 2654 2655 // Now build up the correct list for changedTouches. 2656 if (point.state() == PlatformTouchPoint::TouchReleased) 2657 releasedTouches->append(touch); 2658 else if (point.state() == PlatformTouchPoint::TouchCancelled) 2659 cancelTouches->append(touch); 2660 else if (point.state() == PlatformTouchPoint::TouchPressed) 2661 pressedTouches->append(touch); 2662 else if (point.state() == PlatformTouchPoint::TouchMoved) 2663 movedTouches->append(touch); 2664 } 2665 2666 // Add any stationary touches to targetTouches if they match the target. 2667 EventTarget* targetTouchesTarget = 0; 2668 if (targetTouches->length()) 2669 targetTouchesTarget = targetTouches->item(0)->target(); 2670 else 2671 targetTouchesTarget = m_touchEventTarget.get(); 2672 2673 for (int i = 0; i < stationaryTouches->length(); ++i) { 2674 Touch* stationaryTouch = stationaryTouches->item(i); 2675 if (stationaryTouch->target() == targetTouchesTarget) 2676 targetTouches->append(stationaryTouch); 2677 } 2678 2679 if (!m_touchEventTarget) 2680#if PLATFORM(ANDROID) 2681 return 0; 2682#else 2683 return false; 2684#endif 2685 2686 bool defaultPrevented = false; 2687#if PLATFORM(ANDROID) 2688 // TODO (benm): We should be able to remove this prior to upstreaming once Java side refactorings to make 2689 // preventDeault work better are complete. 2690 bool longPressPrevented = false; 2691 bool doubleTapPrevented = false; 2692#endif 2693 2694 if (event.type() == TouchCancel) { 2695 eventName = &eventNames().touchcancelEvent; 2696 RefPtr<TouchEvent> cancelEv = 2697 TouchEvent::create(TouchList::create().get(), TouchList::create().get(), cancelTouches.get(), 2698 *eventName, m_touchEventTarget->document()->defaultView(), 2699 m_firstTouchScreenPos.x(), m_firstTouchScreenPos.y(), 2700 m_firstTouchPagePos.x(), m_firstTouchPagePos.y(), 2701 event.ctrlKey(), event.altKey(), event.shiftKey(), 2702 event.metaKey()); 2703 2704#if PLATFORM(ANDROID) 2705 cancelEv->setCreateTime(static_cast<DOMTimeStamp>(event.eventTime())); 2706#endif 2707 ExceptionCode ec = 0; 2708 m_touchEventTarget->dispatchEvent(cancelEv.get(), ec); 2709 defaultPrevented |= cancelEv->defaultPrevented(); 2710 } 2711 2712 if (releasedTouches->length() > 0) { 2713 eventName = &eventNames().touchendEvent; 2714 RefPtr<TouchEvent> endEv = 2715 TouchEvent::create(touches.get(), targetTouches.get(), releasedTouches.get(), 2716 *eventName, m_touchEventTarget->document()->defaultView(), 2717 m_firstTouchScreenPos.x(), m_firstTouchScreenPos.y(), 2718 m_firstTouchPagePos.x(), m_firstTouchPagePos.y(), 2719 event.ctrlKey(), event.altKey(), event.shiftKey(), 2720 event.metaKey()); 2721#if PLATFORM(ANDROID) 2722 endEv->setCreateTime(static_cast<DOMTimeStamp>(event.eventTime())); 2723#endif 2724 ExceptionCode ec = 0; 2725 m_touchEventTarget->dispatchEvent(endEv.get(), ec); 2726#if PLATFORM(ANDROID) 2727 defaultPrevented |= endEv->defaultPrevented(); 2728#else 2729 defaultPrevented = endEv->defaultPrevented(); 2730#endif 2731 } 2732 if (pressedTouches->length() > 0) { 2733#if PLATFORM(ANDROID) 2734 if (event.type() == TouchLongPress) { 2735 eventName = &eventNames().touchlongpressEvent; 2736 RefPtr<TouchEvent> longpressEv = 2737 TouchEvent::create(touches.get(), targetTouches.get(), pressedTouches.get(), 2738 *eventName, m_touchEventTarget->document()->defaultView(), 2739 m_firstTouchScreenPos.x(), m_firstTouchScreenPos.y(), 2740 m_firstTouchPagePos.x(), m_firstTouchPagePos.y(), 2741 event.ctrlKey(), event.altKey(), event.shiftKey(), 2742 event.metaKey()); 2743 longpressEv->setCreateTime(static_cast<DOMTimeStamp>(event.eventTime())); 2744 2745 ExceptionCode ec = 0; 2746 m_touchEventTarget->dispatchEvent(longpressEv.get(), ec); 2747 defaultPrevented |= longpressEv->defaultPrevented(); 2748 } else if (event.type() == TouchDoubleTap) { 2749 eventName = &eventNames().touchdoubletapEvent; 2750 RefPtr<TouchEvent> doubleTapEv = 2751 TouchEvent::create(touches.get(), targetTouches.get(), pressedTouches.get(), 2752 *eventName, m_touchEventTarget->document()->defaultView(), 2753 m_firstTouchScreenPos.x(), m_firstTouchScreenPos.y(), 2754 m_firstTouchPagePos.x(), m_firstTouchPagePos.y(), 2755 event.ctrlKey(), event.altKey(), event.shiftKey(), 2756 event.metaKey()); 2757 doubleTapEv->setCreateTime(static_cast<DOMTimeStamp>(event.eventTime())); 2758 2759 ExceptionCode ec = 0; 2760 m_touchEventTarget->dispatchEvent(doubleTapEv.get(), ec); 2761 defaultPrevented |= doubleTapEv->defaultPrevented(); 2762 } else { 2763#endif 2764 eventName = &eventNames().touchstartEvent; 2765 RefPtr<TouchEvent> startEv = 2766 TouchEvent::create(touches.get(), targetTouches.get(), pressedTouches.get(), 2767 *eventName, m_touchEventTarget->document()->defaultView(), 2768 m_firstTouchScreenPos.x(), m_firstTouchScreenPos.y(), 2769 m_firstTouchPagePos.x(), m_firstTouchPagePos.y(), 2770 event.ctrlKey(), event.altKey(), event.shiftKey(), 2771 event.metaKey()); 2772#if PLATFORM(ANDROID) 2773 startEv->setCreateTime(static_cast<DOMTimeStamp>(event.eventTime())); 2774#endif 2775 ExceptionCode ec = 0; 2776 m_touchEventTarget->dispatchEvent(startEv.get(), ec); 2777 defaultPrevented |= startEv->defaultPrevented(); 2778#if PLATFORM(ANDROID) 2779 longPressPrevented |= startEv->longPressPrevented(); 2780 doubleTapPrevented |= startEv->doubleTapPrevented(); 2781 } 2782#endif 2783 } 2784 2785 if (movedTouches->length() > 0) { 2786 eventName = &eventNames().touchmoveEvent; 2787 RefPtr<TouchEvent> moveEv = 2788 TouchEvent::create(touches.get(), targetTouches.get(), movedTouches.get(), 2789 *eventName, m_touchEventTarget->document()->defaultView(), 2790 m_firstTouchScreenPos.x(), m_firstTouchScreenPos.y(), 2791 m_firstTouchPagePos.x(), m_firstTouchPagePos.y(), 2792 event.ctrlKey(), event.altKey(), event.shiftKey(), 2793 event.metaKey()); 2794#if PLATFORM(ANDROID) 2795 moveEv->setCreateTime(static_cast<DOMTimeStamp>(event.eventTime())); 2796#endif 2797 ExceptionCode ec = 0; 2798 m_touchEventTarget->dispatchEvent(moveEv.get(), ec); 2799 defaultPrevented |= moveEv->defaultPrevented(); 2800 } 2801 2802 if (event.type() == TouchEnd || event.type() == TouchCancel) 2803 m_touchEventTarget = 0; 2804 2805#if PLATFORM(ANDROID) 2806 // TODO (benm): We should be able to remove this prior to upstreaming once Java side refactorings to make 2807 // preventDefault work better are complete. 2808 if (event.type() == TouchLongPress || event.type() == TouchDoubleTap) 2809 return 0; 2810 2811 return (defaultPrevented ? preventTouch : 0) 2812 | (longPressPrevented ? preventLongPress : 0) 2813 | (doubleTapPrevented ? preventDoubleTap : 0); 2814#else 2815 return defaultPrevented; 2816#endif 2817} 2818#endif 2819 2820} 2821