Bug 344895 - Spellchecker hangs Firefox when dealing with a largish textarea, patch by brettw, r+sr=roc

This commit is contained in:
martijn.martijn%gmail.com 2006-07-19 19:57:34 +00:00
Родитель a33c51bdb1
Коммит b4ce183f8f
2 изменённых файлов: 54 добавлений и 16 удалений

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

@ -102,7 +102,7 @@ mozInlineSpellChecker::SpellCheckingState
mozInlineSpellChecker::gCanEnableSpellChecking =
mozInlineSpellChecker::SpellCheck_Uninitialized;
mozInlineSpellChecker::mozInlineSpellChecker():mNumWordsInSpellSelection(0), mMaxNumWordsInSpellSelection(250)
mozInlineSpellChecker::mozInlineSpellChecker():mNumWordsInSpellSelection(0),mMaxNumWordsInSpellSelection(250)
{
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
if (prefs)
@ -261,7 +261,10 @@ mozInlineSpellChecker::SetEnableRealTimeSpell(PRBool aEnabled)
}
}
// spellcheck the current content
// spellcheck the current contents. SpellCheckRange doesn't supply a created
// range to DoSpellCheck, which in our case is the entire range. But this
// optimization doesn't matter because there is nothing in the spellcheck
// selection when starting, which triggers a better optimization.
res = SpellCheckRange(nsnull);
}
else
@ -367,7 +370,13 @@ mozInlineSpellChecker::SpellCheckAfterEditorChange(
}
if (rangeToCheck) {
rv = DoSpellCheck(wordUtil, rangeToCheck, wordRange, spellCheckSelection);
if (aAction == kOpInsertText) {
rv = DoSpellCheck(wordUtil, rangeToCheck, wordRange, rangeToCheck,
spellCheckSelection);
} else {
rv = DoSpellCheck(wordUtil, rangeToCheck, wordRange, nsnull,
spellCheckSelection);
}
NS_ENSURE_SUCCESS(rv, rv);
}
@ -397,7 +406,7 @@ mozInlineSpellChecker::SpellCheckRange(nsIDOMRange* aRange)
rv = wordUtil.Init(mEditor);
if (NS_FAILED(rv))
return NS_OK; // editor doesn't like us
rv = DoSpellCheck(wordUtil, aRange, nsnull, spellCheckSelection);
rv = DoSpellCheck(wordUtil, aRange, nsnull, nsnull, spellCheckSelection);
} else
{
// use full range: SpellCheckBetweenNodes will do the somewhat complicated
@ -524,6 +533,9 @@ mozInlineSpellChecker::IgnoreWords(const PRUnichar **aWordsToIgnore,
// selection (i.e. words previsouly marked as misspelled). Therefore callers
// spell check the spell check selection instead of the entire document for
// ignore word and add word.
//
// FIXME TODO Performance: Make sure this works nicely with the empty
// selection optimization of DoSpellCheck
nsresult
mozInlineSpellChecker::SpellCheckSelection(nsISelection* aSelection)
@ -748,7 +760,7 @@ mozInlineSpellChecker::SpellCheckBetweenNodes(nsIDOMNode *aStartNode,
res = wordUtil.Init(mEditor);
if (NS_FAILED(res))
return NS_OK; // editor doesn't like us
return DoSpellCheck(wordUtil, range, nsnull, spellCheckSelection);
return DoSpellCheck(wordUtil, range, nsnull, nsnull, spellCheckSelection);
}
static inline PRBool IsNonwordChar(PRUnichar chr)
@ -827,6 +839,11 @@ mozInlineSpellChecker::SkipSpellCheckForNode(nsIDOMNode *aNode,
// any spell selection removed (this is used to hide the underlining for the
// word that the caret is in). aNoCheckRange should be on word boundaries.
//
// aCreatedRange is a possibly NULL range of new text that was inserted.
// Inside this range, we don't bother to check whether things are inside
// the spellcheck selection, which speeds up large paste operations
// considerably.
//
// Normal case when editing text by typing
// h e l l o w o r k d h o w a r e y o u
// ^ caret
@ -844,6 +861,7 @@ mozInlineSpellChecker::SkipSpellCheckForNode(nsIDOMNode *aNode,
nsresult mozInlineSpellChecker::DoSpellCheck(mozInlineSpellWordUtil& aWordUtil,
nsIDOMRange *aRange,
nsIDOMRange *aNoCheckRange,
nsIDOMRange *aCreatedRange,
nsISelection *aSpellCheckSelection)
{
nsCOMPtr<nsIDOMNode> beginNode, endNode;
@ -855,6 +873,13 @@ nsresult mozInlineSpellChecker::DoSpellCheck(mozInlineSpellWordUtil& aWordUtil,
if (iscollapsed)
return NS_OK;
// see if the selection has any ranges, if not, then we can optimize checking
// range inclusion later (we have no ranges when we are initially checking or
// when there are no misspelled words yet).
PRInt32 originalRangeCount;
rv = aSpellCheckSelection->GetRangeCount(&originalRangeCount);
NS_ENSURE_SUCCESS(rv, rv);
// set the starting DOM position to be the beginning of our range
NS_ENSURE_SUCCESS(rv, rv);
aRange->GetStartContainer(getter_AddRefs(beginNode));
@ -865,9 +890,11 @@ nsresult mozInlineSpellChecker::DoSpellCheck(mozInlineSpellWordUtil& aWordUtil,
aWordUtil.SetPosition(beginNode, beginOffset);
// we need to use IsPointInRange which is on a more specific interface
nsCOMPtr<nsIDOMNSRange> noCheckRange;
nsCOMPtr<nsIDOMNSRange> noCheckRange, createdRange;
if (aNoCheckRange)
noCheckRange = do_QueryInterface(aNoCheckRange);
if (aCreatedRange)
createdRange = do_QueryInterface(aCreatedRange);
nsAutoString wordText;
nsCOMPtr<nsIDOMRange> wordRange;
@ -890,15 +917,24 @@ nsresult mozInlineSpellChecker::DoSpellCheck(mozInlineSpellWordUtil& aWordUtil,
#endif
// see if there is a spellcheck range that already intersects the word
// and remove it
nsCOMPtr<nsIDOMRange> currentRange;
IsPointInSelection(aSpellCheckSelection, beginNode, beginOffset,
getter_AddRefs(currentRange));
if (!currentRange)
IsPointInSelection(aSpellCheckSelection, endNode, endOffset - 1,
getter_AddRefs(currentRange));
if (currentRange)
RemoveRange(aSpellCheckSelection, currentRange);
// and remove it. We only need to remove old ranges, so don't bother if
// there were no ranges when we started out.
if (originalRangeCount > 0) {
// likewise, if this word is inside new text, we won't bother testing
PRBool inCreatedRange = PR_FALSE;
if (createdRange)
createdRange->IsPointInRange(beginNode, beginOffset, &inCreatedRange);
if (! inCreatedRange) {
nsCOMPtr<nsIDOMRange> currentRange;
IsPointInSelection(aSpellCheckSelection, beginNode, beginOffset,
getter_AddRefs(currentRange));
if (!currentRange)
IsPointInSelection(aSpellCheckSelection, endNode, endOffset - 1,
getter_AddRefs(currentRange));
if (currentRange)
RemoveRange(aSpellCheckSelection, currentRange);
}
}
// some words are special and don't need checking
if (dontCheckWord)
@ -1174,7 +1210,8 @@ mozInlineSpellChecker::HandleNavigationEvent(nsIDOMEvent* aEvent,
nsCOMPtr<nsISelection> spellCheckSelection;
GetSpellCheckSelection(getter_AddRefs(spellCheckSelection));
rv = DoSpellCheck(wordUtil, currentWordRange, nsnull, spellCheckSelection);
rv = DoSpellCheck(wordUtil, currentWordRange, nsnull, nsnull,
spellCheckSelection);
NS_ENSURE_SUCCESS(rv, rv);
}

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

@ -169,6 +169,7 @@ public:
// spell check the text contained within aRange
nsresult DoSpellCheck(mozInlineSpellWordUtil& aWordUtil,
nsIDOMRange *aRange, nsIDOMRange* aNoCheckRange,
nsIDOMRange *aCreatedRange,
nsISelection *aSpellCheckSelection);
// helper routine to determine if a point is inside of a the passed in selection.