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:
Masayuki Nakano 2019-03-18 01:51:53 +00:00
Родитель d4cbc09db8
Коммит 448571fd81
13 изменённых файлов: 77 добавлений и 55 удалений

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

@ -2301,7 +2301,9 @@ bool nsTextEditorState::SetValue(const nsAString& aValue,
// transactions typed by user shouldn't be merged with this).
// In this case, we need to dispatch "input" event because
// 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),
"Failed to set the new value");
} else if (aFlags & eSetValue_ForXUL) {

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

@ -2660,19 +2660,6 @@ nsresult EditorBase::InsertTextIntoTextNodeWithTransaction(
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) {
MOZ_ASSERT(aRoot);

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

@ -1816,6 +1816,7 @@ class EditorBase : public nsIEditor,
* because SelectAll() creates AutoEditActionSetter but we should avoid
* to create it as far as possible.
*/
MOZ_CAN_RUN_SCRIPT
virtual nsresult SelectAllInternal();
nsresult DetermineCurrentDirection();
@ -1860,7 +1861,8 @@ class EditorBase : public nsIEditor,
/**
* 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

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

@ -695,7 +695,7 @@ SelectAllCommand::DoCommand(const char* aCommandName,
}
TextEditor* textEditor = editor->AsTextEditor();
MOZ_ASSERT(textEditor);
return textEditor->SelectAll();
return MOZ_KnownLive(textEditor)->SelectAll();
}
NS_IMETHODIMP

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

@ -3603,23 +3603,31 @@ nsresult HTMLEditor::SelectEntireDocument() {
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
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()) {
// 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);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
NS_WARNING_ASSERTION(
NS_SUCCEEDED(rv),
"Failed to move caret to start of the editor root element");
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() {

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

@ -955,6 +955,7 @@ class HTMLEditor final : public TextEditor,
*/
nsresult InsertParagraphSeparatorAsSubAction();
MOZ_CAN_RUN_SCRIPT
virtual nsresult SelectAllInternal() override;
/**
@ -1521,6 +1522,7 @@ class HTMLEditor final : public TextEditor,
/**
* Make the given selection span the entire document.
*/
MOZ_CAN_RUN_SCRIPT
virtual nsresult SelectEntireDocument() override;
/**

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

@ -1198,18 +1198,25 @@ nsresult TextEditor::SetTextAsSubAction(const nsAString& aString) {
// shouldn't receive such selectionchange before the first mutation.
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,
// but TextEditor::SelectEntireDocument doesn't select that BR node.
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);
NS_WARNING_ASSERTION(
NS_SUCCEEDED(rv),
"Failed to move caret to start of the editor root element");
} 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)) {
rv = ReplaceSelectionAsSubAction(aString);
@ -2143,31 +2150,28 @@ nsresult TextEditor::SelectEntireDocument() {
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
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()) {
// get root node
Element* rootElement = GetRoot();
if (NS_WARN_IF(!rootElement)) {
return NS_ERROR_FAILURE;
}
// 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))) {
nsresult rv = SelectionRefPtr()->Collapse(rootElement, 0);
NS_WARNING_ASSERTION(
NS_SUCCEEDED(rv),
"Failed to move caret to start of the editor root element");
return rv;
}
// Don't select the trailing BR node if we have one
nsCOMPtr<nsIContent> childNode;
rv = EditorBase::GetEndChildNode(*SelectionRefPtr(),
getter_AddRefs(childNode));
nsresult rv = EditorBase::GetEndChildNode(*SelectionRefPtr(),
getter_AddRefs(childNode));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -2176,13 +2180,22 @@ nsresult TextEditor::SelectEntireDocument() {
}
if (childNode && TextEditUtils::IsMozBR(childNode)) {
int32_t parentOffset;
nsINode* parentNode = GetNodeLocation(childNode, &parentOffset);
return SelectionRefPtr()->Extend(parentNode, parentOffset);
ErrorResult error;
MOZ_KnownLive(SelectionRefPtr())
->SetStartAndEndInLimiter(RawRangeBoundary(rootElement, 0),
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; }

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

@ -173,6 +173,7 @@ class TextEditor : public EditorBase, public nsIPlaintextEditor {
*
* @ param aString the string to be set
*/
MOZ_CAN_RUN_SCRIPT
nsresult SetText(const nsAString& aString);
/**
@ -183,6 +184,7 @@ class TextEditor : public EditorBase, public nsIPlaintextEditor {
* @param aReplaceRange The range to be replaced.
* If nullptr, all contents will be replaced.
*/
MOZ_CAN_RUN_SCRIPT
nsresult ReplaceTextAsAction(const nsAString& aString,
nsRange* aReplaceRange = nullptr);
@ -365,6 +367,7 @@ class TextEditor : public EditorBase, public nsIPlaintextEditor {
/**
* Make the given selection span the entire document.
*/
MOZ_CAN_RUN_SCRIPT
virtual nsresult SelectEntireDocument() override;
/**

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

@ -305,6 +305,7 @@ interface nsIEditor : nsISupports
/* ------------ Selection methods -------------- */
/** sets the document selection to the entire contents of the document */
[can_run_script]
void selectAll();
/**

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

@ -30,6 +30,7 @@ interface nsIEditorMailSupport : nsISupports
* Rewrap the selected part of the document, re-quoting if necessary.
* @param aRespectNewlines Try to maintain newlines in the original?
*/
[can_run_script]
void rewrap(in boolean aRespectNewlines);
};

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

@ -147,6 +147,7 @@ interface nsIHTMLEditor : nsISupports
*
* @param aSourceString HTML source string of the entire new document
*/
[can_run_script]
void rebuildDocumentFromSource(in AString aSourceString);
/**

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

@ -25,6 +25,7 @@ interface nsIInlineSpellChecker : nsISupports
void spellCheckRange(in Range aSelection);
Range getMisspelledWord(in Node aNode, in long aOffset);
[can_run_script]
void replaceWord(in Node aNode, in long aOffset, in AString aNewword);
void addWordToDictionary(in AString aWord);
void removeWordFromDictionary(in AString aWord);

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

@ -869,7 +869,8 @@ mozInlineSpellChecker::ReplaceWord(nsINode* aNode, int32_t aOffset,
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");
return NS_OK;
}