Bug 243519. Rework root element frame construction and the CanvasFrame so that the CanvasFrame is an abs-pos container and the root element frame can be positioned. r=fantasai,sr=dbaron
authorRobert O'Callahan <robert@ocallahan.org>
Mon, 08 Sep 2008 20:13:17 +1200
changeset 18953 679778dd198fd2799c37c685bc2609dde8f4418a
parent 18952 b7bcdd0095407e1aaa42af7ee2d747762fc82d96
child 18954 f7795cb888df11947925cb7d74bf9767336b41a0
push idunknown
push userunknown
push dateunknown
reviewersfantasai, dbaron
bugs243519
milestone1.9.1b1pre
Bug 243519. Rework root element frame construction and the CanvasFrame so that the CanvasFrame is an abs-pos container and the root element frame can be positioned. r=fantasai,sr=dbaron
layout/base/crashtests/crashtests.list
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsCSSFrameConstructor.h
layout/generic/nsAbsoluteContainingBlock.cpp
layout/generic/nsAbsoluteContainingBlock.h
layout/generic/nsBlockFrame.cpp
layout/generic/nsContainerFrame.cpp
layout/generic/nsFrame.cpp
layout/generic/nsHTMLFrame.cpp
layout/generic/nsHTMLParts.h
layout/generic/nsHTMLReflowState.cpp
layout/generic/nsInlineFrame.cpp
layout/generic/nsPageContentFrame.cpp
layout/generic/nsPageContentFrame.h
layout/generic/nsViewportFrame.cpp
layout/reftests/bugs/243519-9f.html
layout/reftests/bugs/reftest.list
--- a/layout/base/crashtests/crashtests.list
+++ b/layout/base/crashtests/crashtests.list
@@ -1,13 +1,14 @@
 load 56746-1.html
 load 143862-1.html
 load 143862-2.html
 load 243159-1.html
 load 243159-2.xhtml
+load 243519-1.html
 load 306940-1.html
 load 310267-1.xml
 load 310638-1.svg
 load 310638-2.html
 load 313086-1.xml
 load 321058-1.xul
 load 321058-2.xul
 load 321077-1.xul
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -1801,19 +1801,19 @@ nsCSSFrameConstructor::nsCSSFrameConstru
   , mRootElementStyleFrame(nsnull)
   , mFixedContainingBlock(nsnull)
   , mDocElementContainingBlock(nsnull)
   , mGfxScrollFrame(nsnull)
   , mPageSequenceFrame(nsnull)
   , mUpdateCount(0)
   , mQuotesDirty(PR_FALSE)
   , mCountersDirty(PR_FALSE)
-  , mInitialContainingBlockIsAbsPosContainer(PR_FALSE)
   , mIsDestroyingFrameTree(PR_FALSE)
   , mRebuildAllStyleData(PR_FALSE)
+  , mHasRootAbsPosContainingBlock(PR_FALSE)
 {
   if (!gGotXBLFormPrefs) {
     gGotXBLFormPrefs = PR_TRUE;
 
     gUseXBLForms =
       nsContentUtils::GetBoolPref("nglayout.debug.enable_xbl_forms");
   }
 
@@ -3967,42 +3967,16 @@ nsCSSFrameConstructor::GetDisplay(nsIFra
   }
   return aFrame->GetStyleContext()->GetStyleDisplay();
 }
 
 /***********************************************
  * END TABLE SECTION
  ***********************************************/
 
-nsresult
-nsCSSFrameConstructor::ConstructDocElementTableFrame(nsIContent*     aDocElement,
-                                                     nsIFrame*       aParentFrame,
-                                                     nsIFrame**      aNewTableFrame,
-                                                     nsFrameConstructorState& aState)
-{
-  nsFrameItems    frameItems;
-
-  // XXXbz this is wrong.  We should at least be setting the fixed container in
-  // the framestate here.  Better yet, we should pass through aState
-  // unmodified.  Can't do that, though, because then a fixed or absolute
-  // positioned root table with auto offsets would look for a block to compute
-  // its hypothetical box and crash.  So we just disable fixed positioning
-  // altogether in documents where the root is a table.  Oh, well.
-  nsFrameConstructorState state(mPresShell, nsnull, nsnull, nsnull,
-                                aState.mFrameState);
-  ConstructFrame(state, aDocElement, aParentFrame, frameItems);
-  *aNewTableFrame = frameItems.childList;
-  if (!*aNewTableFrame) {
-    NS_WARNING("cannot get table contentFrame");
-    // XXXbz maybe better to return the error from ConstructFrame?
-    return NS_ERROR_FAILURE;
-  }
-  return NS_OK;
-}
-
 static PRBool CheckOverflow(nsPresContext* aPresContext,
                             const nsStyleDisplay* aDisplay)
 {
   if (aDisplay->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE)
     return PR_FALSE;
 
   if (aDisplay->mOverflowX == NS_STYLE_OVERFLOW_CLIP)
     aPresContext->SetViewportOverflowOverride(NS_STYLE_OVERFLOW_HIDDEN,
@@ -4088,39 +4062,16 @@ nsCSSFrameConstructor::PropagateScrollTo
  * New one
  */
 nsresult
 nsCSSFrameConstructor::ConstructDocElementFrame(nsFrameConstructorState& aState,
                                                 nsIContent*              aDocElement,
                                                 nsIFrame*                aParentFrame,
                                                 nsIFrame**               aNewFrame)
 {
-    // how the root frame hierarchy should look
-
-    /*
-
----------------No Scrollbars------
-
-
-     AreaFrame or BoxFrame (InitialContainingBlock)
-  
-
-
----------------Gfx Scrollbars ------
-
-
-     ScrollFrame
-
-         ^
-         |
-         |
-     AreaFrame or BoxFrame (InitialContainingBlock)
-          
-*/    
-
   *aNewFrame = nsnull;
 
   if (!mTempFrameTreeState)
     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.
@@ -4184,157 +4135,219 @@ nsCSSFrameConstructor::ConstructDocEleme
     PropagateScrollToViewport() == aDocElement;
 
   NS_ASSERTION(!display->IsScrollableOverflow() || 
                aState.mPresContext->IsPaginated() ||
                propagatedScrollToViewport,
                "Scrollbars should have been propagated to the viewport");
 #endif
 
-  nsIFrame* contentFrame = nsnull;
-  PRBool isBlockFrame = PR_FALSE;
+  nsFrameConstructorSaveState absoluteSaveState;
+  if (mHasRootAbsPosContainingBlock) {
+    // Push the absolute containing block now so we can absolutely position
+    // the root element
+    aState.PushAbsoluteContainingBlock(mDocElementContainingBlock, absoluteSaveState);
+  }
+
   nsresult rv;
 
   // The rules from CSS 2.1, section 9.2.4, have already been applied
   // by the style system, so we can assume that display->mDisplay is
   // either NONE, BLOCK, or TABLE.
 
   PRBool docElemIsTable = (display->mDisplay == NS_STYLE_DISPLAY_TABLE) &&
                           !IsSpecialContent(aDocElement, aDocElement->Tag(),
                                             aDocElement->GetNameSpaceID(),
                                             styleContext);
 
+  // contentFrame is the primary frame for the root element. *aNewFrame
+  // is the frame that will be the child of the initial containing block.
+  // These are usually the same frame but they can be different, in
+  // particular if the root frame is positioned, in which case
+  // contentFrame is the out-of-flow frame and *aNewFrame is the
+  // placeholder.
+  nsIFrame* contentFrame;
+  PRBool processChildren = PR_FALSE;
   if (docElemIsTable) {
+    nsIFrame* innerTableFrame;
+    nsFrameItems frameItems;
     // if the document is a table then just populate it.
-    rv = ConstructDocElementTableFrame(aDocElement, aParentFrame, &contentFrame,
-                                       aState);
-    if (NS_FAILED(rv)) {
+    rv = ConstructTableFrame(aState, aDocElement,
+                             aParentFrame, styleContext,
+                             kNameSpaceID_None, PR_FALSE, frameItems, contentFrame,
+                             innerTableFrame);
+    if (NS_FAILED(rv))
       return rv;
-    }
-    styleContext = contentFrame->GetStyleContext();
+    if (!contentFrame || !frameItems.childList)
+      return NS_ERROR_FAILURE;
+    *aNewFrame = frameItems.childList;
+    NS_ASSERTION(!frameItems.childList->GetNextSibling(),
+                 "multiple root element frames");
   } else {
     // otherwise build a box or a block
 #ifdef MOZ_XUL
     if (aDocElement->IsNodeOfType(nsINode::eXUL)) {
       contentFrame = NS_NewDocElementBoxFrame(mPresShell, styleContext);
+      if (NS_UNLIKELY(!contentFrame)) {
+        return NS_ERROR_OUT_OF_MEMORY;
+      }
+      InitAndRestoreFrame(aState, aDocElement, aParentFrame, nsnull, contentFrame);
+      *aNewFrame = contentFrame;
+      processChildren = PR_TRUE;
     }
     else
 #endif 
 #ifdef MOZ_SVG
     if (aDocElement->GetNameSpaceID() == kNameSpaceID_SVG) {
       if (aDocElement->Tag() == nsGkAtoms::svg && NS_SVGEnabled()) {
         contentFrame = NS_NewSVGOuterSVGFrame(mPresShell, aDocElement, styleContext);
+        if (NS_UNLIKELY(!contentFrame)) {
+          return NS_ERROR_OUT_OF_MEMORY;
+        }
+        InitAndRestoreFrame(aState, aDocElement,
+                            aState.GetGeometricParent(display, aParentFrame),
+                            nsnull, contentFrame);
+
+        // AddChild takes care of transforming the frame tree for fixed-pos
+        // or abs-pos situations
+        nsFrameItems frameItems;
+        rv = aState.AddChild(contentFrame, frameItems, aDocElement,
+                             styleContext, aParentFrame);
+        if (NS_FAILED(rv) || !frameItems.childList) {
+          return rv;
+        }
+        *aNewFrame = frameItems.childList;
+        processChildren = PR_TRUE;
+
+        // See if we need to create a view, e.g. the frame is absolutely positioned
+        nsHTMLContainerFrame::CreateViewForFrame(contentFrame, aParentFrame, PR_FALSE);
       } else {
         return NS_ERROR_FAILURE;
       }
     }
     else 
 #endif
     {
-      contentFrame = NS_NewDocumentElementFrame(mPresShell, styleContext);
-      isBlockFrame = PR_TRUE;
-    }
-    
-    if (NS_UNLIKELY(!contentFrame)) {
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-
-    // initialize the child
-    InitAndRestoreFrame(aState, aDocElement, aParentFrame, nsnull, contentFrame);
+      contentFrame = NS_NewBlockFrame(mPresShell, styleContext,
+        NS_BLOCK_SPACE_MGR|NS_BLOCK_MARGIN_ROOT);
+      if (!contentFrame)
+        return NS_ERROR_OUT_OF_MEMORY;
+      nsFrameItems frameItems;
+      rv = ConstructBlock(aState, display, aDocElement,
+                          aState.GetGeometricParent(display, aParentFrame),
+                          aParentFrame, styleContext, &contentFrame,
+                          frameItems, display->IsPositioned());
+      if (NS_FAILED(rv) || !frameItems.childList)
+        return rv;
+      *aNewFrame = frameItems.childList;
+      NS_ASSERTION(!frameItems.childList->GetNextSibling(),
+                   "multiple root element frames");
+    }
   }
 
   // set the primary frame
   aState.mFrameManager->SetPrimaryFrameFor(aDocElement, contentFrame);
 
-  *aNewFrame = contentFrame;
-
   mInitialContainingBlock = contentFrame;
-  mInitialContainingBlockIsAbsPosContainer = PR_FALSE;
 
   // Figure out which frame has the main style for the document element,
   // assigning it to mRootElementStyleFrame.
   // Backgrounds should be propagated from that frame to the viewport.
   PRBool isChild;
   contentFrame->GetParentStyleContextFrame(aState.mPresContext,
           &mRootElementStyleFrame, &isChild);
   if (!isChild) {
     mRootElementStyleFrame = mInitialContainingBlock;
   }
 
-  // if it was a table then we don't need to process our children.
-  if (!docElemIsTable) {
-    // Process the child content
-    nsFrameConstructorSaveState absoluteSaveState;
-    nsFrameConstructorSaveState floatSaveState;
-    nsFrameItems                childItems;
-
-    if (isBlockFrame) {
-      PRBool haveFirstLetterStyle, haveFirstLineStyle;
-      ShouldHaveSpecialBlockStyle(aDocElement, styleContext,
-                                  &haveFirstLetterStyle, &haveFirstLineStyle);
-      mInitialContainingBlockIsAbsPosContainer = PR_TRUE;
-      aState.PushAbsoluteContainingBlock(contentFrame, absoluteSaveState);
-      aState.PushFloatContainingBlock(contentFrame, floatSaveState,
-                                      haveFirstLetterStyle,
-                                      haveFirstLineStyle);
-    }
+  if (processChildren) {
+    // Still need to process the child content
+    nsFrameItems childItems;
 
     // Create any anonymous frames the doc element frame requires
     // This must happen before ProcessChildren to ensure that popups are
     // never constructed before the popupset.
     CreateAnonymousFrames(nsnull, aState, aDocElement, contentFrame,
                           PR_FALSE, childItems, PR_TRUE);
+    NS_ASSERTION(!nsLayoutUtils::GetAsBlock(contentFrame),
+                 "Only XUL and SVG frames should reach here");
     ProcessChildren(aState, aDocElement, contentFrame, PR_TRUE, childItems,
-                    isBlockFrame);
+                    PR_FALSE);
 
     // Set the initial child lists
     contentFrame->SetInitialChildList(nsnull, childItems.childList);
   }
 
   return NS_OK;
 }
 
 
 nsresult
 nsCSSFrameConstructor::ConstructRootFrame(nsIContent*     aDocElement,
                                           nsIFrame**      aNewFrame)
 {
   AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
   NS_PRECONDITION(aNewFrame, "null out param");
   
-  // how the root frame hierarchy should look
-
     /*
-
----------------No Scrollbars------
-
-
-
-     ViewPortFrame (FixedContainingBlock) <---- RootView
-
-         ^
-         |
-     RootFrame(DocElementContainingBlock)
-  
-
-
----------------Gfx Scrollbars ------
-
-
-     ViewPortFrame (FixedContainingBlock) <---- RootView
-
-         ^
-         |
-     ScrollFrame
-
-         ^
-         |
-     RootFrame(DocElementContainingBlock)
-          
-*/    
+       how the root frame hierarchy should look
+
+  Galley presentation, non-XUL, with scrolling (i.e. not a frameset):
+  
+      ViewportFrame [fixed-cb]
+        nsHTMLScrollFrame
+          CanvasFrame [abs-cb]
+            root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
+                                nsTableOuterFrame, nsPlaceholderFrame)
+
+  Galley presentation, non-XUL, without scrolling (i.e. a frameset):
+  
+      ViewportFrame [fixed-cb]
+        CanvasFrame [abs-cb]
+          root element frame (nsBlockFrame)
+
+  Galley presentation, XUL
+  
+      ViewportFrame [fixed-cb]
+        nsRootBoxFrame
+          root element frame (nsDocElementBoxFrame)
+
+  Print presentation, non-XUL
+
+      ViewportFrame
+        nsSimplePageSequenceFrame
+          nsPageFrame [fixed-cb]
+            nsPageContentFrame
+              CanvasFrame [abs-cb]
+                root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
+                                    nsTableOuterFrame, nsPlaceholderFrame)
+
+  Print-preview presentation, non-XUL
+
+      ViewportFrame
+        nsHTMLScrollFrame
+          nsSimplePageSequenceFrame
+            nsPageFrame [fixed-cb]
+              nsPageContentFrame
+                CanvasFrame [abs-cb]
+                  root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
+                                      nsTableOuterFrame, nsPlaceholderFrame)
+
+  Print/print preview of XUL is not supported.
+  [fixed-cb]: the default containing block for fixed-pos content
+  [abs-cb]: the default containing block for abs-pos content
+ 
+  Meaning of nsCSSFrameConstructor fields:
+    mInitialContainingBlock is "root element frame".
+    mDocElementContainingBlock is the parent of mInitialContainingBlock
+      (i.e. CanvasFrame or nsRootBoxFrame)
+    mFixedContainingBlock is the [fixed-cb]
+    mGfxScrollFrame is the nsHTMLScrollFrame mentioned above, or null if there isn't one
+    mPageSequenceFrame is the nsSimplePageSequenceFrame, or null if there isn't one
+*/
 
   // Set up our style rule observer.
   {
     mPresShell->StyleSet()->SetBindingManager(mDocument->BindingManager());
   }
 
   // --------- BUILD VIEWPORT -----------
   nsIFrame*                 viewportFrame = nsnull;
