Bug 1404789: When the shadow tree distribution changes, post a restyle + reframe. r=bz
authorEmilio Cobos Álvarez <emilio@crisal.io>
Wed, 18 Oct 2017 15:24:53 +0200
changeset 683840 f5345c4fda8ce6f8e77e8c4d3190841dea6a5470
parent 683839 c097b5cc5c0778706187c42160bdd004309371a1
child 683841 4fae76403e5dffdb5f02f013378b4ae4f932b949
push id85474
push userbmo:emilio@crisal.io
push dateFri, 20 Oct 2017 10:02:12 +0000
reviewersbz
bugs1404789
milestone58.0a1
Bug 1404789: When the shadow tree distribution changes, post a restyle + reframe. r=bz MozReview-Commit-ID: DvRb22UfnJ4
dom/base/ShadowRoot.cpp
dom/base/ShadowRoot.h
--- a/dom/base/ShadowRoot.cpp
+++ b/dom/base/ShadowRoot.cpp
@@ -246,16 +246,34 @@ ShadowRoot::RemoveDestInsertionPoint(nsI
   // other insertion point removals / fallback content redistribution (which
   // does DestInsertionPoints().Clear()).
   if (index >= 0) {
     aDestInsertionPoints.RemoveElementAt(index);
   }
 }
 
 void
+ShadowRoot::DistributionChanged()
+{
+  // FIXME(emilio): We could be more granular in a bunch of cases.
+  auto* host = GetHost();
+  if (!host) {
+    return;
+  }
+
+  auto* shell = OwnerDoc()->GetShell();
+  if (!shell) {
+    return;
+  }
+
+  // FIXME(emilio): Rename this to DestroyFramesForAndRestyle?
+  shell->DestroyFramesFor(host);
+}
+
+void
 ShadowRoot::DistributeSingleNode(nsIContent* aContent)
 {
   // Find the insertion point to which the content belongs.
   HTMLContentElement* foundInsertionPoint = nullptr;
   for (HTMLContentElement* insertionPoint : mInsertionPoints) {
     if (insertionPoint->Match(aContent)) {
       if (insertionPoint->MatchedNodes().Contains(aContent)) {
         // Node is already matched into the insertion point. We are done.
@@ -306,16 +324,18 @@ ShadowRoot::DistributeSingleNode(nsICont
   }
 
   // Handle the case where the parent of the insertion point has a ShadowRoot.
   // The node distributed into the insertion point must be reprojected to the
   // insertion points of the parent's ShadowRoot.
   if (auto* parentShadow = foundInsertionPoint->GetParent()->GetShadowRoot()) {
     parentShadow->DistributeSingleNode(aContent);
   }
+
+  DistributionChanged();
 }
 
 void
 ShadowRoot::RemoveDistributedNode(nsIContent* aContent)
 {
   // Find insertion point containing the content and remove the node.
   for (HTMLContentElement* insertionPoint : mInsertionPoints) {
     if (!insertionPoint->MatchedNodes().Contains(aContent)) {
@@ -335,16 +355,18 @@ ShadowRoot::RemoveDistributedNode(nsICon
     insertionPoint->RemoveMatchedNode(aContent);
 
     // Handle the case where the parent of the insertion point has a ShadowRoot.
     // The removed node needs to be removed from the insertion points of the
     // parent's ShadowRoot.
     if (auto* parentShadow = insertionPoint->GetParent()->GetShadowRoot()) {
       parentShadow->RemoveDistributedNode(aContent);
     }
+
+    DistributionChanged();
     return;
   }
 }
 
 void
 ShadowRoot::DistributeAllNodes()
 {
   // Create node pool.
@@ -381,16 +403,18 @@ ShadowRoot::DistributeAllNodes()
     if (parentShadow && !shadowsToUpdate.Contains(parentShadow)) {
       shadowsToUpdate.AppendElement(parentShadow);
     }
   }
 
   for (ShadowRoot* shadow : shadowsToUpdate) {
     shadow->DistributeAllNodes();
   }
+
+  DistributionChanged();
 }
 
 void
 ShadowRoot::GetInnerHTML(nsAString& aInnerHTML)
 {
   GetMarkup(false, aInnerHTML);
 }
 
--- a/dom/base/ShadowRoot.h
+++ b/dom/base/ShadowRoot.h
@@ -67,16 +67,22 @@ private:
   void DistributeSingleNode(nsIContent* aContent);
 
   /**
    * Removes a single explicit child of the pool host from the content
    * insertion points in this ShadowRoot.
    */
   void RemoveDistributedNode(nsIContent* aContent);
 
+  /**
+   * Called when we redistribute content in such a way that new insertion points
+   * come into existence, or elements are moved between insertion points.
+   */
+  void DistributionChanged();
+
   static bool IsPooledNode(nsIContent* aChild, nsIContent* aContainer,
                            nsIContent* aHost);
 
 public:
   void AddInsertionPoint(HTMLContentElement* aInsertionPoint);
   void RemoveInsertionPoint(HTMLContentElement* aInsertionPoint);
 
   void SetInsertionPointChanged() { mInsertionPointChanged = true; }