mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-18 15:55:36 +00:00
Bug 736695 part 2. Use separate mutation observer batches and script blockers for the removal of newChild from its parent and the other mutations we do during an insert. r=smaug
This commit is contained in:
parent
4d7a424c99
commit
36296f29e2
@ -4208,9 +4208,6 @@ nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
|
||||
nodeToInsertBefore = nodeToInsertBefore->GetNextSibling();
|
||||
}
|
||||
|
||||
mozAutoDocUpdate batch(GetCurrentDoc(), UPDATE_CONTENT_MODEL, true);
|
||||
nsAutoMutationBatch mb;
|
||||
|
||||
// Remove the new child from the old parent if one exists
|
||||
nsCOMPtr<nsINode> oldParent = newContent->GetNodeParent();
|
||||
if (oldParent) {
|
||||
@ -4221,15 +4218,65 @@ nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
}
|
||||
|
||||
nsAutoMutationBatch mb(oldParent, true, true);
|
||||
oldParent->RemoveChildAt(removeIndex, true);
|
||||
if (nsAutoMutationBatch::GetCurrentBatch() == &mb) {
|
||||
mb.RemovalDone();
|
||||
mb.SetPrevSibling(oldParent->GetChildAt(removeIndex - 1));
|
||||
mb.SetNextSibling(oldParent->GetChildAt(removeIndex));
|
||||
// Hold a strong ref to nodeToInsertBefore across the removal of newContent
|
||||
nsCOMPtr<nsINode> kungFuDeathGrip = nodeToInsertBefore;
|
||||
|
||||
// Removing a child can run script, via XBL destructors.
|
||||
nsMutationGuard guard;
|
||||
|
||||
// Scope for the mutation batch and scriptblocker, so they go away
|
||||
// while kungFuDeathGrip is still alive.
|
||||
{
|
||||
mozAutoDocUpdate batch(GetCurrentDoc(), UPDATE_CONTENT_MODEL, true);
|
||||
nsAutoMutationBatch mb(oldParent, true, true);
|
||||
oldParent->RemoveChildAt(removeIndex, true);
|
||||
if (nsAutoMutationBatch::GetCurrentBatch() == &mb) {
|
||||
mb.RemovalDone();
|
||||
mb.SetPrevSibling(oldParent->GetChildAt(removeIndex - 1));
|
||||
mb.SetNextSibling(oldParent->GetChildAt(removeIndex));
|
||||
}
|
||||
}
|
||||
|
||||
// We expect one mutation (the removal) to have happened.
|
||||
if (guard.Mutated(1)) {
|
||||
// XBL destructors, yuck.
|
||||
|
||||
// Verify that nodeToInsertBefore, if non-null, is still our child. If
|
||||
// it's not, there's no way we can do this insert sanely; just bail out.
|
||||
if (nodeToInsertBefore && nodeToInsertBefore->GetParent() != this) {
|
||||
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
|
||||
}
|
||||
|
||||
// Verify that newContent has no parent.
|
||||
if (newContent->GetParent()) {
|
||||
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
|
||||
}
|
||||
|
||||
// And verify that newContent is still allowed as our child.
|
||||
if (aNewChild == aRefChild) {
|
||||
// We've already removed aRefChild. So even if we were doing a replace,
|
||||
// now we're doing a simple insert before nodeToInsertBefore.
|
||||
if (!IsAllowedAsChild(newContent, this, false, nodeToInsertBefore)) {
|
||||
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
|
||||
}
|
||||
} else {
|
||||
if ((aRefChild && aRefChild->GetParent() != this) ||
|
||||
!IsAllowedAsChild(newContent, this, aReplace, aRefChild)) {
|
||||
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
|
||||
}
|
||||
// And recompute nodeToInsertBefore, just in case.
|
||||
if (aReplace) {
|
||||
nodeToInsertBefore = aRefChild->GetNextSibling();
|
||||
} else {
|
||||
nodeToInsertBefore = aRefChild;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mozAutoDocUpdate batch(GetCurrentDoc(), UPDATE_CONTENT_MODEL, true);
|
||||
nsAutoMutationBatch mb;
|
||||
|
||||
// Figure out which index we want to insert at. Note that we use
|
||||
// nodeToInsertBefore to determine this, because it's possible that
|
||||
// aRefChild == aNewChild, in which case we just removed it from the
|
||||
|
Loading…
Reference in New Issue
Block a user