Bug 427017: Disable page-break-before/after for fixed- & absolutely-positioned elements. Also, fix assertion during an iterator-comparison by handling case where lineBox is in overflow-lines. r=fantasai sr=roc a1.9=beltzner
authordholbert@cs.stanford.edu
Fri, 11 Apr 2008 22:32:49 -0700
changeset 14246 47e831506baea8322255d7af20dcf7c6cd78469b
parent 14245 22f96a5df5349894bb01210b10f775358bcf15c8
child 14247 93ab53c19a5d1ac760f94393feaa4c6359e4756e
push id11
push userbsmedberg@mozilla.com
push dateTue, 15 Apr 2008 18:11:53 +0000
treeherdermozilla-central@40e4b99f0dea [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfantasai, roc
bugs427017
milestone1.9pre
Bug 427017: Disable page-break-before/after for fixed- & absolutely-positioned elements. Also, fix assertion during an iterator-comparison by handling case where lineBox is in overflow-lines. r=fantasai sr=roc a1.9=beltzner
layout/base/nsCSSFrameConstructor.cpp
layout/generic/nsBlockFrame.cpp
layout/generic/nsBlockFrame.h
layout/generic/nsHTMLReflowState.cpp
layout/generic/nsPageFrame.cpp
layout/generic/nsPageFrame.h
layout/reftests/bugs/427017-1.xhtml
layout/reftests/bugs/reftest.list
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -7484,28 +7484,35 @@ nsCSSFrameConstructor::ConstructSVGFrame
     return rv;
   }
   else {
     return NS_ERROR_FAILURE;
   }
 }
 #endif // MOZ_SVG
 
+// If page-break-before is set, this function constructs a page break frame,
+// EXCEPT for on these types of elements:
+//  * row groups, rows, cells (these are handled internally by tables)
+//  * fixed- and absolutely-positioned elements (currently, our positioning
+//    code doesn't expect positioned frames to have nsPageBreakFrame siblings)
+//
+// Returns true iff we should construct a page break frame after this element.
 PRBool
 nsCSSFrameConstructor::PageBreakBefore(nsFrameConstructorState& aState,
                                        nsIContent*              aContent,
                                        nsIFrame*                aParentFrame,
                                        nsStyleContext*          aStyleContext,
                                        nsFrameItems&            aFrameItems)
 {
   const nsStyleDisplay* display = aStyleContext->GetStyleDisplay();
 
-  // See if page-break-before is set for all elements except row groups, rows, cells 
-  // (these are handled internally by tables) and construct a page break frame if so.
   if (NS_STYLE_DISPLAY_NONE != display->mDisplay &&
+      NS_STYLE_POSITION_FIXED    != display->mPosition &&
+      NS_STYLE_POSITION_ABSOLUTE != display->mPosition &&
       (NS_STYLE_DISPLAY_TABLE == display->mDisplay ||
        !IsTableRelated(display->mDisplay, PR_TRUE))) { 
     if (display->mBreakBefore) {
       ConstructPageBreakFrame(aState, aContent, aParentFrame, aStyleContext,
                               aFrameItems);
     }
     return display->mBreakAfter;
   }
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -5155,20 +5155,26 @@ nsBlockInFlowLineIterator::nsBlockInFlow
   do {
     if (mLine->Contains(child)) {
       *aFoundValidLine = PR_TRUE;
       return;
     }
   } while (Next());
 }
 
