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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
index 902073e0dd73acc496431ce33711eb029351e7f4..23ab64e216a0dfdaf8d140b35291032b94d34386 100644
--- a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
+++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
@@ -43,6 +43,7 @@
#include "core/editing/commands/TypingCommand.h"
#include "core/editing/iterators/CharacterIterator.h"
#include "core/editing/markers/DocumentMarkerController.h"
+#include "core/editing/markers/SpellCheckMarker.h"
#include "core/editing/spellcheck/IdleSpellCheckCallback.h"
#include "core/editing/spellcheck/SpellCheckRequester.h"
#include "core/editing/spellcheck/SpellCheckerClient.h"
@@ -91,6 +92,45 @@ SelectionInDOMTree SelectWord(const VisiblePosition& position) {
.Build();
}
+EphemeralRange ExpandSelectionRangeIfNecessary(
+ const VisibleSelection& selection) {
+ DCHECK(!selection.IsNone());
+
+ // If some text is actually selected, we can use the selection range as-is to
+ // check for a marker. If no text is selected (we just have a caret
+ // somewhere), we need to expand one character on either side so we can find
+ // a spelling marker immediately before or after the caret.
+
+ // (The spelling markers on these words may be anchored to a different node
+ // than the collapsed selection's Position is, but once we expand the
+ // selection, if we're next to a marker, either the start or end point should
+ // now be anchored relative to the same text node as that marker.)
+
+ // Some text is actually selected
+ if (selection.IsRange())
+ return EphemeralRange(selection.Start(), selection.End());
+
+ // No text is actually selected, need to expand the selection range. This is
+ // to make sure we can find a marker touching the caret. E.g. if we have:
+ // <span>word1 <b>word2</b></span>
+ // with a caret selection immediately before "word2", there's one text node
+ // immediately before the caret ("word1 ") and one immediately after
+ // ("word2"). Expanding the selection by one character on either side ensures
+ // we get a range that intersects both neighboring text nodes (if they exist).
+ const VisiblePosition& caret_position = selection.VisibleStart();
+
+ const Position& previous_position =
+ PreviousPositionOf(caret_position).DeepEquivalent();
+
+ const Position& next_position =
+ NextPositionOf(caret_position).DeepEquivalent();
+
+ return EphemeralRange(
+ previous_position.IsNull() ? caret_position.DeepEquivalent()
+ : previous_position,
+ next_position.IsNull() ? caret_position.DeepEquivalent() : next_position);
+}
+
} // namespace
SpellChecker* SpellChecker::Create(LocalFrame& frame) {
@@ -811,51 +851,57 @@ void SpellChecker::RemoveSpellingAndGrammarMarkers(const HTMLElement& element,
}
}
-void SpellChecker::ReplaceMisspelledRange(const String& text) {
- EphemeralRange caret_range = GetFrame()
- .Selection()
- .ComputeVisibleSelectionInDOMTree()
- .ToNormalizedEphemeralRange();
- if (caret_range.IsNull())
- return;
+Optional<std::pair<Node*, SpellCheckMarker*>>
+SpellChecker::GetSpellCheckMarkerTouchingSelection() {
+ const VisibleSelection& selection =
+ GetFrame().Selection().ComputeVisibleSelectionInDOMTree();
+ if (selection.IsNone())
+ return Optional<std::pair<Node*, SpellCheckMarker*>>();
+
+ const EphemeralRange& range_to_check =
+ ExpandSelectionRangeIfNecessary(selection);
+
+ Node* const start_container =
+ range_to_check.StartPosition().ComputeContainerNode();
+ const unsigned start_offset =
+ range_to_check.StartPosition().ComputeOffsetInContainerNode();
+ Node* const end_container =
+ range_to_check.EndPosition().ComputeContainerNode();
+ const unsigned end_offset =
+ range_to_check.EndPosition().ComputeOffsetInContainerNode();
+
+ for (Node& node : range_to_check.Nodes()) {
+ const DocumentMarkerVector& markers_in_node =
+ GetFrame().GetDocument()->Markers().MarkersFor(
+ &node, DocumentMarker::MisspellingMarkers());
+ for (DocumentMarker* marker : markers_in_node) {
+ if (node == start_container && marker->EndOffset() <= start_offset)
+ continue;
+ if (node == end_container && marker->StartOffset() >= end_offset)
+ continue;
- Node* const caret_start_container =
- caret_range.StartPosition().ComputeContainerNode();
- Node* const caret_end_container =
- caret_range.EndPosition().ComputeContainerNode();
+ return std::make_pair(&node, &ToSpellCheckMarker(*marker));
+ }
+ }
- // We don't currently support the case where a misspelling spans multiple
- // nodes
- if (caret_start_container != caret_end_container)
- return;
+ // No marker found
+ return Optional<std::pair<Node*, SpellCheckMarker*>>();
+}
- const unsigned caret_start_offset =
- caret_range.StartPosition().ComputeOffsetInContainerNode();
- const unsigned caret_end_offset =
- caret_range.EndPosition().ComputeOffsetInContainerNode();
-
- const DocumentMarkerVector& markers_in_node =
- GetFrame().GetDocument()->Markers().MarkersFor(
- caret_start_container, DocumentMarker::MisspellingMarkers());
-
- const auto marker_it =
- std::find_if(markers_in_node.begin(), markers_in_node.end(),
- [=](const DocumentMarker* marker) {
- return marker->StartOffset() < caret_end_offset &&
- marker->EndOffset() > caret_start_offset;
- });
- if (marker_it == markers_in_node.end())
+void SpellChecker::ReplaceMisspelledRange(const String& text) {
+ const Optional<std::pair<Node*, SpellCheckMarker*>>& node_and_marker =
+ GetSpellCheckMarkerTouchingSelection();
+ if (!node_and_marker)
return;
- const DocumentMarker* found_marker = *marker_it;
- EphemeralRange marker_range = EphemeralRange(
- Position(caret_start_container, found_marker->StartOffset()),
- Position(caret_start_container, found_marker->EndOffset()));
- if (marker_range.IsNull())
- return;
+ Node* const container_node = node_and_marker.value().first;
+ const SpellCheckMarker* const marker = node_and_marker.value().second;
GetFrame().Selection().SetSelection(
- SelectionInDOMTree::Builder().SetBaseAndExtent(marker_range).Build());
+ SelectionInDOMTree::Builder()
+ .Collapse(Position(container_node, marker->StartOffset()))
+ .Extend(Position(container_node, marker->EndOffset()))
+ .Build());
Document& current_document = *GetFrame().GetDocument();

Powered by Google App Engine
This is Rietveld 408576698