Bug 907396 - Frame manager support for display:contents. r=bzbarsky
authorMats Palmgren <matspal@gmail.com>
Thu, 20 Nov 2014 18:24:09 +0000
changeset 243110 fbedf09e4ec38d08f956d8383ade5e06b8da6e19
parent 243109 07fe7c94219fa05645ad96b4529a8ab8ca4e3e80
child 243111 af9ca68d20ed255765df49142608d4345689a901
push id660
push userraliiev@mozilla.com
push dateWed, 18 Feb 2015 20:30:48 +0000
treeherdermozilla-release@49e493494178 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs907396
milestone36.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 907396 - Frame manager support for display:contents. r=bzbarsky
dom/base/Element.cpp
dom/xbl/nsXBLService.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsFrameManager.cpp
layout/base/nsFrameManager.h
layout/base/nsFrameManagerBase.h
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -20,16 +20,17 @@
 #include "nsIAtom.h"
 #include "nsIContentInlines.h"
 #include "mozilla/dom/NodeInfo.h"
 #include "nsIDocumentInlines.h"
 #include "nsIDOMNodeList.h"
 #include "nsIDOMDocument.h"
 #include "nsIContentIterator.h"
 #include "nsFocusManager.h"
+#include "nsFrameManager.h"
 #include "nsILinkHandler.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIURL.h"
 #include "nsNetUtil.h"
 #include "nsContainerFrame.h"
 #include "nsIAnonymousContentCreator.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
@@ -971,16 +972,17 @@ Element::CreateShadowRoot(ErrorResult& a
   }
 
   nsIDocument* doc = GetCrossShadowCurrentDoc();
   nsIContent* destroyedFramesFor = nullptr;
   if (doc) {
     nsIPresShell* shell = doc->GetShell();
     if (shell) {
       shell->DestroyFramesFor(this, &destroyedFramesFor);
+      MOZ_ASSERT(!shell->FrameManager()->GetDisplayContentsStyleFor(this));
     }
   }
   MOZ_ASSERT(!GetPrimaryFrame());
 
   // Unlike for XBL, false is the default for inheriting style.
   protoBinding->SetInheritsStyle(false);
 
   // Calling SetPrototypeBinding takes ownership of protoBinding.
--- a/dom/xbl/nsXBLService.cpp
+++ b/dom/xbl/nsXBLService.cpp
@@ -131,27 +131,30 @@ public:
       return;
 
     // If |mBoundElement| is (in addition to having binding |mBinding|)
     // also a descendant of another element with binding |mBinding|,
     // then we might have just constructed it due to the
     // notification of its parent.  (We can know about both if the
     // binding loads were triggered from the DOM rather than frame
     // construction.)  So we have to check both whether the element
-    // has a primary frame and whether it's in the undisplayed map
+    // has a primary frame and whether it's in the frame manager maps
     // before sending a ContentInserted notification, or bad things
     // will happen.
     MOZ_ASSERT(shell == doc->GetShell());
     if (shell) {
       nsIFrame* childFrame = mBoundElement->GetPrimaryFrame();
       if (!childFrame) {
-        // Check to see if it's in the undisplayed content map.
-        nsStyleContext* sc =
-          shell->FrameManager()->GetUndisplayedContent(mBoundElement);
-
+        // Check to see if it's in the undisplayed content map...
+        nsFrameManager* fm = shell->FrameManager();
+        nsStyleContext* sc = fm->GetUndisplayedContent(mBoundElement);
+        if (!sc) {
+          // or in the display:contents map.
+          sc = fm->GetDisplayContentsStyleFor(mBoundElement);
+        }
         if (!sc) {
           shell->CreateFramesFor(destroyedFramesFor);
         }
       }
     }
   }
 
   nsXBLBindingRequest(nsIURI* aURI, nsIContent* aBoundElement)
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -5395,16 +5395,18 @@ nsCSSFrameConstructor::AddFrameConstruct
                                                          nsStyleContext* aStyleContext,
                                                          uint32_t aFlags,
                                                          nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren,
                                                          FrameConstructionItemList& aItems)
 {
   NS_PRECONDITION(aContent->IsNodeOfType(nsINode::eTEXT) ||
                   aContent->IsElement(),
                   "Shouldn't get anything else here!");
+  MOZ_ASSERT(!aContent->GetPrimaryFrame() || aState.mCreatingExtraFrames ||
+             aContent->Tag() == nsGkAtoms::area);
 
   // The following code allows the user to specify the base tag
   // of an element using XBL.  XUL and HTML objects (like boxes, menus, etc.)
   // can then be extended arbitrarily.
   const nsStyleDisplay* display = aStyleContext->StyleDisplay();
   nsRefPtr<nsStyleContext> styleContext(aStyleContext);
   PendingBinding* pendingBinding = nullptr;
   if ((aFlags & ITEM_ALLOW_XBL_BASE) && display->mBinding)
--- a/layout/base/nsFrameManager.cpp
+++ b/layout/base/nsFrameManager.cpp
@@ -35,18 +35,20 @@
 
 #include "nsFrameManager.h"
 #include "GeckoProfiler.h"
 #include "nsIStatefulFrame.h"
 #include "nsContainerFrame.h"
 
   #ifdef DEBUG
     //#define DEBUG_UNDISPLAYED_MAP
+    //#define DEBUG_DISPLAY_CONTENTS_MAP
   #else
     #undef DEBUG_UNDISPLAYED_MAP
+    #undef DEBUG_DISPLAY_CONTENTS_MAP
   #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 //----------------------------------------------------------------------
 
 struct PlaceholderMapEntry : public PLDHashEntryHdr {
@@ -91,16 +93,17 @@ public:
 
   nsresult AddNodeFor(nsIContent* aParentContent,
                                   nsIContent* aChild, nsStyleContext* aStyle);
 
   void RemoveNodeFor(nsIContent* aParentContent,
                                  UndisplayedNode* aNode);
 
   void RemoveNodesFor(nsIContent* aParentContent);
+  UndisplayedNode* UnlinkNodesFor(nsIContent* aParentContent);
 
   // Removes all entries from the hash table
   void  Clear(void);
 
 protected:
   /**
    * Gets the entry for the provided parent content. If the content
    * is a <xbl:children> element, |**aParentContent| is set to
@@ -134,16 +137,18 @@ nsFrameManager::Destroy()
 
   if (mRootFrame) {
     mRootFrame->Destroy();
     mRootFrame = nullptr;
   }
   
   delete mUndisplayedMap;
   mUndisplayedMap = nullptr;
+  delete mDisplayContentsMap;
+  mDisplayContentsMap = nullptr;
 
   mPresShell = nullptr;
 }
 
 //----------------------------------------------------------------------
 
 // Placeholder frame functions
 nsPlaceholderFrame*
@@ -215,87 +220,103 @@ nsFrameManager::ClearPlaceholderFrameMap
     PL_DHashTableEnumerate(&mPlaceholderMap, UnregisterPlaceholders, nullptr);
     PL_DHashTableFinish(&mPlaceholderMap);
     mPlaceholderMap.ops = nullptr;
   }
 }
 
 //----------------------------------------------------------------------
 
-nsStyleContext*
-nsFrameManager::GetUndisplayedContent(nsIContent* aContent)
+/* static */ nsStyleContext*
+nsFrameManager::GetStyleContextInMap(UndisplayedMap* aMap, nsIContent* aContent)
 {
-  if (!aContent || !mUndisplayedMap)
+  if (!aContent) {
     return nullptr;
-
+  }
   nsIContent* parent = aContent->GetParent();
-  for (UndisplayedNode* node = mUndisplayedMap->GetFirstNode(parent);
+  for (UndisplayedNode* node = aMap->GetFirstNode(parent);
          node; node = node->mNext) {
     if (node->mContent == aContent)
       return node->mStyle;
   }
 
   return nullptr;
 }
 
+/* static */ UndisplayedNode*
+nsFrameManager::GetAllUndisplayedNodesInMapFor(UndisplayedMap* aMap,
+                                               nsIContent* aParentContent)
+{
+  return aMap ? aMap->GetFirstNode(aParentContent) : nullptr;
+}
+
 UndisplayedNode*
 nsFrameManager::GetAllUndisplayedContentIn(nsIContent* aParentContent)
 {
-  if (!mUndisplayedMap)
-    return nullptr;
-
-  return mUndisplayedMap->GetFirstNode(aParentContent);
+  return GetAllUndisplayedNodesInMapFor(mUndisplayedMap, aParentContent);
 }
 
-void
-nsFrameManager::SetUndisplayedContent(nsIContent* aContent, 
-                                      nsStyleContext* aStyleContext)
+/* static */ void
+nsFrameManager::SetStyleContextInMap(UndisplayedMap* aMap,
+                                     nsIContent* aContent,
+                                     nsStyleContext* aStyleContext)
 {
   NS_PRECONDITION(!aStyleContext->GetPseudo(),
                   "Should only have actual elements here");
 
-#ifdef DEBUG_UNDISPLAYED_MAP
+#if defined(DEBUG_UNDISPLAYED_MAP) || defined(DEBUG_DISPLAY_BOX_CONTENTS_MAP)
   static int i = 0;
-  printf("SetUndisplayedContent(%d): p=%p \n", i++, (void *)aContent);
+  printf("SetStyleContextInMap(%d): p=%p \n", i++, (void *)aContent);
 #endif
 
-  NS_ASSERTION(!GetUndisplayedContent(aContent),
-               "Already have an undisplayed context entry for aContent");
+  NS_ASSERTION(!GetStyleContextInMap(aMap, aContent),
+               "Already have an entry for aContent");
 
-  if (! mUndisplayedMap) {
-    mUndisplayedMap = new UndisplayedMap;
-  }
   nsIContent* parent = aContent->GetParent();
-  NS_ASSERTION(parent || (mPresShell && mPresShell->GetDocument() &&
-               mPresShell->GetDocument()->GetRootElement() == aContent),
+#ifdef DEBUG
+  nsIPresShell* shell = aStyleContext->PresContext()->PresShell();
+  NS_ASSERTION(parent || (shell && shell->GetDocument() &&
+                          shell->GetDocument()->GetRootElement() == aContent),
                "undisplayed content must have a parent, unless it's the root "
                "element");
-  mUndisplayedMap->AddNodeFor(parent, aContent, aStyleContext);
+#endif
+  aMap->AddNodeFor(parent, aContent, aStyleContext);
 }
 
 void
-nsFrameManager::ChangeUndisplayedContent(nsIContent* aContent, 
-                                         nsStyleContext* aStyleContext)
+nsFrameManager::SetUndisplayedContent(nsIContent* aContent,
+                                      nsStyleContext* aStyleContext)
 {
-  NS_ASSERTION(mUndisplayedMap, "no existing undisplayed content");
-  
-#ifdef DEBUG_UNDISPLAYED_MAP
+  if (!mUndisplayedMap) {
+    mUndisplayedMap = new UndisplayedMap;
+  }
+  SetStyleContextInMap(mUndisplayedMap, aContent, aStyleContext);
+}
+
+/* static */ void
+nsFrameManager::ChangeStyleContextInMap(UndisplayedMap* aMap,
+                                        nsIContent* aContent,
+                                        nsStyleContext* aStyleContext)
+{
+  MOZ_ASSERT(aMap, "expecting a map");
+
+#if defined(DEBUG_UNDISPLAYED_MAP) || defined(DEBUG_DISPLAY_BOX_CONTENTS_MAP)
    static int i = 0;
-   printf("ChangeUndisplayedContent(%d): p=%p \n", i++, (void *)aContent);
+   printf("ChangeStyleContextInMap(%d): p=%p \n", i++, (void *)aContent);
 #endif
 
-  for (UndisplayedNode* node = mUndisplayedMap->GetFirstNode(aContent->GetParent());
+  for (UndisplayedNode* node = aMap->GetFirstNode(aContent->GetParent());
          node; node = node->mNext) {
     if (node->mContent == aContent) {
       node->mStyle = aStyleContext;
       return;
     }
   }
 
-  NS_NOTREACHED("no existing undisplayed content");
+  MOZ_CRASH("couldn't find the entry to change");
 }
 
 void
 nsFrameManager::ClearUndisplayedContentIn(nsIContent* aContent,
                                           nsIContent* aParentContent)
 {
 #ifdef DEBUG_UNDISPLAYED_MAP
   static int i = 0;
@@ -316,16 +337,19 @@ nsFrameManager::ClearUndisplayedContentI
         nsStyleContext *context = GetUndisplayedContent(aContent);
         NS_ASSERTION(context == nullptr, "Found more undisplayed content data after removal");
 #endif
         return;
       }
       node = node->mNext;
     }
   }
+#ifdef DEBUG_UNDISPLAYED_MAP
+  printf( "not found.\n");
+#endif
 }
 
 void
 nsFrameManager::ClearAllUndisplayedContentIn(nsIContent* aParentContent)
 {
 #ifdef DEBUG_UNDISPLAYED_MAP
   static int i = 0;
   printf("ClearAllUndisplayedContentIn(%d): parent=%p \n", i++, (void*)aParentContent);
@@ -343,16 +367,102 @@ nsFrameManager::ClearAllUndisplayedConte
   for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
     if (child->GetParent() != aParentContent) {
       ClearUndisplayedContentIn(child, child->GetParent());
     }
   }
 }
 
 //----------------------------------------------------------------------
+
+void
+nsFrameManager::SetDisplayContents(nsIContent* aContent,
+                                   nsStyleContext* aStyleContext)
+{
+  if (!mDisplayContentsMap) {
+    mDisplayContentsMap = new UndisplayedMap;
+  }
+  SetStyleContextInMap(mDisplayContentsMap, aContent, aStyleContext);
+}
+
+UndisplayedNode*
+nsFrameManager::GetAllDisplayContentsIn(nsIContent* aParentContent)
+{
+  return GetAllUndisplayedNodesInMapFor(mDisplayContentsMap, aParentContent);
+}
+
+void
+nsFrameManager::ClearDisplayContentsIn(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) {
+    UndisplayedNode* node = mDisplayContentsMap->GetFirstNode(aParentContent);
+    while (node) {
+      if (node->mContent == aContent) {
+        mDisplayContentsMap->RemoveNodeFor(aParentContent, node);
+
+#ifdef DEBUG_DISPLAY_CONTENTS_MAP
+        printf( "REMOVED!\n");
+#endif
+#ifdef DEBUG
+        // make sure that there are no more entries for the same content
+        nsStyleContext* context = GetDisplayContentsStyleFor(aContent);
+        NS_ASSERTION(context == nullptr, "Found more entries for aContent after removal");
+#endif
+        ClearAllDisplayContentsIn(aContent);
+        ClearAllUndisplayedContentIn(aContent);
+        return;
+      }
+      node = node->mNext;
+    }
+  }
+#ifdef DEBUG_DISPLAY_CONTENTS_MAP
+  printf( "not found.\n");
+#endif
+}
+
+void
+nsFrameManager::ClearAllDisplayContentsIn(nsIContent* aParentContent)
+{
+#ifdef DEBUG_DISPLAY_CONTENTS_MAP
+  static int i = 0;
+  printf("ClearAllDisplayContentsIn(%d): parent=%p \n", i++, (void*)aParentContent);
+#endif
+
+  if (mDisplayContentsMap) {
+    UndisplayedNode* cur = mDisplayContentsMap->UnlinkNodesFor(aParentContent);
+    while (cur) {
+      UndisplayedNode* next = cur->mNext;
+      cur->mNext = nullptr;
+      ClearAllDisplayContentsIn(cur->mContent);
+      ClearAllUndisplayedContentIn(cur->mContent);
+      delete cur;
+      cur = next;
+    }
+  }
+
+  // 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()) {
+    if (child->GetParent() != aParentContent) {
+      ClearDisplayContentsIn(child, child->GetParent());
+      ClearUndisplayedContentIn(child, child->GetParent());
+    }
+  }
+}
+
+//----------------------------------------------------------------------
 void
 nsFrameManager::AppendFrames(nsContainerFrame* aParentFrame,
                              ChildListID       aListID,
                              nsFrameList&      aFrameList)
 {
   if (aParentFrame->IsAbsoluteContainer() &&
       aListID == aParentFrame->GetAbsoluteListID()) {
     aParentFrame->GetAbsoluteContainingBlock()->
@@ -419,16 +529,17 @@ nsFrameManager::RemoveFrame(ChildListID 
 //----------------------------------------------------------------------
 
 void
 nsFrameManager::NotifyDestroyingFrame(nsIFrame* aFrame)
 {
   nsIContent* content = aFrame->GetContent();
   if (content && content->GetPrimaryFrame() == aFrame) {
     ClearAllUndisplayedContentIn(content);
+    ClearAllDisplayContentsIn(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)
@@ -695,28 +806,36 @@ nsFrameManagerBase::UndisplayedMap::Remo
         }
         node = node->mNext;
       }
     }
   }
   delete aNode;
 }
 