@@ -4389,16 +4402,17 @@ nsCSSFrameConstructor::ConstructRootFram
     {
       // pass a temporary stylecontext, the correct one will be set later
       rootFrame = NS_NewRootBoxFrame(mPresShell, viewportPseudoStyle);
     } else
 #endif
     {
       // pass a temporary stylecontext, the correct one will be set later
       rootFrame = NS_NewCanvasFrame(mPresShell, viewportPseudoStyle);
+      mHasRootAbsPosContainingBlock = PR_TRUE;
     }
 
     rootPseudo = nsCSSAnonBoxes::canvas;
     mDocElementContainingBlock = rootFrame;
   } else {
     // Create a page sequence frame
     rootFrame = NS_NewSimplePageSequenceFrame(mPresShell, viewportPseudoStyle);
     mPageSequenceFrame = rootFrame;
@@ -4517,40 +4531,41 @@ nsCSSFrameConstructor::ConstructRootFram
   
   if (isScrollable) {
     FinishBuildingScrollFrame(parentFrame, rootFrame);
   }
   
   if (isPaginated) { // paginated
     // Create the first page
     // Set the initial child lists
-    nsIFrame *pageFrame, *pageContentFrame;
+    nsIFrame *pageFrame, *canvasFrame;
     ConstructPageFrame(mPresShell, presContext, rootFrame, nsnull,
-                       pageFrame, pageContentFrame);
+                       pageFrame, canvasFrame);
     rootFrame->SetInitialChildList(nsnull, pageFrame);
 
     // The eventual parent of the document element frame.
     // XXX should this be set for every new page (in ConstructPageFrame)?
-    mDocElementContainingBlock = pageContentFrame;
+    mDocElementContainingBlock = canvasFrame;
+    mHasRootAbsPosContainingBlock = PR_TRUE;
   }
 
   viewportFrame->SetInitialChildList(nsnull, newFrame);
   
   *aNewFrame = viewportFrame;
 
   return NS_OK;
 }
 
 nsresult
