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 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
173 visibleHitPos.isNull() | 173 visibleHitPos.isNull() |
174 ? createVisiblePosition( | 174 ? createVisiblePosition( |
175 PositionInFlatTree::firstPositionInOrBeforeNode(innerNode)) | 175 PositionInFlatTree::firstPositionInOrBeforeNode(innerNode)) |
176 : visibleHitPos; | 176 : visibleHitPos; |
177 const VisibleSelectionInFlatTree& selection = | 177 const VisibleSelectionInFlatTree& selection = |
178 this->selection().visibleSelection<EditingInFlatTreeStrategy>(); | 178 this->selection().visibleSelection<EditingInFlatTreeStrategy>(); |
179 | 179 |
180 // Don't restart the selection when the mouse is pressed on an | 180 // Don't restart the selection when the mouse is pressed on an |
181 // existing selection so we can allow for text dragging. | 181 // existing selection so we can allow for text dragging. |
182 if (FrameView* view = m_frame->view()) { | 182 if (FrameView* view = m_frame->view()) { |
183 const LayoutPoint vPoint = | 183 const LayoutPoint vPoint = view->rootFrameToContents( |
184 view->rootFrameToContents(event.event().position()); | 184 flooredIntPoint(event.event().positionInRootFrame())); |
185 if (!extendSelection && this->selection().contains(vPoint)) { | 185 if (!extendSelection && this->selection().contains(vPoint)) { |
186 m_mouseDownWasSingleClickInSelection = true; | 186 m_mouseDownWasSingleClickInSelection = true; |
187 if (!event.event().fromTouch()) | 187 if (!event.event().fromTouch()) |
188 return false; | 188 return false; |
189 | 189 |
190 if (!this->selection().isHandleVisible()) { | 190 if (!this->selection().isHandleVisible()) { |
191 updateSelectionForMouseDownDispatchingSelectStart( | 191 updateSelectionForMouseDownDispatchingSelectStart( |
192 innerNode, selection, CharacterGranularity, | 192 innerNode, selection, CharacterGranularity, |
193 HandleVisibility::Visible); | 193 HandleVisibility::Visible); |
194 return false; | 194 return false; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
238 return false; | 238 return false; |
239 } | 239 } |
240 | 240 |
241 bool isHandleVisible = false; | 241 bool isHandleVisible = false; |
242 if (hasEditableStyle(*innerNode)) { | 242 if (hasEditableStyle(*innerNode)) { |
243 const bool isTextBoxEmpty = | 243 const bool isTextBoxEmpty = |
244 createVisibleSelection(SelectionInFlatTree::Builder() | 244 createVisibleSelection(SelectionInFlatTree::Builder() |
245 .selectAllChildren(*innerNode) | 245 .selectAllChildren(*innerNode) |
246 .build()) | 246 .build()) |
247 .isCaret(); | 247 .isCaret(); |
248 const bool notLeftClick = event.event().pointerProperties().button != | 248 const bool notLeftClick = |
249 WebPointerProperties::Button::Left; | 249 event.event().button != WebPointerProperties::Button::Left; |
250 if (!isTextBoxEmpty || notLeftClick) | 250 if (!isTextBoxEmpty || notLeftClick) |
251 isHandleVisible = event.event().fromTouch(); | 251 isHandleVisible = event.event().fromTouch(); |
252 } | 252 } |
253 | 253 |
254 updateSelectionForMouseDownDispatchingSelectStart( | 254 updateSelectionForMouseDownDispatchingSelectStart( |
255 innerNode, | 255 innerNode, |
256 expandSelectionToRespectUserSelectAll( | 256 expandSelectionToRespectUserSelectAll( |
257 innerNode, createVisibleSelection( | 257 innerNode, createVisibleSelection( |
258 SelectionInFlatTree::Builder() | 258 SelectionInFlatTree::Builder() |
259 .collapse(visiblePos.toPositionWithAffinity()) | 259 .collapse(visiblePos.toPositionWithAffinity()) |
(...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
531 innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), | 531 innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), |
532 WordGranularity, HandleVisibility::NotVisible); | 532 WordGranularity, HandleVisibility::NotVisible); |
533 } | 533 } |
534 | 534 |
535 void SelectionController::selectClosestWordFromMouseEvent( | 535 void SelectionController::selectClosestWordFromMouseEvent( |
536 const MouseEventWithHitTestResults& result) { | 536 const MouseEventWithHitTestResults& result) { |
537 if (!m_mouseDownMayStartSelect) | 537 if (!m_mouseDownMayStartSelect) |
538 return; | 538 return; |
539 | 539 |
540 AppendTrailingWhitespace appendTrailingWhitespace = | 540 AppendTrailingWhitespace appendTrailingWhitespace = |
541 (result.event().clickCount() == 2 && | 541 (result.event().clickCount == 2 && |
542 m_frame->editor().isSelectTrailingWhitespaceEnabled()) | 542 m_frame->editor().isSelectTrailingWhitespaceEnabled()) |
543 ? AppendTrailingWhitespace::ShouldAppend | 543 ? AppendTrailingWhitespace::ShouldAppend |
544 : AppendTrailingWhitespace::DontAppend; | 544 : AppendTrailingWhitespace::DontAppend; |
545 | 545 |
546 DCHECK(!m_frame->document()->needsLayoutTreeUpdate()); | 546 DCHECK(!m_frame->document()->needsLayoutTreeUpdate()); |
547 | 547 |
548 selectClosestWordFromHitTestResult( | 548 selectClosestWordFromHitTestResult( |
549 result.hitTestResult(), appendTrailingWhitespace, | 549 result.hitTestResult(), appendTrailingWhitespace, |
550 result.event().fromTouch() ? SelectInputEventType::Touch | 550 result.event().fromTouch() ? SelectInputEventType::Touch |
551 : SelectInputEventType::Mouse); | 551 : SelectInputEventType::Mouse); |
552 } | 552 } |
553 | 553 |
554 void SelectionController::selectClosestMisspellingFromMouseEvent( | 554 void SelectionController::selectClosestMisspellingFromMouseEvent( |
555 const MouseEventWithHitTestResults& result) { | 555 const MouseEventWithHitTestResults& result) { |
556 if (!m_mouseDownMayStartSelect) | 556 if (!m_mouseDownMayStartSelect) |
557 return; | 557 return; |
558 | 558 |
559 selectClosestMisspellingFromHitTestResult( | 559 selectClosestMisspellingFromHitTestResult( |
560 result.hitTestResult(), | 560 result.hitTestResult(), |
561 (result.event().clickCount() == 2 && | 561 (result.event().clickCount == 2 && |
562 m_frame->editor().isSelectTrailingWhitespaceEnabled()) | 562 m_frame->editor().isSelectTrailingWhitespaceEnabled()) |
563 ? AppendTrailingWhitespace::ShouldAppend | 563 ? AppendTrailingWhitespace::ShouldAppend |
564 : AppendTrailingWhitespace::DontAppend); | 564 : AppendTrailingWhitespace::DontAppend); |
565 } | 565 } |
566 | 566 |
567 void SelectionController::selectClosestWordOrLinkFromMouseEvent( | 567 void SelectionController::selectClosestWordOrLinkFromMouseEvent( |
568 const MouseEventWithHitTestResults& result) { | 568 const MouseEventWithHitTestResults& result) { |
569 if (!result.hitTestResult().isLiveLink()) | 569 if (!result.hitTestResult().isLiveLink()) |
570 return selectClosestWordFromMouseEvent(result); | 570 return selectClosestWordFromMouseEvent(result); |
571 | 571 |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
726 const MouseEventWithHitTestResults& event) { | 726 const MouseEventWithHitTestResults& event) { |
727 TRACE_EVENT0("blink", | 727 TRACE_EVENT0("blink", |
728 "SelectionController::handleMousePressEventDoubleClick"); | 728 "SelectionController::handleMousePressEventDoubleClick"); |
729 | 729 |
730 if (!selection().isAvailable()) | 730 if (!selection().isAvailable()) |
731 return false; | 731 return false; |
732 | 732 |
733 if (!m_mouseDownAllowsMultiClick) | 733 if (!m_mouseDownAllowsMultiClick) |
734 return handleMousePressEventSingleClick(event); | 734 return handleMousePressEventSingleClick(event); |
735 | 735 |
736 if (event.event().pointerProperties().button != | 736 if (event.event().button != WebPointerProperties::Button::Left) |
737 WebPointerProperties::Button::Left) | |
738 return false; | 737 return false; |
739 | 738 |
740 if (selection().isRange()) { | 739 if (selection().isRange()) { |
741 // A double-click when range is already selected | 740 // A double-click when range is already selected |
742 // should not change the selection. So, do not call | 741 // should not change the selection. So, do not call |
743 // selectClosestWordFromMouseEvent, but do set | 742 // selectClosestWordFromMouseEvent, but do set |
744 // m_beganSelectingText to prevent handleMouseReleaseEvent | 743 // m_beganSelectingText to prevent handleMouseReleaseEvent |
745 // from setting caret selection. | 744 // from setting caret selection. |
746 m_selectionState = SelectionState::ExtendedSelection; | 745 m_selectionState = SelectionState::ExtendedSelection; |
747 } else { | 746 } else { |
748 selectClosestWordFromMouseEvent(event); | 747 selectClosestWordFromMouseEvent(event); |
749 } | 748 } |
750 return true; | 749 return true; |
751 } | 750 } |
752 | 751 |
753 bool SelectionController::handleMousePressEventTripleClick( | 752 bool SelectionController::handleMousePressEventTripleClick( |
754 const MouseEventWithHitTestResults& event) { | 753 const MouseEventWithHitTestResults& event) { |
755 TRACE_EVENT0("blink", | 754 TRACE_EVENT0("blink", |
756 "SelectionController::handleMousePressEventTripleClick"); | 755 "SelectionController::handleMousePressEventTripleClick"); |
757 | 756 |
758 if (!selection().isAvailable()) { | 757 if (!selection().isAvailable()) { |
759 // editing/shadow/doubleclick-on-meter-in-shadow-crash.html reach here. | 758 // editing/shadow/doubleclick-on-meter-in-shadow-crash.html reach here. |
760 return false; | 759 return false; |
761 } | 760 } |
762 | 761 |
763 if (!m_mouseDownAllowsMultiClick) | 762 if (!m_mouseDownAllowsMultiClick) |
764 return handleMousePressEventSingleClick(event); | 763 return handleMousePressEventSingleClick(event); |
765 | 764 |
766 if (event.event().pointerProperties().button != | 765 if (event.event().button != WebPointerProperties::Button::Left) |
767 WebPointerProperties::Button::Left) | |
768 return false; | 766 return false; |
769 | 767 |
770 Node* innerNode = event.innerNode(); | 768 Node* innerNode = event.innerNode(); |
771 if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect)) | 769 if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect)) |
772 return false; | 770 return false; |
773 | 771 |
774 VisibleSelectionInFlatTree newSelection; | 772 VisibleSelectionInFlatTree newSelection; |
775 const VisiblePositionInFlatTree& pos = | 773 const VisiblePositionInFlatTree& pos = |
776 visiblePositionOfHitTestResult(event.hitTestResult()); | 774 visiblePositionOfHitTestResult(event.hitTestResult()); |
777 if (pos.isNotNull()) { | 775 if (pos.isNotNull()) { |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
858 return false; | 856 return false; |
859 | 857 |
860 bool handled = false; | 858 bool handled = false; |
861 m_mouseDownMayStartSelect = false; | 859 m_mouseDownMayStartSelect = false; |
862 // Clear the selection if the mouse didn't move after the last mouse | 860 // Clear the selection if the mouse didn't move after the last mouse |
863 // press and it's not a context menu click. We do this so when clicking | 861 // press and it's not a context menu click. We do this so when clicking |
864 // on the selection, the selection goes away. However, if we are | 862 // on the selection, the selection goes away. However, if we are |
865 // editing, place the caret. | 863 // editing, place the caret. |
866 if (m_mouseDownWasSingleClickInSelection && | 864 if (m_mouseDownWasSingleClickInSelection && |
867 m_selectionState != SelectionState::ExtendedSelection && | 865 m_selectionState != SelectionState::ExtendedSelection && |
868 dragStartPos == event.event().position() && selection().isRange() && | 866 dragStartPos == flooredIntPoint(event.event().positionInRootFrame()) && |
869 event.event().pointerProperties().button != | 867 selection().isRange() && |
870 WebPointerProperties::Button::Right) { | 868 event.event().button != WebPointerProperties::Button::Right) { |
871 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets | 869 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets |
872 // needs to be audited. See http://crbug.com/590369 for more details. | 870 // needs to be audited. See http://crbug.com/590369 for more details. |
873 m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets(); | 871 m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets(); |
874 | 872 |
875 SelectionInFlatTree::Builder builder; | 873 SelectionInFlatTree::Builder builder; |
876 Node* node = event.innerNode(); | 874 Node* node = event.innerNode(); |
877 if (node && node->layoutObject() && hasEditableStyle(*node)) { | 875 if (node && node->layoutObject() && hasEditableStyle(*node)) { |
878 const VisiblePositionInFlatTree pos = | 876 const VisiblePositionInFlatTree pos = |
879 visiblePositionOfHitTestResult(event.hitTestResult()); | 877 visiblePositionOfHitTestResult(event.hitTestResult()); |
880 if (pos.isNotNull()) | 878 if (pos.isNotNull()) |
881 builder.collapse(pos.toPositionWithAffinity()); | 879 builder.collapse(pos.toPositionWithAffinity()); |
882 } | 880 } |
883 | 881 |
884 if (selection().visibleSelection<EditingInFlatTreeStrategy>() != | 882 if (selection().visibleSelection<EditingInFlatTreeStrategy>() != |
885 createVisibleSelection(builder.build())) { | 883 createVisibleSelection(builder.build())) { |
886 selection().setSelection(builder.build()); | 884 selection().setSelection(builder.build()); |
887 } | 885 } |
888 | 886 |
889 handled = true; | 887 handled = true; |
890 } | 888 } |
891 | 889 |
892 selection().notifyLayoutObjectOfSelectionChange(UserTriggered); | 890 selection().notifyLayoutObjectOfSelectionChange(UserTriggered); |
893 | 891 |
894 selection().selectFrameElementInParentIfFullySelected(); | 892 selection().selectFrameElementInParentIfFullySelected(); |
895 | 893 |
896 if (event.event().pointerProperties().button == | 894 if (event.event().button == WebPointerProperties::Button::Middle && |
897 WebPointerProperties::Button::Middle && | |
898 !event.isOverLink()) { | 895 !event.isOverLink()) { |
899 // Ignore handled, since we want to paste to where the caret was placed | 896 // Ignore handled, since we want to paste to where the caret was placed |
900 // anyway. | 897 // anyway. |
901 handled = handlePasteGlobalSelection(event.event()) || handled; | 898 handled = handlePasteGlobalSelection(event.event()) || handled; |
902 } | 899 } |
903 | 900 |
904 return handled; | 901 return handled; |
905 } | 902 } |
906 | 903 |
907 bool SelectionController::handlePasteGlobalSelection( | 904 bool SelectionController::handlePasteGlobalSelection( |
908 const PlatformMouseEvent& mouseEvent) { | 905 const WebMouseEvent& mouseEvent) { |
909 // If the event was a middle click, attempt to copy global selection in after | 906 // If the event was a middle click, attempt to copy global selection in after |
910 // the newly set caret position. | 907 // the newly set caret position. |
911 // | 908 // |
912 // This code is called from either the mouse up or mouse down handling. There | 909 // This code is called from either the mouse up or mouse down handling. There |
913 // is some debate about when the global selection is pasted: | 910 // is some debate about when the global selection is pasted: |
914 // xterm: pastes on up. | 911 // xterm: pastes on up. |
915 // GTK: pastes on down. | 912 // GTK: pastes on down. |
916 // Qt: pastes on up. | 913 // Qt: pastes on up. |
917 // Firefox: pastes on up. | 914 // Firefox: pastes on up. |
918 // Chromium: pastes on up. | 915 // Chromium: pastes on up. |
919 // | 916 // |
920 // There is something of a webcompat angle to this well, as highlighted by | 917 // There is something of a webcompat angle to this well, as highlighted by |
921 // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on | 918 // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on |
922 // down then the text is pasted just before the onclick handler runs and | 919 // down then the text is pasted just before the onclick handler runs and |
923 // clears the text box. So it's important this happens after the event | 920 // clears the text box. So it's important this happens after the event |
924 // handlers have been fired. | 921 // handlers have been fired. |
925 if (mouseEvent.type() != PlatformEvent::MouseReleased) | 922 if (mouseEvent.type() != WebInputEvent::MouseUp) |
926 return false; | 923 return false; |
927 | 924 |
928 if (!m_frame->page()) | 925 if (!m_frame->page()) |
929 return false; | 926 return false; |
930 Frame* focusFrame = m_frame->page()->focusController().focusedOrMainFrame(); | 927 Frame* focusFrame = m_frame->page()->focusController().focusedOrMainFrame(); |
931 // Do not paste here if the focus was moved somewhere else. | 928 // Do not paste here if the focus was moved somewhere else. |
932 if (m_frame == focusFrame && | 929 if (m_frame == focusFrame && |
933 m_frame->editor().behavior().supportsGlobalSelection()) | 930 m_frame->editor().behavior().supportsGlobalSelection()) |
934 return m_frame->editor().createCommand("PasteGlobalSelection").execute(); | 931 return m_frame->editor().createCommand("PasteGlobalSelection").execute(); |
935 | 932 |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1015 | 1012 |
1016 selectClosestWordOrLinkFromMouseEvent(mev); | 1013 selectClosestWordOrLinkFromMouseEvent(mev); |
1017 } | 1014 } |
1018 | 1015 |
1019 void SelectionController::passMousePressEventToSubframe( | 1016 void SelectionController::passMousePressEventToSubframe( |
1020 const MouseEventWithHitTestResults& mev) { | 1017 const MouseEventWithHitTestResults& mev) { |
1021 // If we're clicking into a frame that is selected, the frame will appear | 1018 // If we're clicking into a frame that is selected, the frame will appear |
1022 // greyed out even though we're clicking on the selection. This looks | 1019 // greyed out even though we're clicking on the selection. This looks |
1023 // really strange (having the whole frame be greyed out), so we deselect the | 1020 // really strange (having the whole frame be greyed out), so we deselect the |
1024 // selection. | 1021 // selection. |
1025 IntPoint p = m_frame->view()->rootFrameToContents(mev.event().position()); | 1022 IntPoint p = m_frame->view()->rootFrameToContents( |
| 1023 flooredIntPoint(mev.event().positionInRootFrame())); |
1026 if (!selection().contains(p)) | 1024 if (!selection().contains(p)) |
1027 return; | 1025 return; |
1028 | 1026 |
1029 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets | 1027 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets |
1030 // needs to be audited. See http://crbug.com/590369 for more details. | 1028 // needs to be audited. See http://crbug.com/590369 for more details. |
1031 m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets(); | 1029 m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets(); |
1032 | 1030 |
1033 const VisiblePositionInFlatTree& visiblePos = | 1031 const VisiblePositionInFlatTree& visiblePos = |
1034 visiblePositionOfHitTestResult(mev.hitTestResult()); | 1032 visiblePositionOfHitTestResult(mev.hitTestResult()); |
1035 if (visiblePos.isNull()) { | 1033 if (visiblePos.isNull()) { |
(...skipping 28 matching lines...) Expand all Loading... |
1064 m_selectionState = SelectionState::PlacedCaret; | 1062 m_selectionState = SelectionState::PlacedCaret; |
1065 else | 1063 else |
1066 m_selectionState = SelectionState::HaveNotStartedSelection; | 1064 m_selectionState = SelectionState::HaveNotStartedSelection; |
1067 } | 1065 } |
1068 | 1066 |
1069 FrameSelection& SelectionController::selection() const { | 1067 FrameSelection& SelectionController::selection() const { |
1070 return m_frame->selection(); | 1068 return m_frame->selection(); |
1071 } | 1069 } |
1072 | 1070 |
1073 bool isLinkSelection(const MouseEventWithHitTestResults& event) { | 1071 bool isLinkSelection(const MouseEventWithHitTestResults& event) { |
1074 return event.event().altKey() && event.isOverLink(); | 1072 return (event.event().modifiers() & WebInputEvent::Modifiers::AltKey) != 0 && |
| 1073 event.isOverLink(); |
1075 } | 1074 } |
1076 | 1075 |
1077 bool isExtendingSelection(const MouseEventWithHitTestResults& event) { | 1076 bool isExtendingSelection(const MouseEventWithHitTestResults& event) { |
1078 bool isMouseDownOnLinkOrImage = | 1077 bool isMouseDownOnLinkOrImage = |
1079 event.isOverLink() || event.hitTestResult().image(); | 1078 event.isOverLink() || event.hitTestResult().image(); |
1080 return event.event().shiftKey() && !isMouseDownOnLinkOrImage; | 1079 return (event.event().modifiers() & WebInputEvent::Modifiers::ShiftKey) != |
| 1080 0 && |
| 1081 !isMouseDownOnLinkOrImage; |
1081 } | 1082 } |
1082 | 1083 |
1083 } // namespace blink | 1084 } // namespace blink |
OLD | NEW |