-void
-nsFrameManagerBase::UndisplayedMap::RemoveNodesFor(nsIContent* aParentContent)
+
+UndisplayedNode*
+nsFrameManagerBase::UndisplayedMap::UnlinkNodesFor(nsIContent* aParentContent)
 {
   PLHashEntry** entry = GetEntryFor(&aParentContent);
   NS_ASSERTION(entry, "content not in map");
   if (*entry) {
-    UndisplayedNode*  node = (UndisplayedNode*)((*entry)->value);
+    UndisplayedNode* node = (UndisplayedNode*)((*entry)->value);
     NS_ASSERTION(node, "null node for non-null entry in UndisplayedMap");
-    delete node;
     PL_HashTableRawRemove(mTable, entry, *entry);
     mLastLookup = nullptr; // hashtable may have shifted bucket out from under us
+    return node;
   }
+  return nullptr;
+}
+
+void
+nsFrameManagerBase::UndisplayedMap::RemoveNodesFor(nsIContent* aParentContent)
+{
+  delete UnlinkNodesFor(aParentContent);
 }
 
 static int
 RemoveUndisplayedEntry(PLHashEntry* he, int i, void* arg)
 {
   UndisplayedNode*  node = (UndisplayedNode*)(he->value);
   delete node;
   // Remove and free this entry and continue enumerating
--- a/layout/base/nsFrameManager.h
+++ b/layout/base/nsFrameManager.h
@@ -103,27 +103,77 @@ public:
     RegisterPlaceholderFrame(nsPlaceholderFrame* aPlaceholderFrame);
 
   void
     UnregisterPlaceholderFrame(nsPlaceholderFrame* aPlaceholderFrame);
 
   void      ClearPlaceholderFrameMap();
 
   // Mapping undisplayed content
-  nsStyleContext* GetUndisplayedContent(nsIContent* aContent);
+  nsStyleContext* GetUndisplayedContent(nsIContent* aContent)
+  {
+    if (!mUndisplayedMap) {
+      return nullptr;
+    }
+    return GetStyleContextInMap(mUndisplayedMap, aContent);
+  }
   mozilla::UndisplayedNode*
     GetAllUndisplayedContentIn(nsIContent* aParentContent);
   void SetUndisplayedContent(nsIContent* aContent,
-                                         nsStyleContext* aStyleContext);
+                             nsStyleContext* aStyleContext);
   void ChangeUndisplayedContent(nsIContent* aContent,
-                                            nsStyleContext* aStyleContext);
+                                nsStyleContext* aStyleContext)
+  {
+    ChangeStyleContextInMap(mUndisplayedMap, aContent, aStyleContext);
+  }
+
   void ClearUndisplayedContentIn(nsIContent* aContent,
-                                             nsIContent* aParentContent);
+                                 nsIContent* aParentContent);
   void ClearAllUndisplayedContentIn(nsIContent* aParentContent);
 
