Bug 822734 - Make HTMLTextAreaElement handle the mutation changes after all ranges handle them r=smaug
A mutation caused by a call of `Text::SplitText` is handled by 2 method calls, `CharacterDataChanged` and `ContentInserted`, in `nsRange`. Therefore, `nsRange` stores some nodes for the later one, but `HTMLTextAreaElement::ContentInserted` is called before it and that causes another mutation which causes calling `nsRange::CharacterDataChanged` again. Therefore, the assertion detects the recursive call. For avoiding this issue, `HTMLTextAreaElement` needs to wait that all ranges handle the mutation first. Fortunately, `ContentInserted` is called with a script blocker (*1). Therefore, `HTMLTextAreaElement` can use script runner to reset the anonymous subtree. 1. https://searchfox.org/mozilla-central/rev/f1dc2743777711c821d43f9911ee7c4447d60c8e/dom/base/nsINode.cpp#1566,1610 Differential Revision: https://phabricator.services.mozilla.com/D167766
This commit is contained in:
@@ -38,6 +38,7 @@
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsTextControlFrame.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsXULControllers.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(TextArea)
|
||||
@@ -847,10 +848,17 @@ void HTMLTextAreaElement::ContentRemoved(nsIContent* aChild,
|
||||
void HTMLTextAreaElement::ContentChanged(nsIContent* aContent) {
|
||||
if (!mValueChanged && mDoneAddingChildren &&
|
||||
nsContentUtils::IsInSameAnonymousTree(this, aContent)) {
|
||||
// Hard to say what the reset can trigger, so be safe pending
|
||||
// further auditing.
|
||||
nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
|
||||
Reset();
|
||||
// We should wait all ranges finish handling the mutation before updating
|
||||
// the anonymous subtree with a call of Reset.
|
||||
nsContentUtils::AddScriptRunner(NS_NewRunnableFunction(
|
||||
"ResetHTMLTextAreaElementIfValueHasNotChangedYet",
|
||||
[self = RefPtr{this}]() {
|
||||
// However, if somebody has already changed the value, we don't need
|
||||
// to keep doing this.
|
||||
if (!self->mValueChanged) {
|
||||
self->Reset();
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user