-nsCSSFrameConstructor::ConstructPageFrame(nsIPresShell*   aPresShell,
+nsCSSFrameConstructor::ConstructPageFrame(nsIPresShell*  aPresShell,
                                           nsPresContext* aPresContext,
-                                          nsIFrame*       aParentFrame,
-                                          nsIFrame*       aPrevPageFrame,
-                                          nsIFrame*&      aPageFrame,
-                                          nsIFrame*&      aPageContentFrame)
+                                          nsIFrame*      aParentFrame,
+                                          nsIFrame*      aPrevPageFrame,
+                                          nsIFrame*&     aPageFrame,
+                                          nsIFrame*&     aCanvasFrame)
 {
   nsStyleContext* parentStyleContext = aParentFrame->GetStyleContext();
   nsStyleSet *styleSet = aPresShell->StyleSet();
 
   nsRefPtr<nsStyleContext> pagePseudoStyle;
   pagePseudoStyle = styleSet->ResolvePseudoStyleFor(nsnull,
                                                     nsCSSAnonBoxes::page,
                                                     parentStyleContext);
@@ -4563,31 +4578,47 @@ nsCSSFrameConstructor::ConstructPageFram
   // the pages easier and faster.
   aPageFrame->Init(nsnull, aParentFrame, aPrevPageFrame);
 
   nsRefPtr<nsStyleContext> pageContentPseudoStyle;
   pageContentPseudoStyle = styleSet->ResolvePseudoStyleFor(nsnull,
                                                            nsCSSAnonBoxes::pageContent,
                                                            pagePseudoStyle);
 
-  aPageContentFrame = NS_NewPageContentFrame(aPresShell, pageContentPseudoStyle);
-  if (NS_UNLIKELY(!aPageContentFrame))
+  nsIFrame* pageContentFrame = NS_NewPageContentFrame(aPresShell, pageContentPseudoStyle);
+  if (NS_UNLIKELY(!pageContentFrame))
     return NS_ERROR_OUT_OF_MEMORY;
 
   // Initialize the page content frame and force it to have a view. Also make it the
   // containing block for fixed elements which are repeated on every page.
   nsIFrame* prevPageContentFrame = nsnull;
   if (aPrevPageFrame) {
     prevPageContentFrame = aPrevPageFrame->GetFirstChild(nsnull);
     NS_ASSERTION(prevPageContentFrame, "missing page content frame");
   }
-  aPageContentFrame->Init(nsnull, aPageFrame, prevPageContentFrame);
-  mFixedContainingBlock = aPageContentFrame;
-
-  aPageFrame->SetInitialChildList(nsnull, aPageContentFrame);
+  pageContentFrame->Init(nsnull, aPageFrame, prevPageContentFrame);
+  aPageFrame->SetInitialChildList(nsnull, pageContentFrame);
+  mFixedContainingBlock = pageContentFrame;
+
+  nsRefPtr<nsStyleContext> canvasPseudoStyle;
+  canvasPseudoStyle = styleSet->ResolvePseudoStyleFor(nsnull,
+                                                      nsCSSAnonBoxes::canvas,
+                                                      pageContentPseudoStyle);
+
+  aCanvasFrame = NS_NewCanvasFrame(aPresShell, canvasPseudoStyle);
+  if (NS_UNLIKELY(!aCanvasFrame))
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  nsIFrame* prevCanvasFrame = nsnull;
+  if (prevPageContentFrame) {
+    prevCanvasFrame = prevPageContentFrame->GetFirstChild(nsnull);
+    NS_ASSERTION(prevCanvasFrame, "missing canvas frame");
+  }
+  aCanvasFrame->Init(nsnull, pageContentFrame, prevCanvasFrame);
+  pageContentFrame->SetInitialChildList(nsnull, aCanvasFrame);
 
   return NS_OK;
 }
 
 /* static */
 nsresult
 nsCSSFrameConstructor::CreatePlaceholderFrameFor(nsIPresShell*    aPresShell, 
                                                  nsIContent*      aContent,
@@ -6676,27 +6707,34 @@ nsCSSFrameConstructor::InitAndRestoreFra
 
   return rv;
 }
 
 already_AddRefed<nsStyleContext>
 nsCSSFrameConstructor::ResolveStyleContext(nsIFrame*         aParentFrame,
                                            nsIContent*       aContent)
 {
-  nsStyleContext* parentStyleContext;
+  nsStyleContext* parentStyleContext = nsnull;
   if (aContent->GetParent()) {
     aParentFrame = nsFrame::CorrectStyleParentFrame(aParentFrame, nsnull);
   
-    // Resolve the style context based on the content object and the parent
-    // style context
-    parentStyleContext = aParentFrame->GetStyleContext();
+    if (aParentFrame) {
+      // Resolve the style context based on the content object and the parent
+      // style context
+      parentStyleContext = aParentFrame->GetStyleContext();
+    } else {
+      // Perhaps aParentFrame is a canvasFrame and we're replicating
+      // fixed-pos frames.
+      // XXX should we create a way to tell ConstructFrame which style
+      // context to use, and pass it the style context for the
+      // previous page's fixed-pos frame?
+    }
   } else {
     // This has got to be a call from ConstructDocElementTableFrame.
-    // Not sure how best to asserrt that here.
-    parentStyleContext = nsnull;
+    // Not sure how best to assert that here.
   }
 
   nsStyleSet *styleSet = mPresShell->StyleSet();
 
   if (aContent->IsNodeOfType(nsINode::eELEMENT)) {
     return styleSet->ResolveStyleFor(aContent, parentStyleContext);
   } else {
 
@@ -7502,55 +7540,76 @@ nsCSSFrameConstructor::ReconstructDocEle
 
   nsresult rv = NS_OK;
 
   // XXXbz is that null-check needed?  Why?
   if (mDocument && mPresShell) {
     nsIContent *rootContent = mDocument->GetRootContent();
     
     if (rootContent) {
+      nsFrameConstructorState state(mPresShell, mFixedContainingBlock,
+                                    nsnull, nsnull, mTempFrameTreeState);
+
       // Before removing the frames associated with the content object, ask them to save their
       // state onto a temporary state object.
-      CaptureStateForFramesOf(rootContent, mTempFrameTreeState);
-
-      nsFrameConstructorState state(mPresShell, mFixedContainingBlock,
-                                    nsnull, nsnull, mTempFrameTreeState);
+      CaptureStateFor(state.mFrameManager->GetRootFrame(), mTempFrameTreeState);
 
       // 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);
+      }
+
       // 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);
+      rv = RemoveFixedItems(state, docElementFrame);
+
       if (NS_SUCCEEDED(rv)) {
+        nsPlaceholderFrame* placeholderFrame = nsnull;
+        if (docElementFrame &&
+            (docElementFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
+          // Get the placeholder frame now, before we tear down the
+          // placeholder frame map
+          placeholderFrame =
+            state.mFrameManager->GetPlaceholderFrameFor(docElementFrame);
+          NS_ASSERTION(placeholderFrame, "No placeholder for out-of-flow?");
+        }
+
         // Clear the hash tables that map from content to frame and out-of-flow
         // frame to placeholder frame
         state.mFrameManager->ClearPrimaryFrameMap();
         state.mFrameManager->ClearPlaceholderFrameMap();
         state.mFrameManager->ClearUndisplayedContentMap();
 
         if (docElementFrame) {
           // Take the docElementFrame, and remove it from its parent.
-        
           // XXXbz So why can't we reuse ContentRemoved?
 
-          NS_ASSERTION(docElementFrame->GetParent() == mDocElementContainingBlock,
-                       "Unexpected doc element parent frame");
-
           // Notify self that we will destroy the entire frame tree, this blocks
           // RemoveMappingsForFrameSubtree() which would otherwise lead to a
           // crash since we cleared the placeholder map above (bug 398982).
           PRBool wasDestroyingFrameTree = mIsDestroyingFrameTree;
           WillDestroyFrameTree();
-          // Remove the old document element hieararchy
-          rv = state.mFrameManager->RemoveFrame(mDocElementContainingBlock,
-                                                nsnull, docElementFrame);
+
+          rv = state.mFrameManager->RemoveFrame(docElementFrame->GetParent(),
+                    GetChildListNameFor(docElementFrame), docElementFrame);
+          
+          if (placeholderFrame) {
+            // Remove the placeholder frame first (XXX second for now) (so
+            // that it doesn't retain a dangling pointer to memory)
+            rv |= state.mFrameManager->RemoveFrame(placeholderFrame->GetParent(),
+                                            nsnull, placeholderFrame);
+          }
+
           mIsDestroyingFrameTree = wasDestroyingFrameTree;
           if (NS_FAILED(rv)) {
             return rv;
           }
         }
         
         mInitialContainingBlock = nsnull;
         mRootElementStyleFrame = nsnull;
@@ -7637,19 +7696,18 @@ nsCSSFrameConstructor::GetAbsoluteContai
     }
   }
 
   // If we found an absolutely positioned containing block, then use the
   // first-continuation.
   if (containingBlock)
     return AdjustAbsoluteContainingBlock(containingBlock);
 
-  // If we didn't find it, then use the initial containing block if it
-  // supports abs pos kids.
-  return mInitialContainingBlockIsAbsPosContainer ? mInitialContainingBlock : nsnull;
+  // If we didn't find it, then use the document element containing block
+  return mHasRootAbsPosContainingBlock ? mDocElementContainingBlock : nsnull;
 }
 
 nsIFrame*
 nsCSSFrameConstructor::GetFloatContainingBlock(nsIFrame* aFrame)
 {
   NS_PRECONDITION(mInitialContainingBlock, "no initial containing block");
   
   // Starting with aFrame, look for a frame that is a float containing block.
@@ -10224,19 +10282,19 @@ nsCSSFrameConstructor::CreateContinuingF
 
     if (newFrame) {
       newFrame->Init(content, aParentFrame, aFrame);
       // XXXbz should we be passing in a non-null aContentParentFrame?
       nsHTMLContainerFrame::CreateViewForFrame(newFrame, nsnull, PR_FALSE);
     }
 
   } else if (nsGkAtoms::pageFrame == frameType) {
-    nsIFrame* pageContentFrame;
+    nsIFrame* canvasFrame;
     rv = ConstructPageFrame(shell, aPresContext, aParentFrame, aFrame,
-                            newFrame, pageContentFrame);
+                            newFrame, canvasFrame);
   } else if (nsGkAtoms::tableOuterFrame == frameType) {
     rv = CreateContinuingOuterTableFrame(shell, aPresContext, aFrame, aParentFrame,
                                          content, styleContext, &newFrame);
 
   } else if (nsGkAtoms::tableFrame == frameType) {
     rv = CreateContinuingTableFrame(shell, aPresContext, aFrame, aParentFrame,
                                     content, styleContext, &newFrame);
 
@@ -10415,27 +10473,27 @@ nsCSSFrameConstructor::CreateContinuingF
     newFrame->SetNextContinuation(nextContinuation);
   }
   return NS_OK;
 }
 
 nsresult
 nsCSSFrameConstructor::ReplicateFixedFrames(nsPageContentFrame* aParentFrame)
 {
-  // Now deal with fixed-pos things....  They should appear on all pages, and
-  // the placeholders must be kids of a block, so we want to move over the
-  // placeholders when processing the child of the pageContentFrame.
+  // Now deal with fixed-pos things....  They should appear on all pages,
+  // so we want to move over the placeholders when processing the child
+  // of the pageContentFrame.
 
   nsIFrame* prevPageContentFrame = aParentFrame->GetPrevInFlow();
   if (!prevPageContentFrame) {
     return NS_OK;
   }
-  nsIFrame* docRootFrame = aParentFrame->GetFirstChild(nsnull);
-  nsIFrame* prevDocRootFrame = prevPageContentFrame->GetFirstChild(nsnull);
-  if (!docRootFrame || !prevDocRootFrame) {
+  nsIFrame* canvasFrame = aParentFrame->GetFirstChild(nsnull);
+  nsIFrame* prevCanvasFrame = prevPageContentFrame->GetFirstChild(nsnull);
+  if (!canvasFrame || !prevCanvasFrame) {
     // document's root element frame missing
     return NS_ERROR_UNEXPECTED;
   }
 
   nsFrameItems fixedPlaceholders;
   nsIFrame* firstFixed = prevPageContentFrame->GetFirstChild(nsGkAtoms::fixedList);
   if (!firstFixed) {
     return NS_OK;
@@ -10453,29 +10511,29 @@ nsCSSFrameConstructor::ReplicateFixedFra
   // Iterate across fixed frames and replicate each whose placeholder is a
   // descendant of aFrame. (We don't want to explicitly copy placeholders that
   // are within fixed frames, because that would cause duplicates on the new
   // page - bug 389619)
   for (nsIFrame* fixed = firstFixed; fixed; fixed = fixed->GetNextSibling()) {
     nsIFrame* prevPlaceholder = nsnull;
     mPresShell->GetPlaceholderFrameFor(fixed, &prevPlaceholder);
     if (prevPlaceholder &&
-        nsLayoutUtils::IsProperAncestorFrame(prevDocRootFrame, prevPlaceholder)) {
+        nsLayoutUtils::IsProperAncestorFrame(prevCanvasFrame, prevPlaceholder)) {
       nsresult rv = ConstructFrame(state, fixed->GetContent(),
-                                   docRootFrame, fixedPlaceholders);
+                                   canvasFrame, fixedPlaceholders);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   // Add the placeholders to our primary child list.
-  // XXXbz this is a little screwed up, since the fixed frames will have the
-  // wrong parent block and hence auto-positioning will be broken.  Oh, well.
-  NS_ASSERTION(!docRootFrame->GetFirstChild(nsnull),
+  // XXXbz this is a little screwed up, since the fixed frames will have 
+  // broken auto-positioning. Oh, well.
+  NS_ASSERTION(!canvasFrame->GetFirstChild(nsnull),
                "leaking frames; doc root continuation must be empty");
-  docRootFrame->SetInitialChildList(nsnull, fixedPlaceholders.childList);
+  canvasFrame->SetInitialChildList(nsnull, fixedPlaceholders.childList);
   return NS_OK;
 }
 
 static PRBool
 IsBindingAncestor(nsIContent* aContent, nsIContent* aBindingRoot)
 {
   while (PR_TRUE) {
     // Native-anonymous content doesn't contain insertion points, so
@@ -12796,24 +12854,32 @@ nsCSSFrameConstructor::ReframeContaining
       }
     }
   }
 
   // If we get here, we're screwed!
   return ReconstructDocElementHierarchyInternal();
 }
 
-nsresult nsCSSFrameConstructor::RemoveFixedItems(const nsFrameConstructorState& aState)
+nsresult
+nsCSSFrameConstructor::RemoveFixedItems(const nsFrameConstructorState& aState,
+                                        nsIFrame *aRootElementFrame)
 {
   nsresult rv=NS_OK;
 
   if (mFixedContainingBlock) {
     nsIFrame *fixedChild = nsnull;
     do {
       fixedChild = mFixedContainingBlock->GetFirstChild(nsGkAtoms::fixedList);
+      if (fixedChild && fixedChild == aRootElementFrame) {
+        // Skip the root element frame, if it happens to be fixed-positioned
+        // It will be explicitly removed later in
+        // ReconstructDocElementHierarchyInternal
+        fixedChild = fixedChild->GetNextSibling();
+      }
       if (fixedChild) {
         // Remove the placeholder so it doesn't end up sitting about pointing
         // to the removed fixed frame.
         nsPlaceholderFrame *placeholderFrame =
           aState.mFrameManager->GetPlaceholderFrameFor(fixedChild);
         NS_ASSERTION(placeholderFrame, "no placeholder for fixed-pos frame");
         NS_ASSERTION(placeholderFrame->GetType() ==
                      nsGkAtoms::placeholderFrame,
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -265,17 +265,17 @@ private:
   nsresult ReinsertContent(nsIContent*    aContainer,
                            nsIContent*    aChild);
 
   nsresult ConstructPageFrame(nsIPresShell*  aPresShell, 
                               nsPresContext* aPresContext,
                               nsIFrame*      aParentFrame,
                               nsIFrame*      aPrevPageFrame,
                               nsIFrame*&     aPageFrame,
-                              nsIFrame*&     aPageContentFrame);
+                              nsIFrame*&     aCanvasFrame);
 
   void DoContentStateChanged(nsIContent*     aContent,
                              PRInt32         aStateMask);
 
   /* aMinHint is the minimal change that should be made to the element */
   void RestyleElement(nsIContent*     aContent,
                       nsIFrame*       aPrimaryFrame,
                       nsChangeHint    aMinHint);
@@ -1044,17 +1044,18 @@ private:
 
   nsresult InsertFirstLineFrames(nsFrameConstructorState& aState,
                                  nsIContent*              aContent,
                                  nsIFrame*                aBlockFrame,
                                  nsIFrame**               aParentFrame,
                                  nsIFrame*                aPrevSibling,
                                  nsFrameItems&            aFrameItems);
 
-  nsresult RemoveFixedItems(const nsFrameConstructorState& aState);
+  nsresult RemoveFixedItems(const nsFrameConstructorState& aState,
+                            nsIFrame*                      aRootElementFrame);
 
   // Find the right frame to use for aContent when looking for sibling
   // frames for aTargetContent.  If aPrevSibling is true, this
   // will look for last continuations, etc, as necessary.  This calls
   // IsValidSibling as needed; if that returns false it returns null.
   //
   // @param aTargetContentDisplay the CSS display enum for aTargetContent if
   // already known, UNSET_DISPLAY otherwise.
@@ -1159,16 +1160,19 @@ private:
     nsCOMPtr<nsIPresShell> mPresShell;
     nsLazyFrameConstructionCallback* mCallback;
     void* mArg;
   };
 
   nsIDocument*        mDocument;  // Weak ref
   nsIPresShell*       mPresShell; // Weak ref
 
+  // See the comment at the start of ConstructRootFrame for more details
+  // about the following frames.
+  
   // This is not the real CSS 2.1 "initial containing block"! It is just
   // the outermost frame for the root element.
   nsIFrame*           mInitialContainingBlock;
   // This is the frame for the root element that has no pseudo-element style.
   nsIFrame*           mRootElementStyleFrame;
   // This is the containing block for fixed-pos frames --- the viewport
   nsIFrame*           mFixedContainingBlock;
   // This is the containing block that contains the root element ---
@@ -1176,19 +1180,20 @@ private:
   nsIFrame*           mDocElementContainingBlock;
   nsIFrame*           mGfxScrollFrame;
   nsIFrame*           mPageSequenceFrame;
   nsQuoteList         mQuoteList;
   nsCounterManager    mCounterManager;
   PRUint16            mUpdateCount;
   PRPackedBool        mQuotesDirty : 1;
   PRPackedBool        mCountersDirty : 1;
-  PRPackedBool        mInitialContainingBlockIsAbsPosContainer : 1;
   PRPackedBool        mIsDestroyingFrameTree : 1;
   PRPackedBool        mRebuildAllStyleData : 1;
+  // This is true if mDocElementContainingBlock supports absolute positioning
+  PRPackedBool        mHasRootAbsPosContainingBlock : 1;
 
   nsRevocableEventPtr<RestyleEvent> mRestyleEvent;
 
   nsCOMPtr<nsILayoutHistoryState> mTempFrameTreeState;
 
   nsDataHashtable<nsISupportsHashKey, RestyleData> mPendingRestyles;
 
   static nsIXBLService * gXBLService;
--- a/layout/generic/nsAbsoluteContainingBlock.cpp
+++ b/layout/generic/nsAbsoluteContainingBlock.cpp
@@ -47,27 +47,16 @@
 #include "nsHTMLContainerFrame.h"
 #include "nsHTMLParts.h"
 #include "nsPresContext.h"
 
 #ifdef DEBUG
 #include "nsBlockFrame.h"
 #endif
 
-
-nsresult
-nsAbsoluteContainingBlock::FirstChild(const nsIFrame* aDelegatingFrame,
-                                      nsIAtom*        aListName,
-                                      nsIFrame**      aFirstChild) const
-{
-  NS_PRECONDITION(GetChildListName() == aListName, "unexpected child list name");
-  *aFirstChild = mAbsoluteFrames.FirstChild();
-  return NS_OK;
-}
-
 nsresult
 nsAbsoluteContainingBlock::SetInitialChildList(nsIFrame*       aDelegatingFrame,
                                                nsIAtom*        aListName,
                                                nsIFrame*       aChildList)
 {
   NS_PRECONDITION(GetChildListName() == aListName, "unexpected child list name");
 #ifdef NS_DEBUG
   nsFrame::VerifyDirtyBitSet(aChildList);
--- a/layout/generic/nsAbsoluteContainingBlock.h
+++ b/layout/generic/nsAbsoluteContainingBlock.h
@@ -79,20 +79,17 @@ public:
                  mChildListName == nsGkAtoms::fixedList,
                  "should either represent position:fixed or absolute content");
   }
 
 #ifdef DEBUG
   nsIAtom* GetChildListName() const { return mChildListName; }
 #endif
 
-  nsresult FirstChild(const nsIFrame* aDelegatingFrame,
-                      nsIAtom*        aListName,
-                      nsIFrame**      aFirstChild) const;
-  nsIFrame* GetFirstChild() { return mAbsoluteFrames.FirstChild(); }
+  nsIFrame* GetFirstChild() const { return mAbsoluteFrames.FirstChild(); }
 
   nsresult SetInitialChildList(nsIFrame*       aDelegatingFrame,
                                nsIAtom*        aListName,
                                nsIFrame*       aChildList);
   nsresult AppendFrames(nsIFrame*      aDelegatingFrame,
                         nsIAtom*       aListName,
                         nsIFrame*      aFrameList);
   nsresult InsertFrames(nsIFrame*      aDelegatingFrame,
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -515,19 +515,17 @@ nsBlockFrame::GetBaseline() const
 
 /////////////////////////////////////////////////////////////////////////////
 // Child frame enumeration
 
 nsIFrame*
 nsBlockFrame::GetFirstChild(nsIAtom* aListName) const
 {
   if (nsGkAtoms::absoluteList == aListName) {
-    nsIFrame* result = nsnull;
-    mAbsoluteContainer.FirstChild(this, aListName, &result);
-    return result;
+    return mAbsoluteContainer.GetFirstChild();
   }
   else if (nsnull == aListName) {
     return (mLines.empty()) ? nsnull : mLines.front()->mFirstChild;
   }
   else if (aListName == nsGkAtoms::overflowList) {
     nsLineList* overflowLines = GetOverflowLines();
     return overflowLines ? overflowLines->front()->mFirstChild : nsnull;
   }
@@ -798,37 +796,35 @@ CalculateContainingBlockSizeForAbsolutes
 
   nsSize cbSize(aFrameSize);
     // Containing block is relative to the padding edge
   const nsMargin& border =
     aReflowState.mComputedBorderPadding - aReflowState.mComputedPadding;
   cbSize.width -= border.LeftRight();
   cbSize.height -= border.TopBottom();
 
-  if (frame->GetParent()->GetContent() == frame->GetContent()) {
-    // We are a wrapped frame for the content. Use the container's
-    // dimensions, if they have been precomputed.
+  if (frame->GetParent()->GetContent() == frame->GetContent() &&
+      frame->GetParent()->GetType() != nsGkAtoms::canvasFrame) {
+    // We are a wrapped frame for the content (and the wrapper is not the
+    // canvas frame, whose size is not meaningful here).
+    // Use the container's dimensions, if they have been precomputed.
     // XXX This is a hack! We really should be waiting until the outermost
     // frame is fully reflowed and using the resulting dimensions, even
     // if they're intrinsic.
     // In fact we should be attaching absolute children to the outermost
     // frame and not always sticking them in block frames.
 
     // First, find the reflow state for the outermost frame for this
     // content.
     const nsHTMLReflowState* aLastRS = &aReflowState;
     const nsHTMLReflowState* lastButOneRS = &aReflowState;
-    PRBool isCanvasBlock = PR_FALSE;
     while (aLastRS->parentReflowState &&
            aLastRS->parentReflowState->frame->GetContent() == frame->GetContent()) {
       lastButOneRS = aLastRS;
       aLastRS = aLastRS->parentReflowState;
-      if (aLastRS->frame->GetType() == nsGkAtoms::canvasFrame) {
-        isCanvasBlock = PR_TRUE;
-      }
     }
     if (aLastRS != &aReflowState) {
       // Scrollbars need to be specifically excluded, if present, because they are outside the
       // padding-edge. We need better APIs for getting the various boxes from a frame.
       nsIScrollableFrame* scrollFrame;
       CallQueryInterface(aLastRS->frame, &scrollFrame);
       nsMargin scrollbars(0,0,0,0);
       if (scrollFrame) {
@@ -839,33 +835,21 @@ CalculateContainingBlockSizeForAbsolutes
           scrollbars.top = scrollbars.bottom = 0;
         }
         if (!lastButOneRS->mFlags.mAssumingVScrollbar) {
           scrollbars.left = scrollbars.right = 0;
         }
       }
       // We found a reflow state for the outermost wrapping frame, so use
       // its computed metrics if available
-      // XXX grotesque hack for Firefox 2 compatibility until we can
-      // properly fix abs-pos containers! If this is the block for
-      // the root element, don't adjust the width here, just use the block's
-      // width. We have to do this because the abs-pos frame will be
-      // positioned relative to the block, not the canvas frame, and the
-      // block might have borders and margin which will throw things off
-      // if we use the canvas frame width.
-      // Positioning abs-pos frames relative to the canvas is bug 425432.
-      if (aLastRS->ComputedWidth() != NS_UNCONSTRAINEDSIZE && !isCanvasBlock) {
+      if (aLastRS->ComputedWidth() != NS_UNCONSTRAINEDSIZE) {
         cbSize.width = PR_MAX(0,
           aLastRS->ComputedWidth() + aLastRS->mComputedPadding.LeftRight() - scrollbars.LeftRight());
       }
       if (aLastRS->ComputedHeight() != NS_UNCONSTRAINEDSIZE) {
-        // XXX This can be terribly wrong if we're the root element's block,
-        // because our margin and borders will be included in the height
-        // here but the abs-pos element(s) are positioned relative to
-        // our content rect...
         cbSize.height = PR_MAX(0,
           aLastRS->ComputedHeight() + aLastRS->mComputedPadding.TopBottom() - scrollbars.TopBottom());
       }
     }
   }
 
   return cbSize;
 }
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -1587,16 +1587,19 @@ nsContainerFrame::List(FILE* out, PRInt3
             NS_LossyConvertUTF16toASCII(atomString).get());
   }
 
   // Output the children
   nsIAtom* listName = nsnull;
   PRInt32 listIndex = 0;
   PRBool outputOneList = PR_FALSE;
   do {
+    if (!outputOneList) {
+      fputs("\n", out);
+    }
     nsIFrame* kid = GetFirstChild(listName);
     if (nsnull != kid) {
       if (outputOneList) {
         IndentBy(out, aIndent);
       }
       outputOneList = PR_TRUE;
       nsAutoString tmp;
       if (nsnull != listName) {
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -5556,22 +5556,29 @@ nsFrame::CorrectStyleParentFrame(nsIFram
          // ancestor.
          aChildPseudo != nsGkAtoms::placeholderFrame)) {
       return parent;
     }
 
     parent = parent->GetParent();
   } while (parent);
 
-  // We can get here if aProspectiveParent is the scrollframe for a viewport
-  // and the kids are the anonymous scrollbars.
-  NS_ASSERTION(aProspectiveParent->GetStyleContext()->GetPseudoType() ==
-                 nsCSSAnonBoxes::viewportScroll,
+  if (aProspectiveParent->GetStyleContext()->GetPseudoType() ==
+      nsCSSAnonBoxes::viewportScroll) {
+    // aProspectiveParent is the scrollframe for a viewport
+    // and the kids are the anonymous scrollbars
+    return aProspectiveParent;
+  }
+
+  // We can get here if the root element is absolutely positioned.
+  // We can't test for this very accurately, but it can only happen
+  // when the prospective parent is a canvas frame.
+  NS_ASSERTION(aProspectiveParent->GetType() == nsGkAtoms::canvasFrame,
                "Should have found a parent before this");
-  return aProspectiveParent;
+  return nsnull;
 }
 
 nsresult
 nsFrame::DoGetParentStyleContextFrame(nsPresContext* aPresContext,
                                       nsIFrame**      aProviderFrame,
                                       PRBool*         aIsChild)
 {
   *aIsChild = PR_FALSE;
--- a/layout/generic/nsHTMLFrame.cpp
+++ b/layout/generic/nsHTMLFrame.cpp
@@ -49,68 +49,82 @@
 #include "nsGUIEvent.h"
 #include "nsStyleConsts.h"
 #include "nsGkAtoms.h"
 #include "nsIEventStateManager.h"
 #include "nsIDeviceContext.h"
 #include "nsIPresShell.h"
 #include "nsIScrollPositionListener.h"
 #include "nsDisplayList.h"
+#include "nsAbsoluteContainingBlock.h"
 
 // for focus
 #include "nsIDOMWindowInternal.h"
 #include "nsIFocusController.h"
 #include "nsIScrollableFrame.h"
 #include "nsIScrollableView.h"
 #include "nsIDocShell.h"
 #include "nsICanvasFrame.h"
 
 #ifdef DEBUG_rods
 //#define DEBUG_CANVAS_FOCUS
 #endif
 
+#define CANVAS_ABS_POS_CHILD_LIST NS_CONTAINER_LIST_COUNT_INCL_OC
+
 // Interface IDs
 
 /**
  * Root frame class.
  *
  * The root frame is the parent frame for the document element's frame.
  * It only supports having a single child frame which must be an area
  * frame
  */
 class CanvasFrame : public nsHTMLContainerFrame, 
                     public nsIScrollPositionListener, 
                     public nsICanvasFrame {
 public:
   CanvasFrame(nsStyleContext* aContext)
-  : nsHTMLContainerFrame(aContext), mDoPaintFocus(PR_FALSE) {}
+  : nsHTMLContainerFrame(aContext), mDoPaintFocus(PR_FALSE),
+    mAbsoluteContainer(nsGkAtoms::absoluteList) {}
 
    // nsISupports
   NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
 
   NS_IMETHOD Init(nsIContent*      aContent,
                   nsIFrame*        aParent,
                   nsIFrame*        aPrevInFlow);
   virtual void Destroy();
 
+  NS_IMETHOD SetInitialChildList(nsIAtom*        aListName,
+                                 nsIFrame*       aChildList);
   NS_IMETHOD AppendFrames(nsIAtom*        aListName,
                           nsIFrame*       aFrameList);
   NS_IMETHOD InsertFrames(nsIAtom*        aListName,
                           nsIFrame*       aPrevFrame,
                           nsIFrame*       aFrameList);
   NS_IMETHOD RemoveFrame(nsIAtom*        aListName,
                          nsIFrame*       aOldFrame);
 
+  virtual nsIAtom* GetAdditionalChildListName(PRInt32 aIndex) const;
+  virtual nsIFrame* GetFirstChild(nsIAtom* aListName) const;
+
   virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext);
   virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext);
   NS_IMETHOD Reflow(nsPresContext*          aPresContext,
                     nsHTMLReflowMetrics&     aDesiredSize,
                     const nsHTMLReflowState& aReflowState,
                     nsReflowStatus&          aStatus);
   virtual PRBool IsContainingBlock() const { return PR_TRUE; }
+  virtual PRBool IsFrameOfType(PRUint32 aFlags) const
+  {
+    return nsHTMLContainerFrame::IsFrameOfType(aFlags &
+             ~(nsIFrame::eCanContainOverflowContainers));
+  }
 
   NS_IMETHOD BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                               const nsRect&           aDirtyRect,
                               const nsDisplayListSet& aLists);
 
   void PaintFocus(nsIRenderingContext& aRenderingContext, nsPoint aPt);
 
   // nsIScrollPositionListener
@@ -123,31 +137,47 @@ public:
 
   /**
    * Get the "type" of the frame
    *
    * @see nsGkAtoms::canvasFrame
    */
   virtual nsIAtom* GetType() const;
 
+  virtual nsresult StealFrame(nsPresContext* aPresContext,
+                              nsIFrame*      aChild,
+                              PRBool         aForceNormal)
+  {
+    NS_ASSERTION(!aForceNormal, "No-one should be passing this in here");
+
+    // CanvasFrame keeps overflow container continuations of its child
+    // frame in main child list
+    nsresult rv = nsContainerFrame::StealFrame(aPresContext, aChild, PR_TRUE);
+    if (NS_FAILED(rv)) {
+      rv = nsContainerFrame::StealFrame(aPresContext, aChild);
+    }
+    return rv;
+  }
+
 #ifdef DEBUG
   NS_IMETHOD GetFrameName(nsAString& aResult) const;
 #endif
   NS_IMETHOD GetContentForEvent(nsPresContext* aPresContext,
                                 nsEvent* aEvent,
                                 nsIContent** aContent);
 
   nsRect CanvasArea() const;
 
 protected:
   virtual PRIntn GetSkipSides() const;
 
   // Data members
-  PRPackedBool             mDoPaintFocus;
-  nsCOMPtr<nsIViewManager> mViewManager;
+  PRPackedBool              mDoPaintFocus;
+  nsCOMPtr<nsIViewManager>  mViewManager;
+  nsAbsoluteContainingBlock mAbsoluteContainer;
 
 private:
   NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; }
   NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; }
 };
 
 
 //----------------------------------------------------------------------
@@ -193,16 +223,18 @@ CanvasFrame::Init(nsIContent*      aCont
   }
 
   return rv;
 }
 
 void
 CanvasFrame::Destroy()
 {
+  mAbsoluteContainer.DestroyFrames(this);
+
   nsIScrollableView* scrollingView = nsnull;
   mViewManager->GetRootScrollableView(&scrollingView);
   if (scrollingView) {
     scrollingView->RemoveScrollPositionListener(this);
   }
 
   nsHTMLContainerFrame::Destroy();
 }
@@ -241,30 +273,42 @@ CanvasFrame::ScrollPositionDidChange(nsI
   return NS_OK;
 }
 
 NS_IMETHODIMP
 CanvasFrame::SetHasFocus(PRBool aHasFocus)
 {
   if (mDoPaintFocus != aHasFocus) {
     mDoPaintFocus = aHasFocus;
-    nsIViewManager* vm = PresContext()->PresShell()->GetViewManager();
-    if (vm) {
-      vm->UpdateAllViews(NS_VMREFRESH_NO_SYNC);
-    }
+    mViewManager->UpdateAllViews(NS_VMREFRESH_NO_SYNC);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
+CanvasFrame::SetInitialChildList(nsIAtom*        aListName,
+                                 nsIFrame*       aChildList)
+{
+  if (nsGkAtoms::absoluteList == aListName)
+    return mAbsoluteContainer.SetInitialChildList(this, aListName, aChildList);
+
+  NS_ASSERTION(aListName || !aChildList || !aChildList->GetNextSibling(),
+               "Primary child list can have at most one frame in it");
+  return nsHTMLContainerFrame::SetInitialChildList(aListName, aChildList);
+}
+
+NS_IMETHODIMP
 CanvasFrame::AppendFrames(nsIAtom*        aListName,
                           nsIFrame*       aFrameList)
 {
   nsresult  rv;
 
+  if (nsGkAtoms::absoluteList == aListName)
+    return mAbsoluteContainer.AppendFrames(this, aListName, aFrameList);
+
   NS_ASSERTION(!aListName, "unexpected child list name");
   NS_PRECONDITION(mFrames.IsEmpty(), "already have a child frame");
   if (aListName) {
     // We only support unnamed principal child list
     rv = NS_ERROR_INVALID_ARG;
 
   } else if (!mFrames.IsEmpty()) {
     // We only allow a single child frame
@@ -287,16 +331,19 @@ CanvasFrame::AppendFrames(nsIAtom*      
 
 NS_IMETHODIMP
 CanvasFrame::InsertFrames(nsIAtom*        aListName,
                           nsIFrame*       aPrevFrame,
                           nsIFrame*       aFrameList)
 {
   nsresult  rv;
 
+  if (nsGkAtoms::absoluteList == aListName)
+    return mAbsoluteContainer.InsertFrames(this, aListName, aPrevFrame, aFrameList);
+
   // Because we only support a single child frame inserting is the same
   // as appending
   NS_PRECONDITION(!aPrevFrame, "unexpected previous sibling frame");
   if (aPrevFrame) {
     rv = NS_ERROR_UNEXPECTED;
   } else {
     rv = AppendFrames(aListName, aFrameList);
   }
@@ -305,16 +352,19 @@ CanvasFrame::InsertFrames(nsIAtom*      
 }
 
 NS_IMETHODIMP
 CanvasFrame::RemoveFrame(nsIAtom*        aListName,
                          nsIFrame*       aOldFrame)
 {
   nsresult  rv;
 
+  if (nsGkAtoms::absoluteList == aListName)
+    return mAbsoluteContainer.RemoveFrame(this, aListName, aOldFrame);
+
   NS_ASSERTION(!aListName, "unexpected child list name");
   if (aListName) {
     // We only support the unnamed principal child list
     rv = NS_ERROR_INVALID_ARG;
   
   } else if (aOldFrame == mFrames.FirstChild()) {
     // It's our one and only child frame
     // Damage the area occupied by the deleted frame
@@ -330,16 +380,34 @@ CanvasFrame::RemoveFrame(nsIAtom*       
                             NS_FRAME_HAS_DIRTY_CHILDREN);
   } else {
     rv = NS_ERROR_FAILURE;
   }
 
   return rv;
 }
 
+nsIAtom*
+CanvasFrame::GetAdditionalChildListName(PRInt32 aIndex) const
+{
+  if (CANVAS_ABS_POS_CHILD_LIST == aIndex)
+    return nsGkAtoms::absoluteList;
+
+  return nsHTMLContainerFrame::GetAdditionalChildListName(aIndex);
+}
+
+nsIFrame*
+CanvasFrame::GetFirstChild(nsIAtom* aListName) const
+{
+  if (nsGkAtoms::absoluteList == aListName)
+    return mAbsoluteContainer.GetFirstChild();
+
+  return nsHTMLContainerFrame::GetFirstChild(aListName);
+}
+
 nsRect CanvasFrame::CanvasArea() const
 {
   nsRect result(GetOverflowRect());
 
   nsIScrollableFrame *scrollableFrame;
   CallQueryInterface(GetParent(), &scrollableFrame);
   if (scrollableFrame) {
     nsIScrollableView* scrollableView = scrollableFrame->GetScrollableView();
@@ -414,31 +482,38 @@ public:
 };
 
 NS_IMETHODIMP
 CanvasFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                               const nsRect&           aDirtyRect,
                               const nsDisplayListSet& aLists)
 {
   nsresult rv;
+
+  if (GetPrevInFlow()) {
+    DisplayOverflowContainers(aBuilder, aDirtyRect, aLists);
+  }
+
+  aBuilder->MarkFramesForDisplayList(this, mAbsoluteContainer.GetFirstChild(), aDirtyRect);
+  
   // Force a background to be shown. We may have a background propagated to us,
   // in which case GetStyleBackground wouldn't have the right background
   // and the code in nsFrame::DisplayBorderBackgroundOutline might not give us
   // a background.
   // We don't have any border or outline, and our background draws over
   // the overflow area, so just add nsDisplayCanvasBackground instead of
   // calling DisplayBorderBackgroundOutline.
   if (IsVisibleForPainting(aBuilder)) { 
     rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
            nsDisplayCanvasBackground(this));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  nsIFrame* kid = GetFirstChild(nsnull);
-  if (kid) {
+  nsIFrame* kid;
+  for (kid = GetFirstChild(nsnull); kid; kid = kid->GetNextSibling()) {
     // Put our child into its own pseudo-stack.
     rv = BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists,
                                   DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
 #ifdef DEBUG_CANVAS_FOCUS
   nsCOMPtr<nsIContent> focusContent;
@@ -523,88 +598,150 @@ CanvasFrame::GetPrefWidth(nsIRenderingCo
   if (mFrames.IsEmpty())
     result = 0;
   else
     result = mFrames.FirstChild()->GetPrefWidth(aRenderingContext);
   return result;
 }
 
 NS_IMETHODIMP
-CanvasFrame::Reflow(nsPresContext*          aPresContext,
+CanvasFrame::Reflow(nsPresContext*           aPresContext,
                     nsHTMLReflowMetrics&     aDesiredSize,
                     const nsHTMLReflowState& aReflowState,
                     nsReflowStatus&          aStatus)
 {
   DO_GLOBAL_REFLOW_COUNT("CanvasFrame");
   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
   NS_FRAME_TRACE_REFLOW_IN("CanvasFrame::Reflow");
 
   // Initialize OUT parameter
   aStatus = NS_FRAME_COMPLETE;
 
-  // Reflow our one and only child frame
+  CanvasFrame* prevCanvasFrame = static_cast<CanvasFrame*>
+                                               (GetPrevInFlow());
+  if (prevCanvasFrame) {
+    nsIFrame* overflow = prevCanvasFrame->GetOverflowFrames(aPresContext, PR_TRUE);
+    if (overflow) {
+      NS_ASSERTION(!overflow->GetNextSibling(),
+                   "must have doc root as canvas frame's only child");
+      nsHTMLContainerFrame::ReparentFrameView(aPresContext, overflow, prevCanvasFrame, this);
+      // Prepend overflow to the our child list. There may already be
+      // children placeholders for fixed-pos elements, which don't get
+      // reflowed but must not be lost until the canvas frame is destroyed.
+      mFrames.InsertFrames(this, nsnull, overflow);
+    }
+  }
+
+  // Reflow our one and only normal child frame. It's either the root
+  // element's frame or a placeholder for that frame, if the root element
+  // is abs-pos or fixed-pos. We may have additional children which
+  // are placeholders for continuations of fixed-pos content, but those
+  // don't need to be reflowed. The normal child is always comes before
+  // the fixed-pos placeholders, because we insert it at the start
+  // of the child list, above.
   nsHTMLReflowMetrics kidDesiredSize;
   if (mFrames.IsEmpty()) {
     // We have no child frame, so return an empty size
     aDesiredSize.width = aDesiredSize.height = 0;
   } else {
     nsIFrame* kidFrame = mFrames.FirstChild();
     PRBool kidDirty = (kidFrame->GetStateBits() & NS_FRAME_IS_DIRTY) != 0;
 
-    // We must specify an unconstrained available height, because constrained
-    // is only for when we're paginated...
     nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame,
                                      nsSize(aReflowState.availableWidth,
-                                            NS_UNCONSTRAINEDSIZE));
+                                            aReflowState.availableHeight));
 
     if (aReflowState.mFlags.mVResize &&
         (kidFrame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT)) {
       // Tell our kid it's being vertically resized too.  Bit of a
       // hack for framesets.
       kidReflowState.mFlags.mVResize = PR_TRUE;
     }
-    
+
+    nsPoint kidPt(kidReflowState.mComputedMargin.left,
+                  kidReflowState.mComputedMargin.top);
+    // Apply CSS relative positioning
+    const nsStyleDisplay* styleDisp = kidFrame->GetStyleDisplay();
+    if (NS_STYLE_POSITION_RELATIVE == styleDisp->mPosition) {
+      kidPt += nsPoint(kidReflowState.mComputedOffsets.left,
+                       kidReflowState.mComputedOffsets.top);
+    }
+
     // Reflow the frame
     ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState,
-                kidReflowState.mComputedMargin.left, kidReflowState.mComputedMargin.top,
-                0, aStatus);
+                kidPt.x, kidPt.y, 0, aStatus);
 
     // Complete the reflow and position and size the child frame
     FinishReflowChild(kidFrame, aPresContext, &kidReflowState, kidDesiredSize,
-                      kidReflowState.mComputedMargin.left,
-                      kidReflowState.mComputedMargin.top, 0);
+                      kidPt.x, kidPt.y, 0);
+
+    if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
+      nsIFrame* nextFrame = kidFrame->GetNextInFlow();
+      NS_ASSERTION(nextFrame || aStatus & NS_FRAME_REFLOW_NEXTINFLOW,
+        "If it's incomplete and has no nif yet, it must flag a nif reflow.");
+      if (!nextFrame) {
+        nsresult rv = nsHTMLContainerFrame::CreateNextInFlow(aPresContext,
+                                              this, kidFrame, nextFrame);
+        NS_ENSURE_SUCCESS(rv, rv);
+        kidFrame->SetNextSibling(nextFrame->GetNextSibling());
+        nextFrame->SetNextSibling(nsnull);
+        SetOverflowFrames(aPresContext, nextFrame);
+        // Root overflow containers will be normal children of
+        // the canvas frame, but that's ok because there
+        // aren't any other frames we need to isolate them from
+        // during reflow.
+      }
+      if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) {
+        nextFrame->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
+      }
+    }
 
     // If the child frame was just inserted, then we're responsible for making sure
     // it repaints
     if (kidDirty) {
       // But we have a new child, which will affect our background, so
       // invalidate our whole rect.
       // Note: Even though we request to be sized to our child's size, our
       // scroll frame ensures that we are always the size of the viewport.
       // Also note: GetPosition() on a CanvasFrame is always going to return
       // (0, 0). We only want to invalidate GetRect() since GetOverflowRect()
       // could also include overflow to our top and left (out of the viewport)
       // which doesn't need to be painted.
       nsIFrame* viewport = PresContext()->GetPresShell()->GetRootFrame();
       viewport->Invalidate(nsRect(nsPoint(0, 0), viewport->GetSize()));
     }
-
+    
     // Return our desired size (which doesn't matter)
-    aDesiredSize.width = aReflowState.availableWidth;
-    aDesiredSize.height = kidDesiredSize.height +
-                          kidReflowState.mComputedMargin.TopBottom();
+    aDesiredSize.width = aReflowState.ComputedWidth();
+    aDesiredSize.height = aReflowState.ComputedHeight();
 
     aDesiredSize.mOverflowArea.UnionRect(
       nsRect(0, 0, aDesiredSize.width, aDesiredSize.height),
-      kidDesiredSize.mOverflowArea +
-        nsPoint(kidReflowState.mComputedMargin.left,
-                kidReflowState.mComputedMargin.top));
-    FinishAndStoreOverflow(&aDesiredSize);
+      kidDesiredSize.mOverflowArea + kidPt);
+
+    if (mAbsoluteContainer.HasAbsoluteFrames()) {
+      PRBool widthChanged = aDesiredSize.width != mRect.width;
+      PRBool heightChanged = aDesiredSize.height != mRect.height;
+      nsRect absPosBounds;
+      mAbsoluteContainer.Reflow(this, aPresContext, aReflowState, aStatus,
+                                aDesiredSize.width, aDesiredSize.height,
+                                PR_TRUE, widthChanged, heightChanged,
+                                &absPosBounds);
+      aDesiredSize.mOverflowArea.UnionRect(aDesiredSize.mOverflowArea, absPosBounds);
+    }
   }
 
+  if (prevCanvasFrame) {
+    ReflowOverflowContainerChildren(aPresContext, aReflowState,
+                                    aDesiredSize.mOverflowArea, 0,
+                                    aStatus);
+  }
+
+  FinishAndStoreOverflow(&aDesiredSize);
+
   NS_FRAME_TRACE_REFLOW_OUT("CanvasFrame::Reflow", aStatus);
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   return NS_OK;
 }
 
 PRIntn
 CanvasFrame::GetSkipSides() const
 {
--- a/layout/generic/nsHTMLParts.h
+++ b/layout/generic/nsHTMLParts.h
@@ -108,41 +108,34 @@ nsIFrame*
 NS_NewAreaFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, PRUint32 aFlags);
 
 // These AreaFrame's shrink wrap around their contents
 inline nsIFrame*
 NS_NewTableCellInnerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) {
   return NS_NewBlockFrame(aPresShell, aContext);
 }
 
-// This type of AreaFrame is the document root, a margin root, and the
-// initial containing block for absolutely positioned elements
+// This type of BlockFrame is a margin root, but does not shrink wrap
 inline nsIFrame*
-NS_NewDocumentElementFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) {
-  return NS_NewAreaFrame(aPresShell, aContext, NS_BLOCK_SPACE_MGR|NS_BLOCK_MARGIN_ROOT);
+NS_NewAbsoluteItemWrapperFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) {
+  return NS_NewBlockFrame(aPresShell, aContext, NS_BLOCK_SPACE_MGR|NS_BLOCK_MARGIN_ROOT);
 }
 
