handle dynamic insertion with overflow containers properly, b=403369 r=bzbarsky sr=roc
authorfantasai.cvs@inkedblade.net
Sun, 27 Jan 2008 00:13:19 -0800
changeset 10780 cc523909fbf64e6deb7487d7b21595702364dc9a
parent 10779 74ad80a840249a8798ebff270822447548ac45a2
child 10781 34d6f14126e07263f865bf6f03bdd7f942dbbc2c
push id1
push userbsmedberg@mozilla.com
push dateThu, 20 Mar 2008 16:49:24 +0000
treeherdermozilla-central@61007906a1f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky, roc
bugs403369
milestone1.9b3pre
handle dynamic insertion with overflow containers properly, b=403369 r=bzbarsky sr=roc
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/generic/nsFrame.cpp
layout/generic/nsIFrame.h
layout/reftests/pagination/content-inserted-000.ref.xhtml
layout/reftests/pagination/content-inserted-000.xhtml
layout/reftests/pagination/content-inserted-001.ref.xhtml
layout/reftests/pagination/content-inserted-001.xhtml
layout/reftests/pagination/content-inserted-002.ref.xhtml
layout/reftests/pagination/content-inserted-002.xhtml
layout/reftests/pagination/content-inserted-003.xhtml
layout/reftests/pagination/content-inserted-004.xhtml
layout/reftests/pagination/content-inserted-005.xhtml
layout/reftests/pagination/content-inserted-006.xhtml
layout/reftests/pagination/content-inserted-007.xhtml
layout/reftests/pagination/content-inserted-008.xhtml
layout/reftests/pagination/content-inserted-009.xhtml
layout/reftests/pagination/reftest.list
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -8006,17 +8006,19 @@ nsCSSFrameConstructor::AppendFrames(nsFr
     return frameManager->InsertFrames(aParentFrame, nsnull,
                                       frames.GetPrevSiblingFor(aAfterFrame),
                                       aFrameList.childList);
   }
 
   if (IsFrameSpecial(aParentFrame) &&
       !IsInlineFrame(aParentFrame) &&
       IsInlineOutside(aFrameList.lastChild)) {
-    NS_ASSERTION(!aParentFrame->GetNextContinuation(), "Shouldn't happen");
+    NS_ASSERTION(!aParentFrame->GetNextContinuation() ||
+                 !aParentFrame->GetNextContinuation()->GetFirstChild(nsnull),
+                 "Shouldn't happen");
     
     // We want to put some of the frames into the following inline frame.
     nsIFrame* lastBlock = FindLastBlock(aFrameList.childList);
     nsIFrame* firstTrailingInline;
     if (lastBlock) {
       firstTrailingInline = lastBlock->GetNextSibling();
       lastBlock->SetNextSibling(nsnull);
       aFrameList.lastChild = lastBlock;
@@ -8350,21 +8352,17 @@ nsCSSFrameConstructor::FindFrameForConte
     // The frame may be a special frame (a split inline frame that
     // contains a block).  Get the last part of that split.
     if (IsFrameSpecial(sibling)) {
       sibling = GetLastSpecialSibling(sibling);
     }
 
     // The frame may have a continuation. If so, we want the last
     // non-overflow-container continuation as our previous sibling.
-    sibling = sibling->GetLastContinuation();
-    while (sibling->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
-      sibling = sibling->GetPrevInFlow();
-      NS_ASSERTION(sibling, "first-in-flow can't be overflow container");
-    }
+    sibling = sibling->GetTailContinuation();
   }
 
   if (aTargetContent &&
       !IsValidSibling(sibling, aTargetContent, aTargetContentDisplay)) {
     sibling = nsnull;
   }
 
   return sibling;
@@ -8668,18 +8666,18 @@ nsCSSFrameConstructor::ContentAppended(n
     }
 #endif
 
     // Since we're appending, we'll walk to the last anonymous frame
     // that was created for the broken inline frame.
     parentFrame = GetLastSpecialSibling(parentFrame);
   }
 
