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