Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights | 2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights |
| 3 * reserved. | 3 * reserved. |
| 4 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) | 4 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) |
| 5 * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies) | 5 * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies) |
| 6 * Copyright (C) 2015 Google Inc. All rights reserved. | 6 * Copyright (C) 2015 Google Inc. All rights reserved. |
| 7 * | 7 * |
| 8 * Redistribution and use in source and binary forms, with or without | 8 * Redistribution and use in source and binary forms, with or without |
| 9 * modification, are permitted provided that the following conditions | 9 * modification, are permitted provided that the following conditions |
| 10 * are met: | 10 * are met: |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 130 | 130 |
| 131 DCHECK(!m_frame->document()->needsLayoutTreeUpdate()); | 131 DCHECK(!m_frame->document()->needsLayoutTreeUpdate()); |
| 132 Node* innerNode = event.innerNode(); | 132 Node* innerNode = event.innerNode(); |
| 133 if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect)) | 133 if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect)) |
| 134 return false; | 134 return false; |
| 135 | 135 |
| 136 // Extend the selection if the Shift key is down, unless the click is in a | 136 // Extend the selection if the Shift key is down, unless the click is in a |
| 137 // link or image. | 137 // link or image. |
| 138 bool extendSelection = isExtendingSelection(event); | 138 bool extendSelection = isExtendingSelection(event); |
| 139 | 139 |
| 140 VisibleSelectionInFlatTree newSelection = | |
| 141 selection().visibleSelection<EditingInFlatTreeStrategy>(); | |
| 142 | |
| 140 // Don't restart the selection when the mouse is pressed on an | 143 // Don't restart the selection when the mouse is pressed on an |
| 141 // existing selection so we can allow for text dragging. | 144 // existing selection so we can allow for text dragging. |
| 142 if (FrameView* view = m_frame->view()) { | 145 if (!extendSelection && selection().contains(event.hitTestResult())) { |
| 143 LayoutPoint vPoint = view->rootFrameToContents(event.event().position()); | 146 m_mouseDownWasSingleClickInSelection = true; |
| 144 if (!extendSelection && selection().contains(vPoint)) { | 147 if (!event.event().fromTouch()) |
| 145 m_mouseDownWasSingleClickInSelection = true; | |
| 146 return false; | 148 return false; |
| 147 } | |
| 148 } | 149 } |
| 149 | 150 |
| 150 VisiblePositionInFlatTree visiblePos = | 151 VisiblePositionInFlatTree visiblePos = |
| 151 visiblePositionOfHitTestResult(event.hitTestResult()); | 152 visiblePositionOfHitTestResult(event.hitTestResult()); |
| 152 if (visiblePos.isNull()) | 153 if (visiblePos.isNull()) |
| 153 visiblePos = createVisiblePosition( | 154 visiblePos = createVisiblePosition( |
| 154 PositionInFlatTree::firstPositionInOrBeforeNode(innerNode)); | 155 PositionInFlatTree::firstPositionInOrBeforeNode(innerNode)); |
| 155 PositionInFlatTree pos = visiblePos.deepEquivalent(); | 156 PositionInFlatTree pos = visiblePos.deepEquivalent(); |
| 156 | 157 |
| 157 VisibleSelectionInFlatTree newSelection = | |
| 158 selection().visibleSelection<EditingInFlatTreeStrategy>(); | |
| 159 TextGranularity granularity = CharacterGranularity; | 158 TextGranularity granularity = CharacterGranularity; |
| 160 | 159 |
| 161 if (extendSelection && !newSelection.isNone()) { | 160 if (mouseDownWasSingleClickInSelection() && !newSelection.isHandleVisible()) { |
| 161 newSelection.setIsHandleVisible(true); | |
| 162 } else if (extendSelection && !newSelection.isNone()) { | |
| 162 const VisibleSelectionInFlatTree selectionInUserSelectAll( | 163 const VisibleSelectionInFlatTree selectionInUserSelectAll( |
| 163 expandSelectionToRespectUserSelectAll(innerNode, | 164 expandSelectionToRespectUserSelectAll(innerNode, |
| 164 createVisibleSelection(pos))); | 165 createVisibleSelection(pos))); |
| 165 if (selectionInUserSelectAll.isRange()) { | 166 if (selectionInUserSelectAll.isRange()) { |
| 166 if (selectionInUserSelectAll.start().compareTo(newSelection.start()) < 0) | 167 if (selectionInUserSelectAll.start().compareTo(newSelection.start()) < 0) |
| 167 pos = selectionInUserSelectAll.start(); | 168 pos = selectionInUserSelectAll.start(); |
| 168 else if (newSelection.end().compareTo(selectionInUserSelectAll.end()) < 0) | 169 else if (newSelection.end().compareTo(selectionInUserSelectAll.end()) < 0) |
| 169 pos = selectionInUserSelectAll.end(); | 170 pos = selectionInUserSelectAll.end(); |
| 170 } | 171 } |
| 171 | 172 |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 186 newSelection.setExtent(pos); | 187 newSelection.setExtent(pos); |
| 187 } | 188 } |
| 188 | 189 |
| 189 if (selection().granularity() != CharacterGranularity) { | 190 if (selection().granularity() != CharacterGranularity) { |
| 190 granularity = selection().granularity(); | 191 granularity = selection().granularity(); |
| 191 newSelection.expandUsingGranularity(selection().granularity()); | 192 newSelection.expandUsingGranularity(selection().granularity()); |
| 192 } | 193 } |
| 193 } else if (m_selectionState != SelectionState::ExtendedSelection) { | 194 } else if (m_selectionState != SelectionState::ExtendedSelection) { |
| 194 newSelection = expandSelectionToRespectUserSelectAll( | 195 newSelection = expandSelectionToRespectUserSelectAll( |
| 195 innerNode, createVisibleSelection(visiblePos)); | 196 innerNode, createVisibleSelection(visiblePos)); |
| 197 if (newSelection.isContentEditable()) { | |
| 198 bool isTextBoxEmpty = | |
| 199 VisibleSelection::selectionFromContentsOfNode(innerNode).isCaret(); | |
| 200 bool notLeftClick = event.event().pointerProperties().button != | |
| 201 WebPointerProperties::Button::Left; | |
| 202 if (!isTextBoxEmpty || notLeftClick) | |
| 203 newSelection.setIsHandleVisible(event.event().fromTouch()); | |
|
aelias_OOO_until_Jul13
2016/10/07 02:40:20
Can you add a test that handles are *not* created
amaralp
2016/10/14 00:53:07
Added to EventHandlerTest.cpp
| |
| 204 } | |
| 196 } | 205 } |
| 197 | 206 |
| 198 // Updating the selection is considered side-effect of the event and so it | 207 // Updating the selection is considered side-effect of the event and so it |
| 199 // doesn't impact the handled state. | 208 // doesn't impact the handled state. |
| 200 updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, | 209 updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, |
| 201 granularity); | 210 granularity); |
| 202 return false; | 211 return false; |
| 203 } | 212 } |
| 204 | 213 |
| 205 void SelectionController::updateSelectionForMouseDrag( | 214 void SelectionController::updateSelectionForMouseDrag( |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 389 : TextIteratorDefaultBehavior); | 398 : TextIteratorDefaultBehavior); |
| 390 if (str.isEmpty() || str.simplifyWhiteSpace().containsOnlyWhitespace()) | 399 if (str.isEmpty() || str.simplifyWhiteSpace().containsOnlyWhitespace()) |
| 391 return; | 400 return; |
| 392 | 401 |
| 393 if (newSelection.rootEditableElement() && | 402 if (newSelection.rootEditableElement() && |
| 394 pos.deepEquivalent() == | 403 pos.deepEquivalent() == |
| 395 VisiblePositionInFlatTree::lastPositionInNode( | 404 VisiblePositionInFlatTree::lastPositionInNode( |
| 396 newSelection.rootEditableElement()) | 405 newSelection.rootEditableElement()) |
| 397 .deepEquivalent()) | 406 .deepEquivalent()) |
| 398 return; | 407 return; |
| 408 newSelection.setIsHandleVisible(true); | |
| 399 } | 409 } |
| 400 | 410 |
| 401 if (appendTrailingWhitespace == AppendTrailingWhitespace::ShouldAppend && | 411 if (appendTrailingWhitespace == AppendTrailingWhitespace::ShouldAppend && |
| 402 newSelection.isRange()) | 412 newSelection.isRange()) |
| 403 newSelection.appendTrailingWhitespace(); | 413 newSelection.appendTrailingWhitespace(); |
| 404 | 414 |
| 405 updateSelectionForMouseDownDispatchingSelectStart( | 415 updateSelectionForMouseDownDispatchingSelectStart( |
| 406 innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), | 416 innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), |
| 407 WordGranularity); | 417 WordGranularity); |
| 408 } | 418 } |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 547 return false; | 557 return false; |
| 548 | 558 |
| 549 VisibleSelectionInFlatTree newSelection; | 559 VisibleSelectionInFlatTree newSelection; |
| 550 const VisiblePositionInFlatTree& pos = | 560 const VisiblePositionInFlatTree& pos = |
| 551 visiblePositionOfHitTestResult(event.hitTestResult()); | 561 visiblePositionOfHitTestResult(event.hitTestResult()); |
| 552 if (pos.isNotNull()) { | 562 if (pos.isNotNull()) { |
| 553 newSelection = createVisibleSelection(pos); | 563 newSelection = createVisibleSelection(pos); |
| 554 newSelection.expandUsingGranularity(ParagraphGranularity); | 564 newSelection.expandUsingGranularity(ParagraphGranularity); |
| 555 } | 565 } |
| 556 | 566 |
| 567 newSelection.setIsHandleVisible(event.event().fromTouch() && | |
| 568 newSelection.isRange()); | |
| 569 | |
| 557 return updateSelectionForMouseDownDispatchingSelectStart( | 570 return updateSelectionForMouseDownDispatchingSelectStart( |
| 558 innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), | 571 innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), |
| 559 ParagraphGranularity); | 572 ParagraphGranularity); |
| 560 } | 573 } |
| 561 | 574 |
| 562 void SelectionController::handleMousePressEvent( | 575 void SelectionController::handleMousePressEvent( |
| 563 const MouseEventWithHitTestResults& event) { | 576 const MouseEventWithHitTestResults& event) { |
| 564 // If we got the event back, that must mean it wasn't prevented, | 577 // If we got the event back, that must mean it wasn't prevented, |
| 565 // so it's allowed to start a drag or selection if it wasn't in a scrollbar. | 578 // so it's allowed to start a drag or selection if it wasn't in a scrollbar. |
| 566 m_mouseDownMayStartSelect = | 579 m_mouseDownMayStartSelect = |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 713 | 726 |
| 714 Node* innerNode = hitTestResult.innerNode(); | 727 Node* innerNode = hitTestResult.innerNode(); |
| 715 if (!innerNode) | 728 if (!innerNode) |
| 716 return false; | 729 return false; |
| 717 innerNode->document().updateStyleAndLayoutTree(); | 730 innerNode->document().updateStyleAndLayoutTree(); |
| 718 bool innerNodeIsSelectable = | 731 bool innerNodeIsSelectable = |
| 719 hasEditableStyle(*innerNode) || innerNode->canStartSelection(); | 732 hasEditableStyle(*innerNode) || innerNode->canStartSelection(); |
| 720 if (!innerNodeIsSelectable) | 733 if (!innerNodeIsSelectable) |
| 721 return false; | 734 return false; |
| 722 | 735 |
| 736 // If longpress occurs inside of a selection that doesn't have handles | |
| 737 // then we want to show the handes on the entire selection. | |
| 738 VisibleSelectionInFlatTree newSelection = | |
| 739 selection().visibleSelection<EditingInFlatTreeStrategy>(); | |
| 740 if (selection().contains(hitTestResult) && !newSelection.isHandleVisible()) { | |
| 741 newSelection.setIsHandleVisible(true); | |
| 742 selection().setNonDirectionalSelectionIfNeeded(newSelection, | |
| 743 selection().granularity()); | |
| 744 return true; | |
| 745 } | |
| 746 | |
| 723 selectClosestWordFromHitTestResult(hitTestResult, | 747 selectClosestWordFromHitTestResult(hitTestResult, |
| 724 AppendTrailingWhitespace::DontAppend, | 748 AppendTrailingWhitespace::DontAppend, |
| 725 SelectInputEventType::Touch); | 749 SelectInputEventType::Touch); |
| 726 if (!selection().isAvailable()) { | 750 if (!selection().isAvailable()) { |
| 727 // "editing/selection/longpress-selection-in-iframe-removed-crash.html" | 751 // "editing/selection/longpress-selection-in-iframe-removed-crash.html" |
| 728 // reach here. | 752 // reach here. |
| 729 return false; | 753 return false; |
| 730 } | 754 } |
| 731 return selection().isRange(); | 755 return selection().isRange(); |
| 732 } | 756 } |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 746 pos.deepEquivalent().parentAnchoredEquivalent()), | 770 pos.deepEquivalent().parentAnchoredEquivalent()), |
| 747 DocumentMarker::MisspellingMarkers()) | 771 DocumentMarker::MisspellingMarkers()) |
| 748 .size() > 0; | 772 .size() > 0; |
| 749 } | 773 } |
| 750 | 774 |
| 751 void SelectionController::sendContextMenuEvent( | 775 void SelectionController::sendContextMenuEvent( |
| 752 const MouseEventWithHitTestResults& mev, | 776 const MouseEventWithHitTestResults& mev, |
| 753 const LayoutPoint& position) { | 777 const LayoutPoint& position) { |
| 754 if (!selection().isAvailable()) | 778 if (!selection().isAvailable()) |
| 755 return; | 779 return; |
| 756 if (selection().contains(position) || mev.scrollbar() || | 780 if (selection().contains(mev.hitTestResult()) || mev.scrollbar() || |
| 757 // FIXME: In the editable case, word selection sometimes selects content | 781 // FIXME: In the editable case, word selection sometimes selects content |
| 758 // that isn't underneath the mouse. | 782 // that isn't underneath the mouse. |
| 759 // If the selection is non-editable, we do word selection to make it | 783 // If the selection is non-editable, we do word selection to make it |
| 760 // easier to use the contextual menu items available for text selections. | 784 // easier to use the contextual menu items available for text selections. |
| 761 // But only if we're above text. | 785 // But only if we're above text. |
| 762 !(selection().isContentEditable() || | 786 !(selection().isContentEditable() || |
| 763 (mev.innerNode() && mev.innerNode()->isTextNode()))) | 787 (mev.innerNode() && mev.innerNode()->isTextNode()))) |
| 764 return; | 788 return; |
| 765 | 789 |
| 766 // Context menu events are always allowed to perform a selection. | 790 // Context menu events are always allowed to perform a selection. |
| 767 AutoReset<bool> mouseDownMayStartSelectChange(&m_mouseDownMayStartSelect, | 791 AutoReset<bool> mouseDownMayStartSelectChange(&m_mouseDownMayStartSelect, |
| 768 true); | 792 true); |
| 769 | 793 |
| 770 if (hitTestResultIsMisspelled(mev.hitTestResult())) | 794 if (hitTestResultIsMisspelled(mev.hitTestResult())) |
| 771 return selectClosestMisspellingFromMouseEvent(mev); | 795 return selectClosestMisspellingFromMouseEvent(mev); |
| 772 | 796 |
| 773 if (!m_frame->editor().behavior().shouldSelectOnContextualMenuClick()) | 797 if (!m_frame->editor().behavior().shouldSelectOnContextualMenuClick()) |
| 774 return; | 798 return; |
| 775 | 799 |
| 776 selectClosestWordOrLinkFromMouseEvent(mev); | 800 selectClosestWordOrLinkFromMouseEvent(mev); |
| 777 } | 801 } |
| 778 | 802 |
| 779 void SelectionController::passMousePressEventToSubframe( | 803 void SelectionController::passMousePressEventToSubframe( |
| 780 const MouseEventWithHitTestResults& mev) { | 804 const MouseEventWithHitTestResults& mev) { |
| 781 // If we're clicking into a frame that is selected, the frame will appear | 805 // If we're clicking into a frame that is selected, the frame will appear |
| 782 // greyed out even though we're clicking on the selection. This looks | 806 // greyed out even though we're clicking on the selection. This looks |
| 783 // really strange (having the whole frame be greyed out), so we deselect the | 807 // really strange (having the whole frame be greyed out), so we deselect the |
| 784 // selection. | 808 // selection. |
| 785 IntPoint p = m_frame->view()->rootFrameToContents(mev.event().position()); | 809 if (!selection().contains(mev.hitTestResult())) |
| 786 if (!selection().contains(p)) | |
| 787 return; | 810 return; |
| 788 | 811 |
| 789 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets | 812 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets |
| 790 // needs to be audited. See http://crbug.com/590369 for more details. | 813 // needs to be audited. See http://crbug.com/590369 for more details. |
| 791 m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets(); | 814 m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets(); |
| 792 | 815 |
| 793 const VisiblePositionInFlatTree& visiblePos = | 816 const VisiblePositionInFlatTree& visiblePos = |
| 794 visiblePositionOfHitTestResult(mev.hitTestResult()); | 817 visiblePositionOfHitTestResult(mev.hitTestResult()); |
| 795 VisibleSelectionInFlatTree newSelection = createVisibleSelection(visiblePos); | 818 VisibleSelectionInFlatTree newSelection = createVisibleSelection(visiblePos); |
| 796 selection().setSelection(newSelection); | 819 selection().setSelection(newSelection); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 829 return event.event().altKey() && event.isOverLink(); | 852 return event.event().altKey() && event.isOverLink(); |
| 830 } | 853 } |
| 831 | 854 |
| 832 bool isExtendingSelection(const MouseEventWithHitTestResults& event) { | 855 bool isExtendingSelection(const MouseEventWithHitTestResults& event) { |
| 833 bool isMouseDownOnLinkOrImage = | 856 bool isMouseDownOnLinkOrImage = |
| 834 event.isOverLink() || event.hitTestResult().image(); | 857 event.isOverLink() || event.hitTestResult().image(); |
| 835 return event.event().shiftKey() && !isMouseDownOnLinkOrImage; | 858 return event.event().shiftKey() && !isMouseDownOnLinkOrImage; |
| 836 } | 859 } |
| 837 | 860 |
| 838 } // namespace blink | 861 } // namespace blink |
| OLD | NEW |