-  // Get the parent frame's last continuation
-  parentFrame = parentFrame->GetLastContinuation();
+  // Get continuation that parents the last child
+  parentFrame = nsLayoutUtils::GetLastContinuationWithChild(parentFrame);
 
   nsIAtom* frameType = parentFrame->GetType();
   // Deal with fieldsets
   parentFrame = ::GetAdjustedParentFrame(parentFrame, frameType,
                                          aContainer, aNewIndexInContainer);
 
   // Deal with possible :after generated content on the parent
   nsIFrame* parentAfterFrame;
@@ -9116,17 +9114,17 @@ nsCSSFrameConstructor::ContentInserted(n
     // We're inserting the new frame as the first child. See if the
     // parent has a :before pseudo-element
     nsIFrame* firstChild = parentFrame->GetFirstChild(nsnull);
 
     if (firstChild &&
         nsLayoutUtils::IsGeneratedContentFor(aContainer, firstChild,
                                              nsCSSPseudoElements::before)) {
       // Insert the new frames after the last continuation of the :before
-      prevSibling = firstChild->GetLastContinuation();
+      prevSibling = firstChild->GetTailContinuation();
       parentFrame = prevSibling->GetParent();
       // We perhaps could leave this true and take the AppendFrames path
       // below, but we'd have to update appendAfterFrame and it seems safer
       // to force all insert-after-:before cases to take these to take the
       // InsertFrames path
       isAppend = PR_FALSE;
     }
   }
