Bug 1420547: Notify the pres shell before everything else on removals. r=bz

This allows the flattened tree to have a reasonable state before content
removals, allowing us to fix bugs like bug 1420533.

This used to be also the old setup, but was changed in bug 382376, since the
frame constructor used to reconstruct stuff synchronously. This used to break
all sorts of stylo invariants, and I fixed this in bug 1389743, so now the order
can be sane again.

MozReview-Commit-ID: K2pTweGKSq0

--HG--
extra : rebase_source : e53b7314f39f9c1c2e87fbe202f64b06e4c64c57
This commit is contained in:
Emilio Cobos Álvarez 2017-12-11 06:42:38 +01:00
parent bae0ffb7be
commit 2280023199

View File

@ -42,40 +42,51 @@ using namespace mozilla;
using namespace mozilla::dom; using namespace mozilla::dom;
using mozilla::AutoJSContext; using mozilla::AutoJSContext;
enum class IsRemoveNotification
{
Yes,
No,
};
// This macro expects the ownerDocument of content_ to be in scope as // This macro expects the ownerDocument of content_ to be in scope as
// |nsIDocument* doc| // |nsIDocument* doc|
#define IMPL_MUTATION_NOTIFICATION(func_, content_, params_) \ #define IMPL_MUTATION_NOTIFICATION(func_, content_, params_, remove_) \
PR_BEGIN_MACRO \ PR_BEGIN_MACRO \
bool needsEnterLeave = doc->MayHaveDOMMutationObservers(); \ bool needsEnterLeave = doc->MayHaveDOMMutationObservers(); \
if (needsEnterLeave) { \ if (needsEnterLeave) { \
nsDOMMutationObserver::EnterMutationHandling(); \ nsDOMMutationObserver::EnterMutationHandling(); \
} \ } \
nsINode* node = content_; \ nsINode* node = content_; \
NS_ASSERTION(node->OwnerDoc() == doc, "Bogus document"); \ NS_ASSERTION(node->OwnerDoc() == doc, "Bogus document"); \
doc->BindingManager()->func_ params_; \ if (remove_ == IsRemoveNotification::Yes && node->GetComposedDoc()) { \
nsINode* last; \ if (nsIPresShell* shell = doc->GetObservingShell()) { \
do { \ shell->func_ params_; \
nsINode::nsSlots* slots = node->GetExistingSlots(); \ } \
if (slots && !slots->mMutationObservers.IsEmpty()) { \ } \
NS_OBSERVER_AUTO_ARRAY_NOTIFY_OBSERVERS( \ doc->BindingManager()->func_ params_; \
slots->mMutationObservers, nsIMutationObserver, 1, \ nsINode* last; \
func_, params_); \ do { \
} \ nsINode::nsSlots* slots = node->GetExistingSlots(); \
last = node; \ if (slots && !slots->mMutationObservers.IsEmpty()) { \
if (ShadowRoot* shadow = ShadowRoot::FromNode(node)) { \ NS_OBSERVER_AUTO_ARRAY_NOTIFY_OBSERVERS( \
node = shadow->GetHost(); \ slots->mMutationObservers, nsIMutationObserver, 1, \
} else { \ func_, params_); \
node = node->GetParentNode(); \ } \
} \ last = node; \
} while (node); \ if (ShadowRoot* shadow = ShadowRoot::FromNode(node)) { \
if (last == doc) { \ node = shadow->GetHost(); \
if (nsIPresShell* shell = doc->GetObservingShell()) { \ } else { \
shell->func_ params_; \ node = node->GetParentNode(); \
} \ } \
} \ } while (node); \
if (needsEnterLeave) { \ if (remove_ == IsRemoveNotification::No && last == doc) { \
nsDOMMutationObserver::LeaveMutationHandling(); \ if (nsIPresShell* shell = doc->GetObservingShell()) { \
} \ shell->func_ params_; \
} \
} \
if (needsEnterLeave) { \
nsDOMMutationObserver::LeaveMutationHandling(); \
} \
PR_END_MACRO PR_END_MACRO
#define IMPL_ANIMATION_NOTIFICATION(func_, content_, params_) \ #define IMPL_ANIMATION_NOTIFICATION(func_, content_, params_) \
@ -110,7 +121,7 @@ nsNodeUtils::CharacterDataWillChange(nsIContent* aContent,
{ {
nsIDocument* doc = aContent->OwnerDoc(); nsIDocument* doc = aContent->OwnerDoc();
IMPL_MUTATION_NOTIFICATION(CharacterDataWillChange, aContent, IMPL_MUTATION_NOTIFICATION(CharacterDataWillChange, aContent,
(doc, aContent, aInfo)); (doc, aContent, aInfo), IsRemoveNotification::No);
} }
void void
@ -119,7 +130,7 @@ nsNodeUtils::CharacterDataChanged(nsIContent* aContent,
{ {
nsIDocument* doc = aContent->OwnerDoc(); nsIDocument* doc = aContent->OwnerDoc();
IMPL_MUTATION_NOTIFICATION(CharacterDataChanged, aContent, IMPL_MUTATION_NOTIFICATION(CharacterDataChanged, aContent,
(doc, aContent, aInfo)); (doc, aContent, aInfo), IsRemoveNotification::No);
} }
void void
@ -132,7 +143,7 @@ nsNodeUtils::AttributeWillChange(Element* aElement,
nsIDocument* doc = aElement->OwnerDoc(); nsIDocument* doc = aElement->OwnerDoc();
IMPL_MUTATION_NOTIFICATION(AttributeWillChange, aElement, IMPL_MUTATION_NOTIFICATION(AttributeWillChange, aElement,
(doc, aElement, aNameSpaceID, aAttribute, (doc, aElement, aNameSpaceID, aAttribute,
aModType, aNewValue)); aModType, aNewValue), IsRemoveNotification::No);
} }
void void
@ -145,7 +156,7 @@ nsNodeUtils::AttributeChanged(Element* aElement,
nsIDocument* doc = aElement->OwnerDoc(); nsIDocument* doc = aElement->OwnerDoc();
IMPL_MUTATION_NOTIFICATION(AttributeChanged, aElement, IMPL_MUTATION_NOTIFICATION(AttributeChanged, aElement,
(doc, aElement, aNameSpaceID, aAttribute, (doc, aElement, aNameSpaceID, aAttribute,
aModType, aOldValue)); aModType, aOldValue), IsRemoveNotification::No);
} }
void void
@ -155,7 +166,8 @@ nsNodeUtils::AttributeSetToCurrentValue(Element* aElement,
{ {
nsIDocument* doc = aElement->OwnerDoc(); nsIDocument* doc = aElement->OwnerDoc();
IMPL_MUTATION_NOTIFICATION(AttributeSetToCurrentValue, aElement, IMPL_MUTATION_NOTIFICATION(AttributeSetToCurrentValue, aElement,
(doc, aElement, aNameSpaceID, aAttribute)); (doc, aElement, aNameSpaceID, aAttribute),
IsRemoveNotification::No);
} }
void void
@ -165,7 +177,8 @@ nsNodeUtils::ContentAppended(nsIContent* aContainer,
nsIDocument* doc = aContainer->OwnerDoc(); nsIDocument* doc = aContainer->OwnerDoc();
IMPL_MUTATION_NOTIFICATION(ContentAppended, aContainer, IMPL_MUTATION_NOTIFICATION(ContentAppended, aContainer,
(doc, aContainer, aFirstNewContent)); (doc, aContainer, aFirstNewContent),
IsRemoveNotification::No);
} }
void void
@ -174,7 +187,8 @@ nsNodeUtils::NativeAnonymousChildListChange(nsIContent* aContent,
{ {
nsIDocument* doc = aContent->OwnerDoc(); nsIDocument* doc = aContent->OwnerDoc();
IMPL_MUTATION_NOTIFICATION(NativeAnonymousChildListChange, aContent, IMPL_MUTATION_NOTIFICATION(NativeAnonymousChildListChange, aContent,
(doc, aContent, aIsRemove)); (doc, aContent, aIsRemove),
IsRemoveNotification::No);
} }
void void
@ -196,7 +210,8 @@ nsNodeUtils::ContentInserted(nsINode* aContainer,
} }
IMPL_MUTATION_NOTIFICATION(ContentInserted, aContainer, IMPL_MUTATION_NOTIFICATION(ContentInserted, aContainer,
(document, container, aChild)); (document, container, aChild),
IsRemoveNotification::No);
} }
void void
@ -219,7 +234,8 @@ nsNodeUtils::ContentRemoved(nsINode* aContainer,
} }
IMPL_MUTATION_NOTIFICATION(ContentRemoved, aContainer, IMPL_MUTATION_NOTIFICATION(ContentRemoved, aContainer,
(document, container, aChild, aPreviousSibling)); (document, container, aChild, aPreviousSibling),
IsRemoveNotification::Yes);
} }
Maybe<NonOwningAnimationTarget> Maybe<NonOwningAnimationTarget>