зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1630168 - Make `HTMLEditor` stop adding same runnable method into the queue r=m_kato
When `HTMLEditor` is notified of content changes, it may add a runnable method `HTMLEditor::OnModifyDocument` or `HTMLEditor::NotifyRootChanged` for each notification. However, their code do not need running twice nor more. This could cause performance issues on complicated web apps which sets `innerHTML` at every key press. Differential Revision: https://phabricator.services.mozilla.com/D71001
This commit is contained in:
Родитель
3ef497088e
Коммит
9f7fb5bb0f
|
@ -11848,8 +11848,12 @@ EditActionResult HTMLEditor::AddZIndexAsSubAction(int32_t aChange) {
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult HTMLEditor::OnDocumentModified() {
|
nsresult HTMLEditor::OnDocumentModified() {
|
||||||
nsContentUtils::AddScriptRunner(NewRunnableMethod(
|
if (mPendingDocumentModifiedRunner) {
|
||||||
"HTMLEditor::OnModifyDocument", this, &HTMLEditor::OnModifyDocument));
|
return NS_OK; // We've already posted same runnable into the queue.
|
||||||
|
}
|
||||||
|
mPendingDocumentModifiedRunner = NewRunnableMethod(
|
||||||
|
"HTMLEditor::OnModifyDocument", this, &HTMLEditor::OnModifyDocument);
|
||||||
|
nsContentUtils::AddScriptRunner(do_AddRef(mPendingDocumentModifiedRunner));
|
||||||
// Be aware, if OnModifyDocument() may be called synchronously, the
|
// Be aware, if OnModifyDocument() may be called synchronously, the
|
||||||
// editor might have been destroyed here.
|
// editor might have been destroyed here.
|
||||||
return NS_WARN_IF(Destroyed()) ? NS_ERROR_EDITOR_DESTROYED : NS_OK;
|
return NS_WARN_IF(Destroyed()) ? NS_ERROR_EDITOR_DESTROYED : NS_OK;
|
||||||
|
|
|
@ -3650,11 +3650,18 @@ void HTMLEditor::DoContentInserted(nsIContent* aChild,
|
||||||
|
|
||||||
if (ShouldReplaceRootElement()) {
|
if (ShouldReplaceRootElement()) {
|
||||||
UpdateRootElement();
|
UpdateRootElement();
|
||||||
nsContentUtils::AddScriptRunner(NewRunnableMethod(
|
if (mPendingRootElementUpdatedRunner) {
|
||||||
"HTMLEditor::NotifyRootChanged", this, &HTMLEditor::NotifyRootChanged));
|
return;
|
||||||
|
}
|
||||||
|
mPendingRootElementUpdatedRunner = NewRunnableMethod(
|
||||||
|
"HTMLEditor::NotifyRootChanged", this, &HTMLEditor::NotifyRootChanged);
|
||||||
|
nsContentUtils::AddScriptRunner(
|
||||||
|
do_AddRef(mPendingRootElementUpdatedRunner));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't need to handle our own modifications
|
// We don't need to handle our own modifications
|
||||||
else if (!GetTopLevelEditSubAction() && container->IsEditable()) {
|
if (!GetTopLevelEditSubAction() && container->IsEditable()) {
|
||||||
if (EditorUtils::IsPaddingBRElementForEmptyEditor(*aChild)) {
|
if (EditorUtils::IsPaddingBRElementForEmptyEditor(*aChild)) {
|
||||||
// Ignore insertion of the padding <br> element.
|
// Ignore insertion of the padding <br> element.
|
||||||
return;
|
return;
|
||||||
|
@ -3703,11 +3710,18 @@ MOZ_CAN_RUN_SCRIPT_BOUNDARY void HTMLEditor::ContentRemoved(
|
||||||
|
|
||||||
if (SameCOMIdentity(aChild, mRootElement)) {
|
if (SameCOMIdentity(aChild, mRootElement)) {
|
||||||
mRootElement = nullptr;
|
mRootElement = nullptr;
|
||||||
nsContentUtils::AddScriptRunner(NewRunnableMethod(
|
if (mPendingRootElementUpdatedRunner) {
|
||||||
"HTMLEditor::NotifyRootChanged", this, &HTMLEditor::NotifyRootChanged));
|
return;
|
||||||
// We don't need to handle our own modifications
|
}
|
||||||
} else if (!GetTopLevelEditSubAction() &&
|
mPendingRootElementUpdatedRunner = NewRunnableMethod(
|
||||||
aChild->GetParentNode()->IsEditable()) {
|
"HTMLEditor::NotifyRootChanged", this, &HTMLEditor::NotifyRootChanged);
|
||||||
|
nsContentUtils::AddScriptRunner(
|
||||||
|
do_AddRef(mPendingRootElementUpdatedRunner));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't need to handle our own modifications
|
||||||
|
if (!GetTopLevelEditSubAction() && aChild->GetParentNode()->IsEditable()) {
|
||||||
if (aChild && EditorUtils::IsPaddingBRElementForEmptyEditor(*aChild)) {
|
if (aChild && EditorUtils::IsPaddingBRElementForEmptyEditor(*aChild)) {
|
||||||
// Ignore removal of the padding <br> element for empty editor.
|
// Ignore removal of the padding <br> element for empty editor.
|
||||||
return;
|
return;
|
||||||
|
@ -5124,6 +5138,10 @@ bool HTMLEditor::ShouldReplaceRootElement() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTMLEditor::NotifyRootChanged() {
|
void HTMLEditor::NotifyRootChanged() {
|
||||||
|
MOZ_ASSERT(mPendingRootElementUpdatedRunner,
|
||||||
|
"HTMLEditor::NotifyRootChanged() should be called via a runner");
|
||||||
|
mPendingRootElementUpdatedRunner = nullptr;
|
||||||
|
|
||||||
nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
|
nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
|
||||||
|
|
||||||
AutoEditActionDataSetter editActionData(*this, EditAction::eNotEditing);
|
AutoEditActionDataSetter editActionData(*this, EditAction::eNotEditing);
|
||||||
|
@ -5339,6 +5357,10 @@ nsHTMLDocument* HTMLEditor::GetHTMLDocument() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult HTMLEditor::OnModifyDocument() {
|
nsresult HTMLEditor::OnModifyDocument() {
|
||||||
|
MOZ_ASSERT(mPendingDocumentModifiedRunner,
|
||||||
|
"HTMLEditor::OnModifyDocument() should be called via a runner");
|
||||||
|
mPendingDocumentModifiedRunner = nullptr;
|
||||||
|
|
||||||
if (IsEditActionDataAvailable()) {
|
if (IsEditActionDataAvailable()) {
|
||||||
return OnModifyDocumentInternal();
|
return OnModifyDocumentInternal();
|
||||||
}
|
}
|
||||||
|
@ -5357,6 +5379,7 @@ nsresult HTMLEditor::OnModifyDocument() {
|
||||||
|
|
||||||
nsresult HTMLEditor::OnModifyDocumentInternal() {
|
nsresult HTMLEditor::OnModifyDocumentInternal() {
|
||||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||||
|
MOZ_ASSERT(!mPendingDocumentModifiedRunner);
|
||||||
|
|
||||||
// EnsureNoPaddingBRElementForEmptyEditor() below may cause a flush, which
|
// EnsureNoPaddingBRElementForEmptyEditor() below may cause a flush, which
|
||||||
// could destroy the editor
|
// could destroy the editor
|
||||||
|
|
|
@ -54,6 +54,7 @@ class ListItemElementSelectionState;
|
||||||
class MoveNodeResult;
|
class MoveNodeResult;
|
||||||
class ParagraphStateAtSelection;
|
class ParagraphStateAtSelection;
|
||||||
class ResizerSelectionListener;
|
class ResizerSelectionListener;
|
||||||
|
class Runnable;
|
||||||
class SplitRangeOffFromNodeResult;
|
class SplitRangeOffFromNodeResult;
|
||||||
class SplitRangeOffResult;
|
class SplitRangeOffResult;
|
||||||
class WSRunObject;
|
class WSRunObject;
|
||||||
|
@ -4442,6 +4443,9 @@ class HTMLEditor final : public TextEditor,
|
||||||
// Used by TopLevelEditSubActionData::mChangedRange.
|
// Used by TopLevelEditSubActionData::mChangedRange.
|
||||||
mutable RefPtr<nsRange> mChangedRangeForTopLevelEditSubAction;
|
mutable RefPtr<nsRange> mChangedRangeForTopLevelEditSubAction;
|
||||||
|
|
||||||
|
RefPtr<Runnable> mPendingRootElementUpdatedRunner;
|
||||||
|
RefPtr<Runnable> mPendingDocumentModifiedRunner;
|
||||||
|
|
||||||
bool mCRInParagraphCreatesParagraph;
|
bool mCRInParagraphCreatesParagraph;
|
||||||
|
|
||||||
bool mCSSAware;
|
bool mCSSAware;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче