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

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

Issue 2841093002: Algorithm for deciding if a frame's selection should be hidden (Closed)
Patch Set: Rebase + cosmetic changes Created 3 years, 7 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) 2004, 2008, 2009, 2010 Apple Inc. All rights reserved. 2 * Copyright (C) 2004, 2008, 2009, 2010 Apple Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 1. Redistributions of source code must retain the above copyright 7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright 9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 // "FocusIn", |m_frame| may associate to another document. 243 // "FocusIn", |m_frame| may associate to another document.
244 if (!IsAvailable() || GetDocument() != current_document) { 244 if (!IsAvailable() || GetDocument() != current_document) {
245 // Once we get test case to reach here, we should change this 245 // Once we get test case to reach here, we should change this
246 // if-statement to |DCHECK()|. 246 // if-statement to |DCHECK()|.
247 NOTREACHED(); 247 NOTREACHED();
248 return; 248 return;
249 } 249 }
250 } 250 }
251 251
252 frame_caret_->StopCaretBlinkTimer(); 252 frame_caret_->StopCaretBlinkTimer();
253 UpdateAppearance(LayoutSelection::PaintHint::kPaint); 253 UpdateAppearance();
254 254
255 // Always clear the x position used for vertical arrow navigation. 255 // Always clear the x position used for vertical arrow navigation.
256 // It will be restored by the vertical arrow navigation code if necessary. 256 // It will be restored by the vertical arrow navigation code if necessary.
257 x_pos_for_vertical_arrow_navigation_ = NoXPosForVerticalArrowNavigation(); 257 x_pos_for_vertical_arrow_navigation_ = NoXPosForVerticalArrowNavigation();
258 258
259 // TODO(yosin): Can we move this to at end of this function? 259 // TODO(yosin): Can we move this to at end of this function?
260 // This may dispatch a synchronous focus-related events. 260 // This may dispatch a synchronous focus-related events.
261 if (!(options & kDoNotSetFocus)) { 261 if (!(options & kDoNotSetFocus)) {
262 SelectFrameElementInParentIfFullySelected(); 262 SelectFrameElementInParentIfFullySelected();
263 if (!IsAvailable() || GetDocument() != current_document) { 263 if (!IsAvailable() || GetDocument() != current_document) {
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
328 // TODO(yosin): We should move to call |TypingCommand::closeTyping()| to 328 // TODO(yosin): We should move to call |TypingCommand::closeTyping()| to
329 // |Editor| class. 329 // |Editor| class.
330 if (!GetDocument().IsRunningExecCommand()) 330 if (!GetDocument().IsRunningExecCommand())
331 TypingCommand::CloseTyping(frame_); 331 TypingCommand::CloseTyping(frame_);
332 } 332 }
333 333
334 void FrameSelection::DidChangeFocus() { 334 void FrameSelection::DidChangeFocus() {
335 // Hits in 335 // Hits in
336 // virtual/gpu/compositedscrolling/scrollbars/scrollbar-miss-mousemove-disable d.html 336 // virtual/gpu/compositedscrolling/scrollbars/scrollbar-miss-mousemove-disable d.html
337 DisableCompositingQueryAsserts disabler; 337 DisableCompositingQueryAsserts disabler;
338 338 UpdateAppearance();
339 // No focused element means document root has focus.
340 const Element* const focus = GetDocument().FocusedElement()
341 ? GetDocument().FocusedElement()
342 : GetDocument().documentElement();
343
344 // Protection against LayoutTests/editing/selection/selection-crash.html
345 if (!focus) {
346 frame_caret_->ScheduleVisualUpdateForPaintInvalidationIfNeeded();
347 text_control_focused_ = false;
348 return;
349 }
350
351 // Hide the selection when focus goes away from a text-field and into
352 // something that is not a text-field. When focus enters another text-field we
353 // do not need to update appearance; the appearance is updated when the new
354 // selection is set.
355 if (text_control_focused_ && !focus->IsTextControl())
356 UpdateAppearance(LayoutSelection::PaintHint::kHide);
357 text_control_focused_ = focus->IsTextControl();
358 } 339 }
359 340
360 static DispatchEventResult DispatchSelectStart( 341 static DispatchEventResult DispatchSelectStart(
361 const VisibleSelection& selection) { 342 const VisibleSelection& selection) {
362 Node* select_start_target = selection.Extent().ComputeContainerNode(); 343 Node* select_start_target = selection.Extent().ComputeContainerNode();
363 if (!select_start_target) 344 if (!select_start_target)
364 return DispatchEventResult::kNotCanceled; 345 return DispatchEventResult::kNotCanceled;
365 346
366 return select_start_target->DispatchEvent( 347 return select_start_target->DispatchEvent(
367 Event::CreateCancelableBubble(EventTypeNames::selectstart)); 348 Event::CreateCancelableBubble(EventTypeNames::selectstart));
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
437 return true; 418 return true;
438 } 419 }
439 420
440 void FrameSelection::Clear() { 421 void FrameSelection::Clear() {
441 granularity_ = kCharacterGranularity; 422 granularity_ = kCharacterGranularity;
442 if (granularity_strategy_) 423 if (granularity_strategy_)
443 granularity_strategy_->Clear(); 424 granularity_strategy_->Clear();
444 SetSelection(SelectionInDOMTree()); 425 SetSelection(SelectionInDOMTree());
445 } 426 }
446 427
428 bool FrameSelection::IsActive() const {
429 const Node* start = ComputeVisibleSelectionInDOMTreeDeprecated()
430 .Start()
431 .ComputeContainerNode();
432 if (!start)
433 return false;
434
435 // No focused element means document root has focus.
436 const Element* const focus_element = GetDocument().FocusedElement()
Xiaocheng 2017/05/02 20:05:16 nit: s/focus_element/focused_element/g
hugoh_UTC2 2017/05/03 07:18:55 OK, I will change this.
437 ? GetDocument().FocusedElement()
438 : GetDocument().documentElement();
439 if (!focus_element)
440 return false;
Xiaocheng 2017/05/02 20:05:17 Does LayoutTests/editing/selection/selection-crash
hugoh_UTC2 2017/05/03 07:18:55 selection-crash.html doesn't crash right now but s
441
442 if (focus_element->IsTextControl())
443 return focus_element->ContainsIncludingHostElements(*start);
444
445 bool has_editable_style = HasEditableStyle(*start);
446 const Node* current = start;
447 do {
Xiaocheng 2017/05/02 20:05:16 nit: A |for| loop seems to have better readability
hugoh_UTC2 2017/05/03 07:18:55 Not sure I agree :) A for-loop would check |curren
Xiaocheng 2017/05/03 15:03:01 Compared to the loop body, an extra nullptr check
448 if (has_editable_style && !HasEditableStyle(*current)) {
Xiaocheng 2017/05/02 20:05:16 I can't understand this loop body. There seem to b
hugoh_UTC2 2017/05/03 07:18:55 Yes, we have many cases to think of. This logic is
hugoh_UTC2 2017/05/03 20:31:00 I realized that EnclosingTextControl() and the che
449 // We exited an editable sub tree.
450 // Only range selections can be active in this case.
451 if (!GetSelectionInDOMTree().IsRange()) {
452 // Example that triggers this:
453 // <div tabindex='-1' id='parent'>
454 // <!-- Place caret within blabla. -->
455 // <div contenteditable id='ce'>blabla</div>
456 // </div>
457 // When focusing the outer <div>, we must hide the inner <div>'s caret.
458 return false;
459 }
460
461 // So the selection is a range...
462 // Only hide the selection if its inside a text control.
463 const TextControlElement* in_text_control =
464 EnclosingTextControl(GetSelectionInDOMTree().Base());
465 if (in_text_control) {
466 // Example that triggers this:
467 // <div tabindex="-1">
468 // <input value="hola"> <!-- Select hola -->
469 // </div>
470 // When focusing the <div>, we must hide the selection [hola].
471 return false;
472 }
473 } else {
474 // Selection is active (= not hidden) if this sub tree got focus.
475 if (current == focus_element)
476 return true;
477 }
478 current = current->ParentOrShadowHostNode();
479 } while (current);
480
481 return true;
482 }
447 void FrameSelection::DocumentAttached(Document* document) { 483 void FrameSelection::DocumentAttached(Document* document) {
448 DCHECK(document); 484 DCHECK(document);
449 use_secure_keyboard_entry_when_active_ = false; 485 use_secure_keyboard_entry_when_active_ = false;
450 selection_editor_->DocumentAttached(document); 486 selection_editor_->DocumentAttached(document);
451 SetContext(document); 487 SetContext(document);
452 } 488 }
453 489
454 void FrameSelection::ContextDestroyed(Document* document) { 490 void FrameSelection::ContextDestroyed(Document* document) {
455 granularity_ = kCharacterGranularity; 491 granularity_ = kCharacterGranularity;
456 492
(...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after
789 825
790 bool FrameSelection::NeedsLayoutSelectionUpdate() const { 826 bool FrameSelection::NeedsLayoutSelectionUpdate() const {
791 return layout_selection_->HasPendingSelection(); 827 return layout_selection_->HasPendingSelection();
792 } 828 }
793 829
794 void FrameSelection::CommitAppearanceIfNeeded() { 830 void FrameSelection::CommitAppearanceIfNeeded() {
795 return layout_selection_->Commit(); 831 return layout_selection_->Commit();
796 } 832 }
797 833
798 void FrameSelection::DidLayout() { 834 void FrameSelection::DidLayout() {
799 // Upon relayout, a hidden selection must be kept hidden and a visible 835 UpdateAppearance();
800 // selection must be kept visible.
801 UpdateAppearance(LayoutSelection::PaintHint::kKeep);
802 } 836 }
803 837
804 void FrameSelection::UpdateAppearance(LayoutSelection::PaintHint hint) { 838 void FrameSelection::UpdateAppearance() {
805 DCHECK(!frame_->ContentLayoutItem().IsNull()); 839 DCHECK(!frame_->ContentLayoutItem().IsNull());
806 frame_caret_->ScheduleVisualUpdateForPaintInvalidationIfNeeded(); 840 frame_caret_->ScheduleVisualUpdateForPaintInvalidationIfNeeded();
807 layout_selection_->SetHasPendingSelection(hint); 841 layout_selection_->SetHasPendingSelection();
808 } 842 }
809 843
810 void FrameSelection::NotifyLayoutObjectOfSelectionChange( 844 void FrameSelection::NotifyLayoutObjectOfSelectionChange(
811 EUserTriggered user_triggered) { 845 EUserTriggered user_triggered) {
812 TextControlElement* text_control = 846 TextControlElement* text_control =
813 EnclosingTextControl(GetSelectionInDOMTree().Base()); 847 EnclosingTextControl(GetSelectionInDOMTree().Base());
814 if (!text_control) 848 if (!text_control)
815 return; 849 return;
816 text_control->SelectionChanged(user_triggered == kUserTriggered); 850 text_control->SelectionChanged(user_triggered == kUserTriggered);
817 } 851 }
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after
986 1020
987 Position start = ComputeVisibleSelectionInDOMTreeDeprecated().Start(); 1021 Position start = ComputeVisibleSelectionInDOMTreeDeprecated().Start();
988 DCHECK(start.AnchorNode()); 1022 DCHECK(start.AnchorNode());
989 if (start.AnchorNode() && start.AnchorNode()->GetLayoutObject()) { 1023 if (start.AnchorNode() && start.AnchorNode()->GetLayoutObject()) {
990 // FIXME: This code only handles scrolling the startContainer's layer, but 1024 // FIXME: This code only handles scrolling the startContainer's layer, but
991 // the selection rect could intersect more than just that. 1025 // the selection rect could intersect more than just that.
992 if (DocumentLoader* document_loader = frame_->Loader().GetDocumentLoader()) 1026 if (DocumentLoader* document_loader = frame_->Loader().GetDocumentLoader())
993 document_loader->GetInitialScrollState().was_scrolled_by_user = true; 1027 document_loader->GetInitialScrollState().was_scrolled_by_user = true;
994 if (start.AnchorNode()->GetLayoutObject()->ScrollRectToVisible( 1028 if (start.AnchorNode()->GetLayoutObject()->ScrollRectToVisible(
995 rect, alignment, alignment)) 1029 rect, alignment, alignment))
996 UpdateAppearance(LayoutSelection::PaintHint::kPaint); 1030 UpdateAppearance();
997 } 1031 }
998 } 1032 }
999 1033
1000 void FrameSelection::SetSelectionFromNone() { 1034 void FrameSelection::SetSelectionFromNone() {
1001 // Put a caret inside the body if the entire frame is editable (either the 1035 // Put a caret inside the body if the entire frame is editable (either the
1002 // entire WebView is editable or designMode is on for this document). 1036 // entire WebView is editable or designMode is on for this document).
1003 1037
1004 Document* document = frame_->GetDocument(); 1038 Document* document = frame_->GetDocument();
1005 if (!ComputeVisibleSelectionInDOMTreeDeprecated().IsNone() || 1039 if (!ComputeVisibleSelectionInDOMTreeDeprecated().IsNone() ||
1006 !(blink::HasEditableStyle(*document))) 1040 !(blink::HasEditableStyle(*document)))
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
1185 } 1219 }
1186 1220
1187 void showTree(const blink::FrameSelection* sel) { 1221 void showTree(const blink::FrameSelection* sel) {
1188 if (sel) 1222 if (sel)
1189 sel->ShowTreeForThis(); 1223 sel->ShowTreeForThis();
1190 else 1224 else
1191 LOG(INFO) << "Cannot showTree for <null> FrameSelection."; 1225 LOG(INFO) << "Cannot showTree for <null> FrameSelection.";
1192 } 1226 }
1193 1227
1194 #endif 1228 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698