summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/editing/spellcheck/hot_mode_spell_check_requester.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/renderer/core/editing/spellcheck/hot_mode_spell_check_requester.cc')
-rw-r--r--chromium/third_party/blink/renderer/core/editing/spellcheck/hot_mode_spell_check_requester.cc128
1 files changed, 128 insertions, 0 deletions
diff --git a/chromium/third_party/blink/renderer/core/editing/spellcheck/hot_mode_spell_check_requester.cc b/chromium/third_party/blink/renderer/core/editing/spellcheck/hot_mode_spell_check_requester.cc
new file mode 100644
index 00000000000..b9731680d1a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/editing/spellcheck/hot_mode_spell_check_requester.cc
@@ -0,0 +1,128 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/editing/spellcheck/hot_mode_spell_check_requester.h"
+
+#include "third_party/blink/renderer/core/editing/commands/composite_edit_command.h"
+#include "third_party/blink/renderer/core/editing/commands/typing_command.h"
+#include "third_party/blink/renderer/core/editing/editing_utilities.h"
+#include "third_party/blink/renderer/core/editing/editor.h"
+#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
+#include "third_party/blink/renderer/core/editing/frame_selection.h"
+#include "third_party/blink/renderer/core/editing/iterators/backwards_character_iterator.h"
+#include "third_party/blink/renderer/core/editing/iterators/character_iterator.h"
+#include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
+#include "third_party/blink/renderer/core/editing/selection_template.h"
+#include "third_party/blink/renderer/core/editing/spellcheck/spell_check_requester.h"
+#include "third_party/blink/renderer/core/editing/spellcheck/spell_checker.h"
+#include "third_party/blink/renderer/core/editing/visible_position.h"
+
+namespace blink {
+
+namespace {
+
+const int kHotModeCheckAllThreshold = 128;
+const int kHotModeChunkSize = 1024;
+
+EphemeralRange AdjacentWordIfExists(const Position& pos) {
+ const VisiblePosition& visible_pos = CreateVisiblePosition(pos);
+ const VisiblePosition& word_start = PreviousWordPosition(visible_pos);
+ if (word_start.IsNull())
+ return EphemeralRange();
+ const VisiblePosition& word_end = EndOfWord(word_start);
+ if (word_end.IsNull())
+ return EphemeralRange();
+ if (ComparePositions(visible_pos, word_end) > 0)
+ return EphemeralRange();
+ return EphemeralRange(word_start.DeepEquivalent(), word_end.DeepEquivalent());
+}
+
+EphemeralRange CurrentWordIfTypingInPartialWord(const Element& editable) {
+ const LocalFrame& frame = *editable.GetDocument().GetFrame();
+ const SelectionInDOMTree& selection =
+ frame.Selection().GetSelectionInDOMTree();
+ if (!selection.IsCaret())
+ return EphemeralRange();
+ if (RootEditableElementOf(selection.Base()) != &editable)
+ return EphemeralRange();
+
+ CompositeEditCommand* last_command = frame.GetEditor().LastEditCommand();
+ if (!last_command || !last_command->IsTypingCommand())
+ return EphemeralRange();
+ if (!last_command->EndingSelection().IsValidFor(*frame.GetDocument()))
+ return EphemeralRange();
+ if (last_command->EndingSelection().AsSelection() != selection)
+ return EphemeralRange();
+ return AdjacentWordIfExists(selection.Base());
+}
+
+EphemeralRange CalculateHotModeCheckingRange(const Element& editable,
+ const Position& position) {
+ // Check everything in |editable| if its total length is short.
+ const EphemeralRange& full_range = EphemeralRange::RangeOfContents(editable);
+ const int full_length = TextIterator::RangeLength(full_range);
+ // TODO(xiaochengh): There is no need to check if |full_length <= 2|, since
+ // we don't consider two characters as misspelled. However, a lot of layout
+ // tests depend on "zz" as misspelled, which should be changed.
+ if (full_length <= kHotModeCheckAllThreshold)
+ return full_range;
+
+ // Otherwise, if |position| is in a short paragraph, check the paragraph.
+ const EphemeralRange& paragraph_range =
+ ExpandToParagraphBoundary(EphemeralRange(position));
+ const int paragraph_length = TextIterator::RangeLength(paragraph_range);
+ if (paragraph_length <= kHotModeChunkSize)
+ return paragraph_range;
+
+ // Otherwise, check a chunk of text centered at |position|.
+ TextIteratorBehavior behavior = TextIteratorBehavior::Builder()
+ .SetEmitsObjectReplacementCharacter(true)
+ .Build();
+ BackwardsCharacterIterator backward_iterator(
+ EphemeralRange(full_range.StartPosition(), position), behavior);
+ if (!backward_iterator.AtEnd())
+ backward_iterator.Advance(kHotModeChunkSize / 2);
+ const Position& chunk_start = backward_iterator.EndPosition();
+ CharacterIterator forward_iterator(position, full_range.EndPosition(),
+ behavior);
+ if (!forward_iterator.AtEnd())
+ forward_iterator.Advance(kHotModeChunkSize / 2);
+ const Position& chunk_end = forward_iterator.EndPosition();
+ return ExpandRangeToSentenceBoundary(EphemeralRange(chunk_start, chunk_end));
+}
+
+} // namespace
+
+HotModeSpellCheckRequester::HotModeSpellCheckRequester(
+ SpellCheckRequester& requester)
+ : requester_(requester) {}
+
+void HotModeSpellCheckRequester::CheckSpellingAt(const Position& position) {
+ const Element* root_editable = RootEditableElementOf(position);
+ if (!root_editable || !root_editable->isConnected())
+ return;
+
+ if (processed_root_editables_.Contains(root_editable))
+ return;
+ processed_root_editables_.push_back(root_editable);
+
+ if (!root_editable->IsSpellCheckingEnabled() &&
+ !SpellChecker::IsSpellCheckingEnabledAt(position)) {
+ return;
+ }
+
+ const EphemeralRange& current_word =
+ CurrentWordIfTypingInPartialWord(*root_editable);
+ if (current_word.IsNotNull()) {
+ root_editable->GetDocument().Markers().RemoveMarkersInRange(
+ current_word, DocumentMarker::MisspellingMarkers());
+ return;
+ }
+
+ const EphemeralRange& checking_range =
+ CalculateHotModeCheckingRange(*root_editable, position);
+ requester_->RequestCheckingFor(checking_range);
+}
+
+} // namespace blink