зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1533293 - part 2: Rewrite EditorBase::SelectEntireDocument() and its overrides r=m_kato
`EditorBase::SelectEntierDocument()` uses `Selection::Extend()` but it's too slow. It should use `Selection::SetStartAndEndInLimiter()` instead. Additionally, `TextEditor::SelectEntierDocument()` shrink the result of `EditorBase::SelectEntierDocument()` with `Selection::Extend()` if there is a `moz-<br>` element. So, `TextEditor::SelectEntinerDocument()` should set its expected selection with a call for saving the runtime cost. Then, we don't need to make `EditorBase::SelectEntierDocument()` as non-pure virtual method. So, this patch makes each its callers call `Selection->SelectAllChildren()` directly. Differential Revision: https://phabricator.services.mozilla.com/D23461 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
d4cbc09db8
Коммит
448571fd81
|
@ -2301,7 +2301,9 @@ bool nsTextEditorState::SetValue(const nsAString& aValue,
|
||||||
// transactions typed by user shouldn't be merged with this).
|
// transactions typed by user shouldn't be merged with this).
|
||||||
// In this case, we need to dispatch "input" event because
|
// In this case, we need to dispatch "input" event because
|
||||||
// web apps may need to know the user's operation.
|
// web apps may need to know the user's operation.
|
||||||
DebugOnly<nsresult> rv = textEditor->ReplaceTextAsAction(newValue);
|
RefPtr<nsRange> range; // See bug 1506439
|
||||||
|
DebugOnly<nsresult> rv =
|
||||||
|
textEditor->ReplaceTextAsAction(newValue, range);
|
||||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||||
"Failed to set the new value");
|
"Failed to set the new value");
|
||||||
} else if (aFlags & eSetValue_ForXUL) {
|
} else if (aFlags & eSetValue_ForXUL) {
|
||||||
|
|
|
@ -2660,19 +2660,6 @@ nsresult EditorBase::InsertTextIntoTextNodeWithTransaction(
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult EditorBase::SelectEntireDocument() {
|
|
||||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
|
||||||
|
|
||||||
Element* rootElement = GetRoot();
|
|
||||||
if (!rootElement) {
|
|
||||||
return NS_ERROR_NOT_INITIALIZED;
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorResult errorResult;
|
|
||||||
SelectionRefPtr()->SelectAllChildren(*rootElement, errorResult);
|
|
||||||
return errorResult.StealNSResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
nsINode* EditorBase::GetFirstEditableNode(nsINode* aRoot) {
|
nsINode* EditorBase::GetFirstEditableNode(nsINode* aRoot) {
|
||||||
MOZ_ASSERT(aRoot);
|
MOZ_ASSERT(aRoot);
|
||||||
|
|
||||||
|
|
|
@ -1816,6 +1816,7 @@ class EditorBase : public nsIEditor,
|
||||||
* because SelectAll() creates AutoEditActionSetter but we should avoid
|
* because SelectAll() creates AutoEditActionSetter but we should avoid
|
||||||
* to create it as far as possible.
|
* to create it as far as possible.
|
||||||
*/
|
*/
|
||||||
|
MOZ_CAN_RUN_SCRIPT
|
||||||
virtual nsresult SelectAllInternal();
|
virtual nsresult SelectAllInternal();
|
||||||
|
|
||||||
nsresult DetermineCurrentDirection();
|
nsresult DetermineCurrentDirection();
|
||||||
|
@ -1860,7 +1861,8 @@ class EditorBase : public nsIEditor,
|
||||||
/**
|
/**
|
||||||
* Make the given selection span the entire document.
|
* Make the given selection span the entire document.
|
||||||
*/
|
*/
|
||||||
virtual nsresult SelectEntireDocument();
|
MOZ_CAN_RUN_SCRIPT
|
||||||
|
virtual nsresult SelectEntireDocument() = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method for scrolling the selection into view after
|
* Helper method for scrolling the selection into view after
|
||||||
|
|
|
@ -695,7 +695,7 @@ SelectAllCommand::DoCommand(const char* aCommandName,
|
||||||
}
|
}
|
||||||
TextEditor* textEditor = editor->AsTextEditor();
|
TextEditor* textEditor = editor->AsTextEditor();
|
||||||
MOZ_ASSERT(textEditor);
|
MOZ_ASSERT(textEditor);
|
||||||
return textEditor->SelectAll();
|
return MOZ_KnownLive(textEditor)->SelectAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
|
|
|
@ -3603,23 +3603,31 @@ nsresult HTMLEditor::SelectEntireDocument() {
|
||||||
return NS_ERROR_NULL_POINTER;
|
return NS_ERROR_NULL_POINTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RefPtr<Element> rootElement = GetRoot();
|
||||||
|
if (NS_WARN_IF(!rootElement)) {
|
||||||
|
return NS_ERROR_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
|
||||||
// Protect the edit rules object from dying
|
// Protect the edit rules object from dying
|
||||||
RefPtr<TextEditRules> rules(mRules);
|
RefPtr<TextEditRules> rules(mRules);
|
||||||
|
|
||||||
// is doc empty?
|
// If we're empty, don't select all children because that would select the
|
||||||
|
// bogus node.
|
||||||
if (rules->DocumentIsEmpty()) {
|
if (rules->DocumentIsEmpty()) {
|
||||||
// get editor root node
|
|
||||||
Element* rootElement = GetRoot();
|
|
||||||
|
|
||||||
// if its empty dont select entire doc - that would select the bogus node
|
|
||||||
nsresult rv = SelectionRefPtr()->Collapse(rootElement, 0);
|
nsresult rv = SelectionRefPtr()->Collapse(rootElement, 0);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
NS_WARNING_ASSERTION(
|
||||||
return rv;
|
NS_SUCCEEDED(rv),
|
||||||
}
|
"Failed to move caret to start of the editor root element");
|
||||||
return NS_OK;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
return EditorBase::SelectEntireDocument();
|
// Otherwise, select all children.
|
||||||
|
ErrorResult error;
|
||||||
|
SelectionRefPtr()->SelectAllChildren(*rootElement, error);
|
||||||
|
NS_WARNING_ASSERTION(
|
||||||
|
!error.Failed(),
|
||||||
|
"Failed to select all children of the editor root element");
|
||||||
|
return error.StealNSResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult HTMLEditor::SelectAllInternal() {
|
nsresult HTMLEditor::SelectAllInternal() {
|
||||||
|
|
|
@ -955,6 +955,7 @@ class HTMLEditor final : public TextEditor,
|
||||||
*/
|
*/
|
||||||
nsresult InsertParagraphSeparatorAsSubAction();
|
nsresult InsertParagraphSeparatorAsSubAction();
|
||||||
|
|
||||||
|
MOZ_CAN_RUN_SCRIPT
|
||||||
virtual nsresult SelectAllInternal() override;
|
virtual nsresult SelectAllInternal() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1521,6 +1522,7 @@ class HTMLEditor final : public TextEditor,
|
||||||
/**
|
/**
|
||||||
* Make the given selection span the entire document.
|
* Make the given selection span the entire document.
|
||||||
*/
|
*/
|
||||||
|
MOZ_CAN_RUN_SCRIPT
|
||||||
virtual nsresult SelectEntireDocument() override;
|
virtual nsresult SelectEntireDocument() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1198,18 +1198,25 @@ nsresult TextEditor::SetTextAsSubAction(const nsAString& aString) {
|
||||||
// shouldn't receive such selectionchange before the first mutation.
|
// shouldn't receive such selectionchange before the first mutation.
|
||||||
AutoUpdateViewBatch preventSelectionChangeEvent(*this);
|
AutoUpdateViewBatch preventSelectionChangeEvent(*this);
|
||||||
|
|
||||||
|
Element* rootElement = GetRoot();
|
||||||
|
if (NS_WARN_IF(!rootElement)) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
// We want to select trailing BR node to remove all nodes to replace all,
|
// We want to select trailing BR node to remove all nodes to replace all,
|
||||||
// but TextEditor::SelectEntireDocument doesn't select that BR node.
|
// but TextEditor::SelectEntireDocument doesn't select that BR node.
|
||||||
if (rules->DocumentIsEmpty()) {
|
if (rules->DocumentIsEmpty()) {
|
||||||
// if it's empty, don't select entire doc - that would select
|
|
||||||
// the bogus node
|
|
||||||
Element* rootElement = GetRoot();
|
|
||||||
if (NS_WARN_IF(!rootElement)) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
rv = SelectionRefPtr()->Collapse(rootElement, 0);
|
rv = SelectionRefPtr()->Collapse(rootElement, 0);
|
||||||
|
NS_WARNING_ASSERTION(
|
||||||
|
NS_SUCCEEDED(rv),
|
||||||
|
"Failed to move caret to start of the editor root element");
|
||||||
} else {
|
} else {
|
||||||
rv = EditorBase::SelectEntireDocument();
|
ErrorResult error;
|
||||||
|
SelectionRefPtr()->SelectAllChildren(*rootElement, error);
|
||||||
|
NS_WARNING_ASSERTION(
|
||||||
|
!error.Failed(),
|
||||||
|
"Failed to select all children of the editor root element");
|
||||||
|
rv = error.StealNSResult();
|
||||||
}
|
}
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
rv = ReplaceSelectionAsSubAction(aString);
|
rv = ReplaceSelectionAsSubAction(aString);
|
||||||
|
@ -2143,31 +2150,28 @@ nsresult TextEditor::SelectEntireDocument() {
|
||||||
return NS_ERROR_NULL_POINTER;
|
return NS_ERROR_NULL_POINTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Element* rootElement = GetRoot();
|
||||||
|
if (NS_WARN_IF(!rootElement)) {
|
||||||
|
return NS_ERROR_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
|
||||||
// Protect the edit rules object from dying
|
// Protect the edit rules object from dying
|
||||||
RefPtr<TextEditRules> rules(mRules);
|
RefPtr<TextEditRules> rules(mRules);
|
||||||
|
|
||||||
// is doc empty?
|
// If we're empty, don't select all children because that would select the
|
||||||
|
// bogus node.
|
||||||
if (rules->DocumentIsEmpty()) {
|
if (rules->DocumentIsEmpty()) {
|
||||||
// get root node
|
nsresult rv = SelectionRefPtr()->Collapse(rootElement, 0);
|
||||||
Element* rootElement = GetRoot();
|
NS_WARNING_ASSERTION(
|
||||||
if (NS_WARN_IF(!rootElement)) {
|
NS_SUCCEEDED(rv),
|
||||||
return NS_ERROR_FAILURE;
|
"Failed to move caret to start of the editor root element");
|
||||||
}
|
|
||||||
|
|
||||||
// if it's empty don't select entire doc - that would select the bogus node
|
|
||||||
return SelectionRefPtr()->Collapse(rootElement, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
SelectionBatcher selectionBatcher(SelectionRefPtr());
|
|
||||||
nsresult rv = EditorBase::SelectEntireDocument();
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't select the trailing BR node if we have one
|
// Don't select the trailing BR node if we have one
|
||||||
nsCOMPtr<nsIContent> childNode;
|
nsCOMPtr<nsIContent> childNode;
|
||||||
rv = EditorBase::GetEndChildNode(*SelectionRefPtr(),
|
nsresult rv = EditorBase::GetEndChildNode(*SelectionRefPtr(),
|
||||||
getter_AddRefs(childNode));
|
getter_AddRefs(childNode));
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -2176,13 +2180,22 @@ nsresult TextEditor::SelectEntireDocument() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (childNode && TextEditUtils::IsMozBR(childNode)) {
|
if (childNode && TextEditUtils::IsMozBR(childNode)) {
|
||||||
int32_t parentOffset;
|
ErrorResult error;
|
||||||
nsINode* parentNode = GetNodeLocation(childNode, &parentOffset);
|
MOZ_KnownLive(SelectionRefPtr())
|
||||||
|
->SetStartAndEndInLimiter(RawRangeBoundary(rootElement, 0),
|
||||||
return SelectionRefPtr()->Extend(parentNode, parentOffset);
|
EditorRawDOMPoint(childNode), error);
|
||||||
|
NS_WARNING_ASSERTION(!error.Failed(),
|
||||||
|
"Failed to select all children of the editor root "
|
||||||
|
"element except the moz-<br> element");
|
||||||
|
return error.StealNSResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
ErrorResult error;
|
||||||
|
SelectionRefPtr()->SelectAllChildren(*rootElement, error);
|
||||||
|
NS_WARNING_ASSERTION(
|
||||||
|
!error.Failed(),
|
||||||
|
"Failed to select all children of the editor root element");
|
||||||
|
return error.StealNSResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
EventTarget* TextEditor::GetDOMEventTarget() { return mEventTarget; }
|
EventTarget* TextEditor::GetDOMEventTarget() { return mEventTarget; }
|
||||||
|
|
|
@ -173,6 +173,7 @@ class TextEditor : public EditorBase, public nsIPlaintextEditor {
|
||||||
*
|
*
|
||||||
* @ param aString the string to be set
|
* @ param aString the string to be set
|
||||||
*/
|
*/
|
||||||
|
MOZ_CAN_RUN_SCRIPT
|
||||||
nsresult SetText(const nsAString& aString);
|
nsresult SetText(const nsAString& aString);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -183,6 +184,7 @@ class TextEditor : public EditorBase, public nsIPlaintextEditor {
|
||||||
* @param aReplaceRange The range to be replaced.
|
* @param aReplaceRange The range to be replaced.
|
||||||
* If nullptr, all contents will be replaced.
|
* If nullptr, all contents will be replaced.
|
||||||
*/
|
*/
|
||||||
|
MOZ_CAN_RUN_SCRIPT
|
||||||
nsresult ReplaceTextAsAction(const nsAString& aString,
|
nsresult ReplaceTextAsAction(const nsAString& aString,
|
||||||
nsRange* aReplaceRange = nullptr);
|
nsRange* aReplaceRange = nullptr);
|
||||||
|
|
||||||
|
@ -365,6 +367,7 @@ class TextEditor : public EditorBase, public nsIPlaintextEditor {
|
||||||
/**
|
/**
|
||||||
* Make the given selection span the entire document.
|
* Make the given selection span the entire document.
|
||||||
*/
|
*/
|
||||||
|
MOZ_CAN_RUN_SCRIPT
|
||||||
virtual nsresult SelectEntireDocument() override;
|
virtual nsresult SelectEntireDocument() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -305,6 +305,7 @@ interface nsIEditor : nsISupports
|
||||||
/* ------------ Selection methods -------------- */
|
/* ------------ Selection methods -------------- */
|
||||||
|
|
||||||
/** sets the document selection to the entire contents of the document */
|
/** sets the document selection to the entire contents of the document */
|
||||||
|
[can_run_script]
|
||||||
void selectAll();
|
void selectAll();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -30,6 +30,7 @@ interface nsIEditorMailSupport : nsISupports
|
||||||
* Rewrap the selected part of the document, re-quoting if necessary.
|
* Rewrap the selected part of the document, re-quoting if necessary.
|
||||||
* @param aRespectNewlines Try to maintain newlines in the original?
|
* @param aRespectNewlines Try to maintain newlines in the original?
|
||||||
*/
|
*/
|
||||||
|
[can_run_script]
|
||||||
void rewrap(in boolean aRespectNewlines);
|
void rewrap(in boolean aRespectNewlines);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -147,6 +147,7 @@ interface nsIHTMLEditor : nsISupports
|
||||||
*
|
*
|
||||||
* @param aSourceString HTML source string of the entire new document
|
* @param aSourceString HTML source string of the entire new document
|
||||||
*/
|
*/
|
||||||
|
[can_run_script]
|
||||||
void rebuildDocumentFromSource(in AString aSourceString);
|
void rebuildDocumentFromSource(in AString aSourceString);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -25,6 +25,7 @@ interface nsIInlineSpellChecker : nsISupports
|
||||||
void spellCheckRange(in Range aSelection);
|
void spellCheckRange(in Range aSelection);
|
||||||
|
|
||||||
Range getMisspelledWord(in Node aNode, in long aOffset);
|
Range getMisspelledWord(in Node aNode, in long aOffset);
|
||||||
|
[can_run_script]
|
||||||
void replaceWord(in Node aNode, in long aOffset, in AString aNewword);
|
void replaceWord(in Node aNode, in long aOffset, in AString aNewword);
|
||||||
void addWordToDictionary(in AString aWord);
|
void addWordToDictionary(in AString aWord);
|
||||||
void removeWordFromDictionary(in AString aWord);
|
void removeWordFromDictionary(in AString aWord);
|
||||||
|
|
|
@ -869,7 +869,8 @@ mozInlineSpellChecker::ReplaceWord(nsINode* aNode, int32_t aOffset,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugOnly<nsresult> rv = mTextEditor->ReplaceTextAsAction(newword, range);
|
RefPtr<TextEditor> textEditor(mTextEditor);
|
||||||
|
DebugOnly<nsresult> rv = textEditor->ReplaceTextAsAction(newword, range);
|
||||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to insert the new word");
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to insert the new word");
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче