Bug 1303605: Remove the undisplayed maps. r=bz,mats
authorEmilio Cobos Álvarez <emilio@crisal.io>
Thu, 29 Mar 2018 03:49:26 +0200
changeset 412268 bdf546b6ba285227a89c4e8fb31c59f81f19bc10
parent 412267 f3350af3387d7bbed6c617f45a4e666b7ee1e4d2
child 412269 12a824f8d55a8fb0396fb2132974f8223c6a9606
push id101872
push userrgurzau@mozilla.com
push dateSat, 07 Apr 2018 22:16:03 +0000
treeherdermozilla-inbound@aacc170ff3f6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, mats
bugs1303605, 1381017
milestone61.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 1303605: Remove the undisplayed maps. r=bz,mats This is mostly code removal, changing GetDisplayContentsStyle(..) checks by an FFI call to Servo. The tricky parts are: * MaybeCreateLazily, which I fixed to avoid setting bits under display: none stuff. This was a pre-existing problem, which was wallpapered by the sc->IsInDisplayNoneSubtree() check, which effectively made the whole assertion useless (see bug 1381017 for the only crashtest that hit this though). * ContentRemoved, where we can no longer know for sure whether the element is actually display: contents if we're removing it as a response to a style change. See the comment there. That kinda sucks, but that case is relatively weird, and it's better than adding tons of complexity to handle that. * GetParentComputedStyle, which also has a comment there. Also, this function has only one caller now, so we should maybe try to remove it. The different assertions after DestroyFramesForAndRestyle are changed for a single assertion in the function itself, and the node bit used as an optimization to avoid hashtable lookups is taken back. MozReview-Commit-ID: AZm822QnhF9
dom/base/Element.cpp
dom/base/nsINode.h
layout/base/PresShell.cpp
layout/base/ServoRestyleManager.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsCSSFrameConstructor.h
layout/base/nsFrameManager.cpp
layout/base/nsFrameManager.h
layout/base/nsStyleChangeList.cpp
layout/generic/nsFrame.cpp
layout/generic/nsFrameSelection.cpp
layout/generic/nsPlaceholderFrame.cpp
layout/style/ServoBindingList.h
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -1245,17 +1245,16 @@ Element::AttachShadowInternal(ShadowRoot
   RefPtr<mozilla::dom::NodeInfo> nodeInfo =
     mNodeInfo->NodeInfoManager()->GetNodeInfo(
       nsGkAtoms::documentFragmentNodeName, nullptr, kNameSpaceID_None,
       DOCUMENT_FRAGMENT_NODE);
 
   if (nsIDocument* doc = GetComposedDoc()) {
     if (nsIPresShell* shell = doc->GetShell()) {
       shell->DestroyFramesForAndRestyle(this);
-      MOZ_ASSERT(!shell->FrameConstructor()->GetDisplayContentsStyleFor(this));
     }
   }
   MOZ_ASSERT(!GetPrimaryFrame());
 
   /**
    * 4. Let shadow be a new shadow root whose node document is
    *    context object’s node document, host is context object,
    *    and mode is init’s mode.
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -1568,19 +1568,16 @@ private:
     ElementHasWeirdParserInsertionMode,
     // Parser sets this flag if it has notified about the node.
     ParserHasNotified,
     // Sets if the node is apz aware or we have apz aware listeners.
     MayBeApzAware,
     // Set if the element might have any kind of anonymous content children,
     // which would not be found through the element's children list.
     ElementMayHaveAnonymousChildren,
-    // Set if this node has at some point (and may still have)
-    // display:none or display:contents children.
-    NodeMayHaveChildrenWithLayoutBoxesDisabled,
     // Guard value
     BooleanFlagCount
   };
 
   void SetBoolFlag(BooleanFlag name, bool value) {
     static_assert(BooleanFlagCount <= 8*sizeof(mBoolFlags),
                   "Too many boolean flags");
     mBoolFlags = (mBoolFlags & ~(1 << name)) | (value << name);
@@ -1696,29 +1693,16 @@ public:
   bool NodeMayBeApzAware() const
   {
     return GetBoolFlag(MayBeApzAware);
   }
 
   void SetMayHaveAnonymousChildren() { SetBoolFlag(ElementMayHaveAnonymousChildren); }
   bool MayHaveAnonymousChildren() const { return GetBoolFlag(ElementMayHaveAnonymousChildren); }
 
-  void SetMayHaveChildrenWithLayoutBoxesDisabled()
-  {
-    SetBoolFlag(NodeMayHaveChildrenWithLayoutBoxesDisabled);
-  }
-  void UnsetMayHaveChildrenWithLayoutBoxesDisabled()
-  {
-    ClearBoolFlag(NodeMayHaveChildrenWithLayoutBoxesDisabled);
-  }
-  bool MayHaveChildrenWithLayoutBoxesDisabled() const
-  {
-    return GetBoolFlag(NodeMayHaveChildrenWithLayoutBoxesDisabled);
-  }
-
 protected:
   void SetParentIsContent(bool aValue) { SetBoolFlag(ParentIsContent, aValue); }
   void SetIsInDocument() { SetBoolFlag(IsInDocument); }
   void SetNodeIsContent() { SetBoolFlag(NodeIsContent); }
   void ClearInDocument() { ClearBoolFlag(IsInDocument); }
   void SetIsElement() { SetBoolFlag(NodeIsElement); }
   void SetHasID() { SetBoolFlag(ElementHasID); }
   void ClearHasID() { ClearBoolFlag(ElementHasID); }
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -2972,19 +2972,54 @@ nsIPresShell::SlotAssignmentWillChange(E
       // Now the style dirty bits. Note that we can't just do
       // aElement.NoteDirtyForServo(), because the new slot is not setup yet.
       aNewSlot->SetHasDirtyDescendantsForServo();
       aNewSlot->NoteDirtySubtreeForServo();
     }
   }
 }
 
+#ifdef DEBUG
+static void
+AssertNoFramesInSubtree(nsIContent* aContent)
+{
+  for (nsIContent* c = aContent; c; c = c->GetNextNode(aContent)) {
+    MOZ_ASSERT(!c->GetPrimaryFrame());
+    if (auto* shadowRoot = c->GetShadowRoot()) {
+      AssertNoFramesInSubtree(shadowRoot);
+    }
+    if (auto* binding = c->GetXBLBinding()) {
+      if (auto* bindingWithContent = binding->GetBindingWithContent()) {
+        nsIContent* anonContent = bindingWithContent->GetAnonymousContent();
+        MOZ_ASSERT(!anonContent->GetPrimaryFrame());
+
+        // Need to do this instead of just AssertNoFramesInSubtree(anonContent),
+        // because the parent of the children of the <content> element isn't the
+        // <content> element, but the bound element, and that confuses
+        // GetNextNode a lot.
+        for (nsIContent* child = anonContent->GetFirstChild();
+             child;
+             child = child->GetNextSibling()) {
+          AssertNoFramesInSubtree(child);
+        }
+      }
+    }
+  }
+}
+#endif
+
 void
 nsIPresShell::DestroyFramesForAndRestyle(Element* aElement)
 {
+#ifdef DEBUG
+  auto postCondition = mozilla::MakeScopeExit([&]() {
+    AssertNoFramesInSubtree(aElement);
+  });
+#endif
+
   MOZ_ASSERT(aElement);
   if (MOZ_UNLIKELY(!mDidInitialize)) {
     return;
   }
 
   if (!aElement->GetFlattenedTreeParentNode()) {
     // Nothing to do here, the element already is out of the frame tree.
     return;
@@ -4522,27 +4557,31 @@ PresShell::ContentRemoved(nsIContent* aC
   // Editor calls into here with NAC via HTMLEditor::DeleteRefToAnonymousNode.
   // This could be asserted if that caller is fixed.
   if (MOZ_LIKELY(!aChild->IsRootOfAnonymousSubtree())) {
     oldNextSibling = aPreviousSibling
       ? aPreviousSibling->GetNextSibling()
       : container->GetFirstChild();
   }
 
-  mPresContext->RestyleManager()->ContentRemoved(container, aChild, oldNextSibling);
-
   // After removing aChild from tree we should save information about live ancestor
   if (mPointerEventTarget &&
       nsContentUtils::ContentIsDescendantOf(mPointerEventTarget, aChild)) {
     mPointerEventTarget = aChild->GetParent();
   }
 
   mFrameConstructor->ContentRemoved(
       aChild->GetParent(), aChild, oldNextSibling,
       nsCSSFrameConstructor::REMOVE_CONTENT);
+
+  // NOTE(emilio): It's important that this goes after the frame constructor
+  // stuff, otherwise the frame constructor can't see elements which are
+  // display: contents / display: none, because we'd have cleared all the style
+  // data from there.
+  mPresContext->RestyleManager()->ContentRemoved(container, aChild, oldNextSibling);
 }
 
 void
 PresShell::NotifyCounterStylesAreDirty()
 {
   nsAutoCauseReflowNotifier reflowNotifier(this);
   mFrameConstructor->NotifyCounterStylesAreDirty();
 }
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -843,28 +843,30 @@ ServoRestyleManager::ProcessPostTraversa
   }
 
   // TODO(emilio): We could avoid some refcount traffic here, specially in the
   // ComputedStyle case, which uses atomic refcounting.
   //
   // Hold the ComputedStyle alive, because it could become a dangling pointer
   // during the replacement. In practice it's not a huge deal, but better not
   // playing with dangling pointers if not needed.
-  RefPtr<ComputedStyle> oldComputedStyle =
+  //
+  // NOTE(emilio): We could keep around the old computed style for display:
+  // contents elements too, but we don't really need it right now.
+  RefPtr<ComputedStyle> oldOrDisplayContentsStyle =
     styleFrame ? styleFrame->Style() : nullptr;
 
-  ComputedStyle* displayContentsStyle = nullptr;
-  // FIXME(emilio, bug 1303605): This can be simpler for Servo.
-  // Note that we intentionally don't check for display: none content.
-  if (!oldComputedStyle) {
-    displayContentsStyle =
-      PresContext()->FrameConstructor()->GetDisplayContentsStyleFor(aElement);
-    if (displayContentsStyle) {
-      oldComputedStyle = displayContentsStyle;
-    }
+  MOZ_ASSERT(!(styleFrame && Servo_Element_IsDisplayContents(aElement)),
+             "display: contents node has a frame, yet we didn't reframe it"
+             " above?");
+  const bool isDisplayContents =
+    !styleFrame && Servo_Element_IsDisplayContents(aElement);
+  if (isDisplayContents) {
+    oldOrDisplayContentsStyle =
+      aRestyleState.StyleSet().ResolveServoStyle(aElement);
   }
 
   Maybe<ServoRestyleState> thisFrameRestyleState;
   if (styleFrame) {
     auto type = isOutOfFlow
       ? ServoRestyleState::Type::OutOfFlow
       : ServoRestyleState::Type::InFlow;
 
@@ -874,49 +876,45 @@ ServoRestyleManager::ProcessPostTraversa
   // We can't really assume as used changes from display: contents elements (or
   // other elements without frames).
   ServoRestyleState& childrenRestyleState =
     thisFrameRestyleState ? *thisFrameRestyleState : aRestyleState;
 
   RefPtr<ComputedStyle> upToDateContext =
     wasRestyled
       ? aRestyleState.StyleSet().ResolveServoStyle(aElement)
-      : oldComputedStyle;
+      : oldOrDisplayContentsStyle;
 
   ServoPostTraversalFlags childrenFlags =
     wasRestyled ? ServoPostTraversalFlags::ParentWasRestyled
                 : ServoPostTraversalFlags::Empty;
 
-  if (wasRestyled && oldComputedStyle) {
-    MOZ_ASSERT(styleFrame || displayContentsStyle);
-    MOZ_ASSERT(oldComputedStyle->ComputedData() != upToDateContext->ComputedData());
+  if (wasRestyled && oldOrDisplayContentsStyle) {
+    MOZ_ASSERT(styleFrame || isDisplayContents);
 
-    upToDateContext->ResolveSameStructsAs(oldComputedStyle);
+    // Note that upToDateContext could be the same as oldOrDisplayContentsStyle,
+    // but it doesn't matter, since the only point of it is calling FinishStyle
+    // on the relevant structs, and those don't matter for display: contents.
+    upToDateContext->ResolveSameStructsAs(oldOrDisplayContentsStyle);
 
     // We want to walk all the continuations here, even the ones with different
     // styles.  In practice, the only reason we get continuations with different
     // styles here is ::first-line (::first-letter never affects element
     // styles).  But in that case, newStyle is the right context for the
     // _later_ continuations anyway (the ones not affected by ::first-line), not
     // the earlier ones, so there is no point stopping right at the point when
     // we'd actually be setting the right ComputedStyle.
     //
     // This does mean that we may be setting the wrong ComputedStyle on our
     // initial continuations; ::first-line fixes that up after the fact.
     for (nsIFrame* f = styleFrame; f; f = f->GetNextContinuation()) {
       MOZ_ASSERT_IF(f != styleFrame, !f->GetAdditionalComputedStyle(0));
       f->SetComputedStyle(upToDateContext);
     }
 
-    if (MOZ_UNLIKELY(displayContentsStyle)) {
-      MOZ_ASSERT(!styleFrame);
-      PresContext()->FrameConstructor()->
-        ChangeRegisteredDisplayContentsStyleFor(aElement, upToDateContext);
-    }
-
     if (styleFrame) {
       UpdateAdditionalComputedStyles(styleFrame, aRestyleState);
     }
 
     if (!aElement->GetParent()) {
       // This is the root.  Update styles on the viewport as needed.
       ViewportFrame* viewport =
         do_QueryFrame(mPresContext->PresShell()->GetRootFrame());
@@ -933,31 +931,33 @@ ServoRestyleManager::ProcessPostTraversa
     //
     // We can sometimes reach this when the animated style is being removed.
     // Since AddLayerChangesForAnimation checks if |styleFrame| has a transform
     // style or not, we need to call it *after* setting |newStyle| to
     // |styleFrame| to ensure the animated transform has been removed first.
     AddLayerChangesForAnimation(
       styleFrame, aElement, aRestyleState.ChangeList());
 
-    childrenFlags |= SendA11yNotifications(mPresContext, aElement,
-                                           oldComputedStyle,
-                                           upToDateContext, aFlags);
+    childrenFlags |= SendA11yNotifications(mPresContext,
+                                           aElement,
+                                           oldOrDisplayContentsStyle,
+                                           upToDateContext,
+                                           aFlags);
   }
 
   const bool traverseElementChildren =
     aElement->HasAnyOfFlags(Element::kAllServoDescendantBits);
   const bool traverseTextChildren =
     wasRestyled || aElement->HasFlag(NODE_DESCENDANTS_NEED_FRAMES);
   bool recreatedAnyContext = wasRestyled;
   if (traverseElementChildren || traverseTextChildren) {
     StyleChildrenIterator it(aElement);
     TextPostTraversalState textState(*aElement,
                                      upToDateContext,
-                                     displayContentsStyle && wasRestyled,
+                                     isDisplayContents && wasRestyled,
                                      childrenRestyleState);
     for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
       if (traverseElementChildren && n->IsElement()) {
         recreatedAnyContext |= ProcessPostTraversal(n->AsElement(),
                                                     upToDateContext,
                                                     childrenRestyleState,
                                                     childrenFlags);
       } else if (traverseTextChildren && n->IsNodeOfType(nsINode::eTEXT)) {
@@ -1580,16 +1580,18 @@ ServoRestyleManager::DoReparentComputedS
     nsIFrame* outOfFlow =
       nsPlaceholderFrame::GetRealFrameForPlaceholder(aFrame);
     MOZ_ASSERT(outOfFlow, "no out-of-flow frame");
     for (; outOfFlow; outOfFlow = outOfFlow->GetNextContinuation()) {
       DoReparentComputedStyle(outOfFlow, aStyleSet);
     }
   }
 
+  // FIXME(emilio): This is the only caller of GetParentComputedStyle, let's try
+  // to remove it?
   nsIFrame* providerFrame;
   ComputedStyle* newParentStyle =
     aFrame->GetParentComputedStyle(&providerFrame);
   // If our provider is our child, we want to reparent it first, because we
   // inherit style from it.
   bool isChild = providerFrame && providerFrame->GetParent() == aFrame;
   nsIFrame* providerChild = nullptr;
   if (isChild) {
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -413,16 +413,31 @@ GetFieldSetBlockFrame(nsIFrame* aFieldse
  */
 static bool
 IsInlineFrame(const nsIFrame* aFrame)
 {
   return aFrame->IsFrameOfType(nsIFrame::eLineParticipant);
 }
 
 /**
+ * True for display: contents elements.
+ */
+static inline bool
+IsDisplayContents(const Element* aElement)
+{
+  return aElement->HasServoData() && Servo_Element_IsDisplayContents(aElement);
+}
+
+static inline bool
+IsDisplayContents(const nsIContent* aContent)
+{
+  return aContent->IsElement() && IsDisplayContents(aContent->AsElement());
+}
+
+/**
  * True if aFrame is an instance of an SVG frame class or is an inline/block
  * frame being used for SVG text.
  */
 static bool
 IsFrameForSVG(const nsIFrame* aFrame)
 {
   return aFrame->IsFrameOfType(nsIFrame::eSVG) ||
          nsSVGUtils::IsInSVGTextSubtree(aFrame);
@@ -1628,18 +1643,16 @@ nsCSSFrameConstructor::NotifyDestroyingF
       mCounterManager.DestroyNodesFor(aFrame)) {
     // Technically we don't need to update anything if we destroyed only
     // USE nodes.  However, this is unlikely to happen in the real world
     // since USE nodes generally go along with INCREMENT nodes.
     CountersDirty();
   }
 
   RestyleManager()->NotifyDestroyingFrame(aFrame);
-
-  nsFrameManager::NotifyDestroyingFrame(aFrame);
 }
 
 struct nsGenConInitializer {
   nsAutoPtr<nsGenConNode> mNode;
   nsGenConList*           mList;
   void (nsCSSFrameConstructor::*mDirtyAll)();
 
   nsGenConInitializer(nsGenConNode* aNode, nsGenConList* aList,
@@ -2462,17 +2475,16 @@ nsCSSFrameConstructor::ConstructDocEleme
   // --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
 
   NS_ASSERTION(!display->IsScrollableOverflow() ||
                state.mPresContext->IsPaginated() ||
                propagatedScrollFrom == aDocElement,
                "Scrollbars should have been propagated to the viewport");
 
   if (MOZ_UNLIKELY(display->mDisplay == StyleDisplay::None)) {
-    RegisterDisplayNoneStyleFor(aDocElement, computedStyle);
     return nullptr;
   }
 
   // Make sure to start any background image loads for the root element now.
   computedStyle->StartBackgroundImageLoads();
 
   nsFrameConstructorSaveState docElementContainingBlockAbsoluteSaveState;
   if (mHasRootAbsPosContainingBlock) {
@@ -5592,24 +5604,17 @@ nsCSSFrameConstructor::SetAsUndisplayedC
                                                bool aIsGeneratedContent)
 {
   if (aComputedStyle->GetPseudo()) {
     if (aIsGeneratedContent) {
       aContent->UnbindFromTree();
     }
     return;
   }
-  NS_ASSERTION(!aIsGeneratedContent, "Should have had pseudo type");
-
-  if (aState.mCreatingExtraFrames) {
-    MOZ_ASSERT(GetDisplayNoneStyleFor(aContent),
-               "should have called RegisterDisplayNoneStyleFor earlier");
-    return;
-  }
-  aList.AppendUndisplayedItem(aContent, aComputedStyle);
+  MOZ_ASSERT(!aIsGeneratedContent, "Should have had pseudo type");
 }
 
 void
 nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState& aState,
                                                          nsIContent* aContent,
                                                          nsContainerFrame* aParentFrame,
                                                          bool aSuppressWhiteSpaceOptimizations,
                                                          ComputedStyle* aComputedStyle,
@@ -5822,26 +5827,16 @@ nsCSSFrameConstructor::AddFrameConstruct
     AddPageBreakItem(aContent, aItems);
   }
 
   // FIXME(emilio, https://github.com/w3c/csswg-drafts/issues/2167):
   //
   // Figure out what should happen for display: contents in MathML.
   if (display->mDisplay == StyleDisplay::Contents &&
       !foundMathMLData) {
-    if (!GetDisplayContentsStyleFor(aContent)) {
-      MOZ_ASSERT(computedStyle->GetPseudo() || !isGeneratedContent,
-                 "Should have had pseudo type");
-      aState.mFrameManager->RegisterDisplayContentsStyleFor(aContent,
-                                                            computedStyle);
-    } else {
-      aState.mFrameManager->ChangeRegisteredDisplayContentsStyleFor(aContent,
-                                                                    computedStyle);
-    }
-
     if (aParentFrame) {
       aParentFrame->AddStateBits(NS_FRAME_MAY_HAVE_GENERATED_CONTENT);
     }
     CreateGeneratedContentItem(aState, aParentFrame, aContent->AsElement(),
                                computedStyle, CSSPseudoElementType::before,
                                aItems);
 
     FlattenedChildIterator iter(aContent);
@@ -6487,27 +6482,30 @@ nsCSSFrameConstructor::FindSiblingIntern
 
   auto getFarPseudo = [](const nsIContent* aContent) -> nsIFrame* {
     return aDirection == SiblingDirection::Forward
       ? nsLayoutUtils::GetAfterFrame(aContent)
       : nsLayoutUtils::GetBeforeFrame(aContent);
   };
 
   while (nsIContent* sibling = nextDomSibling(aIter)) {
+    // NOTE(emilio): It's important to check GetPrimaryFrame() before
+    // IsDisplayContents to get the correct insertion point when multiple
+    // siblings go from display: non-none to display: contents.
     if (nsIFrame* primaryFrame = sibling->GetPrimaryFrame()) {
       // XXX the GetContent() == sibling check is needed due to bug 135040.
       // Remove it once that's fixed.
       if (primaryFrame->GetContent() == sibling) {
         if (nsIFrame* frame = adjust(primaryFrame)) {
           return frame;
         }
       }
     }
 
-    if (GetDisplayContentsStyleFor(sibling)) {
+    if (IsDisplayContents(sibling)) {
       if (nsIFrame* frame = adjust(getNearPseudo(sibling))) {
         return frame;
       }
 
       const bool startFromBeginning = aDirection == SiblingDirection::Forward;
       FlattenedChildIterator iter(sibling, startFromBeginning);
       nsIFrame* sibling = FindSiblingInternal<aDirection>(
         iter, aTargetContent, aTargetContentDisplay);
@@ -6582,17 +6580,17 @@ nsCSSFrameConstructor::FindSibling(const
   if (sibling) {
     return sibling;
   }
 
   // Our siblings (if any) do not have a frame to guide us. The frame for the
   // target content should be inserted whereever a frame for the container would
   // be inserted. This is needed when inserting into display: contents nodes.
   const nsIContent* current = aIter.Parent();
-  while (GetDisplayContentsStyleFor(current)) {
+  while (IsDisplayContents(current)) {
     const nsIContent* parent = current->GetFlattenedTreeParent();
     MOZ_ASSERT(parent, "No display: contents on the root");
 
     FlattenedChildIterator iter(parent);
     iter.Seek(current);
     sibling = FindSiblingInternal<aDirection>(
         iter, targetContent, aTargetContentDisplay);
     if (sibling) {
@@ -6698,17 +6696,17 @@ nsCSSFrameConstructor::GetInsertionPrevS
   return prevSibling;
 }
 
 nsContainerFrame*
 nsCSSFrameConstructor::GetContentInsertionFrameFor(nsIContent* aContent)
 {
   nsIFrame* frame;
   while (!(frame = aContent->GetPrimaryFrame())) {
-    if (!GetDisplayContentsStyleFor(aContent)) {
+    if (!IsDisplayContents(aContent)) {
       return nullptr;
     }
 
     aContent = aContent->GetFlattenedTreeParent();
     if (!aContent) {
       return nullptr;
     }
   }
@@ -6824,19 +6822,17 @@ nsCSSFrameConstructor::CheckBitsForLazyF
   bool noPrimaryFrame = false;
   bool needsFrameBitSet = false;
   nsIContent* content = aParent;
   while (content && !content->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
     if (content->GetPrimaryFrame() && content->GetPrimaryFrame()->IsLeaf()) {
       noPrimaryFrame = needsFrameBitSet = false;
     }
     if (!noPrimaryFrame && !content->GetPrimaryFrame()) {
-      ComputedStyle* sc = GetDisplayNoneStyleFor(content);
-      noPrimaryFrame = !GetDisplayContentsStyleFor(content) &&
-        (sc && !sc->IsInDisplayNoneSubtree());
+      noPrimaryFrame = !IsDisplayContents(content);
     }
     if (!needsFrameBitSet && content->HasFlag(NODE_NEEDS_FRAME)) {
       needsFrameBitSet = true;
     }
 
     content = content->GetFlattenedTreeParent();
   }
   if (content && content->GetPrimaryFrame() &&
@@ -6877,22 +6873,26 @@ nsCSSFrameConstructor::MaybeConstructLaz
       if (child->IsXULElement()) {
         return false;
       }
     }
   }
 
   // We can construct lazily; just need to set suitable bits in the content
   // tree.
-  nsIContent* parent = aChild->GetFlattenedTreeParent();
+  Element* parent = aChild->GetFlattenedTreeParentElement();
   if (!parent) {
     // Not part of the flat tree, nothing to do.
     return true;
   }
 
+  if (Servo_Element_IsDisplayNone(parent)) {
+    // Nothing to do either.
+    return true;
+  }
 
   // Set NODE_NEEDS_FRAME on the new nodes.
   if (aOperation == CONTENTINSERT) {
     NS_ASSERTION(!aChild->GetPrimaryFrame() ||
                  aChild->GetPrimaryFrame()->GetContent() != aChild,
                  //XXX the aChild->GetPrimaryFrame()->GetContent() != aChild
                  // check is needed due to bug 135040. Remove it once that's
                  // fixed.
@@ -6906,35 +6906,33 @@ nsCSSFrameConstructor::MaybeConstructLaz
                    // check is needed due to bug 135040. Remove it once that's
                    // fixed.
                    "setting NEEDS_FRAME on a node that already has a frame?");
       child->SetFlags(NODE_NEEDS_FRAME);
     }
   }
 
   CheckBitsForLazyFrameConstruction(parent);
-  parent->AsElement()->NoteDescendantsNeedFramesForServo();
+  parent->NoteDescendantsNeedFramesForServo();
 
   return true;
 }
 
 
 void
 nsCSSFrameConstructor::IssueSingleInsertNofications(nsIContent* aContainer,
                                                     nsIContent* aStartChild,
                                                     nsIContent* aEndChild)
 {
   for (nsIContent* child = aStartChild;
        child != aEndChild;
        child = child->GetNextSibling()) {
     // listboxes suck.
     MOZ_ASSERT(MaybeGetListBoxBodyFrame(aContainer, child) ||
-               (!child->GetPrimaryFrame() &&
-                !GetDisplayNoneStyleFor(child) &&
-                !GetDisplayContentsStyleFor(child)));
+               !child->GetPrimaryFrame());
 
     // Call ContentRangeInserted with this node.
     ContentRangeInserted(aContainer, child, child->GetNextSibling(),
                          mTempFrameTreeState, InsertionKind::Sync);
   }
 }
 
 bool
@@ -7089,19 +7087,19 @@ nsCSSFrameConstructor::ContentAppended(n
 #endif
 
 #ifdef DEBUG
   for (nsIContent* child = aFirstNewContent;
        child;
        child = child->GetNextSibling()) {
     // XXX the GetContent() != child check is needed due to bug 135040.
     // Remove it once that's fixed.
-    NS_ASSERTION(!child->GetPrimaryFrame() ||
-                 child->GetPrimaryFrame()->GetContent() != child,
-                 "asked to construct a frame for a node that already has a frame");
+    MOZ_ASSERT(!child->GetPrimaryFrame() ||
+               child->GetPrimaryFrame()->GetContent() != child,
+               "asked to construct a frame for a node that already has a frame");
   }
 #endif
 
   // See comment in ContentRangeInserted for why this is necessary.
   if (!GetContentInsertionFrameFor(aContainer) &&
       !aContainer->IsActiveChildrenElement()) {
     // We're punting on frame construction because there's no container frame.
     // The Servo-backed style system handles this case like the lazy frame
@@ -7167,17 +7165,17 @@ nsCSSFrameConstructor::ContentAppended(n
   // We should never get here with fieldsets or details, since they have
   // multiple insertion points.
   MOZ_ASSERT(!parentFrame->IsFieldSetFrame() && !parentFrame->IsDetailsFrame(),
              "Parent frame should not be fieldset or details!");
 
   // Deal with possible :after generated content on the parent, or display:
   // contents.
   nsIFrame* nextSibling = nullptr;
-  if (GetDisplayContentsStyleFor(insertion.mContainer) ||
+  if (IsDisplayContents(insertion.mContainer) ||
       nsLayoutUtils::GetAfterFrame(insertion.mContainer)) {
     FlattenedChildIterator iter(insertion.mContainer);
     iter.Seek(insertion.mContainer->GetLastChild());
     StyleDisplay unused = UNSET_DISPLAY;
     nextSibling = FindNextSibling(iter, unused);
   }
 
   if (nextSibling) {
@@ -7572,17 +7570,18 @@ nsCSSFrameConstructor::ContentRangeInser
     }
     return;
   }
 
   MOZ_ASSERT_IF(aContainer->IsShadowRoot(), !parentFrame);
 
   // Otherwise, we've got parent content. Find its frame.
   NS_ASSERTION(!parentFrame || parentFrame->GetContent() == aContainer ||
-               GetDisplayContentsStyleFor(aContainer), "New XBL code is possibly wrong!");
+               IsDisplayContents(aContainer),
+               "New XBL code is possibly wrong!");
 
   if (aInsertionKind == InsertionKind::Async &&
       MaybeConstructLazily(CONTENTINSERT, aStartChild)) {
     LazilyStyleNewChildRange(aStartChild, aEndChild);
     return;
   }
 
   // We couldn't construct lazily. Make Servo eagerly traverse the new content
@@ -7992,70 +7991,87 @@ nsCSSFrameConstructor::ContentRemoved(ns
   }
 #endif
 
   nsIFrame* childFrame = aChild->GetPrimaryFrame();
   if (!childFrame || childFrame->GetContent() != aChild) {
     // XXXbz the GetContent() != aChild check is needed due to bug 135040.
     // Remove it once that's fixed.
     childFrame = nullptr;
-    UnregisterDisplayNoneStyleFor(aChild, aContainer);
-  }
-  MOZ_ASSERT(!childFrame || !GetDisplayContentsStyleFor(aChild),
-             "display:contents nodes shouldn't have a frame");
-  if (!childFrame && GetDisplayContentsStyleFor(aChild)) {
-    // NOTE(emilio): We may iterate through ::before and ::after here and they
-    // may be gone after the respective ContentRemoved call. Right now
-    // StyleChildrenIterator handles that properly, so it's not an issue.
-    StyleChildrenIterator iter(aChild);
-    for (nsIContent* c = iter.GetNextChild(); c; c = iter.GetNextChild()) {
-      if (c->GetPrimaryFrame() || GetDisplayContentsStyleFor(c)) {
-        LAYOUT_PHASE_TEMP_EXIT();
-        bool didReconstruct =
-          ContentRemoved(aChild, c, nullptr, REMOVE_FOR_RECONSTRUCTION);
-        LAYOUT_PHASE_TEMP_REENTER();
-        if (didReconstruct) {
-          return true;
-        }
-      }
-    }
-    UnregisterDisplayContentsStyleFor(aChild, aContainer);
-    return false;
   }
 
 #ifdef MOZ_XUL
   if (NotifyListBoxBody(presContext, aContainer, aChild, aOldNextSibling,
                         childFrame, CONTENT_REMOVED)) {
     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
-  // check above, because we do want to clear any undisplayed content we might
-  // have for the root.  Detecting removal of a root is a little exciting; in
-  // particular, having a null aContainer is necessary but NOT sufficient.  Due
-  // to how we process reframes, the content node might not even be in our
-  // document by now.  So explicitly check whether the viewport's first kid's
-  // content node is aChild.
+  // frames above it got created).  Detecting removal of a root is a little
+  // exciting; in particular, having a null aContainer is necessary but NOT
+  // sufficient.  Due to how we process reframes, the content node might not
+  // even be in our document by now.  So explicitly check whether the viewport's
+  // first kid's content node is aChild.
+  //
+  // FIXME(emilio): I think the "might not be in our document" bit is impossible
+  // now.
   bool isRoot = false;
   if (!aContainer) {
-    nsIFrame* viewport = GetRootFrame();
-    if (viewport) {
+    if (nsIFrame* viewport = GetRootFrame()) {
       nsIFrame* firstChild = viewport->PrincipalChildList().FirstChild();
       if (firstChild && firstChild->GetContent() == aChild) {
         isRoot = true;
         childFrame = firstChild;
         NS_ASSERTION(!childFrame->GetNextSibling(), "How did that happen?");
       }
     }
   }
 
+  // We need to be conservative about when to determine whether something has
+  // display: contents or not because at this point our actual display may be
+  // different.
+  //
+  // Consider the case of:
+  //
+  //   <div id="A" style="display: contents"><div id="B"></div></div>
+  //
+  // If we reconstruct A because its display changed to "none", we still need to
+  // cleanup the frame on B, but A's display is now "none", so we can't poke at
+  // the style of it.
+  //
+  // FIXME(emilio, bug 1450366): We can make this faster without adding much
+  // complexity for the display: none -> other case, which right now
+  // unnecessarily walks the content tree down.
+  auto CouldHaveBeenDisplayContents = [aFlags](nsIContent* aContent) -> bool {
+    return aFlags == REMOVE_FOR_RECONSTRUCTION || IsDisplayContents(aContent);
+  };
+
+  if (!childFrame && CouldHaveBeenDisplayContents(aChild)) {
+    // NOTE(emilio): We may iterate through ::before and ::after here and they
+    // may be gone after the respective ContentRemoved call. Right now
+    // StyleChildrenIterator handles that properly, so it's not an issue.
+    StyleChildrenIterator iter(aChild);
+    for (nsIContent* c = iter.GetNextChild(); c; c = iter.GetNextChild()) {
+      if (c->GetPrimaryFrame() || CouldHaveBeenDisplayContents(aChild)) {
+        LAYOUT_PHASE_TEMP_EXIT();
+        bool didReconstruct =
+          ContentRemoved(aChild, c, nullptr, REMOVE_FOR_RECONSTRUCTION);
+        LAYOUT_PHASE_TEMP_REENTER();
+        if (didReconstruct) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+
   if (childFrame) {
     InvalidateCanvasIfNeeded(mPresShell, aChild);
 
     // See whether we need to remove more than just childFrame
     LAYOUT_PHASE_TEMP_EXIT();
     if (MaybeRecreateContainerForFrameRemoval(childFrame)) {
       LAYOUT_PHASE_TEMP_REENTER();
       return true;
@@ -8138,17 +8154,16 @@ nsCSSFrameConstructor::ContentRemoved(ns
       // simpler.
       RemoveLetterFrames(mPresShell, containingBlock);
 
       // Recover childFrame and parentFrame
       childFrame = aChild->GetPrimaryFrame();
       if (!childFrame || childFrame->GetContent() != aChild) {
         // XXXbz the GetContent() != aChild check is needed due to bug 135040.
         // Remove it once that's fixed.
-        UnregisterDisplayNoneStyleFor(aChild, aContainer);
         return false;
       }
       parentFrame = childFrame->GetParent();
       parentType = parentFrame->Type();
 
 #ifdef NOISY_FIRST_LETTER
       printf("  ==> revised parentFrame=");
       nsFrame::ListTag(stdout, parentFrame);
@@ -10165,17 +10180,16 @@ nsCSSFrameConstructor::ConstructFramesFr
   // that information offhand in many cases.
   MOZ_ASSERT(ParentIsWrapperAnonBox(aParentFrame) == aParentIsWrapperAnonBox);
 
   CreateNeededPseudoContainers(aState, aItems, aParentFrame);
   CreateNeededAnonFlexOrGridItems(aState, aItems, aParentFrame);
   CreateNeededPseudoInternalRubyBoxes(aState, aItems, aParentFrame);
   CreateNeededPseudoSiblings(aState, aItems, aParentFrame);
 
-  aItems.SetTriedConstructingFrames();
   for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
     NS_ASSERTION(iter.item().DesiredParentType() == GetParentType(aParentFrame),
                  "Needed pseudos didn't get created; expect bad things");
     ConstructFramesFromItem(aState, iter, aParentFrame, aFrameItems);
   }
 
   VerifyGridFlexContainerChildren(aParentFrame, aFrameItems);
   NS_ASSERTION(!aState.mHavePendingPopupgroup,
@@ -12226,18 +12240,17 @@ nsCSSFrameConstructor::FrameConstruction
 Iterator::AppendItemsToList(nsCSSFrameConstructor* aFCtor, const Iterator& aEnd,
                             FrameConstructionItemList& aTargetList)
 {
   NS_ASSERTION(&aTargetList != &mList, "Unexpected call");
   NS_PRECONDITION(&mList == &aEnd.mList, "End iterator for some other list?");
 
   // We can't just move our guts to the other list if it already has
   // some information or if we're not moving our entire list.
-  if (!AtStart() || !aEnd.IsDone() || !aTargetList.IsEmpty() ||
-      !aTargetList.mUndisplayedItems.IsEmpty()) {
+  if (!AtStart() || !aEnd.IsDone() || !aTargetList.IsEmpty()) {
     do {
       AppendItemToList(aTargetList);
     } while (*this != aEnd);
     return;
   }
 
   // Move our entire list of items into the empty target list.
   aTargetList.mItems = Move(mList.mItems);
@@ -12245,19 +12258,16 @@ Iterator::AppendItemsToList(nsCSSFrameCo
   // Copy over the various counters
   aTargetList.mInlineCount = mList.mInlineCount;
   aTargetList.mBlockCount = mList.mBlockCount;
   aTargetList.mLineParticipantCount = mList.mLineParticipantCount;
   aTargetList.mItemCount = mList.mItemCount;
   memcpy(aTargetList.mDesiredParentCounts, mList.mDesiredParentCounts,
          sizeof(aTargetList.mDesiredParentCounts));
 
-  // Swap out undisplayed item arrays, before we nuke the array on our end
-  aTargetList.mUndisplayedItems.SwapElements(mList.mUndisplayedItems);
-
   // reset mList
   mList.Reset(aFCtor);
 
   // Point ourselves to aEnd, as advertised
   SetToEnd();
   MOZ_ASSERT(*this == aEnd, "How did that happen?");
 }
 
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -828,17 +828,16 @@ private:
       new (this) FrameConstructionItemList();
     }
 
     void SetLineBoundaryAtStart(bool aBoundary) { mLineBoundaryAtStart = aBoundary; }
     void SetLineBoundaryAtEnd(bool aBoundary) { mLineBoundaryAtEnd = aBoundary; }
     void SetParentHasNoXBLChildren(bool aHasNoXBLChildren) {
       mParentHasNoXBLChildren = aHasNoXBLChildren;
     }
-    void SetTriedConstructingFrames() { mTriedConstructingFrames = true; }
     bool HasLineBoundaryAtStart() { return mLineBoundaryAtStart; }
     bool HasLineBoundaryAtEnd() { return mLineBoundaryAtEnd; }
     bool ParentHasNoXBLChildren() { return mParentHasNoXBLChildren; }
     bool IsEmpty() const { return mItems.isEmpty(); }
     bool AnyItemsNeedBlockParent() const { return mLineParticipantCount != 0; }
     bool AreAllItemsInline() const { return mInlineCount == mItemCount; }
     bool AreAllItemsBlock() const { return mBlockCount == mItemCount; }
     bool AllWantParentType(ParentType aDesiredParentType) const {
@@ -883,21 +882,16 @@ private:
                                            aSuppressWhiteSpaceOptimizations,
                                            aAnonChildren);
       mItems.insertFront(item);
       ++mItemCount;
       ++mDesiredParentCounts[item->DesiredParentType()];
       return item;
     }
 
-    void AppendUndisplayedItem(nsIContent* aContent,
-                               ComputedStyle* aComputedStyle) {
-      mUndisplayedItems.AppendElement(UndisplayedItem(aContent, aComputedStyle));
-    }
-
     void InlineItemAdded() { ++mInlineCount; }
     void BlockItemAdded() { ++mBlockCount; }
     void LineParticipantItemAdded() { ++mLineParticipantCount; }
 
     class Iterator {
     public:
       explicit Iterator(FrameConstructionItemList& aList)
         : mCurrent(aList.mItems.getFirst())
@@ -1019,38 +1013,27 @@ private:
   protected:
     FrameConstructionItemList() :
       mInlineCount(0),
       mBlockCount(0),
       mLineParticipantCount(0),
       mItemCount(0),
       mLineBoundaryAtStart(false),
       mLineBoundaryAtEnd(false),
-      mParentHasNoXBLChildren(false),
-      mTriedConstructingFrames(false)
+      mParentHasNoXBLChildren(false)
     {
       MOZ_COUNT_CTOR(FrameConstructionItemList);
       memset(mDesiredParentCounts, 0, sizeof(mDesiredParentCounts));
     }
 
     void Destroy(nsCSSFrameConstructor* aFCtor)
     {
       while (FrameConstructionItem* item = mItems.popFirst()) {
         item->Delete(aFCtor);
       }
-
-      // Create the undisplayed entries for our mUndisplayedItems, if any, but
-      // only if we have tried constructing frames for this item list.  If we
-      // haven't, then we're just throwing it away and will probably try again.
-      if (!mUndisplayedItems.IsEmpty() && mTriedConstructingFrames) {
-        for (uint32_t i = 0; i < mUndisplayedItems.Length(); ++i) {
-          UndisplayedItem& item = mUndisplayedItems[i];
-          aFCtor->RegisterDisplayNoneStyleFor(item.mContent, item.mComputedStyle);
-        }
-      }
     }
 
     // Prevent stack instances (except as AutoFrameConstructionItemList).
     friend struct FrameConstructionItem;
     ~FrameConstructionItemList()
     {
       MOZ_COUNT_DTOR(FrameConstructionItemList);
       MOZ_ASSERT(mItems.isEmpty(), "leaking");
@@ -1076,33 +1059,30 @@ private:
       nsIContent * const mContent;
       RefPtr<ComputedStyle> mComputedStyle;
     };
 
     // Adjust our various counts for aItem being added or removed.  aDelta
     // should be either +1 or -1 depending on which is happening.
     void AdjustCountsForItem(FrameConstructionItem* aItem, int32_t aDelta);
 
-    nsTArray<UndisplayedItem> mUndisplayedItems;
     mozilla::LinkedList<FrameConstructionItem> mItems;
     uint32_t mInlineCount;
     uint32_t mBlockCount;
     uint32_t mLineParticipantCount;
     uint32_t mItemCount;
     uint32_t mDesiredParentCounts[eParentTypeCount];
     // True if there is guaranteed to be a line boundary before the
     // frames created by these items
     bool mLineBoundaryAtStart;
     // True if there is guaranteed to be a line boundary after the
     // frames created by these items
     bool mLineBoundaryAtEnd;
     // True if the parent is guaranteed to have no XBL anonymous children
     bool mParentHasNoXBLChildren;
-    // True if we have tried constructing frames from this list
-    bool mTriedConstructingFrames;
   };
 
   /* A struct representing a list of FrameConstructionItems on the stack. */
   struct MOZ_RAII AutoFrameConstructionItemList final
     : public FrameConstructionItemList
   {
     template<typename... Args>
     explicit AutoFrameConstructionItemList(nsCSSFrameConstructor* aFCtor, Args&&... args)
--- a/layout/base/nsFrameManager.cpp
+++ b/layout/base/nsFrameManager.cpp
@@ -35,69 +35,16 @@
 #include "mozilla/MemoryReporting.h"
 
 // #define DEBUG_UNDISPLAYED_MAP
 // #define DEBUG_DISPLAY_CONTENTS_MAP
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-/**
- * The undisplayed map is a class that maps a parent content node to the
- * undisplayed content children, and their ComputedStyles.
- *
- * The linked list of nodes holds strong references to the ComputedStyle and the
- * content.
- */
-class nsFrameManager::UndisplayedMap :
-  private nsClassHashtable<nsPtrHashKey<nsIContent>,
-                           LinkedList<UndisplayedNode>>
-{
-  typedef nsClassHashtable<nsPtrHashKey<nsIContent>, LinkedList<UndisplayedNode>> base_type;
-
-public:
-  UndisplayedMap();
-  ~UndisplayedMap();
-
-  UndisplayedNode* GetFirstNode(nsIContent* aParentContent);
-
-  void AddNodeFor(nsIContent* aParentContent,
-                  nsIContent* aChild,
-                  ComputedStyle* aStyle);
-
-  void RemoveNodeFor(nsIContent* aParentContent, UndisplayedNode* aNode);
-
-  void RemoveNodesFor(nsIContent* aParentContent);
-
-  nsAutoPtr<LinkedList<UndisplayedNode>>
-    UnlinkNodesFor(nsIContent* aParentContent);
-
-  // Removes all entries from the hash table
-  void  Clear();
-
-  /**
-   * Get the applicable parent for the map lookup. This is almost always the
-   * provided argument, except if it's a <xbl:children> element, in which case
-   * it's the parent of the children element.
-   *
-   * All functions that are entry points into code that handles "parent"
-   * objects (used as the hash table keys) must ensure that the parent objects
-   * that they act on (and pass to other code) have been normalized by calling
-   * this method.
-   */
-  static nsIContent* GetApplicableParent(nsIContent* aParent);
-
-  void AddSizeOfIncludingThis(nsWindowSizes& aSizes) const;
-
-protected:
-  LinkedList<UndisplayedNode>* GetListFor(nsIContent* aParentContent);
-  LinkedList<UndisplayedNode>* GetOrCreateListFor(nsIContent* aParentContent);
-  void AppendNodeFor(UndisplayedNode* aNode, nsIContent* aParentContent);
-};
-
 //----------------------------------------------------------------------
 
 nsFrameManager::~nsFrameManager()
 {
   NS_ASSERTION(!mPresShell, "nsFrameManager::Destroy never called");
 }
 
 void
@@ -108,368 +55,20 @@ nsFrameManager::Destroy()
   // Destroy the frame hierarchy.
   mPresShell->SetIgnoreFrameDestruction(true);
 
   if (mRootFrame) {
     mRootFrame->Destroy();
     mRootFrame = nullptr;
   }
 
-  delete mDisplayNoneMap;
-  mDisplayNoneMap = nullptr;
-  delete mDisplayContentsMap;
-  mDisplayContentsMap = nullptr;
-
   mPresShell = nullptr;
 }
 
 //----------------------------------------------------------------------
-
-/* static */ nsIContent*
-nsFrameManager::ParentForUndisplayedMap(const nsIContent* aContent)
-{
-  MOZ_ASSERT(aContent);
-
-  nsIContent* parent = aContent->GetParentElementCrossingShadowRoot();
-
-  // Normalize the parent:
-  parent = UndisplayedMap::GetApplicableParent(parent);
-
-  return parent;
-}
-
-/* static */ ComputedStyle*
-nsFrameManager::GetComputedStyleInMap(UndisplayedMap* aMap,
-                                     const nsIContent* aContent)
-{
-  UndisplayedNode* node = GetUndisplayedNodeInMapFor(aMap, aContent);
-  return node ? node->mStyle.get() : nullptr;
-}
-
-/* static */ UndisplayedNode*
-nsFrameManager::GetUndisplayedNodeInMapFor(UndisplayedMap* aMap,
-                                           const nsIContent* aContent)
-{
-  if (!aContent) {
-    return nullptr;
-  }
-
-  // This function is an entry point into UndisplayedMap handling code, so the
-  // parent that we act on must be normalized by GetApplicableParent (as per
-  // that function's documentation).  We rely on ParentForUndisplayedMap to
-  // have done that for us.
-  nsIContent* parent = ParentForUndisplayedMap(aContent);
-
-  for (UndisplayedNode* node = aMap->GetFirstNode(parent);
-       node; node = node->getNext()) {
-    if (node->mContent == aContent)
-      return node;
-  }
-
-  return nullptr;
-}
-
-
-/* static */ UndisplayedNode*
-nsFrameManager::GetAllUndisplayedNodesInMapFor(UndisplayedMap* aMap,
-                                               nsIContent* aParentContent)
-{
-  return aMap ? aMap->GetFirstNode(aParentContent) : nullptr;
-}
-
-UndisplayedNode*
-nsFrameManager::GetAllRegisteredDisplayNoneStylesIn(nsIContent* aParentContent)
-{
-  return GetAllUndisplayedNodesInMapFor(mDisplayNoneMap, aParentContent);
-}
-
-/* static */ void
-nsFrameManager::SetComputedStyleInMap(UndisplayedMap* aMap,
-                                     nsIContent* aContent,
-                                     ComputedStyle* aComputedStyle)
-{
-  MOZ_ASSERT(!aComputedStyle->GetPseudo(),
-             "Should only have actual elements here");
-
-#if defined(DEBUG_UNDISPLAYED_MAP) || defined(DEBUG_DISPLAY_BOX_CONTENTS_MAP)
-  static int i = 0;
-  printf("SetComputedStyleInMap(%d): p=%p \n", i++, (void *)aContent);
-#endif
-
-  MOZ_ASSERT(!GetComputedStyleInMap(aMap, aContent),
-             "Already have an entry for aContent");
-
-  // This function is an entry point into UndisplayedMap handling code, so the
-  // parent that we act on must be normalized by GetApplicableParent (as per
-  // that function's documentation).  We rely on ParentForUndisplayedMap to
-  // have done that for us.
-  nsIContent* parent = ParentForUndisplayedMap(aContent);
-  MOZ_ASSERT(parent || !aContent->GetParent(), "no non-elements");
-
-#ifdef DEBUG
-  nsIPresShell* shell = aComputedStyle->PresContext()->PresShell();
-  NS_ASSERTION(parent || (shell && shell->GetDocument() &&
-                          shell->GetDocument()->GetRootElement() == aContent),
-               "undisplayed content must have a parent, unless it's the root "
-               "element");
-#endif
-
-  // We set this bit as an optimization so that we can can know when a content
-  // node may have |display:none| or |display:contents| children.  This allows
-  // other parts of the code to avoid checking for such children in
-  // mDisplayNoneMap and mDisplayContentsMap if the bit isn't present on a node
-  // that it's handling.
-  if (parent) {
-    parent->SetMayHaveChildrenWithLayoutBoxesDisabled();
-  }
-
-  aMap->AddNodeFor(parent, aContent, aComputedStyle);
-}
-
-void
-nsFrameManager::RegisterDisplayNoneStyleFor(nsIContent* aContent,
-                                            ComputedStyle* aComputedStyle)
-{
-  if (!mDisplayNoneMap) {
-    mDisplayNoneMap = new UndisplayedMap;
-  }
-  SetComputedStyleInMap(mDisplayNoneMap, aContent, aComputedStyle);
-}
-
-/* static */ void
-nsFrameManager::ChangeComputedStyleInMap(UndisplayedMap* aMap,
-                                        nsIContent* aContent,
-                                        ComputedStyle* aComputedStyle)
-{
-  MOZ_ASSERT(aMap, "expecting a map");
-
-#if defined(DEBUG_UNDISPLAYED_MAP) || defined(DEBUG_DISPLAY_BOX_CONTENTS_MAP)
-   static int i = 0;
-   printf("ChangeComputedStyleInMap(%d): p=%p \n", i++, (void *)aContent);
-#endif
-
-  // This function is an entry point into UndisplayedMap handling code, so the
-  // parent that we act on must be normalized by GetApplicableParent (as per
-  // that function's documentation).  We rely on ParentForUndisplayedMap to
-  // have done that for us.
-  nsIContent* parent = ParentForUndisplayedMap(aContent);
-  MOZ_ASSERT(parent || !aContent->GetParent(), "no non-elements");
-
-  for (UndisplayedNode* node = aMap->GetFirstNode(parent);
-       node; node = node->getNext()) {
-    if (node->mContent == aContent) {
-      node->mStyle = aComputedStyle;
-      return;
-    }
-  }
-
-  MOZ_CRASH("couldn't find the entry to change");
-}
-
-void
-nsFrameManager::UnregisterDisplayNoneStyleFor(nsIContent* aContent,
-                                              nsIContent* aParentContent)
-{
-#ifdef DEBUG_UNDISPLAYED_MAP
-  static int i = 0;
-  printf("ClearUndisplayedContent(%d): content=%p parent=%p --> ", i++, (void *)aContent, (void*)aParentContent);
-#endif
-
-  if (!mDisplayNoneMap) {
-    return;
-  }
-
-  // This function is an entry point into UndisplayedMap handling code, so we
-  // must call GetApplicableParent so the parent we pass around is correct.
-  aParentContent = UndisplayedMap::GetApplicableParent(aParentContent);
-
-  if (aParentContent &&
-      !aParentContent->MayHaveChildrenWithLayoutBoxesDisabled()) {
-    MOZ_ASSERT(!mDisplayNoneMap->GetFirstNode(aParentContent),
-               "MayHaveChildrenWithLayoutBoxesDisabled bit out of sync - "
-               "may fail to remove node from mDisplayNoneMap");
-    return;
-  }
-
-  UndisplayedNode* node = mDisplayNoneMap->GetFirstNode(aParentContent);
-
-  const bool haveOneDisplayNoneChild = node && !node->getNext();
-
-  for (; node; node = node->getNext()) {
-    if (node->mContent == aContent) {
-      mDisplayNoneMap->RemoveNodeFor(aParentContent, node);
-
-#ifdef DEBUG_UNDISPLAYED_MAP
-      printf( "REMOVED!\n");
-#endif
-      // make sure that there are no more entries for the same content
-      MOZ_ASSERT(!GetDisplayNoneStyleFor(aContent),
-                 "Found more undisplayed content data after removal");
-
-      if (haveOneDisplayNoneChild) {
-        // There are no more children of aParentContent in mDisplayNoneMap.
-        MOZ_ASSERT(!mDisplayNoneMap->GetFirstNode(aParentContent),
-                   "Bad UnsetMayHaveChildrenWithLayoutBoxesDisabled call");
-        // If we also know that none of its children are in mDisplayContentsMap
-        // then we can call UnsetMayHaveChildrenWithLayoutBoxesDisabled.  We
-        // don't want to check mDisplayContentsMap though since that involves a
-        // hash table lookup in relatively hot code.  Still, we know there are
-        // no children in mDisplayContentsMap if the map is empty, so we do
-        // check for that.
-        if (aParentContent && !mDisplayContentsMap) {
-          aParentContent->UnsetMayHaveChildrenWithLayoutBoxesDisabled();
-        }
-      }
-
-      return;
-    }
-  }
-
-#ifdef DEBUG_UNDISPLAYED_MAP
-  printf( "not found.\n");
-#endif
-}
-
-void
-nsFrameManager::ClearAllMapsFor(nsIContent* aParentContent)
-{
-#if defined(DEBUG_UNDISPLAYED_MAP) || defined(DEBUG_DISPLAY_CONTENTS_MAP)
-  static int i = 0;
-  printf("ClearAllMapsFor(%d): parent=%p \n", i++, aParentContent);
-#endif
-
-  if (!aParentContent ||
-      aParentContent->MayHaveChildrenWithLayoutBoxesDisabled()) {
-    if (mDisplayNoneMap) {
-      mDisplayNoneMap->RemoveNodesFor(aParentContent);
-    }
-    if (mDisplayContentsMap) {
-      nsAutoPtr<LinkedList<UndisplayedNode>> list =
-        mDisplayContentsMap->UnlinkNodesFor(aParentContent);
-      if (list) {
-        while (UndisplayedNode* node = list->popFirst()) {
-          ClearAllMapsFor(node->mContent);
-          delete node;
-        }
-      }
-    }
-    if (aParentContent) {
-      aParentContent->UnsetMayHaveChildrenWithLayoutBoxesDisabled();
-    }
-  }
-#ifdef DEBUG
-  else {
-    if (mDisplayNoneMap) {
-      MOZ_ASSERT(!mDisplayNoneMap->GetFirstNode(aParentContent),
-                 "We failed to remove a node from mDisplayNoneMap");
-    }
-    if (mDisplayContentsMap) {
-      MOZ_ASSERT(!mDisplayContentsMap->GetFirstNode(aParentContent),
-                 "We failed to remove a node from mDisplayContentsMap");
-    }
-  }
-#endif
-
-  // Need to look at aParentContent's content list due to XBL insertions.
-  // Nodes in aParentContent's content list do not have aParentContent as a
-  // parent, but are treated as children of aParentContent. We iterate over
-  // the flattened content list and just ignore any nodes we don't care about.
-  FlattenedChildIterator iter(aParentContent);
-  for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
-    auto parent = child->GetParent();
-    if (parent != aParentContent) {
-      UnregisterDisplayNoneStyleFor(child, parent);
-      UnregisterDisplayContentsStyleFor(child, parent);
-    }
-  }
-}
-
-//----------------------------------------------------------------------
-
-void
-nsFrameManager::RegisterDisplayContentsStyleFor(nsIContent* aContent,
-                                                ComputedStyle* aComputedStyle)
-{
-  if (!mDisplayContentsMap) {
-    mDisplayContentsMap = new UndisplayedMap;
-  }
-  SetComputedStyleInMap(mDisplayContentsMap, aContent, aComputedStyle);
-}
-
-UndisplayedNode*
-nsFrameManager::GetAllRegisteredDisplayContentsStylesIn(nsIContent* aParentContent)
-{
-  return GetAllUndisplayedNodesInMapFor(mDisplayContentsMap, aParentContent);
-}
-
-void
-nsFrameManager::UnregisterDisplayContentsStyleFor(nsIContent* aContent,
-                                                  nsIContent* aParentContent)
-{
-#ifdef DEBUG_DISPLAY_CONTENTS_MAP
-  static int i = 0;
-  printf("ClearDisplayContents(%d): content=%p parent=%p --> ", i++, (void *)aContent, (void*)aParentContent);
-#endif
-
-  if (!mDisplayContentsMap) {
-    return;
-  }
-
-  // This function is an entry point into UndisplayedMap handling code, so we
-  // must call GetApplicableParent so the parent we pass around is correct.
-  aParentContent = UndisplayedMap::GetApplicableParent(aParentContent);
-
-  if (aParentContent &&
-      !aParentContent->MayHaveChildrenWithLayoutBoxesDisabled()) {
-    MOZ_ASSERT(!mDisplayContentsMap->GetFirstNode(aParentContent),
-               "MayHaveChildrenWithLayoutBoxesDisabled bit out of sync - "
-               "may fail to remove node from mDisplayContentsMap");
-    return;
-  }
-
-  UndisplayedNode* node = mDisplayContentsMap->GetFirstNode(aParentContent);
-
-  const bool haveOneDisplayContentsChild = node && !node->getNext();
-
-  for (; node; node = node->getNext()) {
-    if (node->mContent == aContent) {
-      mDisplayContentsMap->RemoveNodeFor(aParentContent, node);
-
-#ifdef DEBUG_DISPLAY_CONTENTS_MAP
-      printf( "REMOVED!\n");
-#endif
-      // make sure that there are no more entries for the same content
-      MOZ_ASSERT(!GetDisplayContentsStyleFor(aContent),
-                 "Found more entries for aContent after removal");
-      ClearAllMapsFor(aContent);
-
-      if (haveOneDisplayContentsChild) {
-        // There are no more children of aParentContent in mDisplayContentsMap.
-        MOZ_ASSERT(!mDisplayContentsMap->GetFirstNode(aParentContent),
-                   "Bad UnsetMayHaveChildrenWithLayoutBoxesDisabled call");
-        // If we also know that none of its children are in mDisplayNoneMap
-        // then we can call UnsetMayHaveChildrenWithLayoutBoxesDisabled.  We
-        // don't want to check mDisplayNoneMap though since that involves a
-        // hash table lookup in relatively hot code.  Still, we know there are
-        // no children in mDisplayNoneMap if the map is empty, so we do
-        // check for that.
-        if (aParentContent && !mDisplayNoneMap) {
-          aParentContent->UnsetMayHaveChildrenWithLayoutBoxesDisabled();
-        }
-      }
-
-      return;
-    }
-  }
-#ifdef DEBUG_DISPLAY_CONTENTS_MAP
-  printf( "not found.\n");
-#endif
-}
-
-//----------------------------------------------------------------------
 void
 nsFrameManager::AppendFrames(nsContainerFrame* aParentFrame,
                              ChildListID       aListID,
                              nsFrameList&      aFrameList)
 {
   if (aParentFrame->IsAbsoluteContainer() &&
       aListID == aParentFrame->GetAbsoluteListID()) {
     aParentFrame->GetAbsoluteContainingBlock()->
@@ -530,25 +129,16 @@ nsFrameManager::RemoveFrame(ChildListID 
     parentFrame->RemoveFrame(aListID, aOldFrame);
   }
 
   mIsDestroyingFrames = wasDestroyingFrames;
 }
 
 //----------------------------------------------------------------------
 
-void
-nsFrameManager::NotifyDestroyingFrame(nsIFrame* aFrame)
-{
-  nsIContent* content = aFrame->GetContent();
-  if (content && content->GetPrimaryFrame() == aFrame) {
-    ClearAllMapsFor(content);
-  }
-}
-
 // Capture state for a given frame.
 // Accept a content id here, in some cases we may not have content (scroll position)
 void
 nsFrameManager::CaptureFrameStateFor(nsIFrame* aFrame,
                                      nsILayoutHistoryState* aState)
 {
   if (!aFrame || !aState) {
     NS_WARNING("null frame, or state");
@@ -673,189 +263,18 @@ nsFrameManager::RestoreFrameState(nsIFra
       RestoreFrameState(childFrames.get(), aState);
     }
   }
 }
 
 void
 nsFrameManager::DestroyAnonymousContent(already_AddRefed<nsIContent> aContent)
 {
-  nsCOMPtr<nsIContent> content = aContent;
-  if (content) {
-    // Invoke ClearAllMapsFor before unbinding from the tree. When we unbind,
-    // we remove the mPrimaryFrame pointer, which is used by the frame
-    // teardown code to determine whether to invoke ClearAllMapsFor or not.
-    // These maps will go away when we drop support for the old style system.
-    ClearAllMapsFor(content);
-
+  if (nsCOMPtr<nsIContent> content = aContent) {
     content->UnbindFromTree();
   }
 }
 
 void
 nsFrameManager::AddSizeOfIncludingThis(nsWindowSizes& aSizes) const
 {
   aSizes.mLayoutPresShellSize += aSizes.mState.mMallocSizeOf(this);
-  if (mDisplayNoneMap) {
-    mDisplayNoneMap->AddSizeOfIncludingThis(aSizes);
-  }
-  if (mDisplayContentsMap) {
-    mDisplayContentsMap->AddSizeOfIncludingThis(aSizes);
-  }
 }
-
-//----------------------------------------------------------------------
-
-nsFrameManager::UndisplayedMap::UndisplayedMap()
-{
-  MOZ_COUNT_CTOR(nsFrameManager::UndisplayedMap);
-}
-
-nsFrameManager::UndisplayedMap::~UndisplayedMap(void)
-{
-  MOZ_COUNT_DTOR(nsFrameManager::UndisplayedMap);
-  Clear();
-}
-
-void
-nsFrameManager::UndisplayedMap::Clear()
-{
-  for (auto iter = Iter(); !iter.Done(); iter.Next()) {
-    auto* list = iter.UserData();
-    while (auto* node = list->popFirst()) {
-      delete node;
-    }
-    iter.Remove();
-  }
-}
-
-
-nsIContent*
-nsFrameManager::UndisplayedMap::GetApplicableParent(nsIContent* aParent)
-{
-  // In the case of XBL default content, <xbl:children> elements do not get a
-  // frame causing a mismatch between the content tree and the frame tree.
-  // |GetEntryFor| is sometimes called with the content tree parent (which may
-  // be a <xbl:children> element) but the parent in the frame tree would be the
-  // insertion parent (parent of the <xbl:children> element). Here the children
-  // elements are normalized to the insertion parent to correct for the mismatch.
-  if (aParent && aParent->IsActiveChildrenElement()) {
-    return aParent->GetParent();
-  }
-
-  return aParent;
-}
-
-LinkedList<UndisplayedNode>*
-nsFrameManager::UndisplayedMap::GetListFor(nsIContent* aParent)
-{
-  MOZ_ASSERT(aParent == GetApplicableParent(aParent),
-             "The parent that we use as the hash key must have been normalized");
-
-  LinkedList<UndisplayedNode>* list;
-  if (Get(aParent, &list)) {
-    return list;
-  }
-
-  return nullptr;
-}
-
-LinkedList<UndisplayedNode>*
-nsFrameManager::UndisplayedMap::GetOrCreateListFor(nsIContent* aParent)
-{
-  MOZ_ASSERT(aParent == GetApplicableParent(aParent),
-             "The parent that we use as the hash key must have been normalized");
-
-  return LookupOrAdd(aParent);
-}
-
-
-UndisplayedNode*
-nsFrameManager::UndisplayedMap::GetFirstNode(nsIContent* aParentContent)
-{
-  auto* list = GetListFor(aParentContent);
-  return list ? list->getFirst() : nullptr;
-}
-
-
-void
-nsFrameManager::UndisplayedMap::AppendNodeFor(UndisplayedNode* aNode,
-                                              nsIContent* aParentContent)
-{
-  LinkedList<UndisplayedNode>* list = GetOrCreateListFor(aParentContent);
-
-#ifdef DEBUG
-  for (UndisplayedNode* node = list->getFirst(); node; node = node->getNext()) {
-    // NOTE: In the original code there was a work around for this case, I want
-    // to check it still happens before hacking around it the same way.
-    MOZ_ASSERT(node->mContent != aNode->mContent,
-               "Duplicated content in undisplayed list!");
-  }
-#endif
-
-  list->insertBack(aNode);
-}
-
-void
-nsFrameManager::UndisplayedMap::AddNodeFor(nsIContent* aParentContent,
-                                           nsIContent* aChild,
-                                           ComputedStyle* aStyle)
-{
-  UndisplayedNode*  node = new UndisplayedNode(aChild, aStyle);
-  AppendNodeFor(node, aParentContent);
-}
-
-void
-nsFrameManager::UndisplayedMap::RemoveNodeFor(nsIContent* aParentContent,
-                                              UndisplayedNode* aNode)
-{
-#ifdef DEBUG
-  auto list = GetListFor(aParentContent);
-  MOZ_ASSERT(list, "content not in map");
-  aNode->removeFrom(*list);
-#else
-  aNode->remove();
-#endif
-  delete aNode;
-}
-
-
-nsAutoPtr<LinkedList<UndisplayedNode>>
-nsFrameManager::UndisplayedMap::UnlinkNodesFor(nsIContent* aParentContent)
-{
-  nsAutoPtr<LinkedList<UndisplayedNode>> list;
-  Remove(GetApplicableParent(aParentContent), &list);
-  return list;
-}
-
-void
-nsFrameManager::UndisplayedMap::RemoveNodesFor(nsIContent* aParentContent)
-{
-  nsAutoPtr<LinkedList<UndisplayedNode>> list = UnlinkNodesFor(aParentContent);
-  if (list) {
-    while (auto* node = list->popFirst()) {
-      delete node;
-    }
-  }
-}
-
-void
-nsFrameManager::UndisplayedMap::
-AddSizeOfIncludingThis(nsWindowSizes& aSizes) const
-{
-  MallocSizeOf mallocSizeOf = aSizes.mState.mMallocSizeOf;
-  aSizes.mLayoutPresShellSize += ShallowSizeOfIncludingThis(mallocSizeOf);
-
-  nsWindowSizes staleSizes(aSizes.mState);
-  for (auto iter = ConstIter(); !iter.Done(); iter.Next()) {
-    const LinkedList<UndisplayedNode>* list = iter.UserData();
-    aSizes.mLayoutPresShellSize += list->sizeOfExcludingThis(mallocSizeOf);
-    for (const UndisplayedNode* node = list->getFirst();
-          node; node = node->getNext()) {
-      ComputedStyle* computedStyle = node->mStyle;
-      if (!aSizes.mState.HaveSeenPtr(computedStyle)) {
-        computedStyle->AddSizeOfIncludingThis(
-          staleSizes, &aSizes.mLayoutComputedValuesStale);
-      }
-    }
-  }
-  aSizes.mLayoutComputedValuesStale += staleSizes.getTotalSize();
-}
--- a/layout/base/nsFrameManager.h
+++ b/layout/base/nsFrameManager.h
@@ -14,42 +14,34 @@
 #include "nsFrameList.h"
 
 class nsContainerFrame;
 class nsIFrame;
 class nsILayoutHistoryState;
 class nsIPresShell;
 class nsPlaceholderFrame;
 class nsWindowSizes;
-namespace mozilla {
-class ComputedStyle;
-struct UndisplayedNode;
-}
 
 /**
  * Frame manager interface. The frame manager serves one purpose:
  * <li>handles structural modifications to the frame model. If the frame model
  * lock can be acquired, then the changes are processed immediately; otherwise,
  * they're queued and processed later.
  *
  * FIXME(emilio): The comment above doesn't make any sense, there's no "frame
  * model lock" of any sort afaict.
  */
 class nsFrameManager
 {
-  typedef mozilla::ComputedStyle ComputedStyle;
   typedef mozilla::layout::FrameChildListID ChildListID;
-  typedef mozilla::UndisplayedNode UndisplayedNode;
 
 public:
   explicit nsFrameManager(nsIPresShell* aPresShell)
     : mPresShell(aPresShell)
     , mRootFrame(nullptr)
-    , mDisplayNoneMap(nullptr)
-    , mDisplayContentsMap(nullptr)
     , mIsDestroyingFrames(false)
   {
     MOZ_ASSERT(mPresShell, "need a pres shell");
   }
   ~nsFrameManager();
 
   bool IsDestroyingFrames() const { return mIsDestroyingFrames; }
 
@@ -67,127 +59,29 @@ public:
 
   /*
    * After Destroy is called, it is an error to call any FrameManager methods.
    * Destroy should be called when the frame tree managed by the frame
    * manager is no longer being displayed.
    */
   void Destroy();
 
-
-  // display:none and display:contents content does not get an nsIFrame.  To
-  // enable the style for such content to be obtained we store them in a
-  // couple of hash tables.  The following methods provide the API that's used
-  // to set, reset, obtain and clear these styles.
-  //
-  // FIXME(stylo-everywhere): This should go away now.
-
-  /**
-   * Register the style for the display:none content, aContent.
-   */
-  void RegisterDisplayNoneStyleFor(nsIContent* aContent,
-                                   ComputedStyle* aComputedStyle);
-
-  /**
-   * Register the style for the display:contents content, aContent.
-   */
-  void RegisterDisplayContentsStyleFor(nsIContent* aContent,
-                                       ComputedStyle* aComputedStyle);
-
-  /**
-   * Change the style for the display:none content, aContent.
-   */
-  void ChangeRegisteredDisplayNoneStyleFor(nsIContent* aContent,
-                                           ComputedStyle* aComputedStyle)
-  {
-    ChangeComputedStyleInMap(mDisplayNoneMap, aContent, aComputedStyle);
-  }
-
-  /**
-   * Change the style for the display:contents content, aContent.
-   */
-  void ChangeRegisteredDisplayContentsStyleFor(nsIContent* aContent,
-                                               ComputedStyle* aComputedStyle)
-  {
-    ChangeComputedStyleInMap(mDisplayContentsMap, aContent, aComputedStyle);
-  }
-
-  /**
-   * Get the style for the display:none content, aContent, if any.
-   */
-  ComputedStyle* GetDisplayNoneStyleFor(const nsIContent* aContent)
-  {
-    if (!mDisplayNoneMap) {
-      return nullptr;
-    }
-    return GetComputedStyleInMap(mDisplayNoneMap, aContent);
-  }
-
-  /**
-   * Get the style for the display:contents content, aContent, if any.
-   */
-  ComputedStyle* GetDisplayContentsStyleFor(const nsIContent* aContent)
-  {
-    if (!mDisplayContentsMap) {
-      return nullptr;
-    }
-    return GetComputedStyleInMap(mDisplayContentsMap, aContent);
-  }
-
-  /**
-   * Return the linked list of UndisplayedNodes that contain the styles that
-   * been registered for the display:none children of aParentContent.
-   */
-  UndisplayedNode*
-  GetAllRegisteredDisplayNoneStylesIn(nsIContent* aParentContent);
-
-  /**
-   * Return the linked list of UndisplayedNodes that contain the styles
-   * that have been registered for the display:contents children of
-   * aParentContent.
-   */
-  UndisplayedNode*
-  GetAllRegisteredDisplayContentsStylesIn(nsIContent* aParentContent);
-
-  /**
-   * Unregister the style for the display:none content, aContent, if
-   * any.  If found, then this method also unregisters the styles for any
-   * display:contents and display:none descendants of aContent.
-   */
-  void UnregisterDisplayNoneStyleFor(nsIContent* aContent,
-                                     nsIContent* aParentContent);
-
-  /**
-   * Unregister the style for the display:contents content, aContent, if any.
-   * If found, then this method also unregisters the style for any
-   * display:contents and display:none descendants of aContent.
-   */
-  void UnregisterDisplayContentsStyleFor(nsIContent* aContent,
-                                         nsIContent* aParentContent);
-
-
   // Functions for manipulating the frame model
   void AppendFrames(nsContainerFrame* aParentFrame,
                     ChildListID aListID,
                     nsFrameList& aFrameList);
 
   void InsertFrames(nsContainerFrame* aParentFrame,
                     ChildListID aListID,
                     nsIFrame* aPrevFrame,
                     nsFrameList& aFrameList);
 
   void RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame);
 
   /*
-   * Notification that a frame is about to be destroyed. This allows any
-   * outstanding references to the frame to be cleaned up.
-   */
-  void NotifyDestroyingFrame(nsIFrame* aFrame);
-
-  /*
    * Capture/restore frame state for the frame subtree rooted at aFrame.
    * aState is the document state storage object onto which each frame
    * stores its state.  Callers of CaptureFrameState are responsible for
    * traversing next continuations of special siblings of aFrame as
    * needed; this method will only work with actual frametree descendants
    * of aFrame.
    */
 
@@ -202,39 +96,15 @@ public:
 
   void RestoreFrameStateFor(nsIFrame* aFrame, nsILayoutHistoryState* aState);
 
   void DestroyAnonymousContent(already_AddRefed<nsIContent> aContent);
 
   void AddSizeOfIncludingThis(nsWindowSizes& aSizes) const;
 
 protected:
-  class UndisplayedMap;
-
-  static nsIContent* ParentForUndisplayedMap(const nsIContent* aContent);
-
-  void ClearAllMapsFor(nsIContent* aParentContent);
-
-  static ComputedStyle* GetComputedStyleInMap(UndisplayedMap* aMap,
-                                              const nsIContent* aContent);
-  static UndisplayedNode* GetUndisplayedNodeInMapFor(UndisplayedMap* aMap,
-                                                     const nsIContent* aContent);
-  static UndisplayedNode* GetAllUndisplayedNodesInMapFor(UndisplayedMap* aMap,
-                                                         nsIContent* aParentContent);
-  static void SetComputedStyleInMap(
-      UndisplayedMap* aMap,
-      nsIContent* aContent,
-      ComputedStyle* aComputedStyle);
-
-  static void ChangeComputedStyleInMap(
-      UndisplayedMap* aMap,
-      nsIContent* aContent,
-      ComputedStyle* aComputedStyle);
-
   // weak link, because the pres shell owns us
   nsIPresShell* MOZ_NON_OWNING_REF mPresShell;
   nsIFrame* mRootFrame;
-  UndisplayedMap* mDisplayNoneMap;
-  UndisplayedMap* mDisplayContentsMap;
   bool mIsDestroyingFrames;  // The frame manager is destroying some frame(s).
 };
 
 #endif
--- a/layout/base/nsStyleChangeList.cpp
+++ b/layout/base/nsStyleChangeList.cpp
@@ -6,16 +6,18 @@
 
 /*
  * a list of the recomputation that needs to be done in response to a
  * style change
  */
 
 #include "nsStyleChangeList.h"
 
+#include "mozilla/dom/ElementInlines.h"
+
 #include "nsCSSFrameConstructor.h"
 #include "nsIContent.h"
 #include "nsIFrame.h"
 
 void
 nsStyleChangeList::AppendChange(nsIFrame* aFrame, nsIContent* aContent, nsChangeHint aHint)
 {
   MOZ_ASSERT(aFrame || (aHint & nsChangeHint_ReconstructFrame),
@@ -24,19 +26,19 @@ nsStyleChangeList::AppendChange(nsIFrame
   MOZ_ASSERT(!(aHint & nsChangeHint_NeutralChange),
              "Neutral changes do not need extra processing, "
              "and should be stripped out");
   MOZ_ASSERT(aContent || !(aHint & nsChangeHint_ReconstructFrame),
              "must have content");
   // XXXbz we should make this take Element instead of nsIContent
   MOZ_ASSERT(!aContent || aContent->IsElement() ||
              // display:contents elements posts the changes for their children:
-             (aFrame && aContent->GetParent() &&
-             aFrame->PresContext()->FrameConstructor()->
-               GetDisplayContentsStyleFor(aContent->GetParent())) ||
+             (aFrame && aContent->GetFlattenedTreeParentElementForStyle() &&
+              Servo_Element_IsDisplayContents(
+                aContent->GetFlattenedTreeParentElementForStyle())) ||
              (aContent->IsNodeOfType(nsINode::eTEXT) &&
               aContent->HasFlag(NODE_NEEDS_FRAME) &&
               aHint & nsChangeHint_ReconstructFrame),
              "Shouldn't be trying to restyle non-elements directly, "
              "except if it's a display:contents child or a text node "
              "doing lazy frame construction");
   MOZ_ASSERT(!(aHint & nsChangeHint_AllReflowHints) ||
              (aHint & nsChangeHint_NeedReflow),
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -11,16 +11,17 @@
 #include <stdarg.h>
 #include <algorithm>
 
 #include "gfx2DGlue.h"
 #include "gfxUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ComputedStyle.h"
 #include "mozilla/DebugOnly.h"
+#include "mozilla/dom/ElementInlines.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/PathHelpers.h"
 #include "mozilla/Sprintf.h"
 
 #include "nsCOMPtr.h"
 #include "nsFrameList.h"
 #include "nsPlaceholderFrame.h"
 #include "nsPluginFrame.h"
@@ -101,16 +102,18 @@
 #include "mozilla/EffectSet.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/ServoStyleSet.h"
+#include "mozilla/ServoStyleSetInlines.h"
+#include "mozilla/css/ImageLoader.h"
 #include "mozilla/gfx/Tools.h"
 #include "nsPrintfCString.h"
 #include "ActiveLayerTracker.h"
 
 #include "nsITheme.h"
 #include "nsThemeConstants.h"
 
 #include "ImageLoader.h"
@@ -9896,32 +9899,37 @@ nsFrame::CorrectStyleParentFrame(nsIFram
 ComputedStyle*
 nsFrame::DoGetParentComputedStyle(nsIFrame** aProviderFrame) const
 {
   *aProviderFrame = nullptr;
 
   // Handle display:contents and the root frame, when there's no parent frame
   // to inherit from.
   if (MOZ_LIKELY(mContent)) {
-    nsIContent* parentContent = mContent->GetFlattenedTreeParent();
-    if (MOZ_LIKELY(parentContent)) {
+    Element* parentElement = mContent->GetFlattenedTreeParentElement();
+    if (MOZ_LIKELY(parentElement)) {
       nsAtom* pseudo = Style()->GetPseudo();
       if (!pseudo || !mContent->IsElement() ||
           (!nsCSSAnonBoxes::IsAnonBox(pseudo) &&
            // Ensure that we don't return the display:contents style
            // of the parent content for pseudos that have the same content
            // as their primary frame (like -moz-list-bullets do):
            IsPrimaryFrame()) ||
           /* if next is true then it's really a request for the table frame's
              parent context, see nsTable[Outer]Frame::GetParentComputedStyle. */
           pseudo == nsCSSAnonBoxes::tableWrapper) {
-        nsCSSFrameConstructor* fm = PresContext()->FrameConstructor();
-        ComputedStyle* sc = fm->GetDisplayContentsStyleFor(parentContent);
-        if (MOZ_UNLIKELY(sc)) {
-          return sc;
+        if (Servo_Element_IsDisplayContents(parentElement)) {
+          RefPtr<ComputedStyle> style =
+            PresShell()->StyleSet()->ResolveServoStyle(parentElement);
+          // NOTE(emilio): we return a weak reference because the element also
+          // holds the style context alive. This is a bit silly (we could've
+          // returned a weak ref directly), but it's probably not worth
+          // optimizing, given this function has just one caller which is rare,
+          // and this path is rare itself.
+          return style;
         }
       }
     } else {
       if (!Style()->GetPseudo()) {
         // We're a frame for the root.  We have no style parent.
         return nullptr;
       }
     }
--- a/layout/generic/nsFrameSelection.cpp
+++ b/layout/generic/nsFrameSelection.cpp
@@ -1583,30 +1583,36 @@ nsFrameSelection::RepaintSelection(Selec
   // and that it's a normal selection.
   if (fm->GetActiveWindow() && aSelectionType == SelectionType::eNormal) {
     UpdateSelectionCacheOnRepaintSelection(mDomSelections[index]);
   }
 #endif
   return mDomSelections[index]->Repaint(mShell->GetPresContext());
 }
 
+static bool
+IsDisplayContents(const nsIContent* aContent)
+{
+  return aContent->IsElement() && aContent->AsElement()->HasServoData() &&
+    Servo_Element_IsDisplayContents(aContent->AsElement());
+}
+
 nsIFrame*
 nsFrameSelection::GetFrameForNodeOffset(nsIContent*        aNode,
                                         int32_t            aOffset,
                                         CaretAssociateHint aHint,
                                         int32_t*           aReturnOffset) const
 {
   if (!aNode || !aReturnOffset || !mShell)
     return nullptr;
 
   if (aOffset < 0)
     return nullptr;
 
-  if (!aNode->GetPrimaryFrame() &&
-      !mShell->FrameConstructor()->GetDisplayContentsStyleFor(aNode)) {
+  if (!aNode->GetPrimaryFrame() && !IsDisplayContents(aNode)) {
     return nullptr;
   }
 
   nsIFrame* returnFrame = nullptr;
   nsCOMPtr<nsIContent> theNode;
 
   while (true) {
     *aReturnOffset = aOffset;
--- a/layout/generic/nsPlaceholderFrame.cpp
+++ b/layout/generic/nsPlaceholderFrame.cpp
@@ -8,17 +8,19 @@
  * rendering object for the point that anchors out-of-flow rendering
  * objects such as floats and absolutely positioned elements
  */
 
 #include "nsPlaceholderFrame.h"
 
 #include "gfxContext.h"
 #include "gfxUtils.h"
+#include "mozilla/dom/ElementInlines.h"
 #include "mozilla/gfx/2D.h"
+#include "mozilla/ServoStyleSetInlines.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsDisplayList.h"
 #include "nsLayoutUtils.h"
 #include "nsPresContext.h"
 #include "nsIFrameInlines.h"
 #include "nsIContentInlines.h"
 
 using namespace mozilla;
@@ -210,24 +212,25 @@ nsPlaceholderFrame::CanContinueTextRun()
   return mOutOfFlowFrame->CanContinueTextRun();
 }
 
 ComputedStyle*
 nsPlaceholderFrame::GetParentComputedStyleForOutOfFlow(nsIFrame** aProviderFrame) const
 {
   NS_PRECONDITION(GetParent(), "How can we not have a parent here?");
 
-  nsIContent* parentContent = mContent ? mContent->GetFlattenedTreeParent() : nullptr;
-  if (parentContent) {
-    ComputedStyle* sc =
-      PresContext()->FrameConstructor()->GetDisplayContentsStyleFor(parentContent);
-    if (sc) {
-      *aProviderFrame = nullptr;
-      return sc;
-    }
+  Element* parentElement =
+    mContent ? mContent->GetFlattenedTreeParentElement() : nullptr;
+  if (parentElement && Servo_Element_IsDisplayContents(parentElement)) {
+    RefPtr<ComputedStyle> style =
+      PresShell()->StyleSet()->ResolveServoStyle(parentElement);
+    *aProviderFrame = nullptr;
+    // See the comment in GetParentComputedStyle to see why returning this as a
+    // weak ref is fine.
+    return style;
   }
 
   return GetLayoutParentStyleForOutOfFlow(aProviderFrame);
 }
 
 ComputedStyle*
 nsPlaceholderFrame::GetLayoutParentStyleForOutOfFlow(nsIFrame** aProviderFrame) const
 {
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -32,16 +32,19 @@ SERVO_BINDING_FUNC(Servo_Element_GetPrim
 SERVO_BINDING_FUNC(Servo_Element_HasPseudoComputedValues, bool,
                    RawGeckoElementBorrowed node, size_t index)
 SERVO_BINDING_FUNC(Servo_Element_GetPseudoComputedValues,
                    ComputedStyleStrong,
                    RawGeckoElementBorrowed node, size_t index)
 SERVO_BINDING_FUNC(Servo_Element_IsDisplayNone,
                    bool,
                    RawGeckoElementBorrowed element)
+SERVO_BINDING_FUNC(Servo_Element_IsDisplayContents,
+                   bool,
+                   RawGeckoElementBorrowed element)
 SERVO_BINDING_FUNC(Servo_Element_IsPrimaryStyleReusedViaRuleNode,
                    bool,
                    RawGeckoElementBorrowed element)
 SERVO_BINDING_FUNC(Servo_InvalidateStyleForDocStateChanges,
                    void,
                    RawGeckoElementBorrowed root,
                    RawServoStyleSetBorrowed doc_styles,
                    const nsTArray<RawServoAuthorStylesBorrowed>* non_document_styles,