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