forked from mirrors/gecko-dev
Bug 1502661 - Part 3. Use async API for spell checking. r=masayuki
Previous implementation is - Use idle runnable for spellchecker - If spellchecker runnable spends 1ms (with 5 words), spellchecker is suspended, then resume it after 1s. - If misspell is 3/4 of extensions.spellchecker.inline.max-misspellings per DoSpellCheck, spellchecker is stopped. After this change, IPC is async, so we cannot count misspell words without waiting the result of async call. So I would like to change to - Use idle runnable for spellchecker - If spellchecker runnable spends 1ms (with 5 words), spellchecker is suspended, then resume it after 1s. - If misspell reaches extensions.spellchecker.inline.max-misspellings, stop spellcheck. - spellchecker IPC is called per maximum 25 (INLINESPELL_MAXIMUM_CHUNKED_WORDS_PER_TASK) words. As long as my MacBook (Core m3), spellchecker can check 100-150 words per 1ms after this fix. Also, INLINESPELL_MAXIMUM_CHUNKED_WORDS_PER_TASK define is less than 5, a lot of a11y tests will be failed. Because it uses selection listener to count all misspell words without waiting completion. Differential Revision: https://phabricator.services.mozilla.com/D14837 --HG-- extra : rebase_source : 59185554236409d3320cc77714a776f2228214af
This commit is contained in:
parent
7bc8f8b726
commit
bf48e8ad9d
4 changed files with 129 additions and 52 deletions
|
|
@ -68,6 +68,7 @@
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using namespace mozilla::dom;
|
using namespace mozilla::dom;
|
||||||
|
using namespace mozilla::ipc;
|
||||||
|
|
||||||
// Set to spew messages to the console about what is happening.
|
// Set to spew messages to the console about what is happening.
|
||||||
//#define DEBUG_INLINESPELL
|
//#define DEBUG_INLINESPELL
|
||||||
|
|
@ -81,6 +82,9 @@ using namespace mozilla::dom;
|
||||||
// be too short to a low-end machine.
|
// be too short to a low-end machine.
|
||||||
#define INLINESPELL_MINIMUM_WORDS_BEFORE_TIMEOUT 5
|
#define INLINESPELL_MINIMUM_WORDS_BEFORE_TIMEOUT 5
|
||||||
|
|
||||||
|
// The maximum number of words to check word via IPC.
|
||||||
|
#define INLINESPELL_MAXIMUM_CHUNKED_WORDS_PER_TASK 25
|
||||||
|
|
||||||
// These notifications are broadcast when spell check starts and ends. STARTED
|
// These notifications are broadcast when spell check starts and ends. STARTED
|
||||||
// must always be followed by ENDED.
|
// must always be followed by ENDED.
|
||||||
#define INLINESPELL_STARTED_TOPIC "inlineSpellChecker-spellCheck-started"
|
#define INLINESPELL_STARTED_TOPIC "inlineSpellChecker-spellCheck-started"
|
||||||
|
|
@ -92,7 +96,7 @@ static const PRTime kMaxSpellCheckTimeInUsec =
|
||||||
INLINESPELL_CHECK_TIMEOUT * PR_USEC_PER_MSEC;
|
INLINESPELL_CHECK_TIMEOUT * PR_USEC_PER_MSEC;
|
||||||
|
|
||||||
mozInlineSpellStatus::mozInlineSpellStatus(mozInlineSpellChecker* aSpellChecker)
|
mozInlineSpellStatus::mozInlineSpellStatus(mozInlineSpellChecker* aSpellChecker)
|
||||||
: mSpellChecker(aSpellChecker), mWordCount(0) {}
|
: mSpellChecker(aSpellChecker) {}
|
||||||
|
|
||||||
// mozInlineSpellStatus::InitForEditorChange
|
// mozInlineSpellStatus::InitForEditorChange
|
||||||
//
|
//
|
||||||
|
|
@ -520,7 +524,6 @@ mozInlineSpellChecker::mozInlineSpellChecker()
|
||||||
if (prefs)
|
if (prefs)
|
||||||
prefs->GetIntPref(kMaxSpellCheckSelectionSize,
|
prefs->GetIntPref(kMaxSpellCheckSelectionSize,
|
||||||
&mMaxNumWordsInSpellSelection);
|
&mMaxNumWordsInSpellSelection);
|
||||||
mMaxMisspellingsPerCheck = mMaxNumWordsInSpellSelection * 3 / 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mozInlineSpellChecker::~mozInlineSpellChecker() {}
|
mozInlineSpellChecker::~mozInlineSpellChecker() {}
|
||||||
|
|
@ -1195,8 +1198,6 @@ nsresult mozInlineSpellChecker::DoSpellCheckSelection(
|
||||||
MOZ_ASSERT(
|
MOZ_ASSERT(
|
||||||
doneChecking,
|
doneChecking,
|
||||||
"We gave the spellchecker one word, but it didn't finish checking?!?!");
|
"We gave the spellchecker one word, but it didn't finish checking?!?!");
|
||||||
|
|
||||||
status->mWordCount = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
@ -1238,12 +1239,18 @@ nsresult mozInlineSpellChecker::DoSpellCheck(
|
||||||
const UniquePtr<mozInlineSpellStatus>& aStatus, bool* aDoneChecking) {
|
const UniquePtr<mozInlineSpellStatus>& aStatus, bool* aDoneChecking) {
|
||||||
*aDoneChecking = true;
|
*aDoneChecking = true;
|
||||||
|
|
||||||
NS_ENSURE_TRUE(mSpellCheck, NS_ERROR_NOT_INITIALIZED);
|
if (NS_WARN_IF(!mSpellCheck)) {
|
||||||
|
return NS_ERROR_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SpellCheckSelectionIsFull()) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
// get the editor for ShouldSpellCheckNode, this may fail in reasonable
|
// get the editor for ShouldSpellCheckNode, this may fail in reasonable
|
||||||
// circumstances since the editor could have gone away
|
// circumstances since the editor could have gone away
|
||||||
RefPtr<TextEditor> textEditor = mTextEditor;
|
RefPtr<TextEditor> textEditor = mTextEditor;
|
||||||
if (!textEditor) {
|
if (!textEditor || textEditor->Destroyed()) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1291,25 +1298,34 @@ nsresult mozInlineSpellChecker::DoSpellCheck(
|
||||||
int32_t wordsChecked = 0;
|
int32_t wordsChecked = 0;
|
||||||
PRTime beginTime = PR_Now();
|
PRTime beginTime = PR_Now();
|
||||||
|
|
||||||
|
nsTArray<nsString> words;
|
||||||
|
nsTArray<NodeOffsetRange> checkRanges;
|
||||||
nsAutoString wordText;
|
nsAutoString wordText;
|
||||||
NodeOffsetRange wordNodeOffsetRange;
|
NodeOffsetRange wordNodeOffsetRange;
|
||||||
bool dontCheckWord;
|
bool dontCheckWord;
|
||||||
|
// XXX Spellchecker API isn't async on chrome process.
|
||||||
|
static const size_t requestChunkSize =
|
||||||
|
XRE_IsContentProcess() ? INLINESPELL_MAXIMUM_CHUNKED_WORDS_PER_TASK : 1;
|
||||||
while (NS_SUCCEEDED(aWordUtil.GetNextWord(wordText, &wordNodeOffsetRange,
|
while (NS_SUCCEEDED(aWordUtil.GetNextWord(wordText, &wordNodeOffsetRange,
|
||||||
&dontCheckWord)) &&
|
&dontCheckWord)) &&
|
||||||
!wordNodeOffsetRange.Empty()) {
|
!wordNodeOffsetRange.Empty()) {
|
||||||
// get the range for the current word.
|
// get the range for the current word.
|
||||||
nsINode* beginNode = wordNodeOffsetRange.Begin().mNode;
|
nsINode* beginNode = wordNodeOffsetRange.Begin().Node();
|
||||||
nsINode* endNode = wordNodeOffsetRange.End().mNode;
|
nsINode* endNode = wordNodeOffsetRange.End().Node();
|
||||||
int32_t beginOffset = wordNodeOffsetRange.Begin().mOffset;
|
int32_t beginOffset = wordNodeOffsetRange.Begin().Offset();
|
||||||
int32_t endOffset = wordNodeOffsetRange.End().mOffset;
|
int32_t endOffset = wordNodeOffsetRange.End().Offset();
|
||||||
|
|
||||||
// see if we've done enough words in this round and run out of time.
|
// see if we've done enough words in this round and run out of time.
|
||||||
if (wordsChecked >= INLINESPELL_MINIMUM_WORDS_BEFORE_TIMEOUT &&
|
if (wordsChecked >= INLINESPELL_MINIMUM_WORDS_BEFORE_TIMEOUT &&
|
||||||
PR_Now() > PRTime(beginTime + kMaxSpellCheckTimeInUsec)) {
|
PR_Now() > PRTime(beginTime + kMaxSpellCheckTimeInUsec)) {
|
||||||
// stop checking, our time limit has been exceeded.
|
// stop checking, our time limit has been exceeded.
|
||||||
#ifdef DEBUG_INLINESPELL
|
#ifdef DEBUG_INLINESPELL
|
||||||
printf("We have run out of the time, schedule next round.");
|
printf("We have run out of the time, schedule next round.\n");
|
||||||
#endif
|
#endif
|
||||||
|
CheckCurrentWordsNoSuggest(aSpellCheckSelection, words, checkRanges);
|
||||||
|
words.Clear();
|
||||||
|
checkRanges.Clear();
|
||||||
|
|
||||||
// move the range to encompass the stuff that needs checking.
|
// move the range to encompass the stuff that needs checking.
|
||||||
nsresult rv = aStatus->mRange->SetStart(beginNode, beginOffset);
|
nsresult rv = aStatus->mRange->SetStart(beginNode, beginOffset);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
|
|
@ -1366,39 +1382,31 @@ nsresult mozInlineSpellChecker::DoSpellCheck(
|
||||||
}
|
}
|
||||||
|
|
||||||
// check spelling and add to selection if misspelled
|
// check spelling and add to selection if misspelled
|
||||||
bool isMisspelled;
|
|
||||||
mozInlineSpellWordUtil::NormalizeWord(wordText);
|
mozInlineSpellWordUtil::NormalizeWord(wordText);
|
||||||
nsresult rv =
|
words.AppendElement(wordText);
|
||||||
mSpellCheck->CheckCurrentWordNoSuggest(wordText, &isMisspelled);
|
checkRanges.AppendElement(wordNodeOffsetRange);
|
||||||
if (NS_FAILED(rv)) continue;
|
|
||||||
|
|
||||||
wordsChecked++;
|
wordsChecked++;
|
||||||
if (isMisspelled) {
|
if (words.Length() >= requestChunkSize) {
|
||||||
// misspelled words count extra toward the max
|
CheckCurrentWordsNoSuggest(aSpellCheckSelection, words, checkRanges);
|
||||||
RefPtr<nsRange> wordRange;
|
words.Clear();
|
||||||
// If we somehow can't make a range for this word, just ignore it.
|
checkRanges.Clear();
|
||||||
if (NS_SUCCEEDED(aWordUtil.MakeRange(wordNodeOffsetRange.Begin(),
|
|
||||||
wordNodeOffsetRange.End(),
|
|
||||||
getter_AddRefs(wordRange)))) {
|
|
||||||
AddRange(aSpellCheckSelection, wordRange);
|
|
||||||
aStatus->mWordCount++;
|
|
||||||
if (aStatus->mWordCount >= mMaxMisspellingsPerCheck ||
|
|
||||||
SpellCheckSelectionIsFull()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CheckCurrentWordsNoSuggest(aSpellCheckSelection, words, checkRanges);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// An RAII helper that calls ChangeNumPendingSpellChecks on destruction.
|
// An RAII helper that calls ChangeNumPendingSpellChecks on destruction.
|
||||||
class AutoChangeNumPendingSpellChecks {
|
class MOZ_RAII AutoChangeNumPendingSpellChecks final {
|
||||||
public:
|
public:
|
||||||
AutoChangeNumPendingSpellChecks(mozInlineSpellChecker* aSpellChecker,
|
explicit AutoChangeNumPendingSpellChecks(mozInlineSpellChecker* aSpellChecker,
|
||||||
int32_t aDelta)
|
int32_t aDelta
|
||||||
: mSpellChecker(aSpellChecker), mDelta(aDelta) {}
|
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||||
|
: mSpellChecker(aSpellChecker), mDelta(aDelta) {
|
||||||
|
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||||
|
}
|
||||||
|
|
||||||
~AutoChangeNumPendingSpellChecks() {
|
~AutoChangeNumPendingSpellChecks() {
|
||||||
mSpellChecker->ChangeNumPendingSpellChecks(mDelta);
|
mSpellChecker->ChangeNumPendingSpellChecks(mDelta);
|
||||||
|
|
@ -1407,8 +1415,68 @@ class AutoChangeNumPendingSpellChecks {
|
||||||
private:
|
private:
|
||||||
RefPtr<mozInlineSpellChecker> mSpellChecker;
|
RefPtr<mozInlineSpellChecker> mSpellChecker;
|
||||||
int32_t mDelta;
|
int32_t mDelta;
|
||||||
|
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void mozInlineSpellChecker::CheckCurrentWordsNoSuggest(
|
||||||
|
Selection* aSpellCheckSelection, const nsTArray<nsString>& aWords,
|
||||||
|
const nsTArray<NodeOffsetRange>& aRanges) {
|
||||||
|
if (aWords.IsEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChangeNumPendingSpellChecks(1);
|
||||||
|
|
||||||
|
RefPtr<mozInlineSpellChecker> self = this;
|
||||||
|
RefPtr<Selection> spellCheckerSelection = aSpellCheckSelection;
|
||||||
|
uint32_t token = mDisabledAsyncToken;
|
||||||
|
mSpellCheck->CheckCurrentWordsNoSuggest(aWords)->Then(
|
||||||
|
GetMainThreadSerialEventTarget(), __func__,
|
||||||
|
[self, spellCheckerSelection, aRanges,
|
||||||
|
token](const nsTArray<bool>& aIsMisspelled) {
|
||||||
|
if (token != self->mDisabledAsyncToken) {
|
||||||
|
// This result is never used
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!self->mTextEditor || self->mTextEditor->Destroyed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AutoChangeNumPendingSpellChecks pendingChecks(self, -1);
|
||||||
|
|
||||||
|
if (self->SpellCheckSelectionIsFull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < aIsMisspelled.Length(); i++) {
|
||||||
|
if (!aIsMisspelled[i]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefPtr<nsRange> wordRange =
|
||||||
|
mozInlineSpellWordUtil::MakeRange(aRanges[i]);
|
||||||
|
// If we somehow can't make a range for this word, just ignore
|
||||||
|
// it.
|
||||||
|
if (wordRange) {
|
||||||
|
self->AddRange(spellCheckerSelection, wordRange);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[self, token](nsresult aRv) {
|
||||||
|
if (!self->mTextEditor || self->mTextEditor->Destroyed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token != self->mDisabledAsyncToken) {
|
||||||
|
// This result is never used
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->ChangeNumPendingSpellChecks(-1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// mozInlineSpellChecker::ResumeCheck
|
// mozInlineSpellChecker::ResumeCheck
|
||||||
//
|
//
|
||||||
// Called by the resume event when it fires. We will try to pick up where
|
// Called by the resume event when it fires. We will try to pick up where
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,11 @@
|
||||||
#include "nsIDOMEventListener.h"
|
#include "nsIDOMEventListener.h"
|
||||||
#include "nsIEditorSpellCheck.h"
|
#include "nsIEditorSpellCheck.h"
|
||||||
#include "nsIInlineSpellChecker.h"
|
#include "nsIInlineSpellChecker.h"
|
||||||
|
#include "mozInlineSpellWordUtil.h"
|
||||||
#include "nsRange.h"
|
#include "nsRange.h"
|
||||||
#include "nsWeakReference.h"
|
#include "nsWeakReference.h"
|
||||||
|
|
||||||
class InitEditorSpellCheckCallback;
|
class InitEditorSpellCheckCallback;
|
||||||
class mozInlineSpellWordUtil;
|
|
||||||
class mozInlineSpellChecker;
|
class mozInlineSpellChecker;
|
||||||
class mozInlineSpellResume;
|
class mozInlineSpellResume;
|
||||||
class UpdateCurrentDictionaryCallback;
|
class UpdateCurrentDictionaryCallback;
|
||||||
|
|
@ -52,11 +52,6 @@ class mozInlineSpellStatus {
|
||||||
|
|
||||||
RefPtr<mozInlineSpellChecker> mSpellChecker;
|
RefPtr<mozInlineSpellChecker> mSpellChecker;
|
||||||
|
|
||||||
// The total number of words checked in this sequence, using this tally tells
|
|
||||||
// us when to stop. This count is preserved as we continue checking in new
|
|
||||||
// messages.
|
|
||||||
int32_t mWordCount;
|
|
||||||
|
|
||||||
// what happened?
|
// what happened?
|
||||||
enum Operation {
|
enum Operation {
|
||||||
eOpChange, // for SpellCheckAfterEditorChange except
|
eOpChange, // for SpellCheckAfterEditorChange except
|
||||||
|
|
@ -139,13 +134,6 @@ class mozInlineSpellChecker final : public nsIInlineSpellChecker,
|
||||||
int32_t mNumWordsInSpellSelection;
|
int32_t mNumWordsInSpellSelection;
|
||||||
int32_t mMaxNumWordsInSpellSelection;
|
int32_t mMaxNumWordsInSpellSelection;
|
||||||
|
|
||||||
// How many misspellings we can add at once. This is often less than the max
|
|
||||||
// total number of misspellings. When you have a large textarea prepopulated
|
|
||||||
// with text with many misspellings, we can hit this limit. By making it
|
|
||||||
// lower than the total number of misspelled words, new text typed by the
|
|
||||||
// user can also have spellchecking in it.
|
|
||||||
int32_t mMaxMisspellingsPerCheck;
|
|
||||||
|
|
||||||
// we need to keep track of the current text position in the document
|
// we need to keep track of the current text position in the document
|
||||||
// so we can spell check the old word when the user clicks around the
|
// so we can spell check the old word when the user clicks around the
|
||||||
// document.
|
// document.
|
||||||
|
|
@ -282,6 +270,10 @@ class mozInlineSpellChecker final : public nsIInlineSpellChecker,
|
||||||
|
|
||||||
void StartToListenToEditSubActions() { mIsListeningToEditSubActions = true; }
|
void StartToListenToEditSubActions() { mIsListeningToEditSubActions = true; }
|
||||||
void EndListeningToEditSubActions() { mIsListeningToEditSubActions = false; }
|
void EndListeningToEditSubActions() { mIsListeningToEditSubActions = false; }
|
||||||
|
|
||||||
|
void CheckCurrentWordsNoSuggest(mozilla::dom::Selection* aSpellCheckSelection,
|
||||||
|
const nsTArray<nsString>& aWords,
|
||||||
|
const nsTArray<NodeOffsetRange>& aRanges);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // #ifndef mozilla_mozInlineSpellChecker_h
|
#endif // #ifndef mozilla_mozInlineSpellChecker_h
|
||||||
|
|
|
||||||
|
|
@ -330,6 +330,19 @@ nsresult mozInlineSpellWordUtil::MakeRange(NodeOffset aBegin, NodeOffset aEnd,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
already_AddRefed<nsRange> mozInlineSpellWordUtil::MakeRange(
|
||||||
|
const NodeOffsetRange& aRange) {
|
||||||
|
RefPtr<nsRange> range = new nsRange(aRange.Begin().Node());
|
||||||
|
nsresult rv =
|
||||||
|
range->SetStartAndEnd(aRange.Begin().Node(), aRange.Begin().Offset(),
|
||||||
|
aRange.End().Node(), aRange.End().Offset());
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return range.forget();
|
||||||
|
}
|
||||||
|
|
||||||
/*********** Word Splitting ************/
|
/*********** Word Splitting ************/
|
||||||
|
|
||||||
// classifies a given character in the DOM word
|
// classifies a given character in the DOM word
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,10 @@ class TextEditor;
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
struct NodeOffset {
|
struct NodeOffset {
|
||||||
nsINode* mNode;
|
nsCOMPtr<nsINode> mNode;
|
||||||
int32_t mOffset;
|
int32_t mOffset;
|
||||||
|
|
||||||
NodeOffset() : mNode(nullptr), mOffset(0) {}
|
NodeOffset() : mOffset(0) {}
|
||||||
NodeOffset(nsINode* aNode, int32_t aOffset)
|
NodeOffset(nsINode* aNode, int32_t aOffset)
|
||||||
: mNode(aNode), mOffset(aOffset) {}
|
: mNode(aNode), mOffset(aOffset) {}
|
||||||
|
|
||||||
|
|
@ -34,6 +34,9 @@ struct NodeOffset {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const NodeOffset& aOther) const { return !(*this == aOther); }
|
bool operator!=(const NodeOffset& aOther) const { return !(*this == aOther); }
|
||||||
|
|
||||||
|
nsINode* Node() const { return mNode.get(); }
|
||||||
|
int32_t Offset() const { return mOffset; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class NodeOffsetRange {
|
class NodeOffsetRange {
|
||||||
|
|
@ -47,11 +50,11 @@ class NodeOffsetRange {
|
||||||
NodeOffsetRange(NodeOffset b, NodeOffset e)
|
NodeOffsetRange(NodeOffset b, NodeOffset e)
|
||||||
: mBegin(b), mEnd(e), mEmpty(false) {}
|
: mBegin(b), mEnd(e), mEmpty(false) {}
|
||||||
|
|
||||||
NodeOffset Begin() { return mBegin; }
|
NodeOffset Begin() const { return mBegin; }
|
||||||
|
|
||||||
NodeOffset End() { return mEnd; }
|
NodeOffset End() const { return mEnd; }
|
||||||
|
|
||||||
bool Empty() { return mEmpty; }
|
bool Empty() const { return mEmpty; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -104,6 +107,7 @@ class MOZ_STACK_CLASS mozInlineSpellWordUtil {
|
||||||
|
|
||||||
// Convenience functions, object must be initialized
|
// Convenience functions, object must be initialized
|
||||||
nsresult MakeRange(NodeOffset aBegin, NodeOffset aEnd, nsRange** aRange);
|
nsresult MakeRange(NodeOffset aBegin, NodeOffset aEnd, nsRange** aRange);
|
||||||
|
static already_AddRefed<nsRange> MakeRange(const NodeOffsetRange& aRange);
|
||||||
|
|
||||||
// Moves to the the next word in the range, and retrieves it's text and range.
|
// Moves to the the next word in the range, and retrieves it's text and range.
|
||||||
// An empty word and a nullptr range are returned when we are done checking.
|
// An empty word and a nullptr range are returned when we are done checking.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue