Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserv ed. | 2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserv ed. |
| 3 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) | 3 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) |
| 4 * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies) | 4 * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies) |
| 5 * | 5 * |
| 6 * Redistribution and use in source and binary forms, with or without | 6 * Redistribution and use in source and binary forms, with or without |
| 7 * modification, are permitted provided that the following conditions | 7 * modification, are permitted provided that the following conditions |
| 8 * are met: | 8 * are met: |
| 9 * 1. Redistributions of source code must retain the above copyright | 9 * 1. Redistributions of source code must retain the above copyright |
| 10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 27 | 27 |
| 28 #include "config.h" | 28 #include "config.h" |
| 29 #include "core/page/EventHandler.h" | 29 #include "core/page/EventHandler.h" |
| 30 | 30 |
| 31 #include "bindings/core/v8/ExceptionStatePlaceholder.h" | 31 #include "bindings/core/v8/ExceptionStatePlaceholder.h" |
| 32 #include "core/HTMLNames.h" | 32 #include "core/HTMLNames.h" |
| 33 #include "core/InputTypeNames.h" | 33 #include "core/InputTypeNames.h" |
| 34 #include "core/clipboard/DataObject.h" | 34 #include "core/clipboard/DataObject.h" |
| 35 #include "core/clipboard/DataTransfer.h" | 35 #include "core/clipboard/DataTransfer.h" |
| 36 #include "core/dom/Document.h" | 36 #include "core/dom/Document.h" |
| 37 #include "core/dom/DocumentMarkerController.h" | |
| 38 #include "core/dom/TouchList.h" | 37 #include "core/dom/TouchList.h" |
| 39 #include "core/dom/shadow/ComposedTreeTraversal.h" | 38 #include "core/dom/shadow/ComposedTreeTraversal.h" |
| 40 #include "core/dom/shadow/ShadowRoot.h" | 39 #include "core/dom/shadow/ShadowRoot.h" |
| 41 #include "core/editing/Editor.h" | 40 #include "core/editing/Editor.h" |
| 42 #include "core/editing/FrameSelection.h" | 41 #include "core/editing/FrameSelection.h" |
| 43 #include "core/editing/htmlediting.h" | 42 #include "core/editing/SelectionController.h" |
| 44 #include "core/editing/iterators/TextIterator.h" | |
| 45 #include "core/events/EventPath.h" | 43 #include "core/events/EventPath.h" |
| 46 #include "core/events/KeyboardEvent.h" | 44 #include "core/events/KeyboardEvent.h" |
| 47 #include "core/events/MouseEvent.h" | 45 #include "core/events/MouseEvent.h" |
| 48 #include "core/events/TextEvent.h" | 46 #include "core/events/TextEvent.h" |
| 49 #include "core/events/TouchEvent.h" | 47 #include "core/events/TouchEvent.h" |
| 50 #include "core/events/WheelEvent.h" | 48 #include "core/events/WheelEvent.h" |
| 51 #include "core/fetch/ImageResource.h" | 49 #include "core/fetch/ImageResource.h" |
| 52 #include "core/frame/EventHandlerRegistry.h" | 50 #include "core/frame/EventHandlerRegistry.h" |
| 53 #include "core/frame/FrameHost.h" | 51 #include "core/frame/FrameHost.h" |
| 54 #include "core/frame/FrameView.h" | 52 #include "core/frame/FrameView.h" |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 213 | 211 |
| 214 // FIXME: we should exclude the document in some cases, as part | 212 // FIXME: we should exclude the document in some cases, as part |
| 215 // of crbug.com/410974. | 213 // of crbug.com/410974. |
| 216 scrollChain.prepend(frame.document()->documentElement()); | 214 scrollChain.prepend(frame.document()->documentElement()); |
| 217 } | 215 } |
| 218 | 216 |
| 219 EventHandler::EventHandler(LocalFrame* frame) | 217 EventHandler::EventHandler(LocalFrame* frame) |
| 220 : m_frame(frame) | 218 : m_frame(frame) |
| 221 , m_mousePressed(false) | 219 , m_mousePressed(false) |
| 222 , m_capturesDragging(false) | 220 , m_capturesDragging(false) |
| 223 , m_mouseDownMayStartSelect(false) | |
| 224 , m_mouseDownMayStartDrag(false) | 221 , m_mouseDownMayStartDrag(false) |
| 225 , m_mouseDownWasSingleClickInSelection(false) | 222 , m_selectionController(adoptPtrWillBeNoop(new SelectionController(frame))) |
| 226 , m_selectionInitiationState(HaveNotStartedSelection) | |
| 227 , m_hoverTimer(this, &EventHandler::hoverTimerFired) | 223 , m_hoverTimer(this, &EventHandler::hoverTimerFired) |
| 228 , m_cursorUpdateTimer(this, &EventHandler::cursorUpdateTimerFired) | 224 , m_cursorUpdateTimer(this, &EventHandler::cursorUpdateTimerFired) |
| 229 , m_mouseDownMayStartAutoscroll(false) | 225 , m_mouseDownMayStartAutoscroll(false) |
| 230 , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFire d) | 226 , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFire d) |
| 231 , m_svgPan(false) | 227 , m_svgPan(false) |
| 232 , m_resizeScrollableArea(nullptr) | 228 , m_resizeScrollableArea(nullptr) |
| 233 , m_eventHandlerWillResetCapturingMouseEventsNode(0) | 229 , m_eventHandlerWillResetCapturingMouseEventsNode(0) |
| 234 , m_clickCount(0) | 230 , m_clickCount(0) |
| 235 , m_shouldOnlyFireDragOverEvent(false) | 231 , m_shouldOnlyFireDragOverEvent(false) |
| 236 , m_mousePositionIsUnknown(true) | 232 , m_mousePositionIsUnknown(true) |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 266 visitor->trace(m_frameSetBeingResized); | 262 visitor->trace(m_frameSetBeingResized); |
| 267 visitor->trace(m_latchedWheelEventNode); | 263 visitor->trace(m_latchedWheelEventNode); |
| 268 visitor->trace(m_previousWheelScrolledNode); | 264 visitor->trace(m_previousWheelScrolledNode); |
| 269 visitor->trace(m_scrollbarHandlingScrollGesture); | 265 visitor->trace(m_scrollbarHandlingScrollGesture); |
| 270 visitor->trace(m_targetForTouchID); | 266 visitor->trace(m_targetForTouchID); |
| 271 visitor->trace(m_touchSequenceDocument); | 267 visitor->trace(m_touchSequenceDocument); |
| 272 visitor->trace(m_scrollGestureHandlingNode); | 268 visitor->trace(m_scrollGestureHandlingNode); |
| 273 visitor->trace(m_previousGestureScrolledNode); | 269 visitor->trace(m_previousGestureScrolledNode); |
| 274 visitor->trace(m_lastDeferredTapElement); | 270 visitor->trace(m_lastDeferredTapElement); |
| 275 visitor->trace(m_currentScrollChain); | 271 visitor->trace(m_currentScrollChain); |
| 272 visitor->trace(m_selectionController); | |
| 276 #endif | 273 #endif |
| 277 } | 274 } |
| 278 | 275 |
| 279 DragState& EventHandler::dragState() | 276 DragState& EventHandler::dragState() |
| 280 { | 277 { |
| 281 DEFINE_STATIC_LOCAL(Persistent<DragState>, state, (new DragState())); | 278 DEFINE_STATIC_LOCAL(Persistent<DragState>, state, (new DragState())); |
| 282 return *state; | 279 return *state; |
| 283 } | 280 } |
| 284 | 281 |
| 285 void EventHandler::clear() | 282 void EventHandler::clear() |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 310 m_previousWheelScrolledNode = nullptr; | 307 m_previousWheelScrolledNode = nullptr; |
| 311 m_targetForTouchID.clear(); | 308 m_targetForTouchID.clear(); |
| 312 m_touchSequenceDocument.clear(); | 309 m_touchSequenceDocument.clear(); |
| 313 m_touchSequenceUserGestureToken.clear(); | 310 m_touchSequenceUserGestureToken.clear(); |
| 314 m_scrollGestureHandlingNode = nullptr; | 311 m_scrollGestureHandlingNode = nullptr; |
| 315 m_lastGestureScrollOverWidget = false; | 312 m_lastGestureScrollOverWidget = false; |
| 316 m_previousGestureScrolledNode = nullptr; | 313 m_previousGestureScrolledNode = nullptr; |
| 317 m_scrollbarHandlingScrollGesture = nullptr; | 314 m_scrollbarHandlingScrollGesture = nullptr; |
| 318 m_maxMouseMovedDuration = 0; | 315 m_maxMouseMovedDuration = 0; |
| 319 m_touchPressed = false; | 316 m_touchPressed = false; |
| 320 m_mouseDownMayStartSelect = false; | |
| 321 m_mouseDownMayStartDrag = false; | 317 m_mouseDownMayStartDrag = false; |
| 322 m_lastShowPressTimestamp = 0; | 318 m_lastShowPressTimestamp = 0; |
| 323 m_lastDeferredTapElement = nullptr; | 319 m_lastDeferredTapElement = nullptr; |
| 324 m_eventHandlerWillResetCapturingMouseEventsNode = false; | 320 m_eventHandlerWillResetCapturingMouseEventsNode = false; |
| 325 m_mouseDownWasSingleClickInSelection = false; | |
| 326 m_selectionInitiationState = HaveNotStartedSelection; | |
| 327 m_mouseDownMayStartAutoscroll = false; | 321 m_mouseDownMayStartAutoscroll = false; |
| 328 m_svgPan = false; | 322 m_svgPan = false; |
| 329 m_mouseDownPos = IntPoint(); | 323 m_mouseDownPos = IntPoint(); |
| 330 m_mouseDownTimestamp = 0; | 324 m_mouseDownTimestamp = 0; |
| 331 m_longTapShouldInvokeContextMenu = false; | 325 m_longTapShouldInvokeContextMenu = false; |
| 332 m_dragStartPos = LayoutPoint(); | 326 m_dragStartPos = LayoutPoint(); |
| 333 m_offsetFromResizeCorner = LayoutSize(); | 327 m_offsetFromResizeCorner = LayoutSize(); |
| 334 m_currentMouseCursor = Cursor(); | 328 m_currentMouseCursor = Cursor(); |
| 335 m_mouseDown = PlatformMouseEvent(); | 329 m_mouseDown = PlatformMouseEvent(); |
| 336 | 330 selectionController().clear(); |
| 337 } | 331 } |
| 338 | 332 |
| 339 void EventHandler::nodeWillBeRemoved(Node& nodeToBeRemoved) | 333 void EventHandler::nodeWillBeRemoved(Node& nodeToBeRemoved) |
| 340 { | 334 { |
| 341 if (nodeToBeRemoved.containsIncludingShadowDOM(m_clickNode.get())) { | 335 if (nodeToBeRemoved.containsIncludingShadowDOM(m_clickNode.get())) { |
| 342 // We don't dispatch click events if the mousedown node is removed | 336 // We don't dispatch click events if the mousedown node is removed |
| 343 // before a mouseup event. It is compatible with IE and Firefox. | 337 // before a mouseup event. It is compatible with IE and Firefox. |
| 344 m_clickNode = nullptr; | 338 m_clickNode = nullptr; |
| 345 } | 339 } |
| 346 } | 340 } |
| 347 | 341 |
| 348 static void setSelectionIfNeeded(FrameSelection& selection, const VisibleSelecti on& newSelection) | |
| 349 { | |
| 350 if (selection.selection() != newSelection) | |
| 351 selection.setSelection(newSelection); | |
| 352 } | |
| 353 | |
| 354 static inline bool dispatchSelectStart(Node* node) | |
| 355 { | |
| 356 if (!node || !node->layoutObject()) | |
| 357 return true; | |
| 358 | |
| 359 return node->dispatchEvent(Event::createCancelableBubble(EventTypeNames::sel ectstart)); | |
| 360 } | |
| 361 | |
| 362 static VisibleSelection expandSelectionToRespectUserSelectAll(Node* targetNode, const VisibleSelection& selection) | |
| 363 { | |
| 364 Node* rootUserSelectAll = Position::rootUserSelectAllForNode(targetNode); | |
| 365 if (!rootUserSelectAll) | |
| 366 return selection; | |
| 367 | |
| 368 VisibleSelection newSelection(selection); | |
| 369 newSelection.setBase(positionBeforeNode(rootUserSelectAll).upstream(CanCross EditingBoundary)); | |
| 370 newSelection.setExtent(positionAfterNode(rootUserSelectAll).downstream(CanCr ossEditingBoundary)); | |
| 371 | |
| 372 return newSelection; | |
| 373 } | |
| 374 | |
| 375 bool EventHandler::updateSelectionForMouseDownDispatchingSelectStart(Node* targe tNode, const VisibleSelection& selection, TextGranularity granularity) | |
| 376 { | |
| 377 if (Position::nodeIsUserSelectNone(targetNode)) | |
| 378 return false; | |
| 379 | |
| 380 if (!dispatchSelectStart(targetNode)) | |
| 381 return false; | |
| 382 | |
| 383 if (selection.isRange()) { | |
| 384 m_selectionInitiationState = ExtendedSelection; | |
| 385 } else { | |
| 386 granularity = CharacterGranularity; | |
| 387 m_selectionInitiationState = PlacedCaret; | |
| 388 } | |
| 389 | |
| 390 m_frame->selection().setNonDirectionalSelectionIfNeeded(selection, granulari ty); | |
| 391 | |
| 392 return true; | |
| 393 } | |
| 394 | |
| 395 void EventHandler::selectClosestWordFromHitTestResult(const HitTestResult& resul t, AppendTrailingWhitespace appendTrailingWhitespace) | |
| 396 { | |
| 397 Node* innerNode = result.innerNode(); | |
| 398 VisibleSelection newSelection; | |
| 399 | |
| 400 if (innerNode && innerNode->layoutObject()) { | |
| 401 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(result.l ocalPoint())); | |
| 402 if (pos.isNotNull()) { | |
| 403 newSelection = VisibleSelection(pos); | |
| 404 newSelection.expandUsingGranularity(WordGranularity); | |
| 405 } | |
| 406 | |
| 407 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSel ection.isRange()) | |
| 408 newSelection.appendTrailingWhitespace(); | |
| 409 | |
| 410 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelec tionToRespectUserSelectAll(innerNode, newSelection), WordGranularity); | |
| 411 } | |
| 412 } | |
| 413 | |
| 414 void EventHandler::selectClosestMisspellingFromHitTestResult(const HitTestResult & result, AppendTrailingWhitespace appendTrailingWhitespace) | |
| 415 { | |
| 416 Node* innerNode = result.innerNode(); | |
| 417 VisibleSelection newSelection; | |
| 418 | |
| 419 if (innerNode && innerNode->layoutObject()) { | |
| 420 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(result.l ocalPoint())); | |
| 421 Position start = pos.deepEquivalent(); | |
| 422 Position end = pos.deepEquivalent(); | |
| 423 if (pos.isNotNull()) { | |
| 424 DocumentMarkerVector markers = innerNode->document().markers().marke rsInRange(makeRange(pos, pos).get(), DocumentMarker::MisspellingMarkers()); | |
| 425 if (markers.size() == 1) { | |
| 426 start.moveToOffset(markers[0]->startOffset()); | |
| 427 end.moveToOffset(markers[0]->endOffset()); | |
| 428 newSelection = VisibleSelection(start, end); | |
| 429 } | |
| 430 } | |
| 431 | |
| 432 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSel ection.isRange()) | |
| 433 newSelection.appendTrailingWhitespace(); | |
| 434 | |
| 435 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelec tionToRespectUserSelectAll(innerNode, newSelection), WordGranularity); | |
| 436 } | |
| 437 } | |
| 438 | |
| 439 void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestRe sults& result) | |
| 440 { | |
| 441 if (m_mouseDownMayStartSelect) { | |
| 442 selectClosestWordFromHitTestResult(result.hitTestResult(), | |
| 443 (result.event().clickCount() == 2 && m_frame->editor().isSelectTrail ingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhi tespace); | |
| 444 } | |
| 445 } | |
| 446 | |
| 447 void EventHandler::selectClosestMisspellingFromMouseEvent(const MouseEventWithHi tTestResults& result) | |
| 448 { | |
| 449 if (m_mouseDownMayStartSelect) { | |
| 450 selectClosestMisspellingFromHitTestResult(result.hitTestResult(), | |
| 451 (result.event().clickCount() == 2 && m_frame->editor().isSelectTrail ingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhi tespace); | |
| 452 } | |
| 453 } | |
| 454 | |
| 455 void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHit TestResults& result) | |
| 456 { | |
| 457 if (!result.hitTestResult().isLiveLink()) | |
| 458 return selectClosestWordFromMouseEvent(result); | |
| 459 | |
| 460 Node* innerNode = result.innerNode(); | |
| 461 | |
| 462 if (innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect) { | |
| 463 VisibleSelection newSelection; | |
| 464 Element* URLElement = result.hitTestResult().URLElement(); | |
| 465 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(result.l ocalPoint())); | |
| 466 if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescenda ntOf(URLElement)) | |
| 467 newSelection = VisibleSelection::selectionFromContentsOfNode(URLElem ent); | |
| 468 | |
| 469 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelec tionToRespectUserSelectAll(innerNode, newSelection), WordGranularity); | |
| 470 } | |
| 471 } | |
| 472 | |
| 473 bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestR esults& event) | |
| 474 { | |
| 475 TRACE_EVENT0("blink", "EventHandler::handleMousePressEventDoubleClick"); | |
| 476 | |
| 477 if (event.event().button() != LeftButton) | |
| 478 return false; | |
| 479 | |
| 480 if (m_frame->selection().isRange()) { | |
| 481 // A double-click when range is already selected | |
| 482 // should not change the selection. So, do not call | |
| 483 // selectClosestWordFromMouseEvent, but do set | |
| 484 // m_beganSelectingText to prevent handleMouseReleaseEvent | |
| 485 // from setting caret selection. | |
| 486 m_selectionInitiationState = ExtendedSelection; | |
| 487 } else { | |
| 488 selectClosestWordFromMouseEvent(event); | |
| 489 } | |
| 490 return true; | |
| 491 } | |
| 492 | |
| 493 bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestR esults& event) | |
| 494 { | |
| 495 TRACE_EVENT0("blink", "EventHandler::handleMousePressEventTripleClick"); | |
| 496 | |
| 497 if (event.event().button() != LeftButton) | |
| 498 return false; | |
| 499 | |
| 500 Node* innerNode = event.innerNode(); | |
| 501 if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect)) | |
| 502 return false; | |
| 503 | |
| 504 VisibleSelection newSelection; | |
| 505 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(event.localP oint())); | |
| 506 if (pos.isNotNull()) { | |
| 507 newSelection = VisibleSelection(pos); | |
| 508 newSelection.expandUsingGranularity(ParagraphGranularity); | |
| 509 } | |
| 510 | |
| 511 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSe lectionToRespectUserSelectAll(innerNode, newSelection), ParagraphGranularity); | |
| 512 } | |
| 513 | |
| 514 static int textDistance(const Position& start, const Position& end) | |
| 515 { | |
| 516 RefPtrWillBeRawPtr<Range> range = Range::create(*start.document(), start, en d); | |
| 517 return TextIterator::rangeLength(range->startPosition(), range->endPosition( ), true); | |
| 518 } | |
| 519 | |
| 520 bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestR esults& event) | |
| 521 { | |
| 522 TRACE_EVENT0("blink", "EventHandler::handleMousePressEventSingleClick"); | |
| 523 | |
| 524 m_frame->document()->updateLayoutIgnorePendingStylesheets(); | |
| 525 Node* innerNode = event.innerNode(); | |
| 526 if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect)) | |
| 527 return false; | |
| 528 | |
| 529 // Extend the selection if the Shift key is down, unless the click is in a l ink. | |
| 530 bool extendSelection = event.event().shiftKey() && !event.isOverLink(); | |
| 531 | |
| 532 // Don't restart the selection when the mouse is pressed on an | |
| 533 // existing selection so we can allow for text dragging. | |
| 534 if (FrameView* view = m_frame->view()) { | |
| 535 LayoutPoint vPoint = view->rootFrameToContents(event.event().position()) ; | |
| 536 if (!extendSelection && m_frame->selection().contains(vPoint)) { | |
| 537 m_mouseDownWasSingleClickInSelection = true; | |
| 538 return false; | |
| 539 } | |
| 540 } | |
| 541 | |
| 542 VisiblePosition visiblePos(innerNode->layoutObject()->positionForPoint(event .localPoint())); | |
| 543 if (visiblePos.isNull()) | |
| 544 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(innerNode), DOW NSTREAM); | |
| 545 Position pos = visiblePos.deepEquivalent(); | |
| 546 | |
| 547 VisibleSelection newSelection = m_frame->selection().selection(); | |
| 548 TextGranularity granularity = CharacterGranularity; | |
| 549 | |
| 550 if (extendSelection && newSelection.isCaretOrRange()) { | |
| 551 VisibleSelection selectionInUserSelectAll(expandSelectionToRespectUserSe lectAll(innerNode, VisibleSelection(VisiblePosition(pos)))); | |
| 552 if (selectionInUserSelectAll.isRange()) { | |
| 553 if (comparePositions(selectionInUserSelectAll.start(), newSelection. start()) < 0) | |
| 554 pos = selectionInUserSelectAll.start(); | |
| 555 else if (comparePositions(newSelection.end(), selectionInUserSelectA ll.end()) < 0) | |
| 556 pos = selectionInUserSelectAll.end(); | |
| 557 } | |
| 558 | |
| 559 if (!m_frame->editor().behavior().shouldConsiderSelectionAsDirectional() ) { | |
| 560 if (pos.isNotNull()) { | |
| 561 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click d eselects when selection | |
| 562 // was created right-to-left | |
| 563 Position start = newSelection.start(); | |
| 564 Position end = newSelection.end(); | |
| 565 int distanceToStart = textDistance(start, pos); | |
| 566 int distanceToEnd = textDistance(pos, end); | |
| 567 if (distanceToStart <= distanceToEnd) | |
| 568 newSelection = VisibleSelection(end, pos); | |
| 569 else | |
| 570 newSelection = VisibleSelection(start, pos); | |
| 571 } | |
| 572 } else { | |
| 573 newSelection.setExtent(pos); | |
| 574 } | |
| 575 | |
| 576 if (m_frame->selection().granularity() != CharacterGranularity) { | |
| 577 granularity = m_frame->selection().granularity(); | |
| 578 newSelection.expandUsingGranularity(m_frame->selection().granularity ()); | |
| 579 } | |
| 580 } else { | |
| 581 newSelection = expandSelectionToRespectUserSelectAll(innerNode, VisibleS election(visiblePos)); | |
| 582 } | |
| 583 | |
| 584 // Updating the selection is considered side-effect of the event and so it d oesn't impact the handled state. | |
| 585 updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, g ranularity); | |
| 586 return false; | |
| 587 } | |
| 588 | |
| 589 static inline bool canMouseDownStartSelect(Node* node) | |
| 590 { | |
| 591 if (!node || !node->layoutObject()) | |
| 592 return true; | |
| 593 | |
| 594 if (!node->canStartSelection()) | |
| 595 return false; | |
| 596 | |
| 597 return true; | |
| 598 } | |
| 599 | |
| 600 bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve nt) | 342 bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve nt) |
| 601 { | 343 { |
| 602 TRACE_EVENT0("blink", "EventHandler::handleMousePressEvent"); | 344 TRACE_EVENT0("blink", "EventHandler::handleMousePressEvent"); |
| 603 | 345 |
| 604 // Reset drag state. | 346 // Reset drag state. |
| 605 dragState().m_dragSrc = nullptr; | 347 dragState().m_dragSrc = nullptr; |
| 606 | 348 |
| 607 cancelFakeMouseMoveEvent(); | 349 cancelFakeMouseMoveEvent(); |
| 608 | 350 |
| 609 m_frame->document()->updateLayoutIgnorePendingStylesheets(); | 351 m_frame->document()->updateLayoutIgnorePendingStylesheets(); |
| 610 | 352 |
| 611 if (FrameView* frameView = m_frame->view()) { | 353 if (FrameView* frameView = m_frame->view()) { |
| 612 if (frameView->isPointInScrollbarCorner(event.event().position())) | 354 if (frameView->isPointInScrollbarCorner(event.event().position())) |
| 613 return false; | 355 return false; |
| 614 } | 356 } |
| 615 | 357 |
| 616 bool singleClick = event.event().clickCount() <= 1; | 358 bool singleClick = event.event().clickCount() <= 1; |
| 617 | 359 |
| 618 // If we got the event back, that must mean it wasn't prevented, | |
| 619 // so it's allowed to start a drag or selection if it wasn't in a scrollbar. | |
| 620 m_mouseDownMayStartSelect = canMouseDownStartSelect(event.innerNode()) && !e vent.scrollbar(); | |
| 621 | |
| 622 m_mouseDownMayStartDrag = singleClick; | 360 m_mouseDownMayStartDrag = singleClick; |
| 623 | 361 |
| 624 m_mouseDownWasSingleClickInSelection = false; | 362 selectionController().handleMousePressEvent(event); |
| 625 | 363 |
| 626 m_mouseDown = event.event(); | 364 m_mouseDown = event.event(); |
| 627 | 365 |
| 628 if (m_frame->document()->isSVGDocument() && m_frame->document()->accessSVGEx tensions().zoomAndPanEnabled()) { | 366 if (m_frame->document()->isSVGDocument() && m_frame->document()->accessSVGEx tensions().zoomAndPanEnabled()) { |
| 629 if (event.event().shiftKey() && singleClick) { | 367 if (event.event().shiftKey() && singleClick) { |
| 630 m_svgPan = true; | 368 m_svgPan = true; |
| 631 m_frame->document()->accessSVGExtensions().startPan(m_frame->view()- >rootFrameToContents(event.event().position())); | 369 m_frame->document()->accessSVGExtensions().startPan(m_frame->view()- >rootFrameToContents(event.event().position())); |
| 632 return true; | 370 return true; |
| 633 } | 371 } |
| 634 } | 372 } |
| 635 | 373 |
| 636 // We don't do this at the start of mouse down handling, | 374 // We don't do this at the start of mouse down handling, |
| 637 // because we don't want to do it until we know we didn't hit a widget. | 375 // because we don't want to do it until we know we didn't hit a widget. |
| 638 if (singleClick) | 376 if (singleClick) |
| 639 focusDocumentView(); | 377 focusDocumentView(); |
| 640 | 378 |
| 641 Node* innerNode = event.innerNode(); | 379 Node* innerNode = event.innerNode(); |
| 642 | 380 |
| 643 m_mousePressNode = innerNode; | 381 m_mousePressNode = innerNode; |
| 644 m_dragStartPos = event.event().position(); | 382 m_dragStartPos = event.event().position(); |
| 645 | 383 |
| 646 bool swallowEvent = false; | 384 bool swallowEvent = false; |
| 647 m_mousePressed = true; | 385 m_mousePressed = true; |
| 648 m_selectionInitiationState = HaveNotStartedSelection; | |
| 649 | 386 |
| 650 if (event.event().clickCount() == 2) | 387 if (event.event().clickCount() == 2) |
| 651 swallowEvent = handleMousePressEventDoubleClick(event); | 388 swallowEvent = selectionController().handleMousePressEventDoubleClick(ev ent); |
| 652 else if (event.event().clickCount() >= 3) | 389 else if (event.event().clickCount() >= 3) |
| 653 swallowEvent = handleMousePressEventTripleClick(event); | 390 swallowEvent = selectionController().handleMousePressEventTripleClick(ev ent); |
| 654 else | 391 else |
| 655 swallowEvent = handleMousePressEventSingleClick(event); | 392 swallowEvent = selectionController().handleMousePressEventSingleClick(ev ent); |
| 656 | 393 |
| 657 m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect | 394 m_mouseDownMayStartAutoscroll = selectionController().allowSelection() |
| 658 || (m_mousePressNode && m_mousePressNode->layoutBox() && m_mousePressNod e->layoutBox()->canBeProgramaticallyScrolled()); | 395 || (m_mousePressNode && m_mousePressNode->layoutBox() && m_mousePressNod e->layoutBox()->canBeProgramaticallyScrolled()); |
| 659 | 396 |
| 660 return swallowEvent; | 397 return swallowEvent; |
| 661 } | 398 } |
| 662 | 399 |
| 663 bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& e vent) | 400 bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& e vent) |
| 664 { | 401 { |
| 665 TRACE_EVENT0("blink", "EventHandler::handleMouseDraggedEvent"); | 402 TRACE_EVENT0("blink", "EventHandler::handleMouseDraggedEvent"); |
| 666 | |
| 667 // While resetting m_mousePressed here may seem out of place, it turns out | 403 // While resetting m_mousePressed here may seem out of place, it turns out |
| 668 // to be needed to handle some bugs^Wfeatures in Blink mouse event handling: | 404 // to be needed to handle some bugs^Wfeatures in Blink mouse event handling: |
| 669 // 1. Certain elements, such as <embed>, capture mouse events. They do not | 405 // 1. Certain elements, such as <embed>, capture mouse events. They do not |
| 670 // bubble back up. One way for a <embed> to start capturing mouse events | 406 // bubble back up. One way for a <embed> to start capturing mouse events |
| 671 // is on a mouse press. The problem is the <embed> node only starts | 407 // is on a mouse press. The problem is the <embed> node only starts |
| 672 // capturing mouse events *after* m_mousePressed for the containing frame | 408 // capturing mouse events *after* m_mousePressed for the containing frame |
| 673 // has already been set to true. As a result, the frame's EventHandler | 409 // has already been set to true. As a result, the frame's EventHandler |
| 674 // never sees the mouse release event, which is supposed to reset | 410 // never sees the mouse release event, which is supposed to reset |
| 675 // m_mousePressed... so m_mousePressed ends up remaining true until the | 411 // m_mousePressed... so m_mousePressed ends up remaining true until the |
| 676 // event handler finally gets another mouse released event. Oops. | 412 // event handler finally gets another mouse released event. Oops. |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 704 | 440 |
| 705 m_mouseDownMayStartDrag = false; | 441 m_mouseDownMayStartDrag = false; |
| 706 | 442 |
| 707 if (m_mouseDownMayStartAutoscroll && !panScrollInProgress()) { | 443 if (m_mouseDownMayStartAutoscroll && !panScrollInProgress()) { |
| 708 if (AutoscrollController* controller = autoscrollController()) { | 444 if (AutoscrollController* controller = autoscrollController()) { |
| 709 controller->startAutoscrollForSelection(renderer); | 445 controller->startAutoscrollForSelection(renderer); |
| 710 m_mouseDownMayStartAutoscroll = false; | 446 m_mouseDownMayStartAutoscroll = false; |
| 711 } | 447 } |
| 712 } | 448 } |
| 713 | 449 |
| 714 if (m_selectionInitiationState != ExtendedSelection) { | 450 selectionController().handleMouseDraggedEvent(event, m_mouseDownPos, m_dragS tartPos, m_mousePressNode, m_lastKnownMousePosition); |
| 715 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active ); | |
| 716 HitTestResult result(request, m_mouseDownPos); | |
| 717 m_frame->document()->layoutView()->hitTest(result); | |
| 718 | |
| 719 updateSelectionForMouseDrag(result); | |
| 720 } | |
| 721 updateSelectionForMouseDrag(event.hitTestResult()); | |
| 722 return true; | 451 return true; |
| 723 } | 452 } |
| 724 | 453 |
| 725 void EventHandler::updateSelectionForMouseDrag() | |
| 726 { | |
| 727 FrameView* view = m_frame->view(); | |
| 728 if (!view) | |
| 729 return; | |
| 730 LayoutView* renderer = m_frame->contentRenderer(); | |
| 731 if (!renderer) | |
| 732 return; | |
| 733 | |
| 734 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | H itTestRequest::Move); | |
| 735 HitTestResult result(request, view->rootFrameToContents(m_lastKnownMousePosi tion)); | |
| 736 renderer->hitTest(result); | |
| 737 updateSelectionForMouseDrag(result); | |
| 738 } | |
| 739 | |
| 740 void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResul t) | |
| 741 { | |
| 742 if (!m_mouseDownMayStartSelect) | |
| 743 return; | |
| 744 | |
| 745 Node* target = hitTestResult.innerNode(); | |
| 746 if (!target) | |
| 747 return; | |
| 748 | |
| 749 VisiblePosition targetPosition = m_frame->selection().selection().visiblePos itionRespectingEditingBoundary(hitTestResult.localPoint(), target); | |
| 750 // Don't modify the selection if we're not on a node. | |
| 751 if (targetPosition.isNull()) | |
| 752 return; | |
| 753 | |
| 754 // Restart the selection if this is the first mouse move. This work is usual ly | |
| 755 // done in handleMousePressEvent, but not if the mouse press was on an exist ing selection. | |
| 756 VisibleSelection newSelection = m_frame->selection().selection(); | |
| 757 | |
| 758 // Special case to limit selection to the containing block for SVG text. | |
| 759 // FIXME: Isn't there a better non-SVG-specific way to do this? | |
| 760 if (Node* selectionBaseNode = newSelection.base().deprecatedNode()) { | |
| 761 if (LayoutObject* selectionBaseRenderer = selectionBaseNode->layoutObjec t()) { | |
| 762 if (selectionBaseRenderer->isSVGText()) { | |
| 763 if (target->layoutObject()->containingBlock() != selectionBaseRe nderer->containingBlock()) | |
| 764 return; | |
| 765 } | |
| 766 } | |
| 767 } | |
| 768 | |
| 769 if (m_selectionInitiationState == HaveNotStartedSelection && !dispatchSelect Start(target)) | |
| 770 return; | |
| 771 | |
| 772 if (m_selectionInitiationState != ExtendedSelection) { | |
| 773 // Always extend selection here because it's caused by a mouse drag | |
| 774 m_selectionInitiationState = ExtendedSelection; | |
| 775 newSelection = VisibleSelection(targetPosition); | |
| 776 } | |
| 777 | |
| 778 if (RuntimeEnabledFeatures::userSelectAllEnabled()) { | |
| 779 Node* rootUserSelectAllForMousePressNode = Position::rootUserSelectAllFo rNode(m_mousePressNode.get()); | |
| 780 if (rootUserSelectAllForMousePressNode && rootUserSelectAllForMousePress Node == Position::rootUserSelectAllForNode(target)) { | |
| 781 newSelection.setBase(positionBeforeNode(rootUserSelectAllForMousePre ssNode).upstream(CanCrossEditingBoundary)); | |
| 782 newSelection.setExtent(positionAfterNode(rootUserSelectAllForMousePr essNode).downstream(CanCrossEditingBoundary)); | |
| 783 } else { | |
| 784 // Reset base for user select all when base is inside user-select-al l area and extent < base. | |
| 785 if (rootUserSelectAllForMousePressNode && comparePositions(target->l ayoutObject()->positionForPoint(hitTestResult.localPoint()), m_mousePressNode->l ayoutObject()->positionForPoint(m_dragStartPos)) < 0) | |
| 786 newSelection.setBase(positionAfterNode(rootUserSelectAllForMouse PressNode).downstream(CanCrossEditingBoundary)); | |
| 787 | |
| 788 Node* rootUserSelectAllForTarget = Position::rootUserSelectAllForNod e(target); | |
| 789 if (rootUserSelectAllForTarget && m_mousePressNode->layoutObject() & & comparePositions(target->layoutObject()->positionForPoint(hitTestResult.localP oint()), m_mousePressNode->layoutObject()->positionForPoint(m_dragStartPos)) < 0 ) | |
| 790 newSelection.setExtent(positionBeforeNode(rootUserSelectAllForTa rget).upstream(CanCrossEditingBoundary)); | |
| 791 else if (rootUserSelectAllForTarget && m_mousePressNode->layoutObjec t()) | |
| 792 newSelection.setExtent(positionAfterNode(rootUserSelectAllForTar get).downstream(CanCrossEditingBoundary)); | |
| 793 else | |
| 794 newSelection.setExtent(targetPosition); | |
| 795 } | |
| 796 } else { | |
| 797 newSelection.setExtent(targetPosition); | |
| 798 } | |
| 799 | |
| 800 if (m_frame->selection().granularity() != CharacterGranularity) | |
| 801 newSelection.expandUsingGranularity(m_frame->selection().granularity()); | |
| 802 | |
| 803 m_frame->selection().setNonDirectionalSelectionIfNeeded(newSelection, m_fram e->selection().granularity(), | |
| 804 FrameSelection::AdjustEndpointsAtBidiBoundary); | |
| 805 } | |
| 806 | |
| 807 bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& e vent) | 454 bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& e vent) |
| 808 { | 455 { |
| 809 AutoscrollController* controller = autoscrollController(); | 456 AutoscrollController* controller = autoscrollController(); |
| 810 if (controller && controller->autoscrollInProgress()) | 457 if (controller && controller->autoscrollInProgress()) |
| 811 stopAutoscroll(); | 458 stopAutoscroll(); |
| 812 | 459 |
| 813 // Used to prevent mouseMoveEvent from initiating a drag before | 460 // Used to prevent mouseMoveEvent from initiating a drag before |
| 814 // the mouse is pressed again. | 461 // the mouse is pressed again. |
| 815 m_mousePressed = false; | 462 m_mousePressed = false; |
| 816 m_capturesDragging = false; | 463 m_capturesDragging = false; |
| 817 m_mouseDownMayStartDrag = false; | 464 m_mouseDownMayStartDrag = false; |
| 818 m_mouseDownMayStartSelect = false; | |
| 819 m_mouseDownMayStartAutoscroll = false; | 465 m_mouseDownMayStartAutoscroll = false; |
| 820 | 466 |
| 821 bool handled = false; | 467 return selectionController().handleMouseReleaseEvent(event, m_dragStartPos); |
| 822 | |
| 823 // Clear the selection if the mouse didn't move after the last mouse | |
| 824 // press and it's not a context menu click. We do this so when clicking | |
| 825 // on the selection, the selection goes away. However, if we are | |
| 826 // editing, place the caret. | |
| 827 if (m_mouseDownWasSingleClickInSelection && m_selectionInitiationState != Ex tendedSelection | |
| 828 && m_dragStartPos == event.event().position() | |
| 829 && m_frame->selection().isRange() | |
| 830 && event.event().button() != RightButton) { | |
| 831 VisibleSelection newSelection; | |
| 832 Node* node = event.innerNode(); | |
| 833 bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBr owsingEnabled(); | |
| 834 if (node && node->layoutObject() && (caretBrowsing || node->hasEditableS tyle())) { | |
| 835 VisiblePosition pos = VisiblePosition(node->layoutObject()->position ForPoint(event.localPoint())); | |
| 836 newSelection = VisibleSelection(pos); | |
| 837 } | |
| 838 | |
| 839 setSelectionIfNeeded(m_frame->selection(), newSelection); | |
| 840 | |
| 841 handled = true; | |
| 842 } | |
| 843 | |
| 844 m_frame->selection().notifyRendererOfSelectionChange(UserTriggered); | |
| 845 | |
| 846 m_frame->selection().selectFrameElementInParentIfFullySelected(); | |
| 847 | |
| 848 if (event.event().button() == MiddleButton && !event.isOverLink()) { | |
| 849 // Ignore handled, since we want to paste to where the caret was placed anyway. | |
| 850 handled = handlePasteGlobalSelection(event.event()) || handled; | |
| 851 } | |
| 852 | |
| 853 return handled; | |
| 854 } | 468 } |
| 855 | 469 |
| 856 #if OS(WIN) | 470 #if OS(WIN) |
| 857 | 471 |
| 858 void EventHandler::startPanScrolling(LayoutObject* renderer) | 472 void EventHandler::startPanScrolling(LayoutObject* renderer) |
| 859 { | 473 { |
| 860 if (!renderer->isBox()) | 474 if (!renderer->isBox()) |
| 861 return; | 475 return; |
| 862 AutoscrollController* controller = autoscrollController(); | 476 AutoscrollController* controller = autoscrollController(); |
| 863 if (!controller) | 477 if (!controller) |
| (...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1223 | 837 |
| 1224 bool inResizer = false; | 838 bool inResizer = false; |
| 1225 LayoutObject* renderer = node ? node->layoutObject() : nullptr; | 839 LayoutObject* renderer = node ? node->layoutObject() : nullptr; |
| 1226 if (renderer && m_frame->view()) { | 840 if (renderer && m_frame->view()) { |
| 1227 DeprecatedPaintLayer* layer = renderer->enclosingLayer(); | 841 DeprecatedPaintLayer* layer = renderer->enclosingLayer(); |
| 1228 inResizer = layer->scrollableArea() && layer->scrollableArea()->isPointI nResizeControl(result.roundedPointInMainFrame(), ResizerForPointer); | 842 inResizer = layer->scrollableArea() && layer->scrollableArea()->isPointI nResizeControl(result.roundedPointInMainFrame(), ResizerForPointer); |
| 1229 } | 843 } |
| 1230 | 844 |
| 1231 // During selection, use an I-beam no matter what we're over. | 845 // During selection, use an I-beam no matter what we're over. |
| 1232 // If a drag may be starting or we're capturing mouse events for a particula r node, don't treat this as a selection. | 846 // If a drag may be starting or we're capturing mouse events for a particula r node, don't treat this as a selection. |
| 1233 if (m_mousePressed && m_mouseDownMayStartSelect | 847 if (m_mousePressed && selectionController().allowSelection() |
| 1234 && !m_mouseDownMayStartDrag | 848 && !m_mouseDownMayStartDrag |
| 1235 && m_frame->selection().isCaretOrRange() | 849 && m_frame->selection().isCaretOrRange() |
| 1236 && !m_capturingMouseEventsNode) { | 850 && !m_capturingMouseEventsNode) { |
| 1237 return iBeam; | 851 return iBeam; |
| 1238 } | 852 } |
| 1239 | 853 |
| 1240 if ((editable || (renderer && renderer->isText() && node->canStartSelection( ))) && !inResizer && !result.scrollbar()) | 854 if ((editable || (renderer && renderer->isText() && node->canStartSelection( ))) && !inResizer && !result.scrollbar()) |
| 1241 return iBeam; | 855 return iBeam; |
| 1242 return pointerCursor(); | 856 return pointerCursor(); |
| 1243 } | 857 } |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 1260 m_frame->localFrameRoot()->eventHandler().m_lastMouseDownUserGestureToken = gestureIndicator.currentToken(); | 874 m_frame->localFrameRoot()->eventHandler().m_lastMouseDownUserGestureToken = gestureIndicator.currentToken(); |
| 1261 | 875 |
| 1262 cancelFakeMouseMoveEvent(); | 876 cancelFakeMouseMoveEvent(); |
| 1263 if (m_eventHandlerWillResetCapturingMouseEventsNode) | 877 if (m_eventHandlerWillResetCapturingMouseEventsNode) |
| 1264 m_capturingMouseEventsNode = nullptr; | 878 m_capturingMouseEventsNode = nullptr; |
| 1265 m_mousePressed = true; | 879 m_mousePressed = true; |
| 1266 m_capturesDragging = true; | 880 m_capturesDragging = true; |
| 1267 setLastKnownMousePosition(mouseEvent); | 881 setLastKnownMousePosition(mouseEvent); |
| 1268 m_mouseDownTimestamp = mouseEvent.timestamp(); | 882 m_mouseDownTimestamp = mouseEvent.timestamp(); |
| 1269 m_mouseDownMayStartDrag = false; | 883 m_mouseDownMayStartDrag = false; |
| 1270 m_mouseDownMayStartSelect = false; | 884 selectionController().setAllowSelection(false); |
| 1271 m_mouseDownMayStartAutoscroll = false; | 885 m_mouseDownMayStartAutoscroll = false; |
| 1272 if (FrameView* view = m_frame->view()) { | 886 if (FrameView* view = m_frame->view()) { |
| 1273 m_mouseDownPos = view->rootFrameToContents(mouseEvent.position()); | 887 m_mouseDownPos = view->rootFrameToContents(mouseEvent.position()); |
| 1274 } else { | 888 } else { |
| 1275 invalidateClick(); | 889 invalidateClick(); |
| 1276 return false; | 890 return false; |
| 1277 } | 891 } |
| 1278 | 892 |
| 1279 HitTestRequest request(HitTestRequest::Active); | 893 HitTestRequest request(HitTestRequest::Active); |
| 894 | |
| 1280 // Save the document point we generate in case the window coordinate is inva lidated by what happens | 895 // Save the document point we generate in case the window coordinate is inva lidated by what happens |
| 1281 // when we dispatch the event. | 896 // when we dispatch the event. |
| 1282 LayoutPoint documentPoint = contentPointFromRootFrame(m_frame, mouseEvent.po sition()); | 897 LayoutPoint documentPoint = contentPointFromRootFrame(m_frame, mouseEvent.po sition()); |
| 1283 MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(re quest, documentPoint, mouseEvent); | 898 MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(re quest, documentPoint, mouseEvent); |
| 1284 | 899 |
| 1285 if (!mev.innerNode()) { | 900 if (!mev.innerNode()) { |
| 1286 invalidateClick(); | 901 invalidateClick(); |
| 1287 return false; | 902 return false; |
| 1288 } | 903 } |
| 1289 | 904 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1326 m_resizeScrollableArea->setInResizeMode(true); | 941 m_resizeScrollableArea->setInResizeMode(true); |
| 1327 m_offsetFromResizeCorner = LayoutSize(m_resizeScrollableArea->offset FromResizeCorner(p)); | 942 m_offsetFromResizeCorner = LayoutSize(m_resizeScrollableArea->offset FromResizeCorner(p)); |
| 1328 invalidateClick(); | 943 invalidateClick(); |
| 1329 return true; | 944 return true; |
| 1330 } | 945 } |
| 1331 } | 946 } |
| 1332 | 947 |
| 1333 m_frame->selection().setCaretBlinkingSuspended(true); | 948 m_frame->selection().setCaretBlinkingSuspended(true); |
| 1334 | 949 |
| 1335 bool swallowEvent = !dispatchMouseEvent(EventTypeNames::mousedown, mev.inner Node(), m_clickCount, mouseEvent, true); | 950 bool swallowEvent = !dispatchMouseEvent(EventTypeNames::mousedown, mev.inner Node(), m_clickCount, mouseEvent, true); |
| 951 // SelectionState is initialized after dispatching mousedown event in order not to keep the selection by DOM APIs | |
| 952 // Because we can't give the user the chance to handle the selection by user action like dragging if we keep the selection in case of mousedown. | |
| 953 // FireFox also has the same behavior and it's more compatible with other br owsers. | |
| 954 selectionController().initializeSelectionState(); | |
|
Rick Byers
2015/05/01 13:22:09
This is a behavior change, right?
Miyoung Shin(g)
2015/05/03 01:45:24
Done.
I'd missed this. I should change the behavio
| |
| 955 | |
| 1336 HitTestResult hitTestResult = hitTestResultInFrame(m_frame, mouseEvent.posit ion(), HitTestRequest::ReadOnly); | 956 HitTestResult hitTestResult = hitTestResultInFrame(m_frame, mouseEvent.posit ion(), HitTestRequest::ReadOnly); |
| 1337 swallowEvent = swallowEvent || handleMouseFocus(MouseEventWithHitTestResults (mouseEvent, hitTestResult)); | 957 swallowEvent = swallowEvent || handleMouseFocus(MouseEventWithHitTestResults (mouseEvent, hitTestResult)); |
| 1338 m_capturesDragging = !swallowEvent || mev.scrollbar(); | 958 m_capturesDragging = !swallowEvent || mev.scrollbar(); |
| 1339 | 959 |
| 1340 // If the hit testing originally determined the event was in a scrollbar, re fetch the MouseEventWithHitTestResults | 960 // If the hit testing originally determined the event was in a scrollbar, re fetch the MouseEventWithHitTestResults |
| 1341 // in case the scrollbar widget was destroyed when the mouse event was handl ed. | 961 // in case the scrollbar widget was destroyed when the mouse event was handl ed. |
| 1342 if (mev.scrollbar()) { | 962 if (mev.scrollbar()) { |
| 1343 const bool wasLastScrollBar = mev.scrollbar() == m_lastScrollbarUnderMou se.get(); | 963 const bool wasLastScrollBar = mev.scrollbar() == m_lastScrollbarUnderMou se.get(); |
| 1344 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active ); | 964 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active ); |
| 1345 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mou seEvent); | 965 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mou seEvent); |
| (...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1634 | 1254 |
| 1635 bool swallowMouseReleaseEvent = false; | 1255 bool swallowMouseReleaseEvent = false; |
| 1636 if (!swallowMouseUpEvent) | 1256 if (!swallowMouseUpEvent) |
| 1637 swallowMouseReleaseEvent = handleMouseReleaseEvent(mev); | 1257 swallowMouseReleaseEvent = handleMouseReleaseEvent(mev); |
| 1638 | 1258 |
| 1639 invalidateClick(); | 1259 invalidateClick(); |
| 1640 | 1260 |
| 1641 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent; | 1261 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent; |
| 1642 } | 1262 } |
| 1643 | 1263 |
| 1644 bool EventHandler::handlePasteGlobalSelection(const PlatformMouseEvent& mouseEve nt) | |
| 1645 { | |
| 1646 // If the event was a middle click, attempt to copy global selection in afte r | |
| 1647 // the newly set caret position. | |
| 1648 // | |
| 1649 // This code is called from either the mouse up or mouse down handling. Ther e | |
| 1650 // is some debate about when the global selection is pasted: | |
| 1651 // xterm: pastes on up. | |
| 1652 // GTK: pastes on down. | |
| 1653 // Qt: pastes on up. | |
| 1654 // Firefox: pastes on up. | |
| 1655 // Chromium: pastes on up. | |
| 1656 // | |
| 1657 // There is something of a webcompat angle to this well, as highlighted by | |
| 1658 // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on | |
| 1659 // down then the text is pasted just before the onclick handler runs and | |
| 1660 // clears the text box. So it's important this happens after the event | |
| 1661 // handlers have been fired. | |
| 1662 if (mouseEvent.type() != PlatformEvent::MouseReleased) | |
| 1663 return false; | |
| 1664 | |
| 1665 if (!m_frame->page()) | |
| 1666 return false; | |
| 1667 Frame* focusFrame = m_frame->page()->focusController().focusedOrMainFrame(); | |
| 1668 // Do not paste here if the focus was moved somewhere else. | |
| 1669 if (m_frame == focusFrame && m_frame->editor().behavior().supportsGlobalSele ction()) | |
| 1670 return m_frame->editor().command("PasteGlobalSelection").execute(); | |
| 1671 | |
| 1672 return false; | |
| 1673 } | |
| 1674 | |
| 1675 | |
| 1676 bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTa rget, const PlatformMouseEvent& event, DataTransfer* dataTransfer) | 1264 bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTa rget, const PlatformMouseEvent& event, DataTransfer* dataTransfer) |
| 1677 { | 1265 { |
| 1678 FrameView* view = m_frame->view(); | 1266 FrameView* view = m_frame->view(); |
| 1679 | 1267 |
| 1680 // FIXME: We might want to dispatch a dragleave even if the view is gone. | 1268 // FIXME: We might want to dispatch a dragleave even if the view is gone. |
| 1681 if (!view) | 1269 if (!view) |
| 1682 return false; | 1270 return false; |
| 1683 | 1271 |
| 1684 RefPtrWillBeRawPtr<MouseEvent> me = MouseEvent::create(eventType, | 1272 RefPtrWillBeRawPtr<MouseEvent> me = MouseEvent::create(eventType, |
| 1685 true, true, m_frame->document()->domWindow(), | 1273 true, true, m_frame->document()->domWindow(), |
| (...skipping 742 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2428 IntPoint tappedPosition = gestureEvent.position(); | 2016 IntPoint tappedPosition = gestureEvent.position(); |
| 2429 | 2017 |
| 2430 if (m_clickNode && m_clickNode->isTextNode()) | 2018 if (m_clickNode && m_clickNode->isTextNode()) |
| 2431 m_clickNode = ComposedTreeTraversal::parent(*m_clickNode); | 2019 m_clickNode = ComposedTreeTraversal::parent(*m_clickNode); |
| 2432 | 2020 |
| 2433 PlatformMouseEvent fakeMouseDown(gestureEvent.position(), gestureEvent.globa lPosition(), | 2021 PlatformMouseEvent fakeMouseDown(gestureEvent.position(), gestureEvent.globa lPosition(), |
| 2434 LeftButton, PlatformEvent::MousePressed, gestureEvent.tapCount(), | 2022 LeftButton, PlatformEvent::MousePressed, gestureEvent.tapCount(), |
| 2435 static_cast<PlatformEvent::Modifiers>(modifiers | PlatformEvent::LeftBut tonDown), | 2023 static_cast<PlatformEvent::Modifiers>(modifiers | PlatformEvent::LeftBut tonDown), |
| 2436 PlatformMouseEvent::FromTouch, gestureEvent.timestamp()); | 2024 PlatformMouseEvent::FromTouch, gestureEvent.timestamp()); |
| 2437 bool swallowMouseDownEvent = !dispatchMouseEvent(EventTypeNames::mousedown, currentHitTest.innerNode(), gestureEvent.tapCount(), fakeMouseDown, true); | 2025 bool swallowMouseDownEvent = !dispatchMouseEvent(EventTypeNames::mousedown, currentHitTest.innerNode(), gestureEvent.tapCount(), fakeMouseDown, true); |
| 2026 selectionController().initializeSelectionState(); | |
|
Rick Byers
2015/05/01 13:22:09
is this a a behavior change?
Miyoung Shin(g)
2015/05/03 01:45:24
Done.
| |
| 2438 if (!swallowMouseDownEvent) | 2027 if (!swallowMouseDownEvent) |
| 2439 swallowMouseDownEvent = handleMouseFocus(MouseEventWithHitTestResults(fa keMouseDown, currentHitTest)); | 2028 swallowMouseDownEvent = handleMouseFocus(MouseEventWithHitTestResults(fa keMouseDown, currentHitTest)); |
| 2440 if (!swallowMouseDownEvent) | 2029 if (!swallowMouseDownEvent) |
| 2441 swallowMouseDownEvent = handleMousePressEvent(MouseEventWithHitTestResul ts(fakeMouseDown, currentHitTest)); | 2030 swallowMouseDownEvent = handleMousePressEvent(MouseEventWithHitTestResul ts(fakeMouseDown, currentHitTest)); |
| 2442 | 2031 |
| 2443 // FIXME: Use a hit-test cache to avoid unnecessary hit tests. http://crbug. com/398920 | 2032 // FIXME: Use a hit-test cache to avoid unnecessary hit tests. http://crbug. com/398920 |
| 2444 if (currentHitTest.innerNode()) { | 2033 if (currentHitTest.innerNode()) { |
| 2445 LocalFrame* mainFrame = m_frame->localFrameRoot(); | 2034 LocalFrame* mainFrame = m_frame->localFrameRoot(); |
| 2446 if (mainFrame && mainFrame->view()) | 2035 if (mainFrame && mainFrame->view()) |
| 2447 mainFrame->view()->updateLayoutAndStyleIfNeededRecursive(); | 2036 mainFrame->view()->updateLayoutAndStyleIfNeededRecursive(); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2522 #endif | 2111 #endif |
| 2523 if (shouldLongPressSelectWord) { | 2112 if (shouldLongPressSelectWord) { |
| 2524 IntPoint hitTestPoint = m_frame->view()->rootFrameToContents(gestureEven t.position()); | 2113 IntPoint hitTestPoint = m_frame->view()->rootFrameToContents(gestureEven t.position()); |
| 2525 HitTestResult result = hitTestResultAtPoint(hitTestPoint); | 2114 HitTestResult result = hitTestResultAtPoint(hitTestPoint); |
| 2526 Node* innerNode = result.innerNode(); | 2115 Node* innerNode = result.innerNode(); |
| 2527 if (!result.isLiveLink() && innerNode && (innerNode->isContentEditable() || innerNode->isTextNode() | 2116 if (!result.isLiveLink() && innerNode && (innerNode->isContentEditable() || innerNode->isTextNode() |
| 2528 #if OS(ANDROID) | 2117 #if OS(ANDROID) |
| 2529 || innerNode->canStartSelection() | 2118 || innerNode->canStartSelection() |
| 2530 #endif | 2119 #endif |
| 2531 )) { | 2120 )) { |
| 2532 selectClosestWordFromHitTestResult(result, DontAppendTrailingWhitesp ace); | 2121 selectionController().selectClosestWordFromHitTestResult(result, Don tAppendTrailingWhitespace); |
| 2533 if (m_frame->selection().isRange()) { | 2122 if (m_frame->selection().isRange()) { |
| 2534 focusDocumentView(); | 2123 focusDocumentView(); |
| 2535 return true; | 2124 return true; |
| 2536 } | 2125 } |
| 2537 } | 2126 } |
| 2538 } | 2127 } |
| 2539 return sendContextMenuEventForGesture(targetedEvent); | 2128 return sendContextMenuEventForGesture(targetedEvent); |
| 2540 } | 2129 } |
| 2541 | 2130 |
| 2542 bool EventHandler::handleGestureLongTap(const GestureEventWithHitTestResults& ta rgetedEvent) | 2131 bool EventHandler::handleGestureLongTap(const GestureEventWithHitTestResults& ta rgetedEvent) |
| (...skipping 465 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3008 FrameView* v = m_frame->view(); | 2597 FrameView* v = m_frame->view(); |
| 3009 if (!v) | 2598 if (!v) |
| 3010 return false; | 2599 return false; |
| 3011 | 2600 |
| 3012 // Clear mouse press state to avoid initiating a drag while context menu is up. | 2601 // Clear mouse press state to avoid initiating a drag while context menu is up. |
| 3013 m_mousePressed = false; | 2602 m_mousePressed = false; |
| 3014 LayoutPoint positionInContents = v->rootFrameToContents(event.position()); | 2603 LayoutPoint positionInContents = v->rootFrameToContents(event.position()); |
| 3015 HitTestRequest request(HitTestRequest::Active); | 2604 HitTestRequest request(HitTestRequest::Active); |
| 3016 MouseEventWithHitTestResults mev = doc->prepareMouseEvent(request, positionI nContents, event); | 2605 MouseEventWithHitTestResults mev = doc->prepareMouseEvent(request, positionI nContents, event); |
| 3017 | 2606 |
| 3018 if (!m_frame->selection().contains(positionInContents) | 2607 selectionController().selectionForContextMenu(mev, positionInContents); |
| 3019 && !mev.scrollbar() | |
| 3020 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse. | |
| 3021 // If the selection is non-editable, we do word selection to make it eas ier to use the contextual menu items | |
| 3022 // available for text selections. But only if we're above text. | |
| 3023 && (m_frame->selection().isContentEditable() || (mev.innerNode() && mev. innerNode()->isTextNode()))) { | |
| 3024 m_mouseDownMayStartSelect = true; // context menu events are always allo wed to perform a selection | |
| 3025 | |
| 3026 if (mev.hitTestResult().isMisspelled()) | |
| 3027 selectClosestMisspellingFromMouseEvent(mev); | |
| 3028 else if (m_frame->editor().behavior().shouldSelectOnContextualMenuClick( )) | |
| 3029 selectClosestWordOrLinkFromMouseEvent(mev); | |
| 3030 } | |
| 3031 | 2608 |
| 3032 return !dispatchMouseEvent(EventTypeNames::contextmenu, mev.innerNode(), 0, event, false); | 2609 return !dispatchMouseEvent(EventTypeNames::contextmenu, mev.innerNode(), 0, event, false); |
| 3033 } | 2610 } |
| 3034 | 2611 |
| 3035 bool EventHandler::sendContextMenuEventForKey() | 2612 bool EventHandler::sendContextMenuEventForKey() |
| 3036 { | 2613 { |
| 3037 FrameView* view = m_frame->view(); | 2614 FrameView* view = m_frame->view(); |
| 3038 if (!view) | 2615 if (!view) |
| 3039 return false; | 2616 return false; |
| 3040 | 2617 |
| (...skipping 465 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3506 dragState().m_dragSrc = m_frame->page()->dragController().draggableN ode(m_frame, node, m_mouseDownPos, selectionDragPolicy, dragState().m_dragType); | 3083 dragState().m_dragSrc = m_frame->page()->dragController().draggableN ode(m_frame, node, m_mouseDownPos, selectionDragPolicy, dragState().m_dragType); |
| 3507 } else { | 3084 } else { |
| 3508 dragState().m_dragSrc = nullptr; | 3085 dragState().m_dragSrc = nullptr; |
| 3509 } | 3086 } |
| 3510 | 3087 |
| 3511 if (!dragState().m_dragSrc) | 3088 if (!dragState().m_dragSrc) |
| 3512 m_mouseDownMayStartDrag = false; // no element is draggable | 3089 m_mouseDownMayStartDrag = false; // no element is draggable |
| 3513 } | 3090 } |
| 3514 | 3091 |
| 3515 if (!m_mouseDownMayStartDrag) | 3092 if (!m_mouseDownMayStartDrag) |
| 3516 return initiator == DragInitiator::Mouse && !mouseDownMayStartSelect() & & !m_mouseDownMayStartAutoscroll; | 3093 return initiator == DragInitiator::Mouse && !selectionController().allow Selection() && !m_mouseDownMayStartAutoscroll; |
| 3517 | 3094 |
| 3518 // We are starting a text/image/url drag, so the cursor should be an arrow | 3095 // We are starting a text/image/url drag, so the cursor should be an arrow |
| 3519 // FIXME <rdar://7577595>: Custom cursors aren't supported during drag and d rop (default to pointer). | 3096 // FIXME <rdar://7577595>: Custom cursors aren't supported during drag and d rop (default to pointer). |
| 3520 m_frame->view()->setCursor(pointerCursor()); | 3097 m_frame->view()->setCursor(pointerCursor()); |
| 3521 | 3098 |
| 3522 if (initiator == DragInitiator::Mouse && !dragHysteresisExceeded(event.event ().position())) | 3099 if (initiator == DragInitiator::Mouse && !dragHysteresisExceeded(event.event ().position())) |
| 3523 return true; | 3100 return true; |
| 3524 | 3101 |
| 3525 // Once we're past the hysteresis point, we don't want to treat this gesture as a click | 3102 // Once we're past the hysteresis point, we don't want to treat this gesture as a click |
| 3526 invalidateClick(); | 3103 invalidateClick(); |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3733 Scrollbar* scrollbar = mev.scrollbar(); | 3310 Scrollbar* scrollbar = mev.scrollbar(); |
| 3734 updateLastScrollbarUnderMouse(scrollbar, true); | 3311 updateLastScrollbarUnderMouse(scrollbar, true); |
| 3735 | 3312 |
| 3736 if (!scrollbar || !scrollbar->enabled()) | 3313 if (!scrollbar || !scrollbar->enabled()) |
| 3737 return false; | 3314 return false; |
| 3738 setFrameWasScrolledByUser(); | 3315 setFrameWasScrolledByUser(); |
| 3739 scrollbar->mouseDown(mev.event()); | 3316 scrollbar->mouseDown(mev.event()); |
| 3740 return true; | 3317 return true; |
| 3741 } | 3318 } |
| 3742 | 3319 |
| 3320 void EventHandler::updateSelectionForMouseDrag() | |
| 3321 { | |
| 3322 selectionController().updateSelectionForMouseDrag(m_mousePressNode, m_dragSt artPos, m_lastKnownMouseGlobalPosition); | |
| 3323 } | |
| 3324 | |
| 3743 // If scrollbar (under mouse) is different from last, send a mouse exited. Set | 3325 // If scrollbar (under mouse) is different from last, send a mouse exited. Set |
| 3744 // last to scrollbar if setLast is true; else set last to 0. | 3326 // last to scrollbar if setLast is true; else set last to 0. |
| 3745 void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setL ast) | 3327 void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setL ast) |
| 3746 { | 3328 { |
| 3747 if (m_lastScrollbarUnderMouse != scrollbar) { | 3329 if (m_lastScrollbarUnderMouse != scrollbar) { |
| 3748 // Send mouse exited to the old scrollbar. | 3330 // Send mouse exited to the old scrollbar. |
| 3749 if (m_lastScrollbarUnderMouse) | 3331 if (m_lastScrollbarUnderMouse) |
| 3750 m_lastScrollbarUnderMouse->mouseExited(); | 3332 m_lastScrollbarUnderMouse->mouseExited(); |
| 3751 | 3333 |
| 3752 // Send mouse entered if we're setting a new scrollbar. | 3334 // Send mouse entered if we're setting a new scrollbar. |
| (...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4077 m_lastKnownMousePosition = event.position(); | 3659 m_lastKnownMousePosition = event.position(); |
| 4078 m_lastKnownMouseGlobalPosition = event.globalPosition(); | 3660 m_lastKnownMouseGlobalPosition = event.globalPosition(); |
| 4079 } | 3661 } |
| 4080 | 3662 |
| 4081 bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& m ev, LocalFrame* subframe) | 3663 bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& m ev, LocalFrame* subframe) |
| 4082 { | 3664 { |
| 4083 // If we're clicking into a frame that is selected, the frame will appear | 3665 // If we're clicking into a frame that is selected, the frame will appear |
| 4084 // greyed out even though we're clicking on the selection. This looks | 3666 // greyed out even though we're clicking on the selection. This looks |
| 4085 // really strange (having the whole frame be greyed out), so we deselect the | 3667 // really strange (having the whole frame be greyed out), so we deselect the |
| 4086 // selection. | 3668 // selection. |
| 4087 IntPoint p = m_frame->view()->rootFrameToContents(mev.event().position()); | 3669 selectionController().releaseSelection(mev); |
| 4088 if (m_frame->selection().contains(p)) { | |
| 4089 VisiblePosition visiblePos( | |
| 4090 mev.innerNode()->layoutObject()->positionForPoint(mev.localPoint())) ; | |
| 4091 VisibleSelection newSelection(visiblePos); | |
| 4092 m_frame->selection().setSelection(newSelection); | |
| 4093 } | |
| 4094 | |
| 4095 subframe->eventHandler().handleMousePressEvent(mev.event()); | 3670 subframe->eventHandler().handleMousePressEvent(mev.event()); |
| 4096 return true; | 3671 return true; |
| 4097 } | 3672 } |
| 4098 | 3673 |
| 4099 bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& me v, LocalFrame* subframe, HitTestResult* hoveredNode) | 3674 bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& me v, LocalFrame* subframe, HitTestResult* hoveredNode) |
| 4100 { | 3675 { |
| 4101 if (m_mouseDownMayStartDrag) | 3676 if (m_mouseDownMayStartDrag) |
| 4102 return false; | 3677 return false; |
| 4103 subframe->eventHandler().handleMouseMoveOrLeaveEvent(mev.event(), hoveredNod e); | 3678 subframe->eventHandler().handleMouseMoveOrLeaveEvent(mev.event(), hoveredNod e); |
| 4104 return true; | 3679 return true; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4136 unsigned EventHandler::accessKeyModifiers() | 3711 unsigned EventHandler::accessKeyModifiers() |
| 4137 { | 3712 { |
| 4138 #if OS(MACOSX) | 3713 #if OS(MACOSX) |
| 4139 return PlatformEvent::CtrlKey | PlatformEvent::AltKey; | 3714 return PlatformEvent::CtrlKey | PlatformEvent::AltKey; |
| 4140 #else | 3715 #else |
| 4141 return PlatformEvent::AltKey; | 3716 return PlatformEvent::AltKey; |
| 4142 #endif | 3717 #endif |
| 4143 } | 3718 } |
| 4144 | 3719 |
| 4145 } // namespace blink | 3720 } // namespace blink |
| OLD | NEW |