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