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 |