| Index: third_party/WebKit/Source/core/editing/spellcheck/HotModeSpellCheckRequester.cpp
|
| diff --git a/third_party/WebKit/Source/core/editing/spellcheck/HotModeSpellCheckRequester.cpp b/third_party/WebKit/Source/core/editing/spellcheck/HotModeSpellCheckRequester.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..3b106ceba3650c104d0a449ab02ff6dc54518adb
|
| --- /dev/null
|
| +++ b/third_party/WebKit/Source/core/editing/spellcheck/HotModeSpellCheckRequester.cpp
|
| @@ -0,0 +1,108 @@
|
| +// 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 "core/editing/spellcheck/HotModeSpellCheckRequester.h"
|
| +
|
| +#include "core/editing/EditingUtilities.h"
|
| +#include "core/editing/Editor.h"
|
| +#include "core/editing/VisiblePosition.h"
|
| +#include "core/editing/commands/CompositeEditCommand.h"
|
| +#include "core/editing/commands/TypingCommand.h"
|
| +#include "core/editing/iterators/BackwardsCharacterIterator.h"
|
| +#include "core/editing/iterators/CharacterIterator.h"
|
| +#include "core/editing/spellcheck/SpellCheckRequester.h"
|
| +#include "core/editing/spellcheck/SpellChecker.h"
|
| +
|
| +namespace blink {
|
| +
|
| +namespace {
|
| +
|
| +const int kHotModeChunkSize = 1024;
|
| +
|
| +bool isInOrAdjacentToWord(const Position& pos) {
|
| + const VisiblePosition& visiblePos = createVisiblePosition(pos);
|
| + const VisiblePosition& wordStart = previousWordPosition(visiblePos);
|
| + if (wordStart.isNull())
|
| + return false;
|
| + const VisiblePosition& wordEnd = endOfWord(wordStart);
|
| + if (wordEnd.isNull())
|
| + return false;
|
| + return comparePositions(visiblePos, wordEnd) <= 0;
|
| +}
|
| +
|
| +bool isTypingInPartialWord(const Element& editable) {
|
| + const LocalFrame& frame = *editable.document().frame();
|
| + const SelectionInDOMTree& selection = frame.selection().selectionInDOMTree();
|
| + if (!selection.isCaret())
|
| + return false;
|
| + if (rootEditableElementOf(selection.base()) != &editable)
|
| + return false;
|
| +
|
| + CompositeEditCommand* typingCommand =
|
| + frame.editor().lastTypingCommandIfStillOpenForTyping();
|
| + if (!typingCommand)
|
| + return false;
|
| + if (typingCommand->endingSelection().asSelection() != selection)
|
| + return false;
|
| + return isInOrAdjacentToWord(selection.base());
|
| +}
|
| +
|
| +bool shouldCheckRootEditableInHotMode(const Element& editable,
|
| + const Position& position) {
|
| + if (!editable.isSpellCheckingEnabled() &&
|
| + !SpellChecker::isSpellCheckingEnabledAt(position))
|
| + return false;
|
| + if (editable.visibleBoundsInVisualViewport().isEmpty())
|
| + return false;
|
| + // TODO(xiaochengh): Design more aggressive strategies to reduce checking when
|
| + // we are just moving selection around without modifying anything.
|
| + return !isTypingInPartialWord(editable);
|
| +}
|
| +
|
| +EphemeralRange calculateHotModeCheckingRange(const Element& editable,
|
| + const Position& position) {
|
| + const EphemeralRange& fullRange = EphemeralRange::rangeOfContents(editable);
|
| + const int fullLength = TextIterator::rangeLength(fullRange.startPosition(),
|
| + fullRange.endPosition());
|
| + if (fullLength <= kHotModeChunkSize)
|
| + return fullRange;
|
| +
|
| + TextIteratorBehavior behavior = TextIteratorBehavior::Builder()
|
| + .setEmitsObjectReplacementCharacter(true)
|
| + .build();
|
| + BackwardsCharacterIterator backwardIterator(fullRange.startPosition(),
|
| + position, behavior);
|
| + backwardIterator.advance(kHotModeChunkSize / 2);
|
| + const Position& chunkStart = backwardIterator.endPosition();
|
| + CharacterIterator forwardIterator(position, fullRange.endPosition(),
|
| + behavior);
|
| + forwardIterator.advance(kHotModeChunkSize / 2);
|
| + const Position& chunkEnd = forwardIterator.endPosition();
|
| + return expandRangeToSentenceBoundary(EphemeralRange(chunkStart, chunkEnd));
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +HotModeSpellCheckRequester::HotModeSpellCheckRequester(
|
| + SpellCheckRequester& requester)
|
| + : m_requester(requester) {}
|
| +
|
| +void HotModeSpellCheckRequester::checkSpellingAt(const Position& position) {
|
| + const Element* rootEditable = rootEditableElementOf(position);
|
| + if (!rootEditable || !rootEditable->isConnected())
|
| + return;
|
| +
|
| + if (m_processedRootEditables.contains(rootEditable))
|
| + return;
|
| + m_processedRootEditables.push_back(rootEditable);
|
| +
|
| + if (!shouldCheckRootEditableInHotMode(*rootEditable, position))
|
| + return;
|
| +
|
| + SpellCheckRequest* request = SpellCheckRequest::create(
|
| + calculateHotModeCheckingRange(*rootEditable, position));
|
| + m_requester->requestCheckingFor(request);
|
| +}
|
| +
|
| +} // namespace blink
|
|
|