When re-resolving style, re-resolve root in undisplayed map too. (Bug 473042) r+sr=bzbarsky
authorL. David Baron <dbaron@dbaron.org>
Fri, 16 Jan 2009 13:32:09 -0800
changeset 23830 867b1cf0625288117574f03ee24b9d713cb3eb79
parent 23829 9b832d90d637d21c08ea8be077ebee04181e6037
child 23831 8083041f33436caeea4774fa9b858484f9c97146
push id4748
push userdbaron@mozilla.com
push dateFri, 16 Jan 2009 21:32:37 +0000
treeherdermozilla-central@8083041f3343 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs473042
milestone1.9.2a1pre
When re-resolving style, re-resolve root in undisplayed map too. (Bug 473042) r+sr=bzbarsky
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsCSSFrameConstructor.h
layout/base/nsFrameManager.cpp
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -4074,23 +4074,27 @@ nsCSSFrameConstructor::ConstructDocEleme
     aState.mPresShell->CaptureHistoryState(getter_AddRefs(mTempFrameTreeState));
 
   // ----- reattach gfx scrollbars ------
   // Gfx scrollframes were created in the root frame but the primary frame map may have been destroyed if a 
   // new style sheet was loaded so lets reattach the frames to their content.
   // XXX this seems truly bogus, we wipe out mGfxScrollFrame below
   if (mGfxScrollFrame) {
     nsIFrame* gfxScrollbarFrame1 = mGfxScrollFrame->GetFirstChild(nsnull);
-    if (gfxScrollbarFrame1) {
+    // Check the frame type because when there aren't scrollbars, we'll
+    // get the canvas.
+    if (gfxScrollbarFrame1 &&
+        gfxScrollbarFrame1->GetType() == nsGkAtoms::scrollbarFrame) {
       // XXX This works, but why?
       aState.mFrameManager->
         SetPrimaryFrameFor(gfxScrollbarFrame1->GetContent(), gfxScrollbarFrame1);
 
       nsIFrame* gfxScrollbarFrame2 = gfxScrollbarFrame1->GetNextSibling();
-      if (gfxScrollbarFrame2) {
+      if (gfxScrollbarFrame2 &&
+          gfxScrollbarFrame2->GetType() == nsGkAtoms::scrollbarFrame) {
         // XXX This works, but why?
         aState.mFrameManager->
           SetPrimaryFrameFor(gfxScrollbarFrame2->GetContent(), gfxScrollbarFrame2);
       }
     }
   }
 
   // --------- CREATE AREA OR BOX FRAME -------
@@ -7455,16 +7459,18 @@ nsCSSFrameConstructor::ReconstructDocEle
       // Get the frame that corresponds to the document element
       nsIFrame* docElementFrame =
         state.mFrameManager->GetPrimaryFrameFor(rootContent, -1);
 
       if (docElementFrame) {
         // Destroy out-of-flow frames that might not be in the frame subtree
         // rooted at docElementFrame
         ::DeletingFrameSubtree(state.mFrameManager, docElementFrame);
+      } else {
+        state.mFrameManager->ClearUndisplayedContentIn(rootContent, nsnull);
       }
 
       // Remove any existing fixed items: they are always on the
       // FixedContainingBlock.  Note that this has to be done before we call
       // ClearPlaceholderFrameMap(), since RemoveFixedItems uses the
       // placeholder frame map.
       rv = RemoveFixedItems(state, docElementFrame);
 
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -266,16 +266,20 @@ public:
   nsIFrame* GetInitialContainingBlock() { return mInitialContainingBlock; }
   // This returns the outermost frame for the root element
   nsIFrame* GetRootElementFrame() { return mInitialContainingBlock; }
   // This returns the frame for the root element that does not
   // have a psuedo-element style
   nsIFrame* GetRootElementStyleFrame() { return mRootElementStyleFrame; }
   nsIFrame* GetPageSequenceFrame() { return mPageSequenceFrame; }
 
+  // Get the frame that is the parent of the root element.
+  nsIFrame* GetDocElementContainingBlock()
+    { return mDocElementContainingBlock; }
+
 private:
 
   nsresult ReconstructDocElementHierarchyInternal();
 
   nsresult ReinsertContent(nsIContent*    aContainer,
                            nsIContent*    aChild);
 
   nsresult ConstructPageFrame(nsIPresShell*  aPresShell, 
--- a/layout/base/nsFrameManager.cpp
+++ b/layout/base/nsFrameManager.cpp
@@ -410,16 +410,26 @@ nsFrameManager::GetPrimaryFrameFor(nsICo
 
 nsresult
 nsFrameManager::SetPrimaryFrameFor(nsIContent* aContent,
                                    nsIFrame*   aPrimaryFrame)
 {
   NS_ENSURE_ARG_POINTER(aContent);
   NS_ASSERTION(aPrimaryFrame && aPrimaryFrame->GetParent(),
                "BOGUS!");
+#ifdef DEBUG
+  {
+    nsIFrame *docElementCB = 
+      mPresShell->FrameConstructor()->GetDocElementContainingBlock();
+    NS_ASSERTION(aPrimaryFrame != docElementCB &&
+                 !nsLayoutUtils::IsProperAncestorFrame(aPrimaryFrame,
+                                                       docElementCB),
+                 "too high in the frame tree to be a primary frame");
+  }
+#endif
 
   // This code should be used if/when we switch back to a 2-word entry
   // in the primary frame map.
 #if 0
   NS_PRECONDITION(aPrimaryFrame->GetContent() == aContent, "wrong content");
 #endif
 
   // Create a new hashtable if necessary
@@ -1307,20 +1317,38 @@ nsFrameManager::ReResolveStyleContext(ns
         }
       }
       else {
         break;
       }
     }
 
     // now look for undisplayed child content and pseudos
-    if (!pseudoTag && localContent && mUndisplayedMap) {
+
+    // When the root element is display:none, we still construct *some*
+    // frames that have the root element as their mContent, down to the
+    // DocElementContainingBlock.
+    PRBool checkUndisplayed;
+    nsIContent *undisplayedParent;
+    if (pseudoTag) {
+      checkUndisplayed = aFrame == mPresShell->FrameConstructor()->
+                                     GetDocElementContainingBlock();
+      undisplayedParent = nsnull;
+    } else {
+      checkUndisplayed = !!localContent;
+      undisplayedParent = localContent;
+    }
+    if (checkUndisplayed && mUndisplayedMap) {
       for (UndisplayedNode* undisplayed =
-                                   mUndisplayedMap->GetFirstNode(localContent);
+                              mUndisplayedMap->GetFirstNode(undisplayedParent);
            undisplayed; undisplayed = undisplayed->mNext) {
+        NS_ASSERTION(undisplayedParent ||
+                     undisplayed->mContent ==
+                       mPresShell->GetDocument()->GetRootContent(),
+                     "undisplayed node child of null must be root");
         nsRefPtr<nsStyleContext> undisplayedContext;
         nsIAtom* const undisplayedPseudoTag = undisplayed->mStyle->GetPseudoType();
         if (!undisplayedPseudoTag) {  // child content
           undisplayedContext = styleSet->ResolveStyleFor(undisplayed->mContent,
                                                          newContext);
         }
         else if (undisplayedPseudoTag == nsCSSAnonBoxes::mozNonElement) {
           undisplayedContext = styleSet->ResolveStyleForNonElement(newContext);