@@ -11169,17 +11167,17 @@ nsCSSFrameConstructor::MaybeRecreateCont
   // case when it's needed is if the inline is the only child of the tail end
   // of an {ib} split, because the splitting code doesn't produce this tail end
   // if it would have no kids.  If that ever changes, this code should change.
   if (IsInlineOutside(aFrame) &&
       (
        // Not a kid of the third part of the IB split
        GetSpecialSibling(parent) || !IsInlineOutside(parent) ||
        // Or not the only child
-       aFrame->GetLastContinuation()->GetNextSibling() ||
+       aFrame->GetTailContinuation()->GetNextSibling() ||
        aFrame != parent->GetFirstContinuation()->GetFirstChild(nsnull)
       )) {
     return PR_FALSE;
   }
 
 #ifdef DEBUG
   if (gNoisyContentUpdates) {
     printf("nsCSSFrameConstructor::MaybeRecreateContainerForIBSplitterFrame: "
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -75,16 +75,29 @@
 #include "nsSVGUtils.h"
 #include "nsSVGOuterSVGFrame.h"
 #endif
 
 /**
  * A namespace class for static layout utilities.
  */
 
+
+nsIFrame*
+nsLayoutUtils::GetLastContinuationWithChild(nsIFrame* aFrame)
+{
+  NS_PRECONDITION(aFrame, "NULL frame pointer");
+  aFrame = aFrame->GetLastContinuation();
+  while (!aFrame->GetFirstChild(nsnull) &&
+         aFrame->GetPrevContinuation()) {
+    aFrame = aFrame->GetPrevContinuation();
+  }
+  return aFrame;
+}
+
 /**
  * GetFirstChildFrame returns the first "real" child frame of a
  * given frame.  It will descend down into pseudo-frames (unless the
  * pseudo-frame is the :before generated frame).   
  * @param aFrame the frame
  * @param aFrame the frame's content node
  */
 static nsIFrame*
@@ -116,21 +129,21 @@ GetFirstChildFrame(nsIFrame*       aFram
  * @param aFrame the frame's content node
  */
 static nsIFrame*
 GetLastChildFrame(nsIFrame*       aFrame,
                   nsIContent*     aContent)
 {
   NS_PRECONDITION(aFrame, "NULL frame pointer");
 
-  // Get the last continuation frame
-  nsIFrame* lastContinuation = aFrame->GetLastContinuation();
+  // Get the last continuation frame that's a parent
+  nsIFrame* lastParentContinuation = nsLayoutUtils::GetLastContinuationWithChild(aFrame);
 
   // Get the last child frame
-  nsIFrame* firstChildFrame = lastContinuation->GetFirstChild(nsnull);
+  nsIFrame* firstChildFrame = lastParentContinuation->GetFirstChild(nsnull);
   if (firstChildFrame) {
     nsFrameList frameList(firstChildFrame);
     nsIFrame*   lastChildFrame = frameList.LastChild();
 
     NS_ASSERTION(lastChildFrame, "unexpected error");
 
     // Get the frame's first continuation. This matters in case the frame has
     // been continued across multiple lines or split by BiDi resolution.
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -196,16 +196,22 @@ public:
    */
   static PRInt32 DoCompareTreePosition(nsIFrame* aFrame1,
                                        nsIFrame* aFrame2,
                                        PRInt32 aIf1Ancestor,
                                        PRInt32 aIf2Ancestor,
                                        nsIFrame* aCommonAncestor = nsnull);
 
   /**
+   * GetLastContinuationWithChild gets the last continuation in aFrame's chain
+   * that has a child, or the first continuation if the frame has no children.
+   */
+  static nsIFrame* GetLastContinuationWithChild(nsIFrame* aFrame);
+
+  /**
    * GetLastSibling simply finds the last sibling of aFrame, or returns nsnull if
    * aFrame is null.
    */
   static nsIFrame* GetLastSibling(nsIFrame* aFrame);
 
   /**
    * FindSiblingViewFor locates the child of aParentView that aFrame's
    * view should be inserted 'above' (i.e., before in sibling view
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -3286,16 +3286,32 @@ nsIFrame* nsFrame::GetNextInFlowVirtual(
 }
 
 NS_IMETHODIMP nsFrame::SetNextInFlow(nsIFrame*)
 {
   NS_ERROR("not splittable");
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
+nsIFrame* nsIFrame::GetTailContinuation()
+{
+  nsIFrame* frame = this;
+  while (frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
+    frame = frame->GetPrevContinuation();
+    NS_ASSERTION(frame, "first continuation can't be overflow container");
+  }
+  for (nsIFrame* next = frame->GetNextContinuation();
+       next && !(next->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER);
+       next = frame->GetNextContinuation())  {
+    frame = next;
+  }
+  NS_POSTCONDITION(frame, "illegal state in continuation chain.");
+  return frame;
+}
+
 nsIView*
 nsIFrame::GetParentViewForChildFrame(nsIFrame* aFrame) const
 {
   return GetClosestView();
 }
 
 // Associated view object
 nsIView*
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -1053,17 +1053,24 @@ public:
   virtual nsIFrame* GetNextContinuation() const = 0;
   NS_IMETHOD SetNextContinuation(nsIFrame*) = 0;
   virtual nsIFrame* GetFirstContinuation() const {
     return const_cast<nsIFrame*>(this);
   }
   virtual nsIFrame* GetLastContinuation() const {
     return const_cast<nsIFrame*>(this);
   }
-  
+
+  /**
+   * GetTailContinuation gets the last non-overflow-container continuation
+   * in the continuation chain, i.e. where the next sibling element
+   * should attach).
+   */
+  nsIFrame* GetTailContinuation();
+
   /**
    * Flow member functions
    */
   virtual nsIFrame* GetPrevInFlowVirtual() const = 0;
   nsIFrame* GetPrevInFlow() const { return GetPrevInFlowVirtual(); }
   NS_IMETHOD SetPrevInFlow(nsIFrame*) = 0;
 
   virtual nsIFrame* GetNextInFlowVirtual() const = 0;
new file mode 100644
--- /dev/null
+++ b/layout/reftests/pagination/content-inserted-000.ref.xhtml
@@ -0,0 +1,40 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>Content Appended in {ib} Pagination with Overflow Containers</title>
+
+  <style type="text/css">
+    #colset {
+      height: 400px;
+      width: 450px;
+      -moz-column-width: 150px;
+      -moz-column-gap: 0;
+      border: 3px solid silver;
+    }
+
+    #x {
+      height: 200px;
+      border-bottom: 3px solid blue;
+    }
+
+    #overflow {
+      height: 1000px;
+      border-bottom: 3px solid orange;
+    }
+  </style>
+</head>
+
+<body>
+
+<div id="colset"
+  ><span id="span"
+    ><div id="x"
+      ><div id="overflow"></div
+      >This must be in the last column, below the orange line.
+    </div
+  >This must be in the first column, below the blue line.</span
+></div>
+
+</body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/pagination/content-inserted-000.xhtml
@@ -0,0 +1,40 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>Content Appended in {ib} Pagination with Overflow Containers</title>
+
+  <style type="text/css">
+    #colset {
+      height: 400px;
+      width: 450px;
+      -moz-column-width: 150px;
+      -moz-column-gap: 0;
+      border: 3px solid silver;
+    }
+
+    #x {
+      height: 200px;
+      border-bottom: 3px solid blue;
+    }
+
+    #overflow {
+      height: 1000px;
+      border-bottom: 3px solid orange;
+    }
+  </style>
+</head>
+
+<body onload="document.getElementById('span').appendChild(document.createTextNode('This must be in the first column, below the blue line.'))">
+
+<div id="colset"
+  ><span id="span"
+    ><div id="x"
+      ><div id="overflow"></div
+      >This must be in the last column, below the orange line.
+    </div
+  ></span
+></div>
+
+</body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/pagination/content-inserted-001.ref.xhtml
@@ -0,0 +1,29 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>Content Appended in Paginated Element</title>
+
+  <style type="text/css">
+    #colset {
+      height: 200px;
+      width: 450px;
+      -moz-column-width: 150px;
+      -moz-column-gap: 0;
+      border: 3px solid silver;
+    }
+
+    #x {
+      height: 500px;
+    }
+</style>
+</head>
+
+<body>
+
+<div id="colset">
+  <div id="x">This must be in the first column.</div>
+</div>
+
+</body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/pagination/content-inserted-001.xhtml
@@ -0,0 +1,29 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>Content Appended in Paginated Element</title>
+
+  <style type="text/css">
+    #colset {
+      height: 200px;
+      width: 450px;
+      -moz-column-width: 150px;
+      -moz-column-gap: 0;
+      border: 3px solid silver;
+    }
+
+    #x {
+      height: 500px;
+    }
+</style>
+</head>
+
+<body onload="document.getElementById('x').appendChild(document.createTextNode('This must be in the first column.'))">
+
+<div id="colset">
+  <div id="x"></div>
+</div>
+
+</body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/pagination/content-inserted-002.ref.xhtml
@@ -0,0 +1,37 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>Content Appended in Pagination</title>
+
+  <style type="text/css">
+    #colset {
+      height: 200px;
+      width: 450px;
+      -moz-column-width: 150px;
+      -moz-column-gap: 0;
+      border: 3px solid silver;
+    }
+
+    #mark {
+      border-bottom: 4px solid blue;
+    }
+
+    #shift {
+      height: 201px;
+      border-bottom: 4px solid blue;
+    }
+</style>
+</head>
+
+<body>
+
+<div id="colset">
+  <div id="x">
+    <div id="shift"></div>
+    <div id="mark">This must be in the second column between two 4px blue lines.</div>
+  </div>
+</div>
+
+</body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/pagination/content-inserted-002.xhtml
@@ -0,0 +1,42 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>Content Appended in Pagination before ::after</title>
+
+  <style type="text/css">
+    #colset {
+      height: 200px;
+      width: 450px;
+      -moz-column-width: 150px;
+      -moz-column-gap: 0;
+      border: 3px solid silver;
+    }
+
+    #x {
+      height: 500px;
+    }
+
+    #x:after {
+      display: block;
+      content: "";
+      border-top: 4px solid blue;
+    }
+
+    #shift {
+      height: 201px;
+      border-bottom: 4px solid blue;
+    }
+</style>
+</head>
+
+<body onload="document.getElementById('x').appendChild(document.createTextNode('This must be in the second column between two 4px blue lines.'))">
+
+<div id="colset">
+  <div id="x">
+    <div id="shift"></div>
+  </div>
+</div>
+
+</body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/pagination/content-inserted-003.xhtml
@@ -0,0 +1,43 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>Content Appended in Pagination before ::after (alternate)</title>
+
+  <style type="text/css">
+    #colset {
+      height: 200px;
+      width: 450px;
+      -moz-column-width: 150px;
+      -moz-column-gap: 0;
+      border: 3px solid silver;
+    }
+
+    #x {
+      height: 500px;
+    }
+
+    #x:after {
+      display: block;
+      height: 220px;
+      content: "";
+      border-top: 4px solid blue;
+    }
+
+    #shift {
+      height: 201px;
+      border-bottom: 4px solid blue;
+    }
+</style>
+</head>
+
+<body onload="document.getElementById('x').appendChild(document.createTextNode('This must be in the second column between two 4px blue lines.'))">
+
+<div id="colset">
+  <div id="x">
+    <div id="shift"></div>
+  </div>
+</div>
+
+</body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/pagination/content-inserted-004.xhtml
@@ -0,0 +1,41 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>Content Inserted in Pagination after ::before</title>
+
+  <style type="text/css">
+    #colset {
+      height: 200px;
+      width: 450px;
+      -moz-column-width: 150px;
+      -moz-column-gap: 0;
+      border: 3px solid silver;
+    }
+
+    #x {
+      height: 500px;
+    }
+
+    #x:before {
+      display: block;
+      height: 201px;
+      content: "";
+      border-bottom: 4px solid blue;
+    }
+
+    #shift {
+      height: 220px;
+      border-top: 4px solid blue;
+    }
+</style>
+</head>
+
+<body onload="document.getElementById('x').insertBefore(document.createTextNode('This must be in the second column between two 4px blue lines.'), document.getElementById('shift'))">
+
+<div id="colset">
+  <div id="x"><div id="shift"></div></div>
+</div>
+
+</body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/pagination/content-inserted-005.xhtml
@@ -0,0 +1,37 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>Content Appended in Pagination after ::before</title>
+
+  <style type="text/css">
+    #colset {
+      height: 200px;
+      width: 450px;
+      -moz-column-width: 150px;
+      -moz-column-gap: 0;
+      border: 3px solid silver;
+    }
+
+    #x {
+      border-bottom: 4px solid blue;
+    }
+
+    #x:before {
+      display: block;
+      height: 201px;
+      content: "";
+      border-bottom: 4px solid blue;
+    }
+</style>
+</head>
+
+<body onload="document.getElementById('x').insertBefore(document.createTextNode('This must be in the second column between two 4px blue lines.'), null)">
+
+<div id="colset">
+  <div id="x">
+  </div>
+</div>
+
+</body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/pagination/content-inserted-006.xhtml
@@ -0,0 +1,49 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>Content Appended in Pagination before ::after (alternate)</title>
+
+  <style type="text/css">
+    #colset {
+      height: 200px;
+      width: 450px;
+      -moz-column-width: 150px;
+      -moz-column-gap: 0;
+      border: 3px solid silver;
+    }
+
+    #x {
+      height: 500px;
+    }
+
+    #x:after {
+      display: block;
+      height: 220px;
+      content: "";
+      border-top: 4px solid blue;
+    }
+
+    #shift {
+      height: 201px;
+      border-bottom: 4px solid blue;
+    }
+
+    #overflow {
+      height: 700px;
+    }
+</style>
+</head>
+
+<body onload="document.getElementById('x').appendChild(document.createTextNode('This must be in the second column between two 4px blue lines.'))">
+
+<div id="colset">
+  <div id="x">
+    <div id="shift">
+      <div id="overflow"></div>
+    </div
+  ></div>
+</div>
+
+</body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/pagination/content-inserted-007.xhtml
@@ -0,0 +1,48 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>Content Inserted in Pagination after ::before</title>
+
+  <style type="text/css">
+    #colset {
+      height: 200px;
+      width: 450px;
+      -moz-column-width: 150px;
+      -moz-column-gap: 0;
+      border: 3px solid silver;
+    }
+
+    #x {
+      height: 500px;
+    }
+
+    #x:before {
+      display: block;
+      height: 201px;
+      padding: 0 10px;
+      white-space: pre;
+      font-size: 100px;
+      line-height: 1.9em;
+      color: white;
+      content: "a\a b\a c\a d\a";
+      border-bottom: 4px solid blue;
+    }
+
+    #shift {
+      height: 220px;
+      border-top: 4px solid blue;
+      position: relative;
+      z-index: 1;
+    }
+</style>
+</head>
+
+<body onload="document.getElementById('x').insertBefore(document.createTextNode('This must be in the second column between two 4px blue lines.'), document.getElementById('shift'))">
+
+<div id="colset">
+  <div id="x"><div id="shift"></div></div>
+</div>
+
+</body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/pagination/content-inserted-008.xhtml
@@ -0,0 +1,36 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>Content Appended in Pagination before ::after</title>
+
+  <style type="text/css">
+    #colset {
+      height: 200px;
+      width: 450px;
+      -moz-column-width: 150px;
+      -moz-column-gap: 0;
+      border: 3px solid silver;
+    }
+
+    #shift {
+      height: 0;
+    }
+    #overflow {
+      height: 500px;
+    }
+</style>
+</head>
+
+<body onload="document.getElementById('colset').insertBefore(document.createTextNode('This must be in the first column.'), document.getElementById('x'))">
+
+<div id="colset">
+  <div id="shift">
+    <div id="overflow"></div>
+  </div
+  ><div id="x">
+  </div>
+</div>
+
+</body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/pagination/content-inserted-009.xhtml
@@ -0,0 +1,44 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>Content Appended in Pagination before ::after</title>
+
+  <style type="text/css">
+    #colset {
+      height: 200px;
+      width: 450px;
+      -moz-column-width: 150px;
+      -moz-column-gap: 0;
+      border: 3px solid silver;
+    }
+
+    #shift {
+      height: 201px;
+      border-bottom: 2px solid blue;
+    }
+    #overflow {
+      height: 500px;
+    }
+    div:not([id]) {
+      border-top: 2px solid blue;
+    }
+    #x {
+      border-bottom: 4px solid blue;
+    }
+</style>
+</head>
+
+<body onload="document.getElementById('span').insertBefore(document.createElement('div'), document.getElementById('x'))">
+
+<div id="colset">
+  <span id="span">
+    <div id="shift">
+      <div id="overflow"></div>
+    </div
+    ><div id="x">This must be in the second column between two 4px blue lines.</div
+  ></span
+></div>
+
+</body>
+
+</html>
--- a/layout/reftests/pagination/reftest.list
+++ b/layout/reftests/pagination/reftest.list
@@ -5,8 +5,18 @@
 == abspos-overflow-01.xhtml abspos-overflow-01.ref.xhtml
 == abspos-overflow-01-cols.xhtml abspos-overflow-01-cols.ref.xhtml
 == dynamic-abspos-overflow-01-cols.xhtml dynamic-abspos-overflow-01-cols.ref.xhtml
 == border-breaking-000-cols.xhtml border-breaking-000-cols.ref.xhtml
 == border-breaking-001-cols.xhtml border-breaking-001-cols.ref.xhtml
 == border-breaking-002-cols.xhtml border-breaking-002-cols.ref.xhtml
 == border-breaking-003-cols.xhtml border-breaking-003-cols.ref.xhtml
 == border-breaking-004-cols.xhtml border-breaking-002-cols.ref.xhtml
+== content-inserted-000.xhtml content-inserted-000.ref.xhtml
+== content-inserted-001.xhtml content-inserted-001.ref.xhtml
+== content-inserted-002.xhtml content-inserted-002.ref.xhtml
+== content-inserted-003.xhtml content-inserted-002.ref.xhtml
+== content-inserted-004.xhtml content-inserted-002.ref.xhtml
+== content-inserted-005.xhtml content-inserted-002.ref.xhtml
+== content-inserted-006.xhtml content-inserted-002.ref.xhtml
+== content-inserted-007.xhtml content-inserted-002.ref.xhtml
+== content-inserted-008.xhtml content-inserted-001.ref.xhtml
+== content-inserted-009.xhtml content-inserted-002.ref.xhtml