Bug 1429088: Only style children on non-lazy frame construction after we found an insertion point. r?bz draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Tue, 09 Jan 2018 17:19:00 +0100
changeset 719568 739d8052d82e90e1916ec054909bc5140f91e86f
parent 719567 9a7effdae527bbb9e200e6b461abcbd6acfe2827
child 745829 c2132f75ce3be01aa43ec63bf1826398e3b993b9
push id95292
push userbmo:emilio@crisal.io
push dateFri, 12 Jan 2018 10:28:59 +0000
reviewersbz
bugs1429088
milestone59.0a1
Bug 1429088: Only style children on non-lazy frame construction after we found an insertion point. r?bz Servo tries to keep this invariant that stuff under a display: none element subtree doesn't get styled. This invariant isn't checked in StyleNewChildRange, but we can fix this by just doing the work after finding an insertion point, which guarantees that. Do the same for listboxes, since we also style early for them without knowing whether they actually have a listbox parent frame. MozReview-Commit-ID: Glyx24wQ6qY
layout/base/nsCSSFrameConstructor.cpp
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -7093,25 +7093,23 @@ IsSpecialFramesetChild(nsIContent* aCont
   return aContent->IsAnyOfHTMLElements(nsGkAtoms::frameset, nsGkAtoms::frame);
 }
 
 static void
 InvalidateCanvasIfNeeded(nsIPresShell* presShell, nsIContent* node);
 
 #ifdef MOZ_XUL
 
