Bug 1292279 - Add a helper to get the real container and use it in nsPresShell::Content{Inserted,Removed}. r=heycam
authorBobby Holley <bobbyholley@gmail.com>
Tue, 16 Aug 2016 11:33:30 -0700
changeset 311289 721abe87ead229cd812d108e5e14fe2454b4eaf7
parent 311288 543b6fffb61b1a84bb5aa3480c9899c3b1eaf0e6
child 311290 4f13817111efea19ca9d0eb91979f7ee1e94f267
push id81091
push userbholley@mozilla.com
push dateFri, 26 Aug 2016 04:37:35 +0000
treeherdermozilla-inbound@45d015eed45f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1292279, 862763
milestone51.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1292279 - Add a helper to get the real container and use it in nsPresShell::Content{Inserted,Removed}. r=heycam The existing static_cast checks are totally wrong, by the way, since nsIDocuments are never nsIContent. Looks like they were erroneously added in bug 862763.
layout/base/RestyleManager.cpp
layout/base/RestyleManager.h
layout/base/RestyleManagerHandle.h
layout/base/RestyleManagerHandleInlines.h
layout/base/ServoRestyleManager.cpp
layout/base/ServoRestyleManager.h
layout/base/nsPresShell.cpp
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -396,57 +396,62 @@ RestyleManager::RestyleForEmptyChange(El
   if (grandparent &&
       (grandparent->GetFlags() & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS)) {
     hint = nsRestyleHint(hint | eRestyle_LaterSiblings);
   }
   PostRestyleEvent(aContainer, hint, nsChangeHint(0));
 }
 
 void
