fixed positioned elements print only on first and last pages b=417676 r+sr=roc
authorfantasai.cvs@inkedblade.net
Sun, 24 Feb 2008 04:19:17 -0800
changeset 12177 c0a8f4e30783b54efcf9089b1a801caef26e8791
parent 12176 8aa56b83f9285cd68aa36ebd5d0aeb66742672dd
child 12178 8522ffb5acb28b4d9e7759587547247da452ecb5
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs417676
milestone1.9b4pre
fixed positioned elements print only on first and last pages b=417676 r+sr=roc
layout/generic/nsBlockFrame.h
layout/generic/nsContainerFrame.cpp
layout/generic/nsContainerFrame.h
layout/generic/nsPageContentFrame.cpp
layout/generic/nsPageContentFrame.h
layout/reftests/bugs/417676-ref.html
layout/reftests/bugs/417676.html
layout/reftests/bugs/reftest.list
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -382,18 +382,18 @@ protected:
                            nsHTMLReflowMetrics& aMetrics);
 
   /** add the frames in aFrameList to this block after aPrevSibling
     * this block thinks in terms of lines, but the frame construction code
     * knows nothing about lines at all. So we need to find the line that
     * contains aPrevSibling and add aFrameList after aPrevSibling on that line.
     * new lines are created as necessary to handle block data in aFrameList.
     */
-  nsresult AddFrames(nsIFrame* aFrameList,
-                     nsIFrame* aPrevSibling);
+  virtual nsresult AddFrames(nsIFrame* aFrameList,
+                             nsIFrame* aPrevSibling);
 
 #ifdef IBMBIDI
   /**
    * Perform Bidi resolution on this frame
    */
   nsresult ResolveBidi();
 
   /**
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -1024,16 +1024,24 @@ nsContainerFrame::DisplayOverflowContain
     for (nsIFrame* frame = overflowconts->FirstChild(); frame;
          frame = frame->GetNextSibling()) {
       BuildDisplayListForChild(aBuilder, frame, aDirtyRect, aLists);
     }
   }
 }
 
 nsresult
+nsContainerFrame::AddFrames(nsIFrame* aFrameList,
+                            nsIFrame* aPrevSibling)
+{
+  mFrames.InsertFrames(nsnull, aPrevSibling, aFrameList);
+  return NS_OK;
+}
+
+nsresult
 nsContainerFrame::StealFrame(nsPresContext* aPresContext,
                              nsIFrame*      aChild,
                              PRBool         aForceNormal)
 {
   PRBool removed = PR_TRUE;
   if ((aChild->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)
       && !aForceNormal) {
     // Try removing from the overflow container list
--- a/layout/generic/nsContainerFrame.h
+++ b/layout/generic/nsContainerFrame.h
@@ -268,16 +268,23 @@ public:
    */
   nsresult ReflowOverflowContainerChildren(nsPresContext*           aPresContext,
                                            const nsHTMLReflowState& aReflowState,
                                            nsRect&                  aOverflowRect,
                                            PRUint32                 aFlags,
                                            nsReflowStatus&          aStatus);
 
   /**
+   * Inserts aFrameList's frames into our main child list--without reparenting
+   * or requesting reflow.
+   */
+  virtual nsresult AddFrames(nsIFrame* aFrameList,
+                             nsIFrame* aPrevSibling);
+
+  /**
    * Removes aChild without destroying it and without requesting reflow.
    * Continuations are not affected. Checks the primary and overflow
    * or overflow containers and excess overflow containers lists, depending
    * on whether the NS_FRAME_IS_OVERFLOW_CONTAINER flag is set. Does not
    * check any other auxiliary lists.
    * Returns NS_ERROR_UNEXPECTED if we failed to remove aChild.
    * Returns other error codes if we failed to put back a proptable list.
    * If aForceNormal is true, only checks the primary and overflow lists
--- a/layout/generic/nsPageContentFrame.cpp
+++ b/layout/generic/nsPageContentFrame.cpp
@@ -31,16 +31,17 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 #include "nsPageContentFrame.h"
 #include "nsPageFrame.h"
+#include "nsPlaceholderFrame.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsHTMLContainerFrame.h"
 #include "nsHTMLParts.h"
 #include "nsIContent.h"
 #include "nsPresContext.h"
 #include "nsIRenderingContext.h"
 #include "nsGkAtoms.h"
 #include "nsIPresShell.h"
@@ -63,25 +64,75 @@ 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.
@@ -102,18 +153,26 @@ nsPageContentFrame::Reflow(nsPresContext
   // 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);
 
     mPD->mPageContentSize  = aReflowState.availableWidth;
 
-    // Reflow the page content area to get the child's desired size
-    ReflowChild(frame, aPresContext, aDesiredSize, kidReflowState, 0, 0, 0, aStatus);
+    // 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);
--- a/layout/generic/nsPageContentFrame.h
+++ b/layout/generic/nsPageContentFrame.h
@@ -82,12 +82,16 @@ 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___ */
 
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/417676-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<html class="reftest-print">
+<title>Fixed Positioning Test</title>
+<style type="text/css">
+  html, body { margin: 0; padding: 0; }
+</style>
+
+<div style="width: 3in; border: solid;">
+This box must be repeated at this same position on the first, second, and third pages.
+</div>
+
+<div style="page-break-before: always; width: 3in; border: solid;">
+This box must be repeated at this same position on the first, second, and third pages.
+</div>
+
+<div style="page-break-before: always; width: 3in; border: solid;">
+This box must be repeated at this same position on the first, second, and third pages.
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/417676.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<html class="reftest-print">
+<title>Fixed Positioning Test</title>
+
+<div style="position: fixed; left: 0; top: 0; width: 3in; border: solid;">
+This box must be repeated at this same position on the first, second, and third pages.
+</div>
+
+<p style="width: 0; height: 5in;">
\ No newline at end of file
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -727,8 +727,9 @@ random == 403134-1.html 403134-1-ref.htm
 == 413840-ltr-offsets.html 413840-ltr-offsets-ref.html
 == 413840-rtl-offsets.html 413840-rtl-offsets-ref.html
 == 413840-pushed-line-bullet.html 413840-pushed-line-bullet-ref.html
 == 413840-bullet-first-line.html 413840-bullet-first-line-ref.html
 == 413982.html 413982-ref.html
 == 414123.xhtml 414123-ref.xhtml
 == 414851-1.html 414851-1-ref.html
 == 416106-1.xhtml 416106-1-ref.xhtml
+== 417676.html 417676-ref.html