-static
-bool
+static bool
 IsXULListBox(nsIContent* aContainer)
 {
-  return (aContainer->IsXULElement(nsGkAtoms::listbox));
-}
-
-static
-nsListBoxBodyFrame*
+  return aContainer->IsXULElement(nsGkAtoms::listbox);
+}
+
+static nsListBoxBodyFrame*
 MaybeGetListBoxBodyFrame(nsIContent* aContainer, nsIContent* aChild)
 {
   if (!aContainer)
     return nullptr;
 
   if (IsXULListBox(aContainer) &&
       aChild->IsXULElement(nsGkAtoms::listitem)) {
     RefPtr<nsXULElement> xulElement = nsXULElement::FromContent(aContainer);
@@ -7578,32 +7576,32 @@ nsCSSFrameConstructor::ContentAppended(n
   if (aInsertionKind == InsertionKind::Async &&
       MaybeConstructLazily(CONTENTAPPEND, aContainer, aFirstNewContent)) {
     if (aContainer->IsStyledByServo()) {
       LazilyStyleNewChildRange(aFirstNewContent, nullptr);
     }
     return;
   }
 
-  // We couldn't construct lazily. Make Servo eagerly traverse the new content
-  // if needed (when aInsertionKind == InsertionKind::Sync, we know that the
-  // styles are up-to-date already).
-  if (aInsertionKind == InsertionKind::Async && aContainer->IsStyledByServo()) {
-    StyleNewChildRange(aFirstNewContent, nullptr);
-  }
-
   LAYOUT_PHASE_TEMP_EXIT();
   InsertionPoint insertion =
     GetRangeInsertionPoint(aContainer, aFirstNewContent, nullptr);
   nsContainerFrame*& parentFrame = insertion.mParentFrame;
   LAYOUT_PHASE_TEMP_REENTER();
   if (!parentFrame) {
     return;
   }
 
+  // We couldn't construct lazily. Make Servo eagerly traverse the new content
+  // if needed (when aInsertionKind == InsertionKind::Sync, we know that the
+  // styles are up-to-date already).
+  if (aInsertionKind == InsertionKind::Async && aContainer->IsStyledByServo()) {
+    StyleNewChildRange(aFirstNewContent, nullptr);
+  }
+
   LAYOUT_PHASE_TEMP_EXIT();
   if (MaybeRecreateForFrameset(parentFrame, aFirstNewContent, nullptr)) {
     LAYOUT_PHASE_TEMP_REENTER();
     return;
   }
   LAYOUT_PHASE_TEMP_REENTER();
 
   if (parentFrame->IsLeaf()) {
@@ -7835,52 +7833,42 @@ nsCSSFrameConstructor::ContentAppended(n
     accService->ContentRangeInserted(mPresShell, aContainer,
                                      aFirstNewContent, nullptr);
   }
 #endif
 }
 
 #ifdef MOZ_XUL
 
-enum content_operation
-{
-    CONTENT_INSERTED,
-    CONTENT_REMOVED
-};
-
 // Helper function to lookup the listbox body frame and send a notification
-// for insertion or removal of content
-static
-bool NotifyListBoxBody(nsPresContext*    aPresContext,
-                         nsIContent*        aContainer,
-                         nsIContent*        aChild,
-                         // Only used for the removed notification
-                         nsIContent*        aOldNextSibling,
-                         nsIFrame*          aChildFrame,
-                         content_operation  aOperation)
+// for removal of content.
+static bool
+MaybeNotifyListBoxBodyOfRemoval(nsPresContext* aPresContext,
+                                nsIContent* aContainer,
+                                nsIContent* aChild,
+                                nsIContent* aOldNextSibling,
+                                nsIFrame* aChildFrame)
 {
   nsListBoxBodyFrame* listBoxBodyFrame =
     MaybeGetListBoxBodyFrame(aContainer, aChild);
-  if (listBoxBodyFrame) {
-    if (aOperation == CONTENT_REMOVED) {
-      // Except if we have an aChildFrame and its parent is not the right
-      // thing, then we don't do this.  Pseudo frames are so much fun....
-      if (!aChildFrame || aChildFrame->GetParent() == listBoxBodyFrame) {
-        listBoxBodyFrame->OnContentRemoved(aPresContext, aContainer,
-                                           aChildFrame, aOldNextSibling);
-        return true;
-      }
-    } else {
-      listBoxBodyFrame->OnContentInserted(aChild);
-      return true;
-    }
-  }
-
-  return false;
-}
+  if (!listBoxBodyFrame) {
+    return false;
+  }
+
+  // Except if we have an aChildFrame and its parent is not the right
+  // thing, then we don't do this.  Pseudo frames are so much fun....
+  if (aChildFrame && aChildFrame->GetParent() != listBoxBodyFrame) {
+    return false;
+  }
+
+  listBoxBodyFrame->OnContentRemoved(
+    aPresContext, aContainer, aChildFrame, aOldNextSibling);
+  return true;
+}
+
 #endif // MOZ_XUL
 
 void
 nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer,
                                        nsIContent* aChild,
                                        nsILayoutHistoryState* aFrameState,
                                        InsertionKind aInsertionKind)
 {
@@ -7969,22 +7957,21 @@ nsCSSFrameConstructor::ContentRangeInser
                aInsertionKind == InsertionKind::Sync,
                "range insert shouldn't be lazy");
   NS_ASSERTION(isSingleInsert || aEndChild,
                "range should not include all nodes after aStartChild");
 
 #ifdef MOZ_XUL
   if (aContainer && IsXULListBox(aContainer)) {
     // For XUL list box, we need to style the new children eagerly.
-    styleNewChildRangeEagerly();
     if (isSingleInsert) {
-      if (NotifyListBoxBody(mPresShell->GetPresContext(), aContainer,
-                            // The insert case in NotifyListBoxBody
-                            // doesn't use "old next sibling".
-                            aStartChild, nullptr, nullptr, CONTENT_INSERTED)) {
+      if (nsListBoxBodyFrame* listBoxBodyFrame =
+            MaybeGetListBoxBodyFrame(aContainer, aStartChild)) {
+        styleNewChildRangeEagerly();
+        listBoxBodyFrame->OnContentInserted(aStartChild);
         return;
       }
     } else {
       // We don't handle a range insert to a listbox parent, issue single
       // ContertInserted calls for each node inserted.
       LAYOUT_PHASE_TEMP_EXIT();
       IssueSingleInsertNofications(aContainer, aStartChild, aEndChild);
       LAYOUT_PHASE_TEMP_REENTER();
@@ -8063,20 +8050,16 @@ nsCSSFrameConstructor::ContentRangeInser
   if (aInsertionKind == InsertionKind::Async &&
       MaybeConstructLazily(CONTENTINSERT, aContainer, aStartChild)) {
     if (aContainer->IsStyledByServo()) {
       LazilyStyleNewChildRange(aStartChild, aEndChild);
     }
     return;
   }
 
-  // We couldn't construct lazily. Make Servo eagerly traverse the new content
-  // if needed.
-  styleNewChildRangeEagerly();
-
   InsertionPoint insertion;
   if (isSingleInsert) {
     // See if we have an XBL insertion point. If so, then that's our
     // real parent frame; if not, then the frame hasn't been built yet
     // and we just bail.
     insertion = GetInsertionPoint(aContainer, aStartChild);
   } else {
     // Get our insertion point. If we need to issue single ContentInserted's
@@ -8085,16 +8068,21 @@ nsCSSFrameConstructor::ContentRangeInser
     insertion = GetRangeInsertionPoint(aContainer, aStartChild, aEndChild);
     LAYOUT_PHASE_TEMP_REENTER();
   }
 
   if (!insertion.mParentFrame) {
     return;
   }
 
+  // We couldn't construct lazily.
+  //
+  // Make Servo eagerly traverse the new content if needed.
+  styleNewChildRangeEagerly();
+
   bool isAppend, isRangeInsertSafe;
   nsIFrame* prevSibling = GetInsertionPrevSibling(&insertion, aStartChild,
                                                   &isAppend, &isRangeInsertSafe);
 
   // check if range insert is safe
   if (!isSingleInsert && !isRangeInsertSafe) {
     // must fall back to a single ContertInserted for each child in the range
     LAYOUT_PHASE_TEMP_EXIT();
@@ -8521,18 +8509,18 @@ nsCSSFrameConstructor::ContentRemoved(ns
         }
       }
     }
     UnregisterDisplayContentsStyleFor(aChild, aContainer);
     return false;
   }
 
 #ifdef MOZ_XUL
-  if (NotifyListBoxBody(presContext, aContainer, aChild, aOldNextSibling,
-                        childFrame, CONTENT_REMOVED)) {
+  if (MaybeNotifyListBoxBodyOfRemoval(
+        presContext, aContainer, aChild, aOldNextSibling, childFrame)) {
     return false;
   }
 #endif // MOZ_XUL
 
   // If we're removing the root, then make sure to remove things starting at
   // the viewport's child instead of the primary frame (which might even be
   // null if the root had an XBL binding or display:none, even though the
   // frames above it got created).  We do the adjustment after the childFrame