+nsBlockFrame::line_iterator
+nsBlockInFlowLineIterator::End()
+{
+  return mInOverflowLines ? mInOverflowLines->end() : mFrame->end_lines();
+}
+
 PRBool
 nsBlockInFlowLineIterator::IsLastLineInList()
 {
-  line_iterator end = mInOverflowLines ? mInOverflowLines->end() : mFrame->end_lines();
+  line_iterator end = End();
   return mLine != end && mLine.next() == end;
 }
 
 PRBool
 nsBlockInFlowLineIterator::Next()
 {
   ++mLine;
   return FindValidLine();
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -701,16 +701,23 @@ public:
    */
   nsBlockInFlowLineIterator(nsBlockFrame* aFrame, nsIFrame* aFindFrame,
                             PRBool* aFoundValidLine);
 
   line_iterator GetLine() { return mLine; }
   PRBool IsLastLineInList();
   nsBlockFrame* GetContainer() { return mFrame; }
   PRBool GetInOverflow() { return mInOverflowLines != nsnull; }
+
+
+  /**
+   * Returns the end-iterator of whatever line list we're in.
+   */
+  line_iterator End();
+
   /**
    * Returns false if there are no more lines. After this has returned false,
    * don't call any methods on this object again.
    */
   PRBool Next();
   /**
    * Returns false if there are no more lines. After this has returned false,
    * don't call any methods on this object again.
--- a/layout/generic/nsHTMLReflowState.cpp
+++ b/layout/generic/nsHTMLReflowState.cpp
@@ -945,17 +945,17 @@ nsHTMLReflowState::CalculateHypothetical
       aHypotheticalBox.mTop = lineBox->mBounds.y;
     } else {
       // The element would have been block-level which means it would be below
       // the line containing the placeholder frame, unless all the frames
       // before it are empty.  In that case, it would have been just before
       // this line.      
       // XXXbz the line box is not fully reflown yet if our containing block is
       // relatively positioned...
-      if (lineBox != blockFrame->end_lines()) {
+      if (lineBox != iter.End()) {
         nsIFrame * firstFrame = lineBox->mFirstChild;
         PRBool found = PR_FALSE;
         PRBool allEmpty = PR_TRUE;
         while (firstFrame) { // See bug 223064
           allEmpty = AreAllEarlierInFlowFramesEmpty(firstFrame,
             aPlaceholderFrame, &found);
           if (found || !allEmpty)
             break;
--- a/layout/generic/nsPageFrame.cpp
+++ b/layout/generic/nsPageFrame.cpp
@@ -596,16 +596,22 @@ nsPageBreakFrame::~nsPageBreakFrame()
 }
 
 nscoord
 nsPageBreakFrame::GetIntrinsicWidth()
 {
   return nsPresContext::CSSPixelsToAppUnits(1);
 }
 
+nscoord
+nsPageBreakFrame::GetIntrinsicHeight()
+{
+  return 0;
+}
+
 nsresult 
 nsPageBreakFrame::Reflow(nsPresContext*          aPresContext,
                          nsHTMLReflowMetrics&     aDesiredSize,
                          const nsHTMLReflowState& aReflowState,
                          nsReflowStatus&          aStatus)
 {
   DO_GLOBAL_REFLOW_COUNT("nsPageBreakFrame");
   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
--- a/layout/generic/nsPageFrame.h
+++ b/layout/generic/nsPageFrame.h
@@ -138,16 +138,17 @@ class nsPageBreakFrame : public nsLeafFr
                     const nsHTMLReflowState& aReflowState,
                     nsReflowStatus&          aStatus);
 
   virtual nsIAtom* GetType() const;
 
 protected:
 
   virtual nscoord GetIntrinsicWidth();
+  virtual nscoord GetIntrinsicHeight();
 
     PRBool mHaveReflowed;
 
     friend nsIFrame* NS_NewPageBreakFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 };
 
 #endif /* nsPageFrame_h___ */
 
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/427017-1.xhtml
@@ -0,0 +1,13 @@
+<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-print">
+<body>
+<div style="position: absolute; border: 5px solid black;">
+  <div style="position: fixed; page-break-before: left;"/>
+  <div style="display: table-header-group; page-break-after: right;">
+    <div style="position: absolute;">
+      <div style="position: fixed;"/>
+    </div>
+  </div>
+  <div style="display: table-footer-group;"/>
+</div>
+</body>
+</html>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -792,8 +792,9 @@ fails == 413027-3.html 413027-3-ref.html
 fails-if(MOZ_WIDGET_TOOLKIT=="gtk2") == 424074-1-ref2.xul 424074-1-ref3.xul
 == 424236-10.html 424236-10-ref.html
 == 424434-1.html 424434-1-ref.html
 == 424631-1.html 424631-1-ref.html
 == 424710-1.html 424710-1-ref.html
 == 425972-1.html 425972-1-ref.html
 == 425972-2.html 425972-2-ref.html
 != 425972-1.html 425972-2.html
+!= 427017-1.xhtml about:blank    # crash test (needs reftest-print)