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 * Copyright (C) 2015 Google Inc. All rights reserved. | 5 * Copyright (C) 2015 Google Inc. All rights reserved. |
6 * | 6 * |
7 * Redistribution and use in source and binary forms, with or without | 7 * Redistribution and use in source and binary forms, with or without |
8 * modification, are permitted provided that the following conditions | 8 * modification, are permitted provided that the following conditions |
9 * are met: | 9 * are met: |
10 * 1. Redistributions of source code must retain the above copyright | 10 * 1. Redistributions of source code must retain the above copyright |
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
266 } | 266 } |
267 | 267 |
268 bool SelectionController::updateSelectionForMouseDownDispatchingSelectStart(Node
* targetNode, const VisibleSelectionInFlatTree& selection, TextGranularity granu
larity) | 268 bool SelectionController::updateSelectionForMouseDownDispatchingSelectStart(Node
* targetNode, const VisibleSelectionInFlatTree& selection, TextGranularity granu
larity) |
269 { | 269 { |
270 if (targetNode && targetNode->layoutObject() && !targetNode->layoutObject()-
>isSelectable()) | 270 if (targetNode && targetNode->layoutObject() && !targetNode->layoutObject()-
>isSelectable()) |
271 return false; | 271 return false; |
272 | 272 |
273 if (dispatchSelectStart(targetNode) != DispatchEventResult::NotCanceled) | 273 if (dispatchSelectStart(targetNode) != DispatchEventResult::NotCanceled) |
274 return false; | 274 return false; |
275 | 275 |
276 if (!selection.isValidFor(*m_frame->document())) | 276 // |dispatchSelectStart()| can change document hosted by |m_frame|. |
| 277 if (!this->selection().isAvailable()) |
| 278 return false; |
| 279 |
| 280 if (!selection.isValidFor(this->selection().document())) |
277 return false; | 281 return false; |
278 | 282 |
279 if (selection.isRange()) { | 283 if (selection.isRange()) { |
280 m_selectionState = SelectionState::ExtendedSelection; | 284 m_selectionState = SelectionState::ExtendedSelection; |
281 } else { | 285 } else { |
282 granularity = CharacterGranularity; | 286 granularity = CharacterGranularity; |
283 m_selectionState = SelectionState::PlacedCaret; | 287 m_selectionState = SelectionState::PlacedCaret; |
284 } | 288 } |
285 | 289 |
286 this->selection().setNonDirectionalSelectionIfNeeded(selection, granularity)
; | 290 this->selection().setNonDirectionalSelectionIfNeeded(selection, granularity)
; |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
387 if (pos.isNotNull() && pos.deepEquivalent().anchorNode()->isDescendantOf(URL
Element)) | 391 if (pos.isNotNull() && pos.deepEquivalent().anchorNode()->isDescendantOf(URL
Element)) |
388 newSelection = VisibleSelectionInFlatTree::selectionFromContentsOfNode(U
RLElement); | 392 newSelection = VisibleSelectionInFlatTree::selectionFromContentsOfNode(U
RLElement); |
389 | 393 |
390 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelection
ToRespectUserSelectAll(innerNode, newSelection), WordGranularity); | 394 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelection
ToRespectUserSelectAll(innerNode, newSelection), WordGranularity); |
391 } | 395 } |
392 | 396 |
393 bool SelectionController::handleMousePressEventDoubleClick(const MouseEventWithH
itTestResults& event) | 397 bool SelectionController::handleMousePressEventDoubleClick(const MouseEventWithH
itTestResults& event) |
394 { | 398 { |
395 TRACE_EVENT0("blink", "SelectionController::handleMousePressEventDoubleClick
"); | 399 TRACE_EVENT0("blink", "SelectionController::handleMousePressEventDoubleClick
"); |
396 | 400 |
| 401 if (!selection().isAvailable()) |
| 402 return false; |
| 403 |
397 if (!m_mouseDownAllowsMultiClick) | 404 if (!m_mouseDownAllowsMultiClick) |
398 return handleMousePressEventSingleClick(event); | 405 return handleMousePressEventSingleClick(event); |
399 | 406 |
400 if (event.event().button() != LeftButton) | 407 if (event.event().button() != LeftButton) |
401 return false; | 408 return false; |
402 | 409 |
403 if (selection().isRange()) { | 410 if (selection().isRange()) { |
404 // A double-click when range is already selected | 411 // A double-click when range is already selected |
405 // should not change the selection. So, do not call | 412 // should not change the selection. So, do not call |
406 // selectClosestWordFromMouseEvent, but do set | 413 // selectClosestWordFromMouseEvent, but do set |
407 // m_beganSelectingText to prevent handleMouseReleaseEvent | 414 // m_beganSelectingText to prevent handleMouseReleaseEvent |
408 // from setting caret selection. | 415 // from setting caret selection. |
409 m_selectionState = SelectionState::ExtendedSelection; | 416 m_selectionState = SelectionState::ExtendedSelection; |
410 } else { | 417 } else { |
411 selectClosestWordFromMouseEvent(event); | 418 selectClosestWordFromMouseEvent(event); |
412 } | 419 } |
413 return true; | 420 return true; |
414 } | 421 } |
415 | 422 |
416 bool SelectionController::handleMousePressEventTripleClick(const MouseEventWithH
itTestResults& event) | 423 bool SelectionController::handleMousePressEventTripleClick(const MouseEventWithH
itTestResults& event) |
417 { | 424 { |
418 TRACE_EVENT0("blink", "SelectionController::handleMousePressEventTripleClick
"); | 425 TRACE_EVENT0("blink", "SelectionController::handleMousePressEventTripleClick
"); |
419 | 426 |
| 427 if (!selection().isAvailable()) { |
| 428 // editing/shadow/doubleclick-on-meter-in-shadow-crash.html reach here. |
| 429 return false; |
| 430 } |
| 431 |
420 if (!m_mouseDownAllowsMultiClick) | 432 if (!m_mouseDownAllowsMultiClick) |
421 return handleMousePressEventSingleClick(event); | 433 return handleMousePressEventSingleClick(event); |
422 | 434 |
423 if (event.event().button() != LeftButton) | 435 if (event.event().button() != LeftButton) |
424 return false; | 436 return false; |
425 | 437 |
426 Node* innerNode = event.innerNode(); | 438 Node* innerNode = event.innerNode(); |
427 if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect)) | 439 if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect)) |
428 return false; | 440 return false; |
429 | 441 |
430 VisibleSelectionInFlatTree newSelection; | 442 VisibleSelectionInFlatTree newSelection; |
431 const VisiblePositionInFlatTree& pos = visiblePositionOfHitTestResult(event.
hitTestResult()); | 443 const VisiblePositionInFlatTree& pos = visiblePositionOfHitTestResult(event.
hitTestResult()); |
432 if (pos.isNotNull()) { | 444 if (pos.isNotNull()) { |
433 newSelection = VisibleSelectionInFlatTree(pos); | 445 newSelection = VisibleSelectionInFlatTree(pos); |
434 newSelection.expandUsingGranularity(ParagraphGranularity); | 446 newSelection.expandUsingGranularity(ParagraphGranularity); |
435 } | 447 } |
436 | 448 |
437 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSe
lectionToRespectUserSelectAll(innerNode, newSelection), ParagraphGranularity); | 449 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSe
lectionToRespectUserSelectAll(innerNode, newSelection), ParagraphGranularity); |
438 } | 450 } |
439 | 451 |
440 void SelectionController::handleMousePressEvent(const MouseEventWithHitTestResul
ts& event) | 452 void SelectionController::handleMousePressEvent(const MouseEventWithHitTestResul
ts& event) |
441 { | 453 { |
442 // If we got the event back, that must mean it wasn't prevented, | 454 // If we got the event back, that must mean it wasn't prevented, |
443 // so it's allowed to start a drag or selection if it wasn't in a scrollbar. | 455 // so it's allowed to start a drag or selection if it wasn't in a scrollbar. |
444 m_mouseDownMayStartSelect = (canMouseDownStartSelect(event.innerNode()) || i
sLinkSelection(event)) | 456 m_mouseDownMayStartSelect = (canMouseDownStartSelect(event.innerNode()) || i
sLinkSelection(event)) |
445 && !event.scrollbar(); | 457 && !event.scrollbar(); |
446 m_mouseDownWasSingleClickInSelection = false; | 458 m_mouseDownWasSingleClickInSelection = false; |
| 459 if (!selection().isAvailable()) { |
| 460 // "gesture-tap-frame-removed.html" reaches here. |
| 461 m_mouseDownAllowsMultiClick = !event.event().fromTouch(); |
| 462 return; |
| 463 } |
| 464 |
447 // Avoid double-tap touch gesture confusion by restricting multi-click side | 465 // Avoid double-tap touch gesture confusion by restricting multi-click side |
448 // effects, e.g., word selection, to editable regions. | 466 // effects, e.g., word selection, to editable regions. |
449 m_mouseDownAllowsMultiClick = !event.event().fromTouch() || selection().hasE
ditableStyle(); | 467 m_mouseDownAllowsMultiClick = !event.event().fromTouch() || selection().hasE
ditableStyle(); |
450 } | 468 } |
451 | 469 |
452 void SelectionController::handleMouseDraggedEvent(const MouseEventWithHitTestRes
ults& event, const IntPoint& mouseDownPos, const LayoutPoint& dragStartPos, Node
* mousePressNode, const IntPoint& lastKnownMousePosition) | 470 void SelectionController::handleMouseDraggedEvent(const MouseEventWithHitTestRes
ults& event, const IntPoint& mouseDownPos, const LayoutPoint& dragStartPos, Node
* mousePressNode, const IntPoint& lastKnownMousePosition) |
453 { | 471 { |
| 472 if (!selection().isAvailable()) |
| 473 return; |
454 if (m_selectionState != SelectionState::ExtendedSelection) { | 474 if (m_selectionState != SelectionState::ExtendedSelection) { |
455 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active
); | 475 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active
); |
456 HitTestResult result(request, mouseDownPos); | 476 HitTestResult result(request, mouseDownPos); |
457 m_frame->document()->layoutViewItem().hitTest(result); | 477 m_frame->document()->layoutViewItem().hitTest(result); |
458 | 478 |
459 updateSelectionForMouseDrag(result, mousePressNode, dragStartPos, lastKn
ownMousePosition); | 479 updateSelectionForMouseDrag(result, mousePressNode, dragStartPos, lastKn
ownMousePosition); |
460 } | 480 } |
461 updateSelectionForMouseDrag(event.hitTestResult(), mousePressNode, dragStart
Pos, lastKnownMousePosition); | 481 updateSelectionForMouseDrag(event.hitTestResult(), mousePressNode, dragStart
Pos, lastKnownMousePosition); |
462 } | 482 } |
463 | 483 |
464 void SelectionController::updateSelectionForMouseDrag(Node* mousePressNode, cons
t LayoutPoint& dragStartPos, const IntPoint& lastKnownMousePosition) | 484 void SelectionController::updateSelectionForMouseDrag(Node* mousePressNode, cons
t LayoutPoint& dragStartPos, const IntPoint& lastKnownMousePosition) |
465 { | 485 { |
466 FrameView* view = m_frame->view(); | 486 FrameView* view = m_frame->view(); |
467 if (!view) | 487 if (!view) |
468 return; | 488 return; |
469 LayoutViewItem layoutItem = m_frame->contentLayoutItem(); | 489 LayoutViewItem layoutItem = m_frame->contentLayoutItem(); |
470 if (layoutItem.isNull()) | 490 if (layoutItem.isNull()) |
471 return; | 491 return; |
472 | 492 |
473 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | H
itTestRequest::Move); | 493 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | H
itTestRequest::Move); |
474 HitTestResult result(request, view->rootFrameToContents(lastKnownMousePositi
on)); | 494 HitTestResult result(request, view->rootFrameToContents(lastKnownMousePositi
on)); |
475 layoutItem.hitTest(result); | 495 layoutItem.hitTest(result); |
476 updateSelectionForMouseDrag(result, mousePressNode, dragStartPos, lastKnownM
ousePosition); | 496 updateSelectionForMouseDrag(result, mousePressNode, dragStartPos, lastKnownM
ousePosition); |
477 } | 497 } |
478 | 498 |
479 bool SelectionController::handleMouseReleaseEvent(const MouseEventWithHitTestRes
ults& event, const LayoutPoint& dragStartPos) | 499 bool SelectionController::handleMouseReleaseEvent(const MouseEventWithHitTestRes
ults& event, const LayoutPoint& dragStartPos) |
480 { | 500 { |
| 501 if (!selection().isAvailable()) |
| 502 return false; |
| 503 |
481 bool handled = false; | 504 bool handled = false; |
482 m_mouseDownMayStartSelect = false; | 505 m_mouseDownMayStartSelect = false; |
483 // Clear the selection if the mouse didn't move after the last mouse | 506 // Clear the selection if the mouse didn't move after the last mouse |
484 // press and it's not a context menu click. We do this so when clicking | 507 // press and it's not a context menu click. We do this so when clicking |
485 // on the selection, the selection goes away. However, if we are | 508 // on the selection, the selection goes away. However, if we are |
486 // editing, place the caret. | 509 // editing, place the caret. |
487 if (m_mouseDownWasSingleClickInSelection && m_selectionState != SelectionSta
te::ExtendedSelection | 510 if (m_mouseDownWasSingleClickInSelection && m_selectionState != SelectionSta
te::ExtendedSelection |
488 && dragStartPos == event.event().position() | 511 && dragStartPos == event.event().position() |
489 && selection().isRange() | 512 && selection().isRange() |
490 && event.event().button() != RightButton) { | 513 && event.event().button() != RightButton) { |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
539 Frame* focusFrame = m_frame->page()->focusController().focusedOrMainFrame(); | 562 Frame* focusFrame = m_frame->page()->focusController().focusedOrMainFrame(); |
540 // Do not paste here if the focus was moved somewhere else. | 563 // Do not paste here if the focus was moved somewhere else. |
541 if (m_frame == focusFrame && m_frame->editor().behavior().supportsGlobalSele
ction()) | 564 if (m_frame == focusFrame && m_frame->editor().behavior().supportsGlobalSele
ction()) |
542 return m_frame->editor().createCommand("PasteGlobalSelection").execute()
; | 565 return m_frame->editor().createCommand("PasteGlobalSelection").execute()
; |
543 | 566 |
544 return false; | 567 return false; |
545 } | 568 } |
546 | 569 |
547 bool SelectionController::handleGestureLongPress(const PlatformGestureEvent& ges
tureEvent, const HitTestResult& hitTestResult) | 570 bool SelectionController::handleGestureLongPress(const PlatformGestureEvent& ges
tureEvent, const HitTestResult& hitTestResult) |
548 { | 571 { |
| 572 if (!selection().isAvailable()) |
| 573 return false; |
549 if (hitTestResult.isLiveLink()) | 574 if (hitTestResult.isLiveLink()) |
550 return false; | 575 return false; |
551 | 576 |
552 Node* innerNode = hitTestResult.innerNode(); | 577 Node* innerNode = hitTestResult.innerNode(); |
553 bool innerNodeIsSelectable = innerNode && (innerNode->isContentEditable() ||
innerNode->isTextNode() || innerNode->canStartSelection()); | 578 bool innerNodeIsSelectable = innerNode && (innerNode->isContentEditable() ||
innerNode->isTextNode() || innerNode->canStartSelection()); |
554 if (!innerNodeIsSelectable) | 579 if (!innerNodeIsSelectable) |
555 return false; | 580 return false; |
556 | 581 |
557 selectClosestWordFromHitTestResult(hitTestResult, AppendTrailingWhitespace::
DontAppend, SelectInputEventType::GestureLongPress); | 582 selectClosestWordFromHitTestResult(hitTestResult, AppendTrailingWhitespace::
DontAppend, SelectInputEventType::GestureLongPress); |
| 583 if (!selection().isAvailable()) { |
| 584 // "editing/selection/longpress-selection-in-iframe-removed-crash.html" |
| 585 // reach here. |
| 586 return false; |
| 587 } |
558 return selection().isRange(); | 588 return selection().isRange(); |
559 } | 589 } |
560 | 590 |
561 void SelectionController::sendContextMenuEvent(const MouseEventWithHitTestResult
s& mev, const LayoutPoint& position) | 591 void SelectionController::sendContextMenuEvent(const MouseEventWithHitTestResult
s& mev, const LayoutPoint& position) |
562 { | 592 { |
| 593 if (!selection().isAvailable()) |
| 594 return; |
563 if (selection().contains(position) | 595 if (selection().contains(position) |
564 || mev.scrollbar() | 596 || mev.scrollbar() |
565 // FIXME: In the editable case, word selection sometimes selects content
that isn't underneath the mouse. | 597 // FIXME: In the editable case, word selection sometimes selects content
that isn't underneath the mouse. |
566 // If the selection is non-editable, we do word selection to make it eas
ier to use the contextual menu items | 598 // If the selection is non-editable, we do word selection to make it eas
ier to use the contextual menu items |
567 // available for text selections. But only if we're above text. | 599 // available for text selections. But only if we're above text. |
568 || !(selection().isContentEditable() || (mev.innerNode() && mev.innerNod
e()->isTextNode()))) | 600 || !(selection().isContentEditable() || (mev.innerNode() && mev.innerNod
e()->isTextNode()))) |
569 return; | 601 return; |
570 | 602 |
571 // Context menu events are always allowed to perform a selection. | 603 // Context menu events are always allowed to perform a selection. |
572 TemporaryChange<bool> mouseDownMayStartSelectChange(m_mouseDownMayStartSelec
t, true); | 604 TemporaryChange<bool> mouseDownMayStartSelectChange(m_mouseDownMayStartSelec
t, true); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
629 { | 661 { |
630 return m_frame->selection(); | 662 return m_frame->selection(); |
631 } | 663 } |
632 | 664 |
633 bool isLinkSelection(const MouseEventWithHitTestResults& event) | 665 bool isLinkSelection(const MouseEventWithHitTestResults& event) |
634 { | 666 { |
635 return event.event().altKey() && event.isOverLink(); | 667 return event.event().altKey() && event.isOverLink(); |
636 } | 668 } |
637 | 669 |
638 } // namespace blink | 670 } // namespace blink |
OLD | NEW |