+  // display:contents related methods:
+  /**
+   * Return the registered display:contents style context for aContent, if any.
+   */
+  nsStyleContext* GetDisplayContentsStyleFor(nsIContent* aContent)
+  {
+    if (!mDisplayContentsMap) {
+      return nullptr;
+    }
+    return GetStyleContextInMap(mDisplayContentsMap, aContent);
+  }
+
+  /**
+   * Return the linked list of UndisplayedNodes containing the registered
+   * display:contents children of aParentContent, if any.
+   */
+  mozilla::UndisplayedNode* GetAllDisplayContentsIn(nsIContent* aParentContent);
+  /**
+   * Register aContent having a display:contents style context.
+   */
+  void SetDisplayContents(nsIContent* aContent,
+                          nsStyleContext* aStyleContext);
+  /**
+   * Change the registered style context for aContent to aStyleContext.
+   */
+  void ChangeDisplayContents(nsIContent* aContent,
+                             nsStyleContext* aStyleContext)
+  {
+    ChangeStyleContextInMap(mDisplayContentsMap, aContent, aStyleContext);
+  }
+
+  /**
+   * Unregister the display:contents style context for aContent, if any.
+   * If found, then also unregister any display:contents and display:none
+   * style contexts for its descendants.
+   */
+  void ClearDisplayContentsIn(nsIContent* aContent,
+                              nsIContent* aParentContent);
+  void ClearAllDisplayContentsIn(nsIContent* aParentContent);
+
   // Functions for manipulating the frame model
   void AppendFrames(nsContainerFrame* aParentFrame,
                     ChildListID       aListID,
                     nsFrameList&      aFrameList);
 
   void InsertFrames(nsContainerFrame* aParentFrame,
                     ChildListID       aListID,
                     nsIFrame*         aPrevFrame,
@@ -156,11 +206,23 @@ public:
   /*
    * Add/restore state for one frame
    */
   void CaptureFrameStateFor(nsIFrame*              aFrame,
                                         nsILayoutHistoryState* aState);
 
   void RestoreFrameStateFor(nsIFrame*              aFrame,
                                         nsILayoutHistoryState* aState);
+protected:
+  static nsStyleContext* GetStyleContextInMap(UndisplayedMap* aMap,
+                                              nsIContent* aContent);
+  static mozilla::UndisplayedNode*
+    GetAllUndisplayedNodesInMapFor(UndisplayedMap* aMap,
+                                   nsIContent* aParentContent);
+  static void SetStyleContextInMap(UndisplayedMap* aMap,
+                                   nsIContent* aContent,
+                                   nsStyleContext* aStyleContext);
+  static void ChangeStyleContextInMap(UndisplayedMap* aMap,
+                                      nsIContent* aContent,
+                                      nsStyleContext* aStyleContext);
 };
 
 #endif
