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