-// This type of AreaFrame is a margin root, but does not shrink wrap
-inline nsIFrame*
-NS_NewAbsoluteItemWrapperFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) {
-  return NS_NewAreaFrame(aPresShell, aContext, NS_BLOCK_SPACE_MGR|NS_BLOCK_MARGIN_ROOT);
-}
-
-// This type of AreaFrame shrink wraps
+// This type of BlockFrame shrink wraps
 inline nsIFrame*
 NS_NewFloatingItemWrapperFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) {
-  return NS_NewAreaFrame(aPresShell, aContext,
+  return NS_NewBlockFrame(aPresShell, aContext,
     NS_BLOCK_SPACE_MGR|NS_BLOCK_MARGIN_ROOT);
 }
 
-// This type of AreaFrame doesn't use its own space manager and
+// This type of BlockFrame doesn't use its own space manager and
 // doesn't shrink wrap.
 inline nsIFrame*
 NS_NewRelativeItemWrapperFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, PRUint32 aFlags) {
-  return NS_NewAreaFrame(aPresShell, aContext, aFlags);
+  return NS_NewBlockFrame(aPresShell, aContext, aFlags);
 }
 
 nsIFrame*
 NS_NewBRFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
 nsIFrame*
 NS_NewCommentFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
--- a/layout/generic/nsHTMLReflowState.cpp
+++ b/layout/generic/nsHTMLReflowState.cpp
@@ -1526,35 +1526,17 @@ nsHTMLReflowState::ComputeContainingBloc
       aContainingBlockHeight = aContainingBlockRS->frame->GetRect().height -
         computedBorder.TopBottom();
       NS_ASSERTION(aContainingBlockHeight >= 0,
                    "Negative containing block height!");
     } else {
       // If the ancestor is block-level, the containing block is formed by the
       // padding edge of the ancestor
       aContainingBlockWidth += aContainingBlockRS->mComputedPadding.LeftRight();
-
-      // If the containing block is the initial containing block and it has a
-      // height that depends on its content, then use the viewport height instead.
-      // This gives us a reasonable value against which to compute percentage
-      // based heights and to do bottom relative positioning
-      if ((NS_AUTOHEIGHT == aContainingBlockHeight) &&
-          nsLayoutUtils::IsInitialContainingBlock(aContainingBlockRS->frame)) {
-
-        // Use the viewport height as the containing block height
-        const nsHTMLReflowState* rs = aContainingBlockRS->parentReflowState;
-        while (rs) {
-          aContainingBlockHeight = rs->mComputedHeight;
-          rs = rs->parentReflowState;
-        }
-
-      } else {
-        aContainingBlockHeight +=
-          aContainingBlockRS->mComputedPadding.TopBottom();
-      }
+      aContainingBlockHeight += aContainingBlockRS->mComputedPadding.TopBottom();
     }
   } else {
     // an element in quirks mode gets a containing block based on looking for a
     // parent with a non-auto height if the element has a percent height
     if (NS_AUTOHEIGHT == aContainingBlockHeight) {
       if (eCompatibility_NavQuirks == aPresContext->CompatibilityMode() &&
           mStylePosition->mHeight.GetUnit() == eStyleUnit_Percent) {
         aContainingBlockHeight = CalcQuirkContainingBlockHeight(aContainingBlockRS);
--- a/layout/generic/nsInlineFrame.cpp
+++ b/layout/generic/nsInlineFrame.cpp
@@ -1068,21 +1068,18 @@ nsPositionedInlineFrame::GetAdditionalCh
     return nsGkAtoms::absoluteList;
   }
   return nsnull;
 }
 
 nsIFrame*
 nsPositionedInlineFrame::GetFirstChild(nsIAtom* aListName) const
 {
-  if (nsGkAtoms::absoluteList == aListName) {
-    nsIFrame* result = nsnull;
-    mAbsoluteContainer.FirstChild(this, aListName, &result);
-    return result;
-  }
+  if (nsGkAtoms::absoluteList == aListName)
+    return mAbsoluteContainer.GetFirstChild();
 
   return nsInlineFrame::GetFirstChild(aListName);
 }
 
 nsIAtom*
 nsPositionedInlineFrame::GetType() const
 {
   return nsGkAtoms::positionedInlineFrame;
--- a/layout/generic/nsPageContentFrame.cpp
+++ b/layout/generic/nsPageContentFrame.cpp
@@ -64,137 +64,48 @@ nsPageContentFrame::ComputeSize(nsIRende
 {
   NS_ASSERTION(mPD, "Pages are supposed to have page data");
   nscoord height = (!mPD || mPD->mReflowSize.height == NS_UNCONSTRAINEDSIZE)
                    ? NS_UNCONSTRAINEDSIZE
                    : (mPD->mReflowSize.height - mPD->mReflowMargin.TopBottom());
   return nsSize(aAvailableWidth, height);
 }
 
-/**
- * Returns true if aFrame is a placeholder for one of our fixed frames.
- */
-inline PRBool
-nsPageContentFrame::IsFixedPlaceholder(nsIFrame* aFrame)
-{
-  if (!aFrame || nsGkAtoms::placeholderFrame != aFrame->GetType())
-    return PR_FALSE;
-
-  return static_cast<nsPlaceholderFrame*>(aFrame)->GetOutOfFlowFrame()
-           ->GetParent() == this;
-}
-
-/**
- * Steals replicated fixed placeholder frames from aDocRoot so they don't
- * get in the way of reflow.
- */
-inline nsFrameList
-nsPageContentFrame::StealFixedPlaceholders(nsIFrame* aDocRoot)
-{
-  nsPresContext* presContext = PresContext();
-  nsFrameList list;
-  if (GetPrevInFlow()) {
-    for (nsIFrame* f = aDocRoot->GetFirstChild(nsnull);
-        IsFixedPlaceholder(f); f = aDocRoot->GetFirstChild(nsnull)) {
-      nsresult rv = static_cast<nsContainerFrame*>(aDocRoot)
-                      ->StealFrame(presContext, f);
-      NS_ENSURE_SUCCESS(rv, list);
-      list.AppendFrame(nsnull, f);
-    }
-  }
-  return list;
-}
-
-/**
- * Restores stolen replicated fixed placeholder frames to aDocRoot.
- */
-static inline nsresult
-ReplaceFixedPlaceholders(nsIFrame*    aDocRoot,
-                         nsFrameList& aPlaceholderList)
-{
-  nsresult rv = NS_OK;
-  if (aPlaceholderList.NotEmpty()) {
-    rv = static_cast<nsContainerFrame*>(aDocRoot)
-           ->AddFrames(aPlaceholderList.FirstChild(), nsnull);
-  }
-  return rv;
-}
-
 NS_IMETHODIMP
 nsPageContentFrame::Reflow(nsPresContext*           aPresContext,
                            nsHTMLReflowMetrics&     aDesiredSize,
                            const nsHTMLReflowState& aReflowState,
                            nsReflowStatus&          aStatus)
 {
   DO_GLOBAL_REFLOW_COUNT("nsPageContentFrame");
   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
   aStatus = NS_FRAME_COMPLETE;  // initialize out parameter
   nsresult rv = NS_OK;
 
-  // A PageContentFrame must always have one child: the doc root element's frame.
-  // We only need to get overflow frames if we don't already have that child;
-  // Also we need to avoid repeating the call to ReplicateFixedFrames.
-  nsPageContentFrame* prevPageContentFrame = static_cast<nsPageContentFrame*>
-                                               (GetPrevInFlow());
-  if (mFrames.IsEmpty() && prevPageContentFrame) {
-    // Pull the doc root frame's continuation and copy fixed frames.
-    nsIFrame* overflow = prevPageContentFrame->GetOverflowFrames(aPresContext, PR_TRUE);
-    NS_ASSERTION(overflow && !overflow->GetNextSibling(),
-                 "must have doc root as pageContentFrame's only child");
-    nsHTMLContainerFrame::ReparentFrameView(aPresContext, overflow, prevPageContentFrame, this);
-    // Prepend overflow to the page content frame. There may already be
-    // children placeholders which don't get reflowed but must not be
-    // lost until the page content frame is destroyed.
-    mFrames.InsertFrames(this, nsnull, overflow);
+  if (GetPrevInFlow() && (GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
     nsresult rv = aPresContext->PresShell()->FrameConstructor()
                     ->ReplicateFixedFrames(this);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
+  // A PageContentFrame must always have one child: the canvas frame.
   // Resize our frame allowing it only to be as big as we are
   // XXX Pay attention to the page's border and padding...
   if (mFrames.NotEmpty()) {
     nsIFrame* frame = mFrames.FirstChild();
     nsSize  maxSize(aReflowState.availableWidth, aReflowState.availableHeight);
     nsHTMLReflowState kidReflowState(aPresContext, aReflowState, frame, maxSize);
+    kidReflowState.SetComputedHeight(aReflowState.availableHeight);
 
     mPD->mPageContentSize  = aReflowState.availableWidth;
 
-    // Get replicated fixed frames' placeholders out of the way
-    nsFrameList stolenPlaceholders = StealFixedPlaceholders(frame);
-
     // Reflow the page content area
     rv = ReflowChild(frame, aPresContext, aDesiredSize, kidReflowState, 0, 0, 0, aStatus);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    // Put removed fixed placeholders back
-    rv = ReplaceFixedPlaceholders(frame, stolenPlaceholders);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
-      nsIFrame* nextFrame = frame->GetNextInFlow();
-      NS_ASSERTION(nextFrame || aStatus & NS_FRAME_REFLOW_NEXTINFLOW,
-        "If it's incomplete and has no nif yet, it must flag a nif reflow.");
-      if (!nextFrame) {
-        nsresult rv = nsHTMLContainerFrame::CreateNextInFlow(aPresContext,
-                                              this, frame, nextFrame);
-        NS_ENSURE_SUCCESS(rv, rv);
-        frame->SetNextSibling(nextFrame->GetNextSibling());
-        nextFrame->SetNextSibling(nsnull);
-        SetOverflowFrames(aPresContext, nextFrame);
-        // Root overflow containers will be normal children of
-        // the pageContentFrame, but that's ok because there
-        // aren't any other frames we need to isolate them from
-        // during reflow.
-      }
-      if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) {
-        nextFrame->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
-      }
-    }
-
     // The document element's background should cover the entire canvas, so
     // take into account the combined area and any space taken up by
     // absolutely positioned elements
     nsMargin padding(0,0,0,0);
 
     // XXXbz this screws up percentage padding (sets padding to zero
     // in the percentage padding case)
     kidReflowState.mStylePadding->GetPadding(padding);
--- a/layout/generic/nsPageContentFrame.h
+++ b/layout/generic/nsPageContentFrame.h
@@ -78,16 +78,12 @@ public:
   // Debugging
   NS_IMETHOD  GetFrameName(nsAString& aResult) const;
 #endif
 
 protected:
   nsPageContentFrame(nsStyleContext* aContext) : ViewportFrame(aContext) {}
 
   nsSharedPageData*         mPD;
-
-private:
-  PRBool IsFixedPlaceholder(nsIFrame* aFrame);
-  nsFrameList StealFixedPlaceholders(nsIFrame* aDocRoot);
 };
 
 #endif /* nsPageContentFrame_h___ */
 
--- a/layout/generic/nsViewportFrame.cpp
+++ b/layout/generic/nsViewportFrame.cpp
@@ -174,21 +174,18 @@ ViewportFrame::GetAdditionalChildListNam
   }
 
   return nsnull;
 }
 
 nsIFrame*
 ViewportFrame::GetFirstChild(nsIAtom* aListName) const
 {
-  if (nsGkAtoms::fixedList == aListName) {
-    nsIFrame* result = nsnull;
-    mFixedContainer.FirstChild(this, aListName, &result);
-    return result;
-  }
+  if (nsGkAtoms::fixedList == aListName)
+    return mFixedContainer.GetFirstChild();
 
   return nsContainerFrame::GetFirstChild(aListName);
 }
 
 /* virtual */ nscoord
 ViewportFrame::GetMinWidth(nsIRenderingContext *aRenderingContext)
 {
   nscoord result;
@@ -304,18 +301,17 @@ ViewportFrame::Reflow(nsPresContext*    
                           : kidHeight;
 
   // Make a copy of the reflow state and change the computed width and height
   // to reflect the available space for the fixed items
   nsHTMLReflowState reflowState(aReflowState);
   nsPoint offset = AdjustReflowStateForScrollbars(&reflowState);
   
 #ifdef DEBUG
-  nsIFrame* f;
-  mFixedContainer.FirstChild(this, nsGkAtoms::fixedList, &f);
+  nsIFrame* f = mFixedContainer.GetFirstChild();
   NS_ASSERTION(!f || (offset.x == 0 && offset.y == 0),
                "We don't handle correct positioning of fixed frames with "
                "scrollbars in odd positions");
 #endif
 
   // Just reflow all the fixed-pos frames.
   rv = mFixedContainer.Reflow(this, aPresContext, reflowState, aStatus,
                               reflowState.ComputedWidth(),
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/243519-9f.html
@@ -0,0 +1,5 @@
+<!DOCTYPE HTML>
+<html style="position:relative; height:50%;">
+<body style="position:absolute; width:50%; top:50px; left:50px; height:100%; margin:0; border:10px solid black;">
+</body>
+</html>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -120,16 +120,17 @@ fails == 25888-3r.html 25888-3r-ref.html
 == 163504-1b.html 163504-1-ref.html
 == 163504-2a.html 163504-2-ref.html
 == 163504-2b.html 163504-2-ref.html
 == 169749-1.html 169749-1-ref.html
 == 172073-1.html 172073-1-ref.html
 == 180085-1.html 180085-1-ref.html
 == 180085-2.html 180085-2-ref.html
 == 185388-1.html 185388-1-ref.html
+!= 200774-1.html about:blank # really a crashtest
 == 201215-1.html 201215-1-ref.html
 == 201293-1a.html 201293-1-ref.html
 == 201293-1b.html 201293-1-ref.html
 == 201293-1c.html 201293-1-ref.html
 == 201293-1d.html 201293-1-ref.html
 == 206516-1.html 206516-1-ref.html
 == 210094-1a.html 210094-1-ref.html
 == 210094-1b.html 210094-1-ref.html
@@ -161,16 +162,38 @@ fails == 25888-3r.html 25888-3r-ref.html
 == 234686-19.html 234686-ref.html
 == 234964-1.html 234964-1-ref.html
 == 234964-2.html 234964-2-ref.html
 == 235593-1.html 235593-1-ref.html
 == 236539-1.html 236539-1-ref.html
 == 240470-1.html 240470-1-ref.html
 == 243266-1.html 243266-1-ref.html
 == 243302-1.html 243302-1-ref.html
+== 243519-1.html 243519-1-ref.html
+== 243519-2.html 243519-2-ref.html
+== 243519-3.html 243519-3-ref.html
+== 243519-4a.html 243519-4-ref.html
+== 243519-4b.html 243519-4-ref.html
+== 243519-4c.html 243519-4-ref.html
+== 243519-4d.html 243519-4-ref.html
+== 243519-4e.html 243519-4-ref.html
+== 243519-4f.html 243519-4-ref.html
+== 243519-5a.html 243519-5-ref.html
+== 243519-5b.html 243519-5-ref.html
+== 243519-5c.html 243519-5-ref.html
+== 243519-5d.html 243519-5-ref.html
+== 243519-6.html 243519-6-ref.html
+== 243519-7.html 243519-7-ref.html
+== 243519-8.svg 243519-8-ref.svg
+== 243519-9a.html 243519-9-ref.html
+== 243519-9b.html 243519-9-ref.html
+== 243519-9c.html 243519-9-ref.html
+== 243519-9d.html 243519-9-ref.html
+== 243519-9e.html 243519-9-ref.html
+== 243519-9f.html 243519-9-ref.html
 == 244135-1.html 244135-1-ref.html
 == 244135-2.html 244135-2-ref.html
 == 244932-1.html 244932-1-ref.html
 == 249982-1.html 249982-1-ref.html
 == 253701-1.html 253701-1-ref.html
 == 255820-1.html 255820-1-ref.html
 == 262151-1.html 262151-1-ref.html
 #== 263683-1.html 263683-1-ref.html