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

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

Issue 2925363002: Add SpellChecker::GetSpellCheckMarkerTouchingSelection() (Closed)
Patch Set: Respond to comments Created 3 years, 6 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, 2011 Apple Inc. All rights reserved. 2 * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
8 * 1. Redistributions of source code must retain the above copyright 8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright 10 * 2. Redistributions in binary form must reproduce the above copyright
(...skipping 25 matching lines...) Expand all
36 #include "core/dom/Range.h" 36 #include "core/dom/Range.h"
37 #include "core/editing/EditingUtilities.h" 37 #include "core/editing/EditingUtilities.h"
38 #include "core/editing/Editor.h" 38 #include "core/editing/Editor.h"
39 #include "core/editing/EphemeralRange.h" 39 #include "core/editing/EphemeralRange.h"
40 #include "core/editing/VisibleUnits.h" 40 #include "core/editing/VisibleUnits.h"
41 #include "core/editing/commands/CompositeEditCommand.h" 41 #include "core/editing/commands/CompositeEditCommand.h"
42 #include "core/editing/commands/ReplaceSelectionCommand.h" 42 #include "core/editing/commands/ReplaceSelectionCommand.h"
43 #include "core/editing/commands/TypingCommand.h" 43 #include "core/editing/commands/TypingCommand.h"
44 #include "core/editing/iterators/CharacterIterator.h" 44 #include "core/editing/iterators/CharacterIterator.h"
45 #include "core/editing/markers/DocumentMarkerController.h" 45 #include "core/editing/markers/DocumentMarkerController.h"
46 #include "core/editing/markers/SpellCheckMarker.h"
46 #include "core/editing/spellcheck/IdleSpellCheckCallback.h" 47 #include "core/editing/spellcheck/IdleSpellCheckCallback.h"
47 #include "core/editing/spellcheck/SpellCheckRequester.h" 48 #include "core/editing/spellcheck/SpellCheckRequester.h"
48 #include "core/editing/spellcheck/SpellCheckerClient.h" 49 #include "core/editing/spellcheck/SpellCheckerClient.h"
49 #include "core/editing/spellcheck/TextCheckingParagraph.h" 50 #include "core/editing/spellcheck/TextCheckingParagraph.h"
50 #include "core/frame/LocalFrame.h" 51 #include "core/frame/LocalFrame.h"
51 #include "core/frame/Settings.h" 52 #include "core/frame/Settings.h"
52 #include "core/html/HTMLInputElement.h" 53 #include "core/html/HTMLInputElement.h"
53 #include "core/layout/LayoutTextControl.h" 54 #include "core/layout/LayoutTextControl.h"
54 #include "core/loader/EmptyClients.h" 55 #include "core/loader/EmptyClients.h"
55 #include "core/page/Page.h" 56 #include "core/page/Page.h"
(...skipping 550 matching lines...) Expand 10 before | Expand all | Expand 10 after
606 // TODO(xiaochengh): The following comment does not match the current behavior 607 // TODO(xiaochengh): The following comment does not match the current behavior
607 // and should be rewritten. 608 // and should be rewritten.
608 // Expand the range to encompass entire paragraphs, since text checking needs 609 // Expand the range to encompass entire paragraphs, since text checking needs
609 // that much context. 610 // that much context.
610 int ambiguous_boundary_offset = -1; 611 int ambiguous_boundary_offset = -1;
611 612
612 if (GetFrame().Selection().ComputeVisibleSelectionInDOMTree().IsCaret()) { 613 if (GetFrame().Selection().ComputeVisibleSelectionInDOMTree().IsCaret()) {
613 // TODO(xiaochengh): The following comment does not match the current 614 // TODO(xiaochengh): The following comment does not match the current
614 // behavior and should be rewritten. 615 // behavior and should be rewritten.
615 // Attempt to save the caret position so we can restore it later if needed 616 // Attempt to save the caret position so we can restore it later if needed
616 const Position& caret_position = 617 const Position& caret_positionition =
Xiaocheng 2017/06/09 04:17:26 Irrelevant change.
617 GetFrame().Selection().ComputeVisibleSelectionInDOMTree().End(); 618 GetFrame().Selection().ComputeVisibleSelectionInDOMTree().End();
618 const Position& paragraph_start = checking_range.StartPosition(); 619 const Position& paragraph_start = checking_range.StartPosition();
619 const int selection_offset = 620 const int selection_offset =
620 paragraph_start < caret_position 621 paragraph_start < caret_positionition
621 ? TextIterator::RangeLength(paragraph_start, caret_position) 622 ? TextIterator::RangeLength(paragraph_start, caret_positionition)
622 : 0; 623 : 0;
623 if (selection_offset > 0 && 624 if (selection_offset > 0 &&
624 static_cast<unsigned>(selection_offset) <= 625 static_cast<unsigned>(selection_offset) <=
625 paragraph.GetText().length() && 626 paragraph.GetText().length() &&
626 IsAmbiguousBoundaryCharacter( 627 IsAmbiguousBoundaryCharacter(
627 paragraph.TextCharAt(selection_offset - 1))) { 628 paragraph.TextCharAt(selection_offset - 1))) {
628 ambiguous_boundary_offset = selection_offset - 1; 629 ambiguous_boundary_offset = selection_offset - 1;
629 } 630 }
630 } 631 }
631 632
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
804 DocumentMarker::MarkerTypes marker_types(DocumentMarker::kSpelling); 805 DocumentMarker::MarkerTypes marker_types(DocumentMarker::kSpelling);
805 marker_types.Add(DocumentMarker::kGrammar); 806 marker_types.Add(DocumentMarker::kGrammar);
806 for (Node& node : NodeTraversal::InclusiveDescendantsOf(element)) { 807 for (Node& node : NodeTraversal::InclusiveDescendantsOf(element)) {
807 if (elements_type == ElementsType::kAll || !HasEditableStyle(node)) { 808 if (elements_type == ElementsType::kAll || !HasEditableStyle(node)) {
808 GetFrame().GetDocument()->Markers().RemoveMarkersForNode(&node, 809 GetFrame().GetDocument()->Markers().RemoveMarkersForNode(&node,
809 marker_types); 810 marker_types);
810 } 811 }
811 } 812 }
812 } 813 }
813 814
815 namespace {
Xiaocheng 2017/06/09 04:17:26 We already have an anonymous namespace at the begi
816
817 EphemeralRange ExpandSelectionRangeIfNecessary(
818 const VisibleSelection& selection) {
819 DCHECK(!selection.IsNone());
820
821 // If some text is actually selected, we can use the selection range as-is to
822 // check for a marker. If no text is selected (we just have a caret
823 // somewhere), we need to expand one character on either side so we can find
824 // a spelling marker immediately before or after the caret.
825
826 // (The spelling markers on these words may be anchored to a different node
827 // than the collapsed selection's Position is, but once we expand the
828 // selection, if we're next to a marker, either the start or end point should
829 // now be anchored relative to the same text node as that marker.)
830
831 // Some text is actually selected
832 if (selection.IsRange())
833 return EphemeralRange(selection.Start(), selection.End());
834
835 // No text is actually selected, need to expand the selection range
836 const VisiblePosition& caret_position = selection.VisibleStart();
yosin_UTC9 2017/06/09 03:28:15 Could you add an example, your provided in reply?
837
838 const Position& previous_position =
839 PreviousPositionOf(caret_position).DeepEquivalent();
840
841 const Position& next_position =
842 NextPositionOf(caret_position).DeepEquivalent();
843
844 return EphemeralRange(
845 previous_position.IsNull() ? caret_position.DeepEquivalent()
846 : previous_position,
847 next_position.IsNull() ? caret_position.DeepEquivalent() : next_position);
848 }
849
850 } // namespace
851
852 Optional<std::pair<Node*, SpellCheckMarker*>>
853 SpellChecker::GetSpellCheckMarkerTouchingSelection() {
854 const VisibleSelection& selection =
855 GetFrame().Selection().ComputeVisibleSelectionInDOMTree();
856 if (selection.IsNone())
857 return Optional<std::pair<Node*, SpellCheckMarker*>>();
858
859 const EphemeralRange& range_to_check =
860 ExpandSelectionRangeIfNecessary(selection);
861
862 Node* const start_container =
863 range_to_check.StartPosition().ComputeContainerNode();
864 const unsigned start_offset =
865 range_to_check.StartPosition().ComputeOffsetInContainerNode();
866 Node* const end_container =
867 range_to_check.EndPosition().ComputeContainerNode();
868 const unsigned end_offset =
869 range_to_check.EndPosition().ComputeOffsetInContainerNode();
870
871 for (Node& node : range_to_check.Nodes()) {
872 const DocumentMarkerVector& markers_in_node =
873 GetFrame().GetDocument()->Markers().MarkersFor(
874 &node, DocumentMarker::MisspellingMarkers());
875 for (DocumentMarker* marker : markers_in_node) {
876 if (node == start_container && marker->EndOffset() <= start_offset)
877 continue;
878 if (node == end_container && marker->StartOffset() >= end_offset)
879 continue;
880
881 return std::make_pair(&node, &ToSpellCheckMarker(*marker));
882 }
883 }
884
885 // No marker found
886 return Optional<std::pair<Node*, SpellCheckMarker*>>();
887 }
888
814 void SpellChecker::ReplaceMisspelledRange(const String& text) { 889 void SpellChecker::ReplaceMisspelledRange(const String& text) {
815 EphemeralRange caret_range = GetFrame() 890 const Optional<std::pair<Node*, SpellCheckMarker*>>& node_and_marker =
816 .Selection() 891 GetSpellCheckMarkerTouchingSelection();
817 .ComputeVisibleSelectionInDOMTree() 892 if (!node_and_marker)
818 .ToNormalizedEphemeralRange();
819 if (caret_range.IsNull())
820 return; 893 return;
821 894
822 Node* const caret_start_container = 895 Node* const container_node = node_and_marker.value().first;
823 caret_range.StartPosition().ComputeContainerNode(); 896 const SpellCheckMarker* const marker = node_and_marker.value().second;
824 Node* const caret_end_container =
825 caret_range.EndPosition().ComputeContainerNode();
826
827 // We don't currently support the case where a misspelling spans multiple
828 // nodes
829 if (caret_start_container != caret_end_container)
830 return;
831
832 const unsigned caret_start_offset =
833 caret_range.StartPosition().ComputeOffsetInContainerNode();
834 const unsigned caret_end_offset =
835 caret_range.EndPosition().ComputeOffsetInContainerNode();
836
837 const DocumentMarkerVector& markers_in_node =
838 GetFrame().GetDocument()->Markers().MarkersFor(
839 caret_start_container, DocumentMarker::MisspellingMarkers());
840
841 const auto marker_it =
842 std::find_if(markers_in_node.begin(), markers_in_node.end(),
843 [=](const DocumentMarker* marker) {
844 return marker->StartOffset() < caret_end_offset &&
845 marker->EndOffset() > caret_start_offset;
846 });
847 if (marker_it == markers_in_node.end())
848 return;
849
850 const DocumentMarker* found_marker = *marker_it;
851 EphemeralRange marker_range = EphemeralRange(
852 Position(caret_start_container, found_marker->StartOffset()),
853 Position(caret_start_container, found_marker->EndOffset()));
854 if (marker_range.IsNull())
855 return;
856 897
857 GetFrame().Selection().SetSelection( 898 GetFrame().Selection().SetSelection(
858 SelectionInDOMTree::Builder().SetBaseAndExtent(marker_range).Build()); 899 SelectionInDOMTree::Builder()
900 .Collapse(Position(container_node, marker->StartOffset()))
901 .Extend(Position(container_node, marker->EndOffset()))
902 .Build());
859 903
860 Document& current_document = *GetFrame().GetDocument(); 904 Document& current_document = *GetFrame().GetDocument();
861 905
862 // Dispatch 'beforeinput'. 906 // Dispatch 'beforeinput'.
863 Element* const target = GetFrame().GetEditor().FindEventTargetFromSelection(); 907 Element* const target = GetFrame().GetEditor().FindEventTargetFromSelection();
864 DataTransfer* const data_transfer = DataTransfer::Create( 908 DataTransfer* const data_transfer = DataTransfer::Create(
865 DataTransfer::DataTransferType::kInsertReplacementText, 909 DataTransfer::DataTransferType::kInsertReplacementText,
866 DataTransferAccessPolicy::kDataTransferReadable, 910 DataTransferAccessPolicy::kDataTransferReadable,
867 DataObject::CreateFromString(text)); 911 DataObject::CreateFromString(text));
868 912
(...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after
1239 if (!input.IsFocusedElementInDocument()) 1283 if (!input.IsFocusedElementInDocument())
1240 return false; 1284 return false;
1241 } 1285 }
1242 } 1286 }
1243 HTMLElement* element = 1287 HTMLElement* element =
1244 Traversal<HTMLElement>::FirstAncestorOrSelf(*position.AnchorNode()); 1288 Traversal<HTMLElement>::FirstAncestorOrSelf(*position.AnchorNode());
1245 return element && element->IsSpellCheckingEnabled(); 1289 return element && element->IsSpellCheckingEnabled();
1246 } 1290 }
1247 1291
1248 } // namespace blink 1292 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698