Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(251)

Side by Side Diff: third_party/WebKit/Source/core/editing/SelectionController.cpp

Issue 2201853002: Blink handle selection handle visibility (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fixed contextual search test function Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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 // Don't restart the selection when the mouse is pressed on an
141 // existing selection so we can allow for text dragging.
142 if (FrameView* view = m_frame->view()) {
143 LayoutPoint vPoint = view->rootFrameToContents(event.event().position());
144 if (!extendSelection && selection().contains(vPoint)) {
145 m_mouseDownWasSingleClickInSelection = true;
146 return false;
147 }
148 }
149
150 VisiblePositionInFlatTree visiblePos = 140 VisiblePositionInFlatTree visiblePos =
151 visiblePositionOfHitTestResult(event.hitTestResult()); 141 visiblePositionOfHitTestResult(event.hitTestResult());
152 if (visiblePos.isNull()) 142 if (visiblePos.isNull())
153 visiblePos = createVisiblePosition( 143 visiblePos = createVisiblePosition(
154 PositionInFlatTree::firstPositionInOrBeforeNode(innerNode)); 144 PositionInFlatTree::firstPositionInOrBeforeNode(innerNode));
155 PositionInFlatTree pos = visiblePos.deepEquivalent(); 145 PositionInFlatTree pos = visiblePos.deepEquivalent();
156 146
157 VisibleSelectionInFlatTree newSelection = 147 VisibleSelectionInFlatTree newSelection =
158 selection().visibleSelection<EditingInFlatTreeStrategy>(); 148 selection().visibleSelection<EditingInFlatTreeStrategy>();
159 TextGranularity granularity = CharacterGranularity; 149 TextGranularity granularity = CharacterGranularity;
160 150
151 // Don't restart the selection when the mouse is pressed on an
152 // existing selection so we can allow for text dragging.
153 if (!extendSelection && selection().contains(event.hitTestResult())) {
154 m_mouseDownWasSingleClickInSelection = true;
155 if (!event.event().fromTouch())
156 return false;
157
158 if (!selection().isHandleVisible()) {
159 updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection,
160 granularity, true);
161 return false;
162 }
163 }
164
161 if (extendSelection && !newSelection.isNone()) { 165 if (extendSelection && !newSelection.isNone()) {
162 const VisibleSelectionInFlatTree selectionInUserSelectAll( 166 const VisibleSelectionInFlatTree selectionInUserSelectAll(
163 expandSelectionToRespectUserSelectAll(innerNode, 167 expandSelectionToRespectUserSelectAll(innerNode,
164 createVisibleSelection(pos))); 168 createVisibleSelection(pos)));
165 if (selectionInUserSelectAll.isRange()) { 169 if (selectionInUserSelectAll.isRange()) {
166 if (selectionInUserSelectAll.start().compareTo(newSelection.start()) < 0) 170 if (selectionInUserSelectAll.start().compareTo(newSelection.start()) < 0)
167 pos = selectionInUserSelectAll.start(); 171 pos = selectionInUserSelectAll.start();
168 else if (newSelection.end().compareTo(selectionInUserSelectAll.end()) < 0) 172 else if (newSelection.end().compareTo(selectionInUserSelectAll.end()) < 0)
169 pos = selectionInUserSelectAll.end(); 173 pos = selectionInUserSelectAll.end();
170 } 174 }
(...skipping 17 matching lines...) Expand all
188 192
189 if (selection().granularity() != CharacterGranularity) { 193 if (selection().granularity() != CharacterGranularity) {
190 granularity = selection().granularity(); 194 granularity = selection().granularity();
191 newSelection.expandUsingGranularity(selection().granularity()); 195 newSelection.expandUsingGranularity(selection().granularity());
192 } 196 }
193 } else if (m_selectionState != SelectionState::ExtendedSelection) { 197 } else if (m_selectionState != SelectionState::ExtendedSelection) {
194 newSelection = expandSelectionToRespectUserSelectAll( 198 newSelection = expandSelectionToRespectUserSelectAll(
195 innerNode, createVisibleSelection(visiblePos)); 199 innerNode, createVisibleSelection(visiblePos));
196 } 200 }
197 201
202 bool isHandleVisible = false;
203 if (newSelection.isContentEditable()) {
204 bool isTextBoxEmpty =
205 VisibleSelection::selectionFromContentsOfNode(innerNode).isCaret();
206 bool notLeftClick = event.event().pointerProperties().button !=
207 WebPointerProperties::Button::Left;
208 if (!isTextBoxEmpty || notLeftClick)
209 isHandleVisible = event.event().fromTouch();
210 }
211
198 // Updating the selection is considered side-effect of the event and so it 212 // Updating the selection is considered side-effect of the event and so it
199 // doesn't impact the handled state. 213 // doesn't impact the handled state.
200 updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, 214 updateSelectionForMouseDownDispatchingSelectStart(
201 granularity); 215 innerNode, newSelection, granularity, isHandleVisible);
202 return false; 216 return false;
203 } 217 }
204 218
205 void SelectionController::updateSelectionForMouseDrag( 219 void SelectionController::updateSelectionForMouseDrag(
206 const HitTestResult& hitTestResult, 220 const HitTestResult& hitTestResult,
207 Node* mousePressNode, 221 Node* mousePressNode,
208 const LayoutPoint& dragStartPos, 222 const LayoutPoint& dragStartPos,
209 const IntPoint& lastKnownMousePosition) { 223 const IntPoint& lastKnownMousePosition) {
210 if (!m_mouseDownMayStartSelect) 224 if (!m_mouseDownMayStartSelect)
211 return; 225 return;
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
319 newSelection.expandUsingGranularity(selection().granularity()); 333 newSelection.expandUsingGranularity(selection().granularity());
320 334
321 selection().setNonDirectionalSelectionIfNeeded( 335 selection().setNonDirectionalSelectionIfNeeded(
322 newSelection, selection().granularity(), 336 newSelection, selection().granularity(),
323 FrameSelection::AdjustEndpointsAtBidiBoundary); 337 FrameSelection::AdjustEndpointsAtBidiBoundary);
324 } 338 }
325 339
326 bool SelectionController::updateSelectionForMouseDownDispatchingSelectStart( 340 bool SelectionController::updateSelectionForMouseDownDispatchingSelectStart(
327 Node* targetNode, 341 Node* targetNode,
328 const VisibleSelectionInFlatTree& selection, 342 const VisibleSelectionInFlatTree& selection,
329 TextGranularity granularity) { 343 TextGranularity granularity,
344 bool isHandleVisible) {
330 if (targetNode && targetNode->layoutObject() && 345 if (targetNode && targetNode->layoutObject() &&
331 !targetNode->layoutObject()->isSelectable()) 346 !targetNode->layoutObject()->isSelectable())
332 return false; 347 return false;
333 348
334 if (dispatchSelectStart(targetNode) != DispatchEventResult::NotCanceled) 349 if (dispatchSelectStart(targetNode) != DispatchEventResult::NotCanceled)
335 return false; 350 return false;
336 351
337 // |dispatchSelectStart()| can change document hosted by |m_frame|. 352 // |dispatchSelectStart()| can change document hosted by |m_frame|.
338 if (!this->selection().isAvailable()) 353 if (!this->selection().isAvailable())
339 return false; 354 return false;
340 355
341 if (!selection.isValidFor(this->selection().document())) 356 if (!selection.isValidFor(this->selection().document()))
342 return false; 357 return false;
343 358
344 if (selection.isRange()) { 359 if (selection.isRange()) {
345 m_selectionState = SelectionState::ExtendedSelection; 360 m_selectionState = SelectionState::ExtendedSelection;
346 } else { 361 } else {
347 granularity = CharacterGranularity; 362 granularity = CharacterGranularity;
348 m_selectionState = SelectionState::PlacedCaret; 363 m_selectionState = SelectionState::PlacedCaret;
349 } 364 }
350 365
351 this->selection().setNonDirectionalSelectionIfNeeded(selection, granularity); 366 this->selection().setNonDirectionalSelectionIfNeeded(
367 selection, granularity, FrameSelection::DoNotAdjustEndpoints,
368 isHandleVisible);
352 369
353 return true; 370 return true;
354 } 371 }
355 372
356 void SelectionController::selectClosestWordFromHitTestResult( 373 void SelectionController::selectClosestWordFromHitTestResult(
357 const HitTestResult& result, 374 const HitTestResult& result,
358 AppendTrailingWhitespace appendTrailingWhitespace, 375 AppendTrailingWhitespace appendTrailingWhitespace,
359 SelectInputEventType selectInputEventType) { 376 SelectInputEventType selectInputEventType) {
360 Node* innerNode = result.innerNode(); 377 Node* innerNode = result.innerNode();
361 VisibleSelectionInFlatTree newSelection; 378 VisibleSelectionInFlatTree newSelection;
(...skipping 10 matching lines...) Expand all
372 adjustedHitTestResult.setNodeAndPosition(result.innerNode(), 389 adjustedHitTestResult.setNodeAndPosition(result.innerNode(),
373 LayoutPoint(0, 0)); 390 LayoutPoint(0, 0));
374 391
375 const VisiblePositionInFlatTree& pos = 392 const VisiblePositionInFlatTree& pos =
376 visiblePositionOfHitTestResult(adjustedHitTestResult); 393 visiblePositionOfHitTestResult(adjustedHitTestResult);
377 if (pos.isNotNull()) { 394 if (pos.isNotNull()) {
378 newSelection = createVisibleSelection(pos); 395 newSelection = createVisibleSelection(pos);
379 newSelection.expandUsingGranularity(WordGranularity); 396 newSelection.expandUsingGranularity(WordGranularity);
380 } 397 }
381 398
399 bool isHandleVisible = false;
382 if (selectInputEventType == SelectInputEventType::Touch) { 400 if (selectInputEventType == SelectInputEventType::Touch) {
383 // If node doesn't have text except space, tab or line break, do not 401 // If node doesn't have text except space, tab or line break, do not
384 // select that 'empty' area. 402 // select that 'empty' area.
385 EphemeralRangeInFlatTree range(newSelection.start(), newSelection.end()); 403 EphemeralRangeInFlatTree range(newSelection.start(), newSelection.end());
386 const String& str = 404 const String& str =
387 plainText(range, hasEditableStyle(*innerNode) 405 plainText(range, hasEditableStyle(*innerNode)
388 ? TextIteratorEmitsObjectReplacementCharacter 406 ? TextIteratorEmitsObjectReplacementCharacter
389 : TextIteratorDefaultBehavior); 407 : TextIteratorDefaultBehavior);
390 if (str.isEmpty() || str.simplifyWhiteSpace().containsOnlyWhitespace()) 408 if (str.isEmpty() || str.simplifyWhiteSpace().containsOnlyWhitespace())
391 return; 409 return;
392 410
393 if (newSelection.rootEditableElement() && 411 if (newSelection.rootEditableElement() &&
394 pos.deepEquivalent() == 412 pos.deepEquivalent() ==
395 VisiblePositionInFlatTree::lastPositionInNode( 413 VisiblePositionInFlatTree::lastPositionInNode(
396 newSelection.rootEditableElement()) 414 newSelection.rootEditableElement())
397 .deepEquivalent()) 415 .deepEquivalent())
398 return; 416 return;
417 isHandleVisible = true;
399 } 418 }
400 419
401 if (appendTrailingWhitespace == AppendTrailingWhitespace::ShouldAppend && 420 if (appendTrailingWhitespace == AppendTrailingWhitespace::ShouldAppend &&
402 newSelection.isRange()) 421 newSelection.isRange())
403 newSelection.appendTrailingWhitespace(); 422 newSelection.appendTrailingWhitespace();
404 423
405 updateSelectionForMouseDownDispatchingSelectStart( 424 updateSelectionForMouseDownDispatchingSelectStart(
406 innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), 425 innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection),
407 WordGranularity); 426 WordGranularity, isHandleVisible);
408 } 427 }
409 428
410 void SelectionController::selectClosestMisspellingFromHitTestResult( 429 void SelectionController::selectClosestMisspellingFromHitTestResult(
411 const HitTestResult& result, 430 const HitTestResult& result,
412 AppendTrailingWhitespace appendTrailingWhitespace) { 431 AppendTrailingWhitespace appendTrailingWhitespace) {
413 Node* innerNode = result.innerNode(); 432 Node* innerNode = result.innerNode();
414 VisibleSelectionInFlatTree newSelection; 433 VisibleSelectionInFlatTree newSelection;
415 434
416 if (!innerNode || !innerNode->layoutObject()) 435 if (!innerNode || !innerNode->layoutObject())
417 return; 436 return;
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
547 return false; 566 return false;
548 567
549 VisibleSelectionInFlatTree newSelection; 568 VisibleSelectionInFlatTree newSelection;
550 const VisiblePositionInFlatTree& pos = 569 const VisiblePositionInFlatTree& pos =
551 visiblePositionOfHitTestResult(event.hitTestResult()); 570 visiblePositionOfHitTestResult(event.hitTestResult());
552 if (pos.isNotNull()) { 571 if (pos.isNotNull()) {
553 newSelection = createVisibleSelection(pos); 572 newSelection = createVisibleSelection(pos);
554 newSelection.expandUsingGranularity(ParagraphGranularity); 573 newSelection.expandUsingGranularity(ParagraphGranularity);
555 } 574 }
556 575
576 bool isHandleVisible = event.event().fromTouch() && newSelection.isRange();
577
557 return updateSelectionForMouseDownDispatchingSelectStart( 578 return updateSelectionForMouseDownDispatchingSelectStart(
558 innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), 579 innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection),
559 ParagraphGranularity); 580 ParagraphGranularity, isHandleVisible);
560 } 581 }
561 582
562 void SelectionController::handleMousePressEvent( 583 void SelectionController::handleMousePressEvent(
563 const MouseEventWithHitTestResults& event) { 584 const MouseEventWithHitTestResults& event) {
564 // If we got the event back, that must mean it wasn't prevented, 585 // 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. 586 // so it's allowed to start a drag or selection if it wasn't in a scrollbar.
566 m_mouseDownMayStartSelect = 587 m_mouseDownMayStartSelect =
567 (canMouseDownStartSelect(event.innerNode()) || isLinkSelection(event)) && 588 (canMouseDownStartSelect(event.innerNode()) || isLinkSelection(event)) &&
568 !event.scrollbar(); 589 !event.scrollbar();
569 m_mouseDownWasSingleClickInSelection = false; 590 m_mouseDownWasSingleClickInSelection = false;
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
743 pos.deepEquivalent().parentAnchoredEquivalent()), 764 pos.deepEquivalent().parentAnchoredEquivalent()),
744 DocumentMarker::MisspellingMarkers()) 765 DocumentMarker::MisspellingMarkers())
745 .size() > 0; 766 .size() > 0;
746 } 767 }
747 768
748 void SelectionController::sendContextMenuEvent( 769 void SelectionController::sendContextMenuEvent(
749 const MouseEventWithHitTestResults& mev, 770 const MouseEventWithHitTestResults& mev,
750 const LayoutPoint& position) { 771 const LayoutPoint& position) {
751 if (!selection().isAvailable()) 772 if (!selection().isAvailable())
752 return; 773 return;
753 if (selection().contains(position) || mev.scrollbar() || 774 if (selection().contains(mev.hitTestResult()) || mev.scrollbar() ||
754 // FIXME: In the editable case, word selection sometimes selects content 775 // FIXME: In the editable case, word selection sometimes selects content
755 // that isn't underneath the mouse. 776 // that isn't underneath the mouse.
756 // If the selection is non-editable, we do word selection to make it 777 // If the selection is non-editable, we do word selection to make it
757 // easier to use the contextual menu items available for text selections. 778 // easier to use the contextual menu items available for text selections.
758 // But only if we're above text. 779 // But only if we're above text.
759 !(selection().isContentEditable() || 780 !(selection().isContentEditable() ||
760 (mev.innerNode() && mev.innerNode()->isTextNode()))) 781 (mev.innerNode() && mev.innerNode()->isTextNode())))
761 return; 782 return;
762 783
763 // Context menu events are always allowed to perform a selection. 784 // Context menu events are always allowed to perform a selection.
764 AutoReset<bool> mouseDownMayStartSelectChange(&m_mouseDownMayStartSelect, 785 AutoReset<bool> mouseDownMayStartSelectChange(&m_mouseDownMayStartSelect,
765 true); 786 true);
766 787
767 if (hitTestResultIsMisspelled(mev.hitTestResult())) 788 if (hitTestResultIsMisspelled(mev.hitTestResult()))
768 return selectClosestMisspellingFromMouseEvent(mev); 789 return selectClosestMisspellingFromMouseEvent(mev);
769 790
770 if (!m_frame->editor().behavior().shouldSelectOnContextualMenuClick()) 791 if (!m_frame->editor().behavior().shouldSelectOnContextualMenuClick())
771 return; 792 return;
772 793
773 selectClosestWordOrLinkFromMouseEvent(mev); 794 selectClosestWordOrLinkFromMouseEvent(mev);
774 } 795 }
775 796
776 void SelectionController::passMousePressEventToSubframe( 797 void SelectionController::passMousePressEventToSubframe(
777 const MouseEventWithHitTestResults& mev) { 798 const MouseEventWithHitTestResults& mev) {
778 // If we're clicking into a frame that is selected, the frame will appear 799 // If we're clicking into a frame that is selected, the frame will appear
779 // greyed out even though we're clicking on the selection. This looks 800 // greyed out even though we're clicking on the selection. This looks
780 // really strange (having the whole frame be greyed out), so we deselect the 801 // really strange (having the whole frame be greyed out), so we deselect the
781 // selection. 802 // selection.
782 IntPoint p = m_frame->view()->rootFrameToContents(mev.event().position()); 803 if (!selection().contains(mev.hitTestResult()))
783 if (!selection().contains(p))
784 return; 804 return;
785 805
786 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets 806 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
787 // needs to be audited. See http://crbug.com/590369 for more details. 807 // needs to be audited. See http://crbug.com/590369 for more details.
788 m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets(); 808 m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets();
789 809
790 const VisiblePositionInFlatTree& visiblePos = 810 const VisiblePositionInFlatTree& visiblePos =
791 visiblePositionOfHitTestResult(mev.hitTestResult()); 811 visiblePositionOfHitTestResult(mev.hitTestResult());
792 VisibleSelectionInFlatTree newSelection = createVisibleSelection(visiblePos); 812 VisibleSelectionInFlatTree newSelection = createVisibleSelection(visiblePos);
793 selection().setSelection(newSelection); 813 selection().setSelection(newSelection);
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
826 return event.event().altKey() && event.isOverLink(); 846 return event.event().altKey() && event.isOverLink();
827 } 847 }
828 848
829 bool isExtendingSelection(const MouseEventWithHitTestResults& event) { 849 bool isExtendingSelection(const MouseEventWithHitTestResults& event) {
830 bool isMouseDownOnLinkOrImage = 850 bool isMouseDownOnLinkOrImage =
831 event.isOverLink() || event.hitTestResult().image(); 851 event.isOverLink() || event.hitTestResult().image();
832 return event.event().shiftKey() && !isMouseDownOnLinkOrImage; 852 return event.event().shiftKey() && !isMouseDownOnLinkOrImage;
833 } 853 }
834 854
835 } // namespace blink 855 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698