-RestyleManager::RestyleForAppend(Element* aContainer,
+RestyleManager::RestyleForAppend(nsIContent* aContainer,
                                  nsIContent* aFirstNewContent)
 {
-  NS_ASSERTION(aContainer, "must have container for append");
+  // The container cannot be a document, but might be a ShadowRoot.
+  if (!aContainer->IsElement()) {
+    return;
+  }
+  Element* container = aContainer->AsElement();
+
 #ifdef DEBUG
   {
     for (nsIContent* cur = aFirstNewContent; cur; cur = cur->GetNextSibling()) {
       NS_ASSERTION(!cur->IsRootOfAnonymousSubtree(),
                    "anonymous nodes should not be in child lists");
     }
   }
 #endif
   uint32_t selectorFlags =
-    aContainer->GetFlags() & (NODE_ALL_SELECTOR_FLAGS &
-                              ~NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS);
+    container->GetFlags() & (NODE_ALL_SELECTOR_FLAGS &
+                             ~NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS);
   if (selectorFlags == 0)
     return;
 
   if (selectorFlags & NODE_HAS_EMPTY_SELECTOR) {
     // see whether we need to restyle the container
     bool wasEmpty = true; // :empty or :-moz-only-whitespace
-    for (nsIContent* cur = aContainer->GetFirstChild();
+    for (nsIContent* cur = container->GetFirstChild();
          cur != aFirstNewContent;
          cur = cur->GetNextSibling()) {
       // We don't know whether we're testing :empty or :-moz-only-whitespace,
       // so be conservative and assume :-moz-only-whitespace (i.e., make
       // IsSignificantChild less likely to be true, and thus make us more
       // likely to restyle).
       if (nsStyleUtil::IsSignificantChild(cur, true, false)) {
         wasEmpty = false;
         break;
       }
     }
     if (wasEmpty) {
-      RestyleForEmptyChange(aContainer);
+      RestyleForEmptyChange(container);
       return;
     }
   }
 
   if (selectorFlags & NODE_HAS_SLOW_SELECTOR) {
-    PostRestyleEvent(aContainer, eRestyle_Subtree, nsChangeHint(0));
+    PostRestyleEvent(container, eRestyle_Subtree, nsChangeHint(0));
     // Restyling the container is the most we can do here, so we're done.
     return;
   }
 
   if (selectorFlags & NODE_HAS_EDGE_CHILD_SELECTOR) {
     // restyle the last element child before this node
     for (nsIContent* cur = aFirstNewContent->GetPreviousSibling();
          cur;
@@ -480,81 +485,87 @@ RestyleSiblingsStartingWith(RestyleManag
 
 // Restyling for a ContentInserted or CharacterDataChanged notification.
 // This could be used for ContentRemoved as well if we got the
 // notification before the removal happened (and sometimes
 // CharacterDataChanged is more like a removal than an addition).
 // The comments are written and variables are named in terms of it being
 // a ContentInserted notification.
 void
-RestyleManager::RestyleForInsertOrChange(Element* aContainer,
+RestyleManager::RestyleForInsertOrChange(nsINode* aContainer,
                                          nsIContent* aChild)
 {
+  // The container might be a document or a ShadowRoot.
+  if (!aContainer->IsElement()) {
+    return;
+  }
+  Element* container = aContainer->AsElement();
+
   NS_ASSERTION(!aChild->IsRootOfAnonymousSubtree(),
                "anonymous nodes should not be in child lists");
   uint32_t selectorFlags =
-    aContainer ? (aContainer->GetFlags() & NODE_ALL_SELECTOR_FLAGS) : 0;
+    container ? (container->GetFlags() & NODE_ALL_SELECTOR_FLAGS) : 0;
   if (selectorFlags == 0)
     return;
 
   if (selectorFlags & NODE_HAS_EMPTY_SELECTOR) {
     // see whether we need to restyle the container
     bool wasEmpty = true; // :empty or :-moz-only-whitespace
-    for (nsIContent* child = aContainer->GetFirstChild();
+    for (nsIContent* child = container->GetFirstChild();
          child;
          child = child->GetNextSibling()) {
       if (child == aChild)
         continue;
       // We don't know whether we're testing :empty or :-moz-only-whitespace,
       // so be conservative and assume :-moz-only-whitespace (i.e., make
       // IsSignificantChild less likely to be true, and thus make us more
       // likely to restyle).
       if (nsStyleUtil::IsSignificantChild(child, true, false)) {
         wasEmpty = false;
         break;
       }
     }
     if (wasEmpty) {
-      RestyleForEmptyChange(aContainer);
+      RestyleForEmptyChange(container);
       return;
     }
   }
 
   if (selectorFlags & NODE_HAS_SLOW_SELECTOR) {
-    PostRestyleEvent(aContainer, eRestyle_Subtree, nsChangeHint(0));
+    PostRestyleEvent(container, eRestyle_Subtree, nsChangeHint(0));
     // Restyling the container is the most we can do here, so we're done.
     return;
   }
 
   if (selectorFlags & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS) {
     // Restyle all later siblings.
     RestyleSiblingsStartingWith(this, aChild->GetNextSibling());
   }
 
   if (selectorFlags & NODE_HAS_EDGE_CHILD_SELECTOR) {
     // restyle the previously-first element child if it is after this node
     bool passedChild = false;
-    for (nsIContent* content = aContainer->GetFirstChild();
+    for (nsIContent* content = container->GetFirstChild();
          content;
          content = content->GetNextSibling()) {
       if (content == aChild) {
         passedChild = true;
         continue;
       }
       if (content->IsElement()) {
         if (passedChild) {
           PostRestyleEvent(content->AsElement(), eRestyle_Subtree,
                            nsChangeHint(0));
         }
         break;
       }
     }
     // restyle the previously-last element child if it is before this node
     passedChild = false;
-    for (nsIContent* content = aContainer->GetLastChild();
+    for (nsIContent* content = container->GetLastChild();
          content;
          content = content->GetPreviousSibling()) {
       if (content == aChild) {
         passedChild = true;
         continue;
       }
       if (content->IsElement()) {
         if (passedChild) {
@@ -563,84 +574,91 @@ RestyleManager::RestyleForInsertOrChange
         }
         break;
       }
     }
   }
 }
 
 void
-RestyleManager::ContentRemoved(Element* aContainer, nsIContent* aOldChild,
+RestyleManager::ContentRemoved(nsINode* aContainer,
+                               nsIContent* aOldChild,
                                nsIContent* aFollowingSibling)
 {
+  // The container might be a document or a ShadowRoot.
+  if (!aContainer->IsElement()) {
+    return;
+  }
+  Element* container = aContainer->AsElement();
+
   if (aOldChild->IsRootOfAnonymousSubtree()) {
     // This should be an assert, but this is called incorrectly in
     // HTMLEditor::DeleteRefToAnonymousNode and the assertions were clogging
     // up the logs.  Make it an assert again when that's fixed.
     MOZ_ASSERT(aOldChild->GetProperty(nsGkAtoms::restylableAnonymousNode),
                "anonymous nodes should not be in child lists (bug 439258)");
   }
   uint32_t selectorFlags =
-    aContainer ? (aContainer->GetFlags() & NODE_ALL_SELECTOR_FLAGS) : 0;
+    container ? (container->GetFlags() & NODE_ALL_SELECTOR_FLAGS) : 0;
   if (selectorFlags == 0)
     return;
 
   if (selectorFlags & NODE_HAS_EMPTY_SELECTOR) {
     // see whether we need to restyle the container
     bool isEmpty = true; // :empty or :-moz-only-whitespace
-    for (nsIContent* child = aContainer->GetFirstChild();
+    for (nsIContent* child = container->GetFirstChild();
          child;
          child = child->GetNextSibling()) {
       // We don't know whether we're testing :empty or :-moz-only-whitespace,
       // so be conservative and assume :-moz-only-whitespace (i.e., make
       // IsSignificantChild less likely to be true, and thus make us more
       // likely to restyle).
       if (nsStyleUtil::IsSignificantChild(child, true, false)) {
         isEmpty = false;
         break;
       }
     }
     if (isEmpty) {
-      RestyleForEmptyChange(aContainer);
+      RestyleForEmptyChange(container);
       return;
     }
   }
 
   if (selectorFlags & NODE_HAS_SLOW_SELECTOR) {
-    PostRestyleEvent(aContainer, eRestyle_Subtree, nsChangeHint(0));
+    PostRestyleEvent(container, eRestyle_Subtree, nsChangeHint(0));
     // Restyling the container is the most we can do here, so we're done.
     return;
   }
 
   if (selectorFlags & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS) {
     // Restyle all later siblings.
     RestyleSiblingsStartingWith(this, aFollowingSibling);
   }
 
   if (selectorFlags & NODE_HAS_EDGE_CHILD_SELECTOR) {
     // restyle the now-first element child if it was after aOldChild
     bool reachedFollowingSibling = false;
-    for (nsIContent* content = aContainer->GetFirstChild();
+    for (nsIContent* content = container->GetFirstChild();
          content;
          content = content->GetNextSibling()) {
       if (content == aFollowingSibling) {
         reachedFollowingSibling = true;
         // do NOT continue here; we might want to restyle this node
       }
       if (content->IsElement()) {
         if (reachedFollowingSibling) {
           PostRestyleEvent(content->AsElement(), eRestyle_Subtree,
                            nsChangeHint(0));
         }
         break;
       }
     }
     // restyle the now-last element child if it was before aOldChild
     reachedFollowingSibling = (aFollowingSibling == nullptr);
-    for (nsIContent* content = aContainer->GetLastChild();
+    for (nsIContent* content = container->GetLastChild();
          content;
          content = content->GetPreviousSibling()) {
       if (content->IsElement()) {
         if (reachedFollowingSibling) {
           PostRestyleEvent(content->AsElement(), eRestyle_Subtree, nsChangeHint(0));
         }
         break;
       }
--- a/layout/base/RestyleManager.h
+++ b/layout/base/RestyleManager.h
@@ -277,46 +277,46 @@ public:
     return mAnimationsWithDestroyedFrame;
   }
 
 private:
   void RestyleForEmptyChange(Element* aContainer);
 
 public:
   // Handle ContentInserted notifications.
-  void ContentInserted(Element* aContainer, nsIContent* aChild)
+  void ContentInserted(nsINode* aContainer, nsIContent* aChild)
   {
     RestyleForInsertOrChange(aContainer, aChild);
   }
 
   // Handle ContentAppended notifications.
-  void ContentAppended(Element* aContainer, nsIContent* aFirstNewContent)
+  void ContentAppended(nsIContent* aContainer, nsIContent* aFirstNewContent)
   {
     RestyleForAppend(aContainer, aFirstNewContent);
   }
 
   // Handle ContentRemoved notifications.
   //
   // This would be have the same logic as RestyleForInsertOrChange if we got the
   // notification before the removal.  However, we get it after, so we need the
   // following sibling in addition to the old child.  |aContainer| must be
   // non-null; when the container is null, no work is needed.  aFollowingSibling
   // is the sibling that used to come after aOldChild before the removal.
-  void ContentRemoved(Element* aContainer, nsIContent* aOldChild,
+  void ContentRemoved(nsINode* aContainer, nsIContent* aOldChild,
                       nsIContent* aFollowingSibling);
 
   // Restyling for a ContentInserted (notification after insertion) or
   // for a CharacterDataChanged.  |aContainer| must be non-null; when
   // the container is null, no work is needed.
-  void RestyleForInsertOrChange(Element* aContainer, nsIContent* aChild);
+  void RestyleForInsertOrChange(nsINode* aContainer, nsIContent* aChild);
 
   // Restyling for a ContentAppended (notification after insertion) or
   // for a CharacterDataChanged.  |aContainer| must be non-null; when
   // the container is null, no work is needed.
-  void RestyleForAppend(Element* aContainer, nsIContent* aFirstNewContent);
+  void RestyleForAppend(nsIContent* aContainer, nsIContent* aFirstNewContent);
 
   // Process any pending restyles. This should be called after
   // CreateNeededFrames.
   // Note: It's the caller's responsibility to make sure to wrap a
   // ProcessPendingRestyles call in a view update batch and a script blocker.
   // This function does not call ProcessAttachedQueue() on the binding manager.
   // If the caller wants that to happen synchronously, it needs to handle that
   // itself.
--- a/layout/base/RestyleManagerHandle.h
+++ b/layout/base/RestyleManagerHandle.h
@@ -109,26 +109,26 @@ public:
                                  nsRestyleHint aRestyleHint,
                                  nsChangeHint aMinChangeHint);
     inline void PostRestyleEventForLazyConstruction();
     inline void RebuildAllStyleData(nsChangeHint aExtraHint,
                                     nsRestyleHint aRestyleHint);
     inline void PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
                                              nsRestyleHint aRestyleHint);
     inline void ProcessPendingRestyles();
-    inline void ContentInserted(dom::Element* aContainer,
+    inline void ContentInserted(nsINode* aContainer,
                                 nsIContent* aChild);
-    inline void ContentAppended(dom::Element* aContainer,
+    inline void ContentAppended(nsIContent* aContainer,
                                 nsIContent* aFirstNewContent);
-    inline void ContentRemoved(dom::Element* aContainer,
+    inline void ContentRemoved(nsINode* aContainer,
                                nsIContent* aOldChild,
                                nsIContent* aFollowingSibling);
-    inline void RestyleForInsertOrChange(dom::Element* aContainer,
+    inline void RestyleForInsertOrChange(nsINode* aContainer,
                                          nsIContent* aChild);
-    inline void RestyleForAppend(dom::Element* aContainer,
+    inline void RestyleForAppend(nsIContent* aContainer,
                                  nsIContent* aFirstNewContent);
     inline nsresult ContentStateChanged(nsIContent* aContent,
                                         EventStates aStateMask);
     inline void AttributeWillChange(dom::Element* aElement,
                                     int32_t aNameSpaceID,
                                     nsIAtom* aAttribute,
                                     int32_t aModType,
                                     const nsAttrValue* aNewValue);
--- a/layout/base/RestyleManagerHandleInlines.h
+++ b/layout/base/RestyleManagerHandleInlines.h
@@ -82,52 +82,51 @@ RestyleManagerHandle::Ptr::ProcessRestyl
 
 void
 RestyleManagerHandle::Ptr::FlushOverflowChangedTracker()
 {
   FORWARD(FlushOverflowChangedTracker, ());
 }
 
 void
-RestyleManagerHandle::Ptr::ContentInserted(dom::Element* aContainer,
+RestyleManagerHandle::Ptr::ContentInserted(nsINode* aContainer,
                                            nsIContent* aChild)
 {
   FORWARD(ContentInserted, (aContainer, aChild));
 }
 
 void
-RestyleManagerHandle::Ptr::ContentAppended(dom::Element* aContainer,
+RestyleManagerHandle::Ptr::ContentAppended(nsIContent* aContainer,
                                            nsIContent* aFirstNewContent)
 {
   FORWARD(ContentAppended, (aContainer, aFirstNewContent));
 }
 
 void
-RestyleManagerHandle::Ptr::ContentRemoved(dom::Element* aContainer,
-                                            nsIContent* aOldChild,
-                                            nsIContent* aFollowingSibling)
+RestyleManagerHandle::Ptr::ContentRemoved(nsINode* aContainer,
+                                          nsIContent* aOldChild,
+                                          nsIContent* aFollowingSibling)
 {
   FORWARD(ContentRemoved, (aContainer, aOldChild, aFollowingSibling));
 }
 
 void
-RestyleManagerHandle::Ptr::RestyleForInsertOrChange(dom::Element* aContainer,
+RestyleManagerHandle::Ptr::RestyleForInsertOrChange(nsINode* aContainer,
                                                     nsIContent* aChild)
 {
   FORWARD(RestyleForInsertOrChange, (aContainer, aChild));
 }
 
 void
-RestyleManagerHandle::Ptr::RestyleForAppend(dom::Element* aContainer,
+RestyleManagerHandle::Ptr::RestyleForAppend(nsIContent* aContainer,
                                             nsIContent* aFirstNewContent)
 {
   FORWARD(RestyleForAppend, (aContainer, aFirstNewContent));
 }
 
-
 nsresult
 RestyleManagerHandle::Ptr::ContentStateChanged(nsIContent* aContent,
                                           EventStates aStateMask)
 {
   FORWARD(ContentStateChanged, (aContent, aStateMask));
 }
 
 void
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -333,60 +333,60 @@ ServoRestyleManager::ProcessPendingResty
   MOZ_ASSERT(!doc->HasDirtyDescendantsForServo());
 
   mModifiedElements.Clear();
 
   IncrementRestyleGeneration();
 }
 
 void
-ServoRestyleManager::RestyleForInsertOrChange(Element* aContainer,
+ServoRestyleManager::RestyleForInsertOrChange(nsINode* aContainer,
                                               nsIContent* aChild)
 {
   //
   // XXXbholley: We need the Gecko logic here to correctly restyle for things
   // like :empty and positional selectors (though we may not need to post
   // restyle events as agressively as the Gecko path does).
   //
   // Bug 1297899 tracks this work.
   //
 }
 
 void
-ServoRestyleManager::ContentInserted(Element* aContainer, nsIContent* aChild)
+ServoRestyleManager::ContentInserted(nsINode* aContainer, nsIContent* aChild)
 {
   if (!aContainer->ServoData().get()) {
     // This can happen with display:none. Bug 1297249 tracks more investigation
     // and assertions here.
     return;
   }
 
   // Style the new subtree because we will most likely need it during subsequent
   // frame construction. Bug 1298281 tracks deferring this work in the lazy
   // frame construction case.
   StyleSet()->StyleNewSubtree(aChild);
 
   RestyleForInsertOrChange(aContainer, aChild);
 }
 
 void
-ServoRestyleManager::RestyleForAppend(Element* aContainer,
+ServoRestyleManager::RestyleForAppend(nsIContent* aContainer,
                                       nsIContent* aFirstNewContent)
 {
   //
   // XXXbholley: We need the Gecko logic here to correctly restyle for things
   // like :empty and positional selectors (though we may not need to post
   // restyle events as agressively as the Gecko path does).
   //
   // Bug 1297899 tracks this work.
   //
 }
 
 void
-ServoRestyleManager::ContentAppended(Element* aContainer,
+ServoRestyleManager::ContentAppended(nsIContent* aContainer,
                                      nsIContent* aFirstNewContent)
 {
   if (!aContainer->ServoData().get()) {
     // This can happen with display:none. Bug 1297249 tracks more investigation
     // and assertions here.
     return;
   }
 
@@ -399,17 +399,17 @@ ServoRestyleManager::ContentAppended(Ele
   } else {
     StyleSet()->StyleNewSubtree(aFirstNewContent);
   }
 
   RestyleForAppend(aContainer, aFirstNewContent);
 }
 
 void
-ServoRestyleManager::ContentRemoved(Element* aContainer,
+ServoRestyleManager::ContentRemoved(nsINode* aContainer,
                                     nsIContent* aOldChild,
                                     nsIContent* aFollowingSibling)
 {
   NS_WARNING("stylo: ServoRestyleManager::ContentRemoved not implemented");
 }
 
 nsresult
 ServoRestyleManager::ContentStateChanged(nsIContent* aContent,
--- a/layout/base/ServoRestyleManager.h
+++ b/layout/base/ServoRestyleManager.h
@@ -47,28 +47,27 @@ public:
                         nsChangeHint aMinChangeHint);
   void PostRestyleEventForLazyConstruction();
   void RebuildAllStyleData(nsChangeHint aExtraHint,
                            nsRestyleHint aRestyleHint);
   void PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
                                     nsRestyleHint aRestyleHint);
   void ProcessPendingRestyles();
 
-  void ContentInserted(dom::Element* aContainer, nsIContent* aChild);
-  void ContentAppended(dom::Element* aContainer,
+  void ContentInserted(nsINode* aContainer, nsIContent* aChild);
+  void ContentAppended(nsIContent* aContainer,
                        nsIContent* aFirstNewContent);
-  void ContentRemoved(dom::Element* aContainer,
+  void ContentRemoved(nsINode* aContainer,
                       nsIContent* aOldChild,
                       nsIContent* aFollowingSibling);
 
-  void RestyleForInsertOrChange(dom::Element* aContainer,
+  void RestyleForInsertOrChange(nsINode* aContainer,
                                 nsIContent* aChild);
-  void RestyleForAppend(dom::Element* aContainer,
+  void RestyleForAppend(nsIContent* aContainer,
                         nsIContent* aFirstNewContent);
-
   nsresult ContentStateChanged(nsIContent* aContent,
                                EventStates aStateMask);
   void AttributeWillChange(dom::Element* aElement,
                            int32_t aNameSpaceID,
                            nsIAtom* aAttribute,
                            int32_t aModType,
                            const nsAttrValue* aNewValue);
 
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -4298,154 +4298,153 @@ PresShell::AttributeChanged(nsIDocument*
     nsAutoCauseReflowNotifier crNotifier(this);
     mPresContext->RestyleManager()->AttributeChanged(aElement, aNameSpaceID,
                                                      aAttribute, aModType,
                                                      aOldValue);
     VERIFY_STYLE_TREE;
   }
 }
 
+// nsIMutationObserver callbacks have this terrible API where aContainer is
+// null in the case that the container is the document (since nsIDocument is
+// not an nsIContent), and callees are supposed to figure this out and use the
+// document instead. It would be nice to fix that API to just pass a single
+// nsINode* parameter in place of the nsIDocument*, nsIContent* pair, but
+// there are quite a lot of consumers. So we fix things up locally with this
+// routine for now.
+static inline nsINode*
+RealContainer(nsIDocument* aDocument, nsIContent* aContainer, nsIContent* aContent)
+{
+  MOZ_ASSERT(aDocument);
+  MOZ_ASSERT_IF(aContainer, aContainer->OwnerDoc() == aDocument);
+  MOZ_ASSERT(aContent->OwnerDoc() == aDocument);
+  MOZ_ASSERT_IF(!aContainer, aContent->GetParentNode() == aDocument);
+  if (!aContainer) {
+    return aDocument;
+  }
+  return aContainer;
+}
+
 void
 PresShell::ContentAppended(nsIDocument *aDocument,
                            nsIContent* aContainer,
                            nsIContent* aFirstNewContent,
                            int32_t     aNewIndexInContainer)
 {
   NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentAppended");
   NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
-  NS_PRECONDITION(aContainer, "must have container");
+
+  // We never call ContentAppended with a document as the container, so we can
+  // assert that we have an nsIContent container.
+  MOZ_ASSERT(aContainer);
+  MOZ_ASSERT(aContainer->IsElement() ||
+             aContainer->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT));
+  if (!mDidInitialize) {
+    return;
+  }
+
+  nsAutoCauseReflowNotifier crNotifier(this);
+
+  // Call this here so it only happens for real content mutations and
+  // not cases when the frame constructor calls its own methods to force
+  // frame reconstruction.
+  mPresContext->RestyleManager()->ContentAppended(aContainer, aFirstNewContent);
+
+  mFrameConstructor->ContentAppended(aContainer, aFirstNewContent, true);
+
+  VERIFY_STYLE_TREE;
+}
+
+void
+PresShell::ContentInserted(nsIDocument* aDocument,
+                           nsIContent*  aMaybeContainer,
+                           nsIContent*  aChild,
+                           int32_t      aIndexInContainer)
+{
+  NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentInserted");
+  NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
+  nsINode* container = RealContainer(aDocument, aMaybeContainer, aChild);
 
   if (!mDidInitialize) {
     return;
   }
 
   nsAutoCauseReflowNotifier crNotifier(this);
 
   // Call this here so it only happens for real content mutations and
   // not cases when the frame constructor calls its own methods to force
   // frame reconstruction.
-  if (aContainer->IsElement()) {
-    // Ensure the container is an element before trying to restyle
-    // because it can be the case that the container is a ShadowRoot
-    // which is a document fragment.
-    mPresContext->RestyleManager()->
-      ContentAppended(aContainer->AsElement(), aFirstNewContent);
-  }
-
-  mFrameConstructor->ContentAppended(aContainer, aFirstNewContent, true);
-
-  if (static_cast<nsINode*>(aContainer) == static_cast<nsINode*>(aDocument) &&
-      aFirstNewContent->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) {
-    NotifyFontSizeInflationEnabledIsDirty();
-  }
-
-  VERIFY_STYLE_TREE;
-}
-
-void
-PresShell::ContentInserted(nsIDocument* aDocument,
-                           nsIContent*  aContainer,
-                           nsIContent*  aChild,
-                           int32_t      aIndexInContainer)
-{
-  NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentInserted");
-  NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
-
-  if (!mDidInitialize) {
-    return;
-  }
-
-  nsAutoCauseReflowNotifier crNotifier(this);
-
-  // Call this here so it only happens for real content mutations and
-  // not cases when the frame constructor calls its own methods to force
-  // frame reconstruction.
-  if (aContainer && aContainer->IsElement()) {
-    // Ensure the container is an element before trying to restyle
-    // because it can be the case that the container is a ShadowRoot
-    // which is a document fragment.
-    mPresContext->RestyleManager()->
-      ContentInserted(aContainer->AsElement(), aChild);
-  }
-
-  mFrameConstructor->ContentInserted(aContainer, aChild, nullptr, true);
-
-  if (((!aContainer && aDocument) ||
-      (static_cast<nsINode*>(aContainer) == static_cast<nsINode*>(aDocument))) &&
-      aChild->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) {
+  mPresContext->RestyleManager()->ContentInserted(container, aChild);
+
+  mFrameConstructor->ContentInserted(aMaybeContainer, aChild, nullptr, true);
+
+  if (aChild->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) {
+    MOZ_ASSERT(container == aDocument);
     NotifyFontSizeInflationEnabledIsDirty();
   }
 
   VERIFY_STYLE_TREE;
 }
 
 void
 PresShell::ContentRemoved(nsIDocument *aDocument,
-                          nsIContent* aContainer,
+                          nsIContent* aMaybeContainer,
                           nsIContent* aChild,
                           int32_t     aIndexInContainer,
                           nsIContent* aPreviousSibling)
 {
   NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentRemoved");
   NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
+  nsINode* container = RealContainer(aDocument, aMaybeContainer, aChild);
 
   // Notify the ESM that the content has been removed, so that
   // it can clean up any state related to the content.
 
   // XXX_jwir3: There is no null check for aDocument necessary, since, even
   //            though by nsIMutationObserver, aDocument could be null, the
   //            precondition check that mDocument == aDocument ensures that
   //            aDocument will not be null (since mDocument can't be null unless
   //            we're still intializing).
   mPresContext->EventStateManager()->ContentRemoved(aDocument, aChild);
 
   nsAutoCauseReflowNotifier crNotifier(this);
 
   // Call this here so it only happens for real content mutations and
   // not cases when the frame constructor calls its own methods to force
   // frame reconstruction.
-  nsIContent* oldNextSibling;
-  if (aContainer) {
-    oldNextSibling = aContainer->GetChildAt(aIndexInContainer);
-  } else {
-    oldNextSibling = nullptr;
-  }
-
-  if (aContainer && aContainer->IsElement()) {
-    mPresContext->RestyleManager()->
-      ContentRemoved(aContainer->AsElement(), aChild, oldNextSibling);
-  }
+  nsIContent* oldNextSibling = container->GetChildAt(aIndexInContainer);
+
+  mPresContext->RestyleManager()->ContentRemoved(container, aChild, oldNextSibling);
 
   // After removing aChild from tree we should save information about live ancestor
   if (mPointerEventTarget) {
     if (nsContentUtils::ContentIsDescendantOf(mPointerEventTarget, aChild)) {
-      mPointerEventTarget = aContainer;
+      mPointerEventTarget = aMaybeContainer;
     }
   }
 
   // We should check that aChild does not contain pointer capturing elements.
   // If it does we should release the pointer capture for the elements.
   for (auto iter = gPointerCaptureList->Iter(); !iter.Done(); iter.Next()) {
     nsIPresShell::PointerCaptureInfo* data = iter.UserData();
     if (data && data->mOverrideContent &&
         nsContentUtils::ContentIsDescendantOf(data->mOverrideContent,
                                               aChild)) {
       nsIPresShell::ReleasePointerCapturingContent(iter.Key());
     }
   }
 
   bool didReconstruct;
-  mFrameConstructor->ContentRemoved(aContainer, aChild, oldNextSibling,
+  mFrameConstructor->ContentRemoved(aMaybeContainer, aChild, oldNextSibling,
                                     nsCSSFrameConstructor::REMOVE_CONTENT,
                                     &didReconstruct);
 
 
-  if (((aContainer &&
-      static_cast<nsINode*>(aContainer) == static_cast<nsINode*>(aDocument)) ||
-      aDocument) && aChild->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) {
+  if (aChild->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) {
+    MOZ_ASSERT(container == aDocument);
     NotifyFontSizeInflationEnabledIsDirty();
   }
 
   VERIFY_STYLE_TREE;
 }
 
 void
 PresShell::NotifyCounterStylesAreDirty()