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