Bug 1396980 - Spending too much time making ranges for spellchecker on Facebook page, r=smaug

This commit is contained in:
jj.evelyn@gmail.com 2018-01-06 16:10:29 +02:00
Родитель 042dcb26b0
Коммит 5a9bc69d68
3 изменённых файлов: 86 добавлений и 44 удалений

Просмотреть файл

@ -1491,23 +1491,17 @@ nsresult mozInlineSpellChecker::DoSpellCheck(mozInlineSpellWordUtil& aWordUtil,
PRTime beginTime = PR_Now();
nsAutoString wordText;
RefPtr<nsRange> wordRange;
NodeOffsetRange wordNodeOffsetRange;
bool dontCheckWord;
while (NS_SUCCEEDED(aWordUtil.GetNextWord(wordText,
getter_AddRefs(wordRange),
while (NS_SUCCEEDED(aWordUtil.GetNextWord(wordText, &wordNodeOffsetRange,
&dontCheckWord)) &&
wordRange) {
!wordNodeOffsetRange.Empty()) {
// get the range for the current word.
nsINode *beginNode;
nsINode *endNode;
int32_t beginOffset, endOffset;
ErrorResult erv;
beginNode = wordRange->GetStartContainer(erv);
endNode = wordRange->GetEndContainer(erv);
beginOffset = wordRange->GetStartOffset(erv);
endOffset = wordRange->GetEndOffset(erv);
nsINode* beginNode = wordNodeOffsetRange.Begin().mNode;
nsINode* endNode = wordNodeOffsetRange.End().mNode;
int32_t beginOffset = wordNodeOffsetRange.Begin().mOffset;
int32_t endOffset = wordNodeOffsetRange.End().mOffset;
// see if we've done enough words in this round and run out of time.
if (wordsChecked >= INLINESPELL_MINIMUM_WORDS_BEFORE_TIMEOUT &&
@ -1535,6 +1529,7 @@ nsresult mozInlineSpellChecker::DoSpellCheck(mozInlineSpellWordUtil& aWordUtil,
printf("\n");
#endif
ErrorResult erv;
// see if there is a spellcheck range that already intersects the word
// and remove it. We only need to remove old ranges, so don't bother if
// there were no ranges when we started out.
@ -1582,15 +1577,19 @@ nsresult mozInlineSpellChecker::DoSpellCheck(mozInlineSpellWordUtil& aWordUtil,
continue;
wordsChecked++;
if (isMisspelled) {
// misspelled words count extra toward the max
AddRange(aSpellCheckSelection, wordRange);
aStatus->mWordCount ++;
if (aStatus->mWordCount >= mMaxMisspellingsPerCheck ||
SpellCheckSelectionIsFull()) {
break;
RefPtr<nsRange> wordRange;
// If we somehow can't make a range for this word, just ignore it.
if(NS_SUCCEEDED(aWordUtil.MakeRange(wordNodeOffsetRange.Begin(),
wordNodeOffsetRange.End(),
getter_AddRefs(wordRange)))) {
AddRange(aSpellCheckSelection, wordRange);
aStatus->mWordCount++;
if (aStatus->mWordCount >= mMaxMisspellingsPerCheck ||
SpellCheckSelectionIsFull()) {
break;
}
}
}
}

Просмотреть файл

@ -231,6 +231,14 @@ mozInlineSpellWordUtil::MakeRangeForWord(const RealWord& aWord, nsRange** aRange
NodeOffset end = MapSoftTextOffsetToDOMPosition(aWord.EndOffset(), HINT_END);
return MakeRange(begin, end, aRange);
}
void
mozInlineSpellWordUtil::MakeNodeOffsetRangeForWord(const RealWord& aWord,
NodeOffsetRange* aNodeOffsetRange)
{
NodeOffset begin = MapSoftTextOffsetToDOMPosition(aWord.mSoftTextOffset, HINT_BEGIN);
NodeOffset end = MapSoftTextOffsetToDOMPosition(aWord.EndOffset(), HINT_END);
*aNodeOffsetRange = NodeOffsetRange(begin, end);
}
// mozInlineSpellWordUtil::GetRangeForWord
@ -289,7 +297,8 @@ NormalizeWord(const nsAString& aInput, int32_t aPos, int32_t aLen, nsAString& aO
// range unless the word was misspelled. This may or may not be possible.
nsresult
mozInlineSpellWordUtil::GetNextWord(nsAString& aText, nsRange** aRange,
mozInlineSpellWordUtil::GetNextWord(nsAString& aText,
NodeOffsetRange* aNodeOffsetRange,
bool* aSkipChecking)
{
#ifdef DEBUG_SPELLCHECK
@ -299,14 +308,13 @@ mozInlineSpellWordUtil::GetNextWord(nsAString& aText, nsRange** aRange,
if (mNextWordIndex < 0 ||
mNextWordIndex >= int32_t(mRealWords.Length())) {
mNextWordIndex = -1;
*aRange = nullptr;
*aNodeOffsetRange = NodeOffsetRange();
*aSkipChecking = true;
return NS_OK;
}
const RealWord& word = mRealWords[mNextWordIndex];
nsresult rv = MakeRangeForWord(word, aRange);
NS_ENSURE_SUCCESS(rv, rv);
MakeNodeOffsetRangeForWord(word, aNodeOffsetRange);
++mNextWordIndex;
*aSkipChecking = !word.mCheckableWord;
::NormalizeWord(mSoftText, word.mSoftTextOffset, word.mLength, aText);
@ -965,7 +973,7 @@ FindLastNongreaterOffset(const nsTArray<T>& aContainer, int32_t aSoftTextOffset,
} // namespace
mozInlineSpellWordUtil::NodeOffset
NodeOffset
mozInlineSpellWordUtil::MapSoftTextOffsetToDOMPosition(int32_t aSoftTextOffset,
DOMMapHint aHint)
{

Просмотреть файл

@ -21,6 +21,53 @@ namespace mozilla {
class TextEditor;
} // namespace mozilla
struct NodeOffset
{
nsINode* mNode;
int32_t mOffset;
NodeOffset(): mNode(nullptr), mOffset(0) {}
NodeOffset(nsINode* aNode, int32_t aOffset)
: mNode(aNode), mOffset(aOffset) {}
bool operator==(const NodeOffset& aOther) const
{
return mNode == aOther.mNode && mOffset == aOther.mOffset;
}
bool operator!=(const NodeOffset& aOther) const
{
return !(*this == aOther);
}
};
class NodeOffsetRange
{
private:
NodeOffset mBegin;
NodeOffset mEnd;
bool mEmpty;
public:
NodeOffsetRange() : mEmpty(true) {}
NodeOffsetRange(NodeOffset b, NodeOffset e)
: mBegin(b), mEnd(e), mEmpty(false) {}
NodeOffset Begin()
{
return mBegin;
}
NodeOffset End()
{
return mEnd;
}
bool Empty()
{
return mEmpty;
}
};
/**
* This class extracts text from the DOM and builds it into a single string.
* The string includes whitespace breaks whereever non-inline elements begin
@ -44,22 +91,6 @@ class TextEditor;
class mozInlineSpellWordUtil
{
public:
struct NodeOffset {
nsINode* mNode;
int32_t mOffset;
NodeOffset(nsINode* aNode, int32_t aOffset) :
mNode(aNode), mOffset(aOffset) {}
bool operator==(const NodeOffset& aOther) const {
return mNode == aOther.mNode && mOffset == aOther.mOffset;
}
bool operator!=(const NodeOffset& aOther) const {
return !(*this == aOther);
}
};
mozInlineSpellWordUtil()
: mRootNode(nullptr),
mSoftBegin(nullptr, 0), mSoftEnd(nullptr, 0),
@ -85,11 +116,15 @@ public:
nsresult GetRangeForWord(nsIDOMNode* aWordNode, int32_t aWordOffset,
nsRange** aRange);
// Convenience functions, object must be initialized
nsresult MakeRange(NodeOffset aBegin, NodeOffset aEnd, nsRange** aRange);
// 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.
// aSkipChecking will be set if the word is "special" and shouldn't be
// checked (e.g., an email address).
nsresult GetNextWord(nsAString& aText, nsRange** aRange,
nsresult GetNextWord(nsAString& aText,
NodeOffsetRange* aNodeOffsetRange,
bool* aSkipChecking);
// Call to normalize some punctuation. This function takes an autostring
@ -175,9 +210,9 @@ private:
nsresult SplitDOMWord(int32_t aStart, int32_t aEnd);
// Convenience functions, object must be initialized
nsresult MakeRange(NodeOffset aBegin, NodeOffset aEnd, nsRange** aRange);
nsresult MakeRangeForWord(const RealWord& aWord, nsRange** aRange);
void MakeNodeOffsetRangeForWord(const RealWord& aWord,
NodeOffsetRange* aNodeOffsetRange);
};
#endif