--- a/layout/base/nsFrameManagerBase.h
+++ b/layout/base/nsFrameManagerBase.h
@@ -29,16 +29,17 @@ class nsStyleSet;
 class nsFrameManagerBase
 {
 public:
   nsFrameManagerBase()
     : mPresShell(nullptr)
     , mStyleSet(nullptr)
     , mRootFrame(nullptr)
     , mUndisplayedMap(nullptr)
+    , mDisplayContentsMap(nullptr)
     , mIsDestroyingFrames(false)
   {
     mPlaceholderMap.ops = nullptr;
   }
 
   bool IsDestroyingFrames() { return mIsDestroyingFrames; }
 
   /*
@@ -60,16 +61,17 @@ protected:
 
   // weak link, because the pres shell owns us
   nsIPresShell*                   mPresShell;
   // the pres shell owns the style set
   nsStyleSet*                     mStyleSet;
   nsIFrame*                       mRootFrame;
   PLDHashTable                    mPlaceholderMap;
   UndisplayedMap*                 mUndisplayedMap;
+  UndisplayedMap*                 mDisplayContentsMap;
   bool                            mIsDestroyingFrames;  // The frame manager is destroying some frame(s).
 
   // The frame tree generation number
   // We use this to avoid unnecessary screenshotting
   // on Android. Unfortunately, this is static to match
   // the single consumer which is also static. Keeping
   // this the same greatly simplifies lifetime issues and
   // makes sure we always using the correct number.