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

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

Issue 2925363002: Add SpellChecker::GetSpellCheckMarkerTouchingSelection() (Closed)
Patch Set: Respond to commments 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 28 matching lines...) Expand all
84 // TODO(yosin): We should fix |startOfWord()| and |endOfWord()| not to return 85 // TODO(yosin): We should fix |startOfWord()| and |endOfWord()| not to return
85 // null position. 86 // null position.
86 const VisiblePosition& start = StartOfWord(position, kLeftWordIfOnBoundary); 87 const VisiblePosition& start = StartOfWord(position, kLeftWordIfOnBoundary);
87 const VisiblePosition& end = EndOfWord(position, kRightWordIfOnBoundary); 88 const VisiblePosition& end = EndOfWord(position, kRightWordIfOnBoundary);
88 return SelectionInDOMTree::Builder() 89 return SelectionInDOMTree::Builder()
89 .SetBaseAndExtentDeprecated(start.DeepEquivalent(), end.DeepEquivalent()) 90 .SetBaseAndExtentDeprecated(start.DeepEquivalent(), end.DeepEquivalent())
90 .SetAffinity(start.Affinity()) 91 .SetAffinity(start.Affinity())
91 .Build(); 92 .Build();
92 } 93 }
93 94
95 EphemeralRange ExpandSelectionRangeIfNecessary(
96 const VisibleSelection& selection) {
97 DCHECK(!selection.IsNone());
98
99 // If some text is actually selected, we can use the selection range as-is to
100 // check for a marker. If no text is selected (we just have a caret
101 // somewhere), we need to expand one character on either side so we can find
102 // a spelling marker immediately before or after the caret.
103
104 // (The spelling markers on these words may be anchored to a different node
105 // than the collapsed selection's Position is, but once we expand the
106 // selection, if we're next to a marker, either the start or end point should
107 // now be anchored relative to the same text node as that marker.)
108
109 // Some text is actually selected
110 if (selection.IsRange())
111 return EphemeralRange(selection.Start(), selection.End());
112
113 // No text is actually selected, need to expand the selection range. This is
114 // to make sure we can find a marker touching the caret. E.g. if we have:
115 // <span>word1 <b>word2</b></span>
116 // with a caret selection immediately before "word2", there's one text node
117 // immediately before the caret ("word1 ") and one immediately after
118 // ("word2"). Expanding the selection by one character on either side ensures
119 // we get a range that intersects both neighboring text nodes (if they exist).
120 const VisiblePosition& caret_position = selection.VisibleStart();
121
122 const Position& previous_position =
123 PreviousPositionOf(caret_position).DeepEquivalent();
124
125 const Position& next_position =
126 NextPositionOf(caret_position).DeepEquivalent();
127
128 return EphemeralRange(
129 previous_position.IsNull() ? caret_position.DeepEquivalent()
130 : previous_position,
131 next_position.IsNull() ? caret_position.DeepEquivalent() : next_position);
132 }
133
94 } // namespace 134 } // namespace
95 135
96 SpellChecker* SpellChecker::Create(LocalFrame& frame) { 136 SpellChecker* SpellChecker::Create(LocalFrame& frame) {
97 return new SpellChecker(frame); 137 return new SpellChecker(frame);
98 } 138 }
99 139
100 static SpellCheckerClient& GetEmptySpellCheckerClient() { 140 static SpellCheckerClient& GetEmptySpellCheckerClient() {
101 DEFINE_STATIC_LOCAL(EmptySpellCheckerClient, client, ()); 141 DEFINE_STATIC_LOCAL(EmptySpellCheckerClient, client, ());
102 return client; 142 return client;
103 } 143 }
(...skipping 700 matching lines...) Expand 10 before | Expand all | Expand 10 after
804 DocumentMarker::MarkerTypes marker_types(DocumentMarker::kSpelling); 844 DocumentMarker::MarkerTypes marker_types(DocumentMarker::kSpelling);
805 marker_types.Add(DocumentMarker::kGrammar); 845 marker_types.Add(DocumentMarker::kGrammar);
806 for (Node& node : NodeTraversal::InclusiveDescendantsOf(element)) { 846 for (Node& node : NodeTraversal::InclusiveDescendantsOf(element)) {
807 if (elements_type == ElementsType::kAll || !HasEditableStyle(node)) { 847 if (elements_type == ElementsType::kAll || !HasEditableStyle(node)) {
808 GetFrame().GetDocument()->Markers().RemoveMarkersForNode(&node, 848 GetFrame().GetDocument()->Markers().RemoveMarkersForNode(&node,
809 marker_types); 849 marker_types);
810 } 850 }
811 } 851 }
812 } 852 }
813 853
854 Optional<std::pair<Node*, SpellCheckMarker*>>
855 SpellChecker::GetSpellCheckMarkerTouchingSelection() {
856 const VisibleSelection& selection =
857 GetFrame().Selection().ComputeVisibleSelectionInDOMTree();
858 if (selection.IsNone())
859 return Optional<std::pair<Node*, SpellCheckMarker*>>();
860
861 const EphemeralRange& range_to_check =
862 ExpandSelectionRangeIfNecessary(selection);
863
864 Node* const start_container =
865 range_to_check.StartPosition().ComputeContainerNode();
866 const unsigned start_offset =
867 range_to_check.StartPosition().ComputeOffsetInContainerNode();
868 Node* const end_container =
869 range_to_check.EndPosition().ComputeContainerNode();
870 const unsigned end_offset =
871 range_to_check.EndPosition().ComputeOffsetInContainerNode();
872
873 for (Node& node : range_to_check.Nodes()) {
874 const DocumentMarkerVector& markers_in_node =
875 GetFrame().GetDocument()->Markers().MarkersFor(
876 &node, DocumentMarker::MisspellingMarkers());
877 for (DocumentMarker* marker : markers_in_node) {
878 if (node == start_container && marker->EndOffset() <= start_offset)
879 continue;
880 if (node == end_container && marker->StartOffset() >= end_offset)
881 continue;
882
883 return std::make_pair(&node, &ToSpellCheckMarker(*marker));
884 }
885 }
886
887 // No marker found
888 return Optional<std::pair<Node*, SpellCheckMarker*>>();
889 }
890
814 void SpellChecker::ReplaceMisspelledRange(const String& text) { 891 void SpellChecker::ReplaceMisspelledRange(const String& text) {
815 EphemeralRange caret_range = GetFrame() 892 const Optional<std::pair<Node*, SpellCheckMarker*>>& node_and_marker =
816 .Selection() 893 GetSpellCheckMarkerTouchingSelection();
817 .ComputeVisibleSelectionInDOMTree() 894 if (!node_and_marker)
818 .ToNormalizedEphemeralRange();
819 if (caret_range.IsNull())
820 return; 895 return;
821 896
822 Node* const caret_start_container = 897 Node* const container_node = node_and_marker.value().first;
823 caret_range.StartPosition().ComputeContainerNode(); 898 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 899
857 GetFrame().Selection().SetSelection( 900 GetFrame().Selection().SetSelection(
858 SelectionInDOMTree::Builder().SetBaseAndExtent(marker_range).Build()); 901 SelectionInDOMTree::Builder()
902 .Collapse(Position(container_node, marker->StartOffset()))
903 .Extend(Position(container_node, marker->EndOffset()))
904 .Build());
859 905
860 Document& current_document = *GetFrame().GetDocument(); 906 Document& current_document = *GetFrame().GetDocument();
861 907
862 // Dispatch 'beforeinput'. 908 // Dispatch 'beforeinput'.
863 Element* const target = GetFrame().GetEditor().FindEventTargetFromSelection(); 909 Element* const target = GetFrame().GetEditor().FindEventTargetFromSelection();
864 DataTransfer* const data_transfer = DataTransfer::Create( 910 DataTransfer* const data_transfer = DataTransfer::Create(
865 DataTransfer::DataTransferType::kInsertReplacementText, 911 DataTransfer::DataTransferType::kInsertReplacementText,
866 DataTransferAccessPolicy::kDataTransferReadable, 912 DataTransferAccessPolicy::kDataTransferReadable,
867 DataObject::CreateFromString(text)); 913 DataObject::CreateFromString(text));
868 914
(...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after
1239 if (!input.IsFocusedElementInDocument()) 1285 if (!input.IsFocusedElementInDocument())
1240 return false; 1286 return false;
1241 } 1287 }
1242 } 1288 }
1243 HTMLElement* element = 1289 HTMLElement* element =
1244 Traversal<HTMLElement>::FirstAncestorOrSelf(*position.AnchorNode()); 1290 Traversal<HTMLElement>::FirstAncestorOrSelf(*position.AnchorNode());
1245 return element && element->IsSpellCheckingEnabled(); 1291 return element && element->IsSpellCheckingEnabled();
1246 } 1292 }
1247 1293
1248 } // namespace blink 1294 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698