Relanding bug 390425, with attempted performance regression fix. r+sr+a=roc
authorbzbarsky@mit.edu
Wed, 15 Aug 2007 16:20:25 -0700
changeset 4696 69c3364243030555fea43009c78fbaa887bc9cf3
parent 4695 89f69c3ee44fb7d52af11d048d5e321a8cb227b3
child 4697 c9dd8a158cce7626d9249b1a97cd2ced42331511
push idunknown
push userunknown
push dateunknown
bugs390425
milestone1.9a8pre
Relanding bug 390425, with attempted performance regression fix. r+sr+a=roc
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsCSSFrameConstructor.h
layout/base/nsPresShell.cpp
layout/reftests/ib-split/insert-into-split-inline-10-ref.html
layout/reftests/ib-split/insert-into-split-inline-10.html
layout/reftests/ib-split/insert-into-split-inline-11-ref.html
layout/reftests/ib-split/insert-into-split-inline-11.html
layout/reftests/ib-split/insert-into-split-inline-8c.html
layout/reftests/ib-split/insert-into-split-inline-9-ref.html
layout/reftests/ib-split/insert-into-split-inline-9.html
layout/reftests/ib-split/reftest.list
layout/reftests/reftest.list
layout/style/nsRuleNode.cpp
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -446,33 +446,32 @@ GetFieldSetAreaFrame(nsIFrame* aFieldset
 // more easily.
 
 static inline PRBool
 IsFrameSpecial(nsIFrame* aFrame)
 {
   return (aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL) != 0;
 }
 
-static void
-GetSpecialSibling(nsFrameManager* aFrameManager, nsIFrame* aFrame, nsIFrame** aResult)
+static nsIFrame* GetSpecialSibling(nsIFrame* aFrame)
 {
   // We only store the "special sibling" annotation with the first
-  // frame in the flow. Walk back to find that frame now.
-  aFrame = aFrame->GetFirstInFlow();
+  // frame in the continuation chain. Walk back to find that frame now.
+  aFrame = aFrame->GetFirstContinuation();
 
   void* value = aFrame->GetProperty(nsGkAtoms::IBSplitSpecialSibling);
 
-  *aResult = static_cast<nsIFrame*>(value);
+  return static_cast<nsIFrame*>(value);
 }
 
 static nsIFrame*
-GetLastSpecialSibling(nsFrameManager* aFrameManager, nsIFrame* aFrame)
+GetLastSpecialSibling(nsIFrame* aFrame)
 {
   for (nsIFrame *frame = aFrame, *next; ; frame = next) {
-    GetSpecialSibling(aFrameManager, frame, &next);
+    next = GetSpecialSibling(frame);
     if (!next)
       return frame;
   }
   NS_NOTREACHED("unreachable code");
   return nsnull;
 }
 
 static void
@@ -532,20 +531,28 @@ GetIBContainingBlockFor(nsIFrame* aFrame
 //----------------------------------------------------------------------
 
 static PRBool
 IsInlineOutside(nsIFrame* aFrame)
 {
   return aFrame->GetStyleDisplay()->IsInlineOutside();
 }
 
+/**
+ * True if aFrame is an actual inline frame in the sense of non-replaced
+ * display:inline CSS boxes.  In other words, it can be affected by {ib}
+ * splitting and can contain first-letter frames.  Basically, this is either an
+ * inline frame (positioned or otherwise) or an line frame (this last because
+ * it can contain first-letter and because inserting blocks in the middle of it
+ * needs to terminate it).
+ */
 static PRBool
-IsBlockOutside(nsIFrame* aFrame)
-{
-  return aFrame->GetStyleDisplay()->IsBlockOutside();
+IsInlineFrame(const nsIFrame* aFrame)
+{
+  return aFrame->IsFrameOfType(nsIFrame::eLineParticipant);
 }
 
 //----------------------------------------------------------------------
 
 // Block/inline frame construction logic. We maintain a few invariants here:
 //
 // 1. Block frames contain block and inline frames.
 //
@@ -1411,17 +1418,17 @@ nsFrameConstructorState::AddChild(nsIFra
     frameItems->InsertChildAfter(aNewFrame, aInsertAfterFrame);
   } else {
     frameItems->AddChild(aNewFrame);
   }
 
   // Now add the special siblings too.
   nsIFrame* specialSibling = aNewFrame;
   while (specialSibling && IsFrameSpecial(specialSibling)) {
-    GetSpecialSibling(mFrameManager, specialSibling, &specialSibling);
+    specialSibling = GetSpecialSibling(specialSibling);
     if (specialSibling) {
       NS_ASSERTION(frameItems == &aFrameItems,
                    "IB split ending up in an out-of-flow childlist?");
       frameItems->AddChild(specialSibling);
     }
   }
   
   return NS_OK;
@@ -1612,25 +1619,22 @@ AdjustFloatParentPtrs(nsIFrame*         
     // XXX_kin: Do we need to prevent descent into anonymous content here?
 
     AdjustFloatParentPtrs(childFrame, aState, aOuterState);
     childFrame = childFrame->GetNextSibling();
   }
 }
 
 /**
- * Moves frames to a new parent, updating the style context and
- * propagating relevant frame state bits. |aNewParentSC| may be null,
- * in which case the child frames' style contexts will remain
- * untouched. |aState| may be null, in which case the parent
+ * Moves frames to a new parent, updating the style context and propagating
+ * relevant frame state bits. |aState| may be null, in which case the parent
  * pointers of out-of-flow frames will remain untouched.
  */
 static void
 MoveChildrenTo(nsFrameManager*          aFrameManager,
-               nsStyleContext*          aNewParentSC,
                nsIFrame*                aNewParent,
                nsIFrame*                aFrameList,
                nsFrameConstructorState* aState,
                nsFrameConstructorState* aOuterState)
 {
   PRBool setHasChildWithView = PR_FALSE;
 
   while (aFrameList) {
@@ -1644,34 +1648,25 @@ MoveChildrenTo(nsFrameManager*          
     // If aState is not null, the caller expects us to make adjustments so that
     // floats whose placeholders are descendants of frames in aFrameList point
     // to the correct parent.
     if (aState) {
       NS_ASSERTION(aOuterState, "need an outer state too");
       AdjustFloatParentPtrs(aFrameList, *aState, *aOuterState);
     }
 
-#if 0
-    // XXX When this is used with {ib} frame hierarchies, it seems
-    // fine to leave the style contexts of the children of the
-    // anonymous block frame parented by the original inline
-    // frame. (In fact, one would expect some inheritance
-    // relationships to be broken if we reparented them to the
-    // anonymous block frame, but oddly they aren't -- need to
-    // investigate that...)
-    if (aNewParentSC)
-      aPresContext->FrameManager()->ReParentStyleContext(aFrameList,
-                                                         aNewParentSC);
-#endif
-
     aFrameList = aFrameList->GetNextSibling();
   }
 
   if (setHasChildWithView) {
-    aNewParent->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
+    do {
+      aNewParent->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
+      aNewParent = aNewParent->GetParent();
+    } while (aNewParent &&
+             !(aNewParent->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW));
   }
 }
 
 // -----------------------------------------------------------
 
 
 // Structure used to ensure that bindings are properly enqueued in the
 // binding manager's attached queue.
@@ -7871,42 +7866,142 @@ AdjustAppendParentForAfterContent(nsPres
 
 /**
  * This function is called by ContentAppended() and ContentInserted()
  * when appending flowed frames to a parent's principal child list. It
  * handles the case where the parent frame has :after pseudo-element
  * generated content.
  */
 nsresult
-nsCSSFrameConstructor::AppendFrames(const nsFrameConstructorState& aState,
+nsCSSFrameConstructor::AppendFrames(nsFrameConstructorState&       aState,
                                     nsIContent*                    aContainer,
                                     nsIFrame*                      aParentFrame,
-                                    nsIFrame*                      aFrameList,
+                                    nsFrameItems&                  aFrameList,
                                     nsIFrame*                      aAfterFrame)
 {
 #ifdef DEBUG
   nsIFrame* debugAfterFrame;
   nsIFrame* debugNewParent =
     ::AdjustAppendParentForAfterContent(aState.mPresContext, aContainer,
                                         aParentFrame, &debugAfterFrame);
   NS_ASSERTION(debugNewParent == aParentFrame, "Incorrect parent");
   NS_ASSERTION(debugAfterFrame == aAfterFrame, "Incorrect after frame");
 #endif
 
   nsFrameManager* frameManager = aState.mFrameManager;
   if (aAfterFrame) {
+    NS_ASSERTION(!IsFrameSpecial(aParentFrame) ||
+                 IsInlineFrame(aParentFrame) ||
+                 !IsInlineOutside(aAfterFrame),
+                 "Shouldn't have inline :after content on the block in an "
+                 "{ib} split");
     nsFrameList frames(aParentFrame->GetFirstChild(nsnull));
 
     // Insert the frames before the :after pseudo-element.
     return frameManager->InsertFrames(aParentFrame, nsnull,
                                       frames.GetPrevSiblingFor(aAfterFrame),
-                                      aFrameList);
-  }
-
-  return frameManager->AppendFrames(aParentFrame, nsnull, aFrameList);
+                                      aFrameList.childList);
+  }
+
+  if (IsFrameSpecial(aParentFrame) &&
+      !IsInlineFrame(aParentFrame) &&
+      IsInlineOutside(aFrameList.lastChild)) {
+    NS_ASSERTION(!aParentFrame->GetNextContinuation(), "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;
+    } else {
+      firstTrailingInline = aFrameList.childList;
+      aFrameList = nsFrameItems();
+    }
+
+    NS_ASSERTION(firstTrailingInline, "How did that happen?");
+    nsIFrame* parentFrame = aParentFrame;
+
+    // Now we loop, because it might be the case that the parent of our special
+    // block is another special block, and that we're at the very end of it,
+    // and in that case if we create a new special inline we'll have to create
+    // a parent for it too.
+    do {
+      NS_ASSERTION(IsFrameSpecial(parentFrame) && !IsInlineFrame(parentFrame),
+                   "Shouldn't be in this code");
+      nsIFrame* inlineSibling = GetSpecialSibling(parentFrame);
+      PRBool isPositioned = PR_FALSE;
+      nsIContent* content = nsnull;
+      nsStyleContext* styleContext = nsnull;
+      if (!inlineSibling) {
+        nsIFrame* firstInline =
+          static_cast<nsIFrame*>
+                     (aState.mPresContext->PropertyTable()->
+                      GetProperty(parentFrame->GetFirstContinuation(),
+                                  nsGkAtoms::IBSplitSpecialPrevSibling));
+        NS_ASSERTION(firstInline, "How did that happen?");
+
+        content = firstInline->GetContent();
+        styleContext = firstInline->GetStyleContext();
+        isPositioned = (styleContext->GetStyleDisplay()->mPosition ==
+                        NS_STYLE_POSITION_RELATIVE);
+      }
+
+      nsIFrame* stateParent =
+        inlineSibling ? inlineSibling->GetParent() : parentFrame->GetParent();
+
+      nsFrameConstructorState
+        targetState(mPresShell, mFixedContainingBlock,
+                    GetAbsoluteContainingBlock(stateParent),
+                    GetFloatContainingBlock(stateParent));
+      nsIFrame* newInlineSibling =
+        MoveFramesToEndOfIBSplit(aState, inlineSibling,
+                                 isPositioned, content,
+                                 styleContext, firstTrailingInline,
+                                 parentFrame, &targetState);
+
+      if (inlineSibling) {
+        // we're all set -- we just moved things to a frame that was already
+        // there.
+        NS_ASSERTION(newInlineSibling == inlineSibling, "What happened?");
+        break;
+      }
+
+      SetFrameIsSpecial(parentFrame, newInlineSibling);
+      
+      // We had to create a frame for this new inline sibling.  Figure out
+      // the right parentage for it.
+      // XXXbz add a test for this?
+      nsIFrame* newParentFrame = parentFrame->GetParent();
+      NS_ASSERTION(!IsInlineFrame(newParentFrame),
+                   "The block in an {ib} split shouldn't be living inside "
+                   "an inline");
+      if (!IsFrameSpecial(newParentFrame) ||
+          newParentFrame->GetNextContinuation() ||
+          parentFrame->GetNextSibling()) {
+        // Just insert after parentFrame
+        frameManager->InsertFrames(newParentFrame, nsnull, parentFrame,
+                                   newInlineSibling);
+        firstTrailingInline = nsnull;
+      } else {
+        // recurse up the tree
+        parentFrame = newParentFrame;
+        firstTrailingInline = newInlineSibling;
+      }      
+    } while (firstTrailingInline);
+  }
+    
+  if (!aFrameList.childList) {
+    // It all got eaten by the special inline
+    return NS_OK;
+  }
+  
+  return frameManager->AppendFrames(aParentFrame, nsnull,
+                                    aFrameList.childList);
 }
 
 /**
  * Find the ``rightmost'' frame for the anonymous content immediately
  * preceding aChild, following continuation if necessary.
  */
 static nsIFrame*
 FindPreviousAnonymousSibling(nsIPresShell* aPresShell,
@@ -7953,18 +8048,17 @@ FindPreviousAnonymousSibling(nsIPresShel
 
     // Get its frame. If it doesn't have one, continue on to the
     // anonymous element that preceded it.
     nsIFrame* prevSibling = aPresShell->GetPrimaryFrameFor(child);
     if (prevSibling) {
       // The frame may be a special frame (a split inline frame that
       // contains a block).  Get the last part of that split.
       if (IsFrameSpecial(prevSibling)) {
-        prevSibling = GetLastSpecialSibling(aPresShell->FrameManager(),
-                                            prevSibling);
+        prevSibling = GetLastSpecialSibling(prevSibling);
       }
 
       // The frame may have a continuation. If so, we want the
       // last continuation as our previous sibling.
       prevSibling = prevSibling->GetLastContinuation();
 
       // If the frame is out-of-flow, GPFF() will have returned the
       // out-of-flow frame; we want the placeholder.
@@ -8139,18 +8233,17 @@ nsCSSFrameConstructor::FindPreviousSibli
   // `display: hidden') so keep looking until we find a previous frame
   while (iter-- != first) {
     nsIFrame* prevSibling = mPresShell->GetPrimaryFrameFor(nsCOMPtr<nsIContent>(*iter));
 
     if (prevSibling) {
       // The frame may be a special frame (a split inline frame that
       // contains a block).  Get the last part of that split.
       if (IsFrameSpecial(prevSibling)) {
-        prevSibling = GetLastSpecialSibling(mPresShell->FrameManager(),
-                                            prevSibling);
+        prevSibling = GetLastSpecialSibling(prevSibling);
       }
 
       // The frame may have a continuation. Get the last continuation
       prevSibling = prevSibling->GetLastContinuation();
 
       // XXXbz should the IsValidSibling check be after we get the
       // placeholder for out-of-flows?
       const nsStyleDisplay* display = prevSibling->GetStyleDisplay();
@@ -8413,17 +8506,17 @@ nsCSSFrameConstructor::ContentAppended(n
         for (ChildIterator::Init(insertionContent, &iter, &last);
          iter != last;
          ++iter) {
           LAYOUT_PHASE_TEMP_EXIT();
           nsIContent* item = nsCOMPtr<nsIContent>(*iter);
           if (item == child)
             // Call ContentInserted with this index.
             ContentInserted(aContainer, child,
-                            iter.index(), mTempFrameTreeState, PR_FALSE);
+                            iter.index(), mTempFrameTreeState);
           LAYOUT_PHASE_TEMP_REENTER();
         }
       }
 
       return NS_OK;
     }
   }
 
@@ -8440,72 +8533,31 @@ nsCSSFrameConstructor::ContentAppended(n
     }
   }
   
   if (parentFrame->IsLeaf()) {
     // Nothing to do here; we shouldn't be constructing kids of leaves
     return NS_OK;
   }
   
-  // If the frame we are manipulating is a ``special'' frame (that
-  // is, one that's been created as a result of a block-in-inline
-  // situation) then do something different instead of just
-  // appending newly created frames. Note that only the
-  // first-in-flow is marked so we check before getting to the
-  // last-in-flow.
-  //
-  // We run into this situation occasionally while loading web
-  // pages, typically when some content generation tool has
-  // sprinkled invalid markup into the document. More often than
-  // not, we'll be able to just use the normal fast-path frame
-  // construction code, because the frames will be appended to the
-  // ``anonymous'' block that got created to parent the block
-  // children of the inline.
+  // If the frame we are manipulating is a ``special'' frame (that is, one
+  // that's been created as a result of a block-in-inline situation) then we
+  // need to append to the last special sibling, not to the frame itself.
   if (IsFrameSpecial(parentFrame)) {
 #ifdef DEBUG
     if (gNoisyContentUpdates) {
       printf("nsCSSFrameConstructor::ContentAppended: parentFrame=");
       nsFrame::ListTag(stdout, parentFrame);
       printf(" is special\n");
     }
 #endif
 
     // Since we're appending, we'll walk to the last anonymous frame
     // that was created for the broken inline frame.
-    nsFrameManager *frameManager = mPresShell->FrameManager();
-
-    while (1) {
-      nsIFrame* sibling;
-      GetSpecialSibling(frameManager, parentFrame, &sibling);
-      if (! sibling)
-        break;
-
-      parentFrame = sibling;
-    }
-
-    // If this frame is the anonymous block frame, then all's well:
-    // just append frames as usual.
-    const nsStyleDisplay* display = parentFrame->GetStyleDisplay();
-
-    if (NS_STYLE_DISPLAY_BLOCK != display->mDisplay) {
-      // Nope, it's an inline, so just reframe the entire stinkin' mess if the
-      // content is a block. We _could_ do better here with a little more work...
-      // find out if the child is a block or inline, an inline means we don't have to reframe
-      nsIContent *child = aContainer->GetChildAt(aNewIndexInContainer);
-      PRBool needReframe = !child;
-      if (child && child->IsNodeOfType(nsINode::eELEMENT)) {
-        nsRefPtr<nsStyleContext> styleContext;
-        styleContext = ResolveStyleContext(parentFrame, child);
-        // XXX since the block child goes in the last inline of the sacred triad, frames would 
-        // need to be moved into the 2nd triad (block) but that is more work, for now bail.
-        needReframe = styleContext->GetStyleDisplay()->IsBlockOutside();
-      }
-      if (needReframe)
-        return ReframeContainingBlock(parentFrame);
-    }
+    parentFrame = GetLastSpecialSibling(parentFrame);
   }
 
   // Get the parent frame's last continuation
   parentFrame = parentFrame->GetLastContinuation();
 
   nsIAtom* frameType = parentFrame->GetType();
   // Deal with fieldsets
   parentFrame = ::GetAdjustedParentFrame(parentFrame, frameType,
@@ -8515,17 +8567,16 @@ nsCSSFrameConstructor::ContentAppended(n
   nsIFrame* parentAfterFrame;
   parentFrame =
     ::AdjustAppendParentForAfterContent(mPresShell->GetPresContext(),
                                         aContainer, parentFrame,
                                         &parentAfterFrame);
   
   // Create some new frames
   PRUint32                count;
-  nsIFrame*               firstAppendedFrame = nsnull;
   nsFrameItems            frameItems;
   nsFrameConstructorState state(mPresShell, mFixedContainingBlock,
                                 GetAbsoluteContainingBlock(parentFrame),
                                 GetFloatContainingBlock(parentFrame));
 
   // See if the containing block has :first-letter style applied.
   PRBool haveFirstLetterStyle = PR_FALSE, haveFirstLineStyle = PR_FALSE;
   nsIFrame* containingBlock = state.mFloatedItems.containingBlock;
@@ -8581,48 +8632,50 @@ nsCSSFrameConstructor::ContentAppended(n
   if (haveFirstLineStyle && parentFrame == containingBlock) {
     // It's possible that some of the new frames go into a
     // first-line frame. Look at them and see...
     AppendFirstLineFrames(state, containingBlock->GetContent(),
                           containingBlock, frameItems); 
   }
 
   nsresult result = NS_OK;
-  firstAppendedFrame = frameItems.childList;
-  if (!firstAppendedFrame) {
-    firstAppendedFrame = captionItems.childList;
-  }
 
   // Notify the parent frame passing it the list of new frames
-  if (NS_SUCCEEDED(result) && firstAppendedFrame) {
+  if (NS_SUCCEEDED(result) &&
+      (frameItems.childList || captionItems.childList)) {
     // Perform special check for diddling around with the frames in
     // a special inline frame.
 
-    if (WipeContainingBlock(state, containingBlock, parentFrame,
-                            frameItems.childList)) {
+    // We can't have a block ::after inside an inline, so it's safe to ignore
+    // the fact that we're not really appending if there's ::after content.
+    // Indeed, if we're inserting before the ::after content that means the
+    // ::after content is not the last child of the block in the {ib} split,
+    // which is the only case in which we care whether we're appending.
+    if (WipeContainingBlock(state, containingBlock, parentFrame, frameItems,
+                            PR_TRUE, nsnull)) {
       return NS_OK;
     }
 
     // Append the flowed frames to the principal child list, tables need special treatment
     if (nsGkAtoms::tableFrame == frameType) {
       if (captionItems.childList) { // append the caption to the outer table
         nsIFrame* outerTable = parentFrame->GetParent();
         if (outerTable) { 
           state.mFrameManager->AppendFrames(outerTable,
                                             nsGkAtoms::captionList,
                                             captionItems.childList);
         }
       }
       if (frameItems.childList) { // append children of the inner table
-        AppendFrames(state, aContainer, parentFrame, frameItems.childList,
+        AppendFrames(state, aContainer, parentFrame, frameItems,
                      parentAfterFrame);
       }
     }
     else {
-      AppendFrames(state, aContainer, parentFrame, firstAppendedFrame,
+      AppendFrames(state, aContainer, parentFrame, frameItems,
                    parentAfterFrame);
     }
   }
 
   // Recover first-letter frames
   if (haveFirstLetterStyle) {
     RecoverLetterFrames(state, containingBlock);
   }
@@ -8636,131 +8689,16 @@ nsCSSFrameConstructor::ContentAppended(n
       fdbg->List(stdout, 0);
     }
   }
 #endif
 
   return NS_OK;
 }
 
-// Return TRUE if the insertion of aChild into aParent1,2 should force a reframe. aParent1 is 
-// the special inline container which contains a block. aParentFrame is approximately aParent1's
-// primary frame and will be set to the correct parent of aChild if a reframe is not necessary. 
-// aParent2 is aParentFrame's content. aPrevSibling will be set to the correct prev sibling of
-// aChild if a reframe is not necessary.
-PRBool
-nsCSSFrameConstructor::NeedSpecialFrameReframe(nsIContent*     aParent1,     
-                                               nsIContent*     aParent2,     
-                                               nsIFrame*&      aParentFrame, 
-                                               nsIContent*     aChild,
-                                               PRInt32         aIndexInContainer,
-                                               nsIFrame*&      aPrevSibling,
-                                               nsIFrame*       aNextSibling)
-{
-  // XXXbz aNextSibling is utterly unused.  Why?
-  
-  if (IsBlockOutside(aParentFrame)) 
-    return PR_FALSE;
-
-  // find out if aChild is a block or inline
-  PRBool childIsBlock = PR_FALSE;
-  if (aChild->IsNodeOfType(nsINode::eELEMENT)) {
-    nsRefPtr<nsStyleContext> styleContext;
-    styleContext = ResolveStyleContext(aParentFrame, aChild);
-    const nsStyleDisplay* display = styleContext->GetStyleDisplay();
-    childIsBlock = display->IsBlockOutside();
-  }
-  nsIFrame* prevParent; // parent of prev sibling
-  nsIFrame* nextParent; // parent of next sibling
-
-  if (childIsBlock) { 
-    if (aPrevSibling) {
-      prevParent = aPrevSibling->GetParent(); 
-      NS_ASSERTION(prevParent, "program error - null parent frame");
-      if (!IsBlockOutside(prevParent)) { // prevParent is an inline
-        // XXX we need to find out if prevParent is the 1st inline or the last. If it
-        // is the 1st, then aChild and the frames after aPrevSibling within the 1st inline
-        // need to be moved to the block(inline). If it is the last, then aChild and the
-        // frames before aPrevSibling within the last need to be moved to the block(inline). 
-        return PR_TRUE; // For now, bail.
-      }        
-      aParentFrame = prevParent; // prevParent is a block, put aChild there
-    }
-    else {
-      // XXXbz see comments in ContentInserted about this being wrong in many
-      // cases!  Why doesn't this just use aNextSibling anyway?  Why are we
-      // looking sometimes in aParent1 and sometimes in aParent2?
-      nsIFrame* nextSibling = (aIndexInContainer >= 0)
-                              ? FindNextSibling(aParent2, aParentFrame,
-                                                aIndexInContainer)
-                              : FindNextAnonymousSibling(mPresShell, mDocument,
-                                                         aParent1, aChild);
-      if (nextSibling) {
-        nextParent = nextSibling->GetParent(); 
-        NS_ASSERTION(nextParent, "program error - null parent frame");
-        if (!IsBlockOutside(nextParent)) {
-          // XXX we need to move aChild, aNextSibling and all the frames after aNextSibling within
-          // the 1st inline to the block(inline).
-          return PR_TRUE; // for now, bail
-        }
-        // put aChild in nextParent which is the block(inline) and leave aPrevSibling null
-        aParentFrame = nextParent;
-      }
-    }           
-  }
-  else { // aChild is an inline
-    if (aPrevSibling) {
-      prevParent = aPrevSibling->GetParent(); 
-      NS_ASSERTION(prevParent, "program error - null parent frame");
-      if (!IsBlockOutside(prevParent)) { // prevParent is an inline
-        // aChild goes into the same inline frame as aPrevSibling
-        aParentFrame = aPrevSibling->GetParent();
-        NS_ASSERTION(aParentFrame, "program error - null parent frame");
-      }
-      else { // prevParent is a block
-        // XXXbz see comments in ContentInserted about this being wrong in many
-        // cases!  Why doesn't this just use aNextSibling anyway?  Why are we
-        // looking sometimes in aParent1 and sometimes in aParent2?
-        nsIFrame* nextSibling = (aIndexInContainer >= 0)
-                                ? FindNextSibling(aParent2, aParentFrame,
-                                                  aIndexInContainer)
-                                : FindNextAnonymousSibling(mPresShell,
-                                                           mDocument, aParent1,
-                                                           aChild);
-        if (nextSibling) {
-          nextParent = nextSibling->GetParent();
-          NS_ASSERTION(nextParent, "program error - null parent frame");
-          if (!IsBlockOutside(nextParent)) {
-            // nextParent is the ending inline frame. Put aChild there and
-            // set aPrevSibling to null so aChild is its first element.
-            aParentFrame = nextSibling->GetParent(); 
-            NS_ASSERTION(aParentFrame, "program error - null parent frame");
-            aPrevSibling = nsnull; 
-          }
-          else { // nextParent is a block
-            // prevParent and nextParent should be the same, and aChild goes there
-            NS_ASSERTION(prevParent == nextParent, "special frame error");
-            aParentFrame = prevParent;
-          }
-        }
-        else {
-          // The child has no next sibling, so we can't find the ending inline
-          // frame (which might not exist in this case anyway!), but aChild
-          // should go in there.  Force a reframe.
-          // XXXbz wouldn't getting prevParent's special sibling work, with
-          // reframing only needed if that's null?
-          return PR_TRUE;
-        }
-      }
-    }
-    // else aChild goes into the 1st inline frame which is aParentFrame
-  }
-  return PR_FALSE;
-}
-
 #ifdef MOZ_XUL
 
 enum content_operation
 {
     CONTENT_INSERTED,
     CONTENT_REMOVED
 };
 
@@ -8823,18 +8761,17 @@ PRBool NotifyListBoxBody(nsPresContext* 
   return PR_FALSE;
 }
 #endif // MOZ_XUL
 
 nsresult
 nsCSSFrameConstructor::ContentInserted(nsIContent*            aContainer,
                                        nsIContent*            aChild,
                                        PRInt32                aIndexInContainer,
-                                       nsILayoutHistoryState* aFrameState,
-                                       PRBool                 aInReinsertContent)
+                                       nsILayoutHistoryState* aFrameState)
 {
   AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
   // XXXldb Do we need to re-resolve style to handle the CSS2 + combinator and
   // the :empty pseudo-class?
 #ifdef DEBUG
   if (gNoisyContentUpdates) {
     printf("nsCSSFrameConstructor::ContentInserted container=%p child=%p index=%d\n",
            static_cast<void*>(aContainer),
@@ -8950,28 +8887,24 @@ nsCSSFrameConstructor::ContentInserted(n
     
   // If there is no previous sibling, then find the frame that follows
   if (! prevSibling) {
     nextSibling = (aIndexInContainer >= 0)
       ? FindNextSibling(container, parentFrame, aIndexInContainer, aChild)
       : FindNextAnonymousSibling(mPresShell, mDocument, aContainer, aChild);
   }
 
-  PRBool handleSpecialFrame = IsFrameSpecial(parentFrame) && !aInReinsertContent;
-
   // Now, find the geometric parent so that we can handle
   // continuations properly. Use the prev sibling if we have it;
   // otherwise use the next sibling.
   if (prevSibling) {
-    if (!handleSpecialFrame)
-      parentFrame = prevSibling->GetParent()->GetContentInsertionFrame();
+    parentFrame = prevSibling->GetParent()->GetContentInsertionFrame();
   }
   else if (nextSibling) {
-    if (!handleSpecialFrame)
-      parentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
+    parentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
   }
   else {
     // No previous or next sibling, so treat this like an appended frame.
     isAppend = PR_TRUE;
     // Deal with fieldsets
     parentFrame = ::GetAdjustedParentFrame(parentFrame, parentFrame->GetType(),
                                            aContainer, aIndexInContainer);
     parentFrame =
@@ -8986,50 +8919,28 @@ nsCSSFrameConstructor::ContentInserted(n
     return RecreateFramesForContent(parentFrame->GetContent());
   }
   
   // Don't construct kids of leaves
   if (parentFrame->IsLeaf()) {
     return NS_OK;
   }
   
-  // If the frame we are manipulating is a special frame then see if we need to reframe 
-  // NOTE: if we are in ReinsertContent, then don't reframe as we are already doing just that!
-  if (handleSpecialFrame) {
-    // a special inline frame has propagated some of its children upward to be children 
-    // of the block and those frames may need to move around. Sometimes we may need to reframe
-#ifdef DEBUG
-    if (gNoisyContentUpdates) {
-      printf("nsCSSFrameConstructor::ContentInserted: parentFrame=");
-      nsFrame::ListTag(stdout, parentFrame);
-      printf(" is special\n");
-    }
-#endif
-    // if we don't need to reframe then set parentFrame and prevSibling to the correct values
-    if (NeedSpecialFrameReframe(aContainer, container, parentFrame, 
-                                aChild, aIndexInContainer, prevSibling,
-                                nextSibling)) {
-      return ReframeContainingBlock(parentFrame);
-    }
-  }
-
   nsFrameConstructorState state(mPresShell, mFixedContainingBlock,
                                 GetAbsoluteContainingBlock(parentFrame),
                                 GetFloatContainingBlock(parentFrame),
                                 aFrameState);
 
 
   // Recover state for the containing block - we need to know if
   // it has :first-letter or :first-line style applied to it. The
   // reason we care is that the internal structure in these cases
   // is not the normal structure and requires custom updating
   // logic.
   nsIFrame* containingBlock = state.mFloatedItems.containingBlock;
-  nsStyleContext* blockSC;
-  nsIContent* blockContent = nsnull;
   PRBool haveFirstLetterStyle = PR_FALSE;
   PRBool haveFirstLineStyle = PR_FALSE;
 
   // In order to shave off some cycles, we only dig up the
   // containing block haveFirst* flags if the parent frame where
   // the insertion/append is occurring is an inline or block
   // container. For other types of containers this isn't relevant.
   const nsStyleDisplay* parentDisplay = parentFrame->GetStyleDisplay();
@@ -9072,43 +8983,16 @@ nsCSSFrameConstructor::ContentInserted(n
                                        aChild);
 
       // If there is no previous sibling, then find the frame that follows
       if (! prevSibling) {
         nextSibling = (aIndexInContainer >= 0)
           ? FindNextSibling(container, parentFrame, aIndexInContainer, aChild)
           : FindNextAnonymousSibling(mPresShell, mDocument, aContainer, aChild);
       }
-
-      handleSpecialFrame = IsFrameSpecial(parentFrame) && !aInReinsertContent;
-      if (handleSpecialFrame &&
-          NeedSpecialFrameReframe(aContainer, container, parentFrame,
-                                  aChild, aIndexInContainer, prevSibling,
-                                  nextSibling)) {
-#ifdef DEBUG
-        nsIContent* parentContainer = blockContent->GetParent();
-        if (gNoisyContentUpdates) {
-          printf("nsCSSFrameConstructor::ContentInserted: parentFrame=");
-          nsFrame::ListTag(stdout, parentFrame);
-          printf(" is special inline\n");
-          printf("  ==> blockContent=%p, parentContainer=%p\n",
-                 static_cast<void*>(blockContent),
-                 static_cast<void*>(parentContainer));
-        }
-#endif
-
-        NS_ASSERTION(GetFloatContainingBlock(parentFrame) == containingBlock,
-                     "Unexpected block ancestor for parentFrame");
-
-        // Note that in this case we're guaranteed that the closest block
-        // containing parentFrame is |containingBlock|.  So
-        // ReframeContainingBlock(parentFrame) will make sure to rebuild the
-        // first-letter stuff we just blew away.
-        return ReframeContainingBlock(parentFrame);
-      }
     }
   }
 
   // if the container is a table and a caption will be appended, it needs to be
   // put in the outer table frame's additional child list.
   
   nsFrameItems frameItems, captionItems;
 
@@ -9140,18 +9024,23 @@ nsCSSFrameConstructor::ContentInserted(n
       ::AdjustAppendParentForAfterContent(mPresShell->GetPresContext(),
                                           aContainer,
                                           frameItems.childList->GetParent(),
                                           &appendAfterFrame);
   }
 
   // Perform special check for diddling around with the frames in
   // a special inline frame.
-  if (WipeContainingBlock(state, containingBlock, parentFrame,
-                          frameItems.childList))
+  // We can't have a block ::after inside an inline, so it's safe to ignore
+  // the fact that we're not really appending if there's ::after content.
+  // Indeed, if we're inserting before the ::after content that means the
+  // ::after content is not the last child of the block in the {ib} split,
+  // which is the only case in which we care whether we're appending.
+  if (WipeContainingBlock(state, containingBlock, parentFrame, frameItems,
+                          isAppend, prevSibling))
     return NS_OK;
 
   if (haveFirstLineStyle && parentFrame == containingBlock) {
     // It's possible that the new frame goes into a first-line
     // frame. Look at it and see...
     if (isAppend) {
       // Use append logic when appending
       AppendFirstLineFrames(state, containingBlock->GetContent(),
@@ -9159,17 +9048,17 @@ nsCSSFrameConstructor::ContentInserted(n
     }
     else {
       // Use more complicated insert logic when inserting
       InsertFirstLineFrames(state, aContainer, containingBlock, &parentFrame,
                             prevSibling, frameItems);
     }
   }
       
-  nsIFrame* newFrame = frameItems.childList;
+  nsIFrame* const newFrame = frameItems.childList;
   if (NS_SUCCEEDED(rv) && newFrame) {
     NS_ASSERTION(!captionItems.childList, "leaking caption frames");
     if (!prevSibling) {
       // 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 &&
@@ -9189,17 +9078,18 @@ nsCSSFrameConstructor::ContentInserted(n
         // to force all insert-after-:before cases to take these to take the
         // InsertFrames path
         isAppend = PR_FALSE;
       }
     }
 
     // Notify the parent frame
     if (isAppend) {
-      AppendFrames(state, aContainer, parentFrame, newFrame, appendAfterFrame);
+      AppendFrames(state, aContainer, parentFrame, frameItems,
+                   appendAfterFrame);
     } else {
       state.mFrameManager->InsertFrames(parentFrame,
                                         nsnull, prevSibling, newFrame);
     }
   }
   else {
     // we might have a caption treat it here
     nsIFrame* newCaptionFrame = captionItems.childList;
@@ -9259,17 +9149,17 @@ nsCSSFrameConstructor::ReinsertContent(n
   PRInt32 ix = aContainer->IndexOf(aChild);
   // XXX For now, do a brute force remove and insert.
   // XXXbz this probably doesn't work so well with anonymous content
   // XXXbz doesn't this need to do the state-saving stuff that
   // RecreateFramesForContent does?
   nsresult res = ContentRemoved(aContainer, aChild, ix, PR_TRUE);
 
   if (NS_SUCCEEDED(res)) {
-    res = ContentInserted(aContainer, aChild, ix, nsnull, PR_TRUE);
+    res = ContentInserted(aContainer, aChild, ix, nsnull);
   }
 
   return res;
 }
 
 /**
  * Called when a frame subtree is about to be deleted. Two important
  * things happen:
@@ -9482,31 +9372,19 @@ nsCSSFrameConstructor::ContentRemoved(ns
   if (childFrame) {
     InvalidateCanvasIfNeeded(childFrame);
     
     // If the frame we are manipulating is a special frame then do
     // something different instead of just inserting newly created
     // frames.
     // NOTE: if we are in ReinsertContent, 
     //       then do not reframe as we are already doing just that!
-    if (IsFrameSpecial(childFrame) && !aInReinsertContent) {
-      // We are pretty harsh here (and definitely not optimal) -- we
-      // wipe out the entire containing block and recreate it from
-      // scratch. The reason is that because we know that a special
-      // inline frame has propagated some of its children upward to be
-      // children of the block and that those frames may need to move
-      // around. This logic guarantees a correct answer.
-#ifdef DEBUG
-      if (gNoisyContentUpdates) {
-        printf("nsCSSFrameConstructor::ContentRemoved: childFrame=");
-        nsFrame::ListTag(stdout, childFrame);
-        printf(" is special\n");
-      }
-#endif
-      return ReframeContainingBlock(childFrame);
+    if (!aInReinsertContent &&
+        MaybeRecreateContainerForIBSplitterFrame(childFrame, &rv)) {
+      return rv;
     }
 
     // Get the childFrame's parent frame
     nsIFrame* parentFrame = childFrame->GetParent();
 
     if (parentFrame->GetType() == nsGkAtoms::frameSetFrame &&
         IsSpecialFramesetChild(aChild)) {
       // Just reframe the parent, since framesets are weird like that.
@@ -10905,19 +10783,17 @@ nsCSSFrameConstructor::FindPrimaryFrameF
         aFrameManager->SetPrimaryFrameFor(aContent, *aFrame);
         break;
       }
       else if (IsFrameSpecial(parentFrame)) {
         // If it's a "special" frame (that is, part of an inline
         // that's been split because it contained a block), we need to
         // follow the out-of-flow "special sibling" link, and search
         // *that* subtree as well.
-        nsIFrame* specialSibling = nsnull;
-        GetSpecialSibling(aFrameManager, parentFrame, &specialSibling);
-        parentFrame = specialSibling;
+        parentFrame = GetSpecialSibling(parentFrame);
       }
       else {
         break;
       }
     }
   }
 
   if (aHint && !*aFrame)
@@ -11051,29 +10927,59 @@ nsCSSFrameConstructor::MaybeRecreateFram
     if (newContext->GetStyleDisplay()->mDisplay != NS_STYLE_DISPLAY_NONE) {
       result = RecreateFramesForContent(aContent);
     }
   }
   return result;
 }
 
 PRBool
-nsCSSFrameConstructor::MaybeRecreateContainerForIBSplitterFrame(nsIFrame* aFrame, nsresult* aResult)
-{
-  if (!aFrame || !IsFrameSpecial(aFrame))
+nsCSSFrameConstructor::MaybeRecreateContainerForIBSplitterFrame(nsIFrame* aFrame,
+                                                                nsresult* aResult)
+{
+  NS_PRECONDITION(aFrame, "Must have a frame");
+  NS_PRECONDITION(aFrame->GetParent(), "Frame shouldn't be root");
+  NS_PRECONDITION(aResult, "Null out param?");
+  NS_PRECONDITION(aFrame == aFrame->GetFirstContinuation(),
+                  "aFrame not the result of GetPrimaryFrameFor()?");
+
+  if (IsFrameSpecial(aFrame)) {
+    // The removal functions can't handle removal of an {ib} split directly; we
+    // need to rebuild the containing block.
+#ifdef DEBUG
+    if (gNoisyContentUpdates) {
+      printf("nsCSSFrameConstructor::MaybeRecreateContainerForIBSplitterFrame: "
+             "frame=");
+      nsFrame::ListTag(stdout, aFrame);
+      printf(" is special\n");
+    }
+#endif
+
+    *aResult = ReframeContainingBlock(aFrame);
+    return PR_TRUE;
+  }
+
+  // We might still need to reconstruct things if the parent of aFrame is
+  // special, since in that case the removal of aFrame might affect the
+  // splitting of its parent.
+  nsIFrame* parent = aFrame->GetParent();
+  if (!IsFrameSpecial(parent)) {
     return PR_FALSE;
+  }
 
 #ifdef DEBUG
-  if (gNoisyContentUpdates) {
-    printf("nsCSSFrameConstructor::RecreateFramesForContent: frame=");
-    nsFrame::ListTag(stdout, aFrame);
+  if (gNoisyContentUpdates || 1) {
+    printf("nsCSSFrameConstructor::MaybeRecreateContainerForIBSplitterFrame: "
+           "frame=");
+    nsFrame::ListTag(stdout, parent);
     printf(" is special\n");
   }
 #endif
-  *aResult = ReframeContainingBlock(aFrame);
+
+  *aResult = ReframeContainingBlock(parent);
   return PR_TRUE;
 }
  
 nsresult
 nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent)
 {
   // If there is no document, we don't want to recreate frames for it.  (You
   // shouldn't generally be giving this method content without a document
@@ -11081,33 +10987,25 @@ nsCSSFrameConstructor::RecreateFramesFor
   // Rebuilding the frame tree can have bad effects, especially if it's the
   // frame tree for chrome (see bug 157322).
   NS_ENSURE_TRUE(aContent->GetDocument(), NS_ERROR_FAILURE);
 
   // Is the frame `special'? If so, we need to reframe the containing
   // block *here*, rather than trying to remove and re-insert the
   // content (which would otherwise result in *two* nested reframe
   // containing block from ContentRemoved() and ContentInserted(),
-  // below!)
+  // below!).  We'd really like to optimize away one of those
+  // containing block reframes, hence the code here.
 
   nsIFrame* frame = mPresShell->GetPrimaryFrameFor(aContent);
 
   nsresult rv = NS_OK;
 
-  if (frame) {
-    // If the frame is an anonymous frame created as part of inline-in-block
-    // splitting --- or if its parent is such an anonymous frame (i.e., this
-    // frame might have been the cause of such splitting), then recreate the
-    // containing block.  Note that if |frame| is an inline, then it can't
-    // possibly have caused the splitting, and if the inline is changing to a
-    // block, any reframing that's needed will happen in ContentInserted.
-    if (MaybeRecreateContainerForIBSplitterFrame(frame, &rv) ||
-        (!IsInlineOutside(frame) &&
-         MaybeRecreateContainerForIBSplitterFrame(frame->GetParent(), &rv)))
-      return rv;
+  if (frame && MaybeRecreateContainerForIBSplitterFrame(frame, &rv)) {
+    return rv;
   }
 
   nsCOMPtr<nsIContent> container = aContent->GetParent();
   if (container) {
     // XXXbz what if this is anonymous content?
     PRInt32 indexInContainer = container->IndexOf(aContent);
     // Before removing the frames associated with the content object,
     // ask them to save their state onto a temporary state object.
@@ -11116,17 +11014,17 @@ nsCSSFrameConstructor::RecreateFramesFor
     // Remove the frames associated with the content object on which
     // the attribute change occurred.
     rv = ContentRemoved(container, aContent, indexInContainer,
                         PR_FALSE);
 
     if (NS_SUCCEEDED(rv)) {
       // Now, recreate the frames associated with this content object.
       rv = ContentInserted(container, aContent,
-                           indexInContainer, mTempFrameTreeState, PR_FALSE);
+                           indexInContainer, mTempFrameTreeState);
     }
   } else {
     // The content is the root node, so just rebuild the world.
     ReconstructDocElementHierarchy();
   }
 
 #ifdef ACCESSIBILITY
   if (mPresShell->IsAccessibilityActive()) {
@@ -11947,18 +11845,17 @@ nsCSSFrameConstructor::WrapFramesInFirst
   nsresult rv = NS_OK;
 
   nsIFrame* prevFrame = nsnull;
   nsIFrame* frame = aParentFrameList;
 
   while (frame) {
     nsIFrame* nextFrame = frame->GetNextSibling();
 
-    nsIAtom* frameType = frame->GetType();
-    if (nsGkAtoms::textFrame == frameType) {
+    if (nsGkAtoms::textFrame == frame->GetType()) {
       // Wrap up first-letter content in a letter frame
       nsIContent* textContent = frame->GetContent();
       if (IsFirstLetterContent(textContent)) {
         // Create letter frame to wrap up the text
         rv = CreateLetterFrame(aState, aBlockFrame, textContent,
                                aParentFrame, aLetterFrames);
         if (NS_FAILED(rv)) {
           return rv;
@@ -11967,19 +11864,17 @@ nsCSSFrameConstructor::WrapFramesInFirst
         // Provide adjustment information for parent
         *aModifiedParent = aParentFrame;
         *aTextFrame = frame;
         *aPrevFrame = prevFrame;
         *aStopLooking = PR_TRUE;
         return NS_OK;
       }
     }
-    else if ((nsGkAtoms::inlineFrame == frameType) ||
-             (nsGkAtoms::lineFrame == frameType) ||
-             (nsGkAtoms::positionedInlineFrame == frameType)) {
+    else if (IsInlineFrame(frame)) {
       nsIFrame* kids = frame->GetFirstChild(nsnull);
       WrapFramesInFirstLetterFrame(aState, aBlockFrame, frame, kids,
                                    aModifiedParent, aTextFrame,
                                    aPrevFrame, aLetterFrames, aStopLooking);
       if (*aStopLooking) {
         return NS_OK;
       }
     }
@@ -12122,18 +12017,17 @@ nsCSSFrameConstructor::RemoveFirstLetter
                                                nsFrameManager* aFrameManager,
                                                nsIFrame* aFrame,
                                                PRBool* aStopLooking)
 {
   nsIFrame* prevSibling = nsnull;
   nsIFrame* kid = aFrame->GetFirstChild(nsnull);
 
   while (kid) {
-    nsIAtom* frameType = kid->GetType();
-    if (nsGkAtoms::letterFrame == frameType) {
+    if (nsGkAtoms::letterFrame == kid->GetType()) {
       // Bingo. Found it. First steal away the text frame.
       nsIFrame* textFrame = kid->GetFirstChild(nsnull);
       if (!textFrame) {
         break;
       }
 
       // Create a new textframe
       nsStyleContext* parentSC = aFrame->GetStyleContext();
@@ -12157,19 +12051,17 @@ nsCSSFrameConstructor::RemoveFirstLetter
       aFrameManager->RemoveFrame(aFrame, nsnull, kid);
 
       // Insert text frame in its place
       aFrameManager->InsertFrames(aFrame, nsnull, prevSibling, textFrame);
 
       *aStopLooking = PR_TRUE;
       break;
     }
-    else if ((nsGkAtoms::inlineFrame == frameType) ||
-             (nsGkAtoms::lineFrame == frameType) ||
-             (nsGkAtoms::positionedInlineFrame == frameType)) {
+    else if (IsInlineFrame(kid)) {
       // Look inside child inline frame for the letter frame
       RemoveFirstLetterFrames(aPresContext, aPresShell, aFrameManager, kid,
                               aStopLooking);
       if (*aStopLooking) {
         break;
       }
     }
     prevSibling = kid;
@@ -12511,57 +12403,41 @@ nsCSSFrameConstructor::ConstructInline(n
                                 GetAbsoluteContainingBlock(blockFrame),
                                 GetFloatContainingBlock(blockFrame));
 
   // If we have an inline between two blocks all inside an inline and the inner
   // inline contains a float, the float will end up in the float list of the
   // parent block of the inline, but its parent pointer will be the anonymous
   // block we create...  AdjustFloatParentPtrs() deals with this by moving the
   // float from the outer state |aState| to the inner |state|.
-  MoveChildrenTo(state.mFrameManager, blockSC, blockFrame, list2, &state, &aState);
+  MoveChildrenTo(state.mFrameManager, blockFrame, list2, &state, &aState);
 
   // list3's frames belong to another inline frame
   nsIFrame* inlineFrame = nsnull;
 
+  // If we ever start constructing a second inline in the split even when
+  // list3 is null, the logic in MaybeRecreateContainerForIBSplitterFrame
+  // needs to be adjusted.  Also, if you're changing this code also change
+  // AppendFrames().
   if (list3) {
-    if (aIsPositioned) {
-      inlineFrame = NS_NewPositionedInlineFrame(mPresShell, aStyleContext);
-    }
-    else {
-      inlineFrame = NS_NewInlineFrame(mPresShell, aStyleContext);
-    }
-
-    InitAndRestoreFrame(aState, aContent, aParentFrame, nsnull, inlineFrame, PR_FALSE);
-
-    // Any frame might need a view
-    // XXXbz should we be passing in a non-null aContentParentFrame?
-    nsHTMLContainerFrame::CreateViewForFrame(inlineFrame, nsnull, PR_FALSE);
-
-    if (inlineFrame->HasView() || aNewFrame->HasView()) {
-      // Move list3's frames into the new view
-      nsHTMLContainerFrame::ReparentFrameViewList(aState.mPresContext, list3,
-                                                  list3->GetParent(), inlineFrame);
-    }
-
-    // Reparent (cheaply) the frames in list3 - we don't have to futz
-    // with their style context because they already have the right one.
-    inlineFrame->SetInitialChildList(nsnull, list3);
-    MoveChildrenTo(aState.mFrameManager, nsnull, inlineFrame, list3, nsnull, nsnull);
-  }
-
-  // Mark the 3 frames as special. That way if any of the
-  // append/insert/remove methods try to fiddle with the children, the
-  // containing block will be reframed instead.
+    inlineFrame = MoveFramesToEndOfIBSplit(aState, nsnull,
+                                           aIsPositioned, aContent,
+                                           aStyleContext, list3,
+                                           blockFrame, nsnull);
+    
+  }
+
+  // Mark the frames as special (note: marking for inlineFrame is handled by
+  // MoveFramesToEndOfIBSplit). That way if any of the append/insert/remove
+  // methods try to fiddle with the children, the containing block will be
+  // reframed instead.
   SetFrameIsSpecial(aNewFrame, blockFrame);
   SetFrameIsSpecial(blockFrame, inlineFrame);
   MarkIBSpecialPrevSibling(aState.mPresContext, blockFrame, aNewFrame);
 
-  if (inlineFrame)
-    SetFrameIsSpecial(inlineFrame, nsnull);
-
 #ifdef DEBUG
   if (gNoisyInlineConstruction) {
     nsIFrameDebug*  frameDebug;
 
     printf("nsCSSFrameConstructor::ConstructInline:\n");
     if (NS_SUCCEEDED(CallQueryInterface(aNewFrame, &frameDebug))) {
       printf("  ==> leading inline frame:\n");
       frameDebug->List(stdout, 2);
@@ -12576,16 +12452,68 @@ nsCSSFrameConstructor::ConstructInline(n
       frameDebug->List(stdout, 2);
     }
   }
 #endif
 
   return rv;
 }
 
+nsIFrame*
+nsCSSFrameConstructor::MoveFramesToEndOfIBSplit(nsFrameConstructorState& aState,
+                                                nsIFrame* aExistingEndFrame,
+                                                PRBool aIsPositioned,
+                                                nsIContent* aContent,
+                                                nsStyleContext* aStyleContext,
+                                                nsIFrame* aFramesToMove,
+                                                nsIFrame* aBlockPart,
+                                                nsFrameConstructorState* aTargetState)
+{
+  NS_PRECONDITION(aFramesToMove, "Must have frames to move");
+  NS_PRECONDITION(aBlockPart, "Must have a block part");
+
+  nsIFrame* inlineFrame = aExistingEndFrame;
+  if (!inlineFrame) {
+    if (aIsPositioned) {
+      inlineFrame = NS_NewPositionedInlineFrame(mPresShell, aStyleContext);
+    }
+    else {
+      inlineFrame = NS_NewInlineFrame(mPresShell, aStyleContext);
+    }
+
+    InitAndRestoreFrame(aState, aContent, aBlockPart->GetParent(), nsnull,
+                        inlineFrame, PR_FALSE);
+
+    // Any frame might need a view
+    // XXXbz should we be passing in a non-null aContentParentFrame?
+    nsHTMLContainerFrame::CreateViewForFrame(inlineFrame, nsnull, PR_FALSE);
+  }
+  
+  if (inlineFrame->HasView() || aFramesToMove->GetParent()->HasView()) {
+    // Move list3's frames into the new view
+    nsHTMLContainerFrame::ReparentFrameViewList(aState.mPresContext,
+                                                aFramesToMove,
+                                                aFramesToMove->GetParent(),
+                                                inlineFrame);
+  }
+
+  // Reparent (cheaply) the frames in list3
+  if (!inlineFrame->GetFirstChild(nsnull) &&
+      (inlineFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
+    inlineFrame->SetInitialChildList(nsnull, aFramesToMove);
+  } else {
+    inlineFrame->InsertFrames(nsnull, nsnull, aFramesToMove);
+  }
+  nsFrameConstructorState* startState = aTargetState ? &aState : nsnull;
+  MoveChildrenTo(aState.mFrameManager, inlineFrame, aFramesToMove,
+                 aTargetState, startState);
+  SetFrameIsSpecial(inlineFrame, nsnull);
+  return inlineFrame;
+}
+ 
 nsresult
 nsCSSFrameConstructor::ProcessInlineChildren(nsFrameConstructorState& aState,
                                              nsIContent*              aContent,
                                              nsIFrame*                aFrame,
                                              PRBool                   aCanHaveGeneratedContent,
                                              nsFrameItems&            aFrameItems,
                                              PRBool*                  aKidsAllInline)
 {
@@ -12671,58 +12599,91 @@ nsCSSFrameConstructor::ProcessInlineChil
 
   return rv;
 }
 
 PRBool
 nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
                                            nsIFrame* aContainingBlock,
                                            nsIFrame* aFrame,
-                                           nsIFrame* aFrameList)
-{
+                                           const nsFrameItems& aFrameList,
+                                           PRBool aIsAppend,
+                                           nsIFrame* aPrevSibling)
+{
+  if (!aFrameList.childList) {
+    return PR_FALSE;
+  }
+  
   // Before we go and append the frames, check for a special
   // situation: an inline frame that will now contain block
   // frames. This is a no-no and the frame construction logic knows
-  // how to fix this.
-
-  // If we don't have a block within an inline, just return false.  Here
-  // "an inline" is an actual inline frame (positioned or not) or a lineframe
-  // (corresponding to :first-line), since the latter should stop at the first
-  // block it runs into and we might be inserting one in the middle of it.
-  // Whether we have "a block" is tested for by AreAllKidsInline.
-  nsIAtom* frameType = aFrame->GetType();
-  if ((frameType != nsGkAtoms::inlineFrame &&
-       frameType != nsGkAtoms::positionedInlineFrame &&
-       frameType != nsGkAtoms::lineFrame) ||
-      AreAllKidsInline(aFrameList))
+  // how to fix this.  See defition of IsInlineFrame() for what "an
+  // inline" is.  Whether we have "a block" is tested for by
+  // AreAllKidsInline.
+
+  // We also need to check for an append of content ending in an
+  // inline to the block in an {ib} split or an insert of content
+  // starting with an inline to the start of that block.  If that
+  // happens, we also need to reframe, since that content needs to go
+  // into the following or preceding inline in the split.
+
+  if (IsInlineFrame(aFrame)) {
+    // Nothing to do if all kids are inline
+    if (AreAllKidsInline(aFrameList.childList)) {
+      return PR_FALSE;
+    }
+  } else if (!IsFrameSpecial(aFrame)) {
     return PR_FALSE;
+  } else {
+    // aFrame is the block in an {ib} split.  Check that we're not
+    // messing up either end of it.
+    if (aIsAppend) {
+      // Will be handled in AppendFrames()
+      return PR_FALSE;
+    }
+    
+    if (aPrevSibling && !aPrevSibling->GetNextSibling()) {
+      // This is an append that won't go through AppendFrames.  We can bail out
+      // if the last frame we're appending is not inline
+      if (!aFrameList.lastChild->GetStyleDisplay()->IsInlineOutside()) {
+        return PR_FALSE;
+      }
+    } else {
+      // We can bail out if we're not inserting at the beginning or if
+      // the first frame we're inserting is not inline.
+      if (aPrevSibling ||
+          !aFrameList.childList->GetStyleDisplay()->IsInlineOutside()) {
+        return PR_FALSE;
+      }
+    }
+  }
 
   // Ok, reverse tracks: wipe out the frames we just created
   nsFrameManager *frameManager = aState.mFrameManager;
 
   // Destroy the frames. As we do make sure any content to frame mappings
   // or entries in the undisplayed content map are removed
   frameManager->ClearAllUndisplayedContentIn(aFrame->GetContent());
 
-  CleanupFrameReferences(frameManager, aFrameList);
+  CleanupFrameReferences(frameManager, aFrameList.childList);
   if (aState.mAbsoluteItems.childList) {
     CleanupFrameReferences(frameManager, aState.mAbsoluteItems.childList);
   }
   if (aState.mFixedItems.childList) {
     CleanupFrameReferences(frameManager, aState.mFixedItems.childList);
   }
   if (aState.mFloatedItems.childList) {
     CleanupFrameReferences(frameManager, aState.mFloatedItems.childList);
   }
 #ifdef MOZ_XUL
   if (aState.mPopupItems.childList) {
     CleanupFrameReferences(frameManager, aState.mPopupItems.childList);
   }
 #endif
-  nsFrameList tmp(aFrameList);
+  nsFrameList tmp(aFrameList.childList);
   tmp.DestroyFrames();
 
   tmp.SetFrames(aState.mAbsoluteItems.childList);
   tmp.DestroyFrames();
   aState.mAbsoluteItems.childList = nsnull;
 
   tmp.SetFrames(aState.mFixedItems.childList);
   tmp.DestroyFrames();
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -106,18 +106,17 @@ public:
   nsresult ReconstructDocElementHierarchy();
 
   nsresult ContentAppended(nsIContent*     aContainer,
                            PRInt32         aNewIndexInContainer);
 
   nsresult ContentInserted(nsIContent*            aContainer,
                            nsIContent*            aChild,
                            PRInt32                aIndexInContainer,
-                           nsILayoutHistoryState* aFrameState,
-                           PRBool                 aInReinsertContent);
+                           nsILayoutHistoryState* aFrameState);
 
   nsresult ContentRemoved(nsIContent*     aContainer,
                           nsIContent*     aChild,
                           PRInt32         aIndexInContainer,
                           PRBool          aInReinsertContent);
 
   nsresult CharacterDataChanged(nsIContent*     aContent,
                                 PRBool          aAppend);
@@ -300,20 +299,23 @@ private:
 
   PRBool CreateGeneratedContentFrame(nsFrameConstructorState& aState,
                                      nsIFrame*                aFrame,
                                      nsIContent*              aContent,
                                      nsStyleContext*          aStyleContext,
                                      nsIAtom*                 aPseudoElement,
                                      nsIFrame**               aResult);
 
-  nsresult AppendFrames(const nsFrameConstructorState& aState,
+  // This method can change aFrameList: it can chop off the end and
+  // put it in a special sibling of aParentFrame.  It can also change
+  // aState by moving some floats out of it.
+  nsresult AppendFrames(nsFrameConstructorState&       aState,
                         nsIContent*                    aContainer,
                         nsIFrame*                      aParentFrame,
-                        nsIFrame*                      aFrameList,
+                        nsFrameItems&                  aFrameList,
                         nsIFrame*                      aAfterFrame);
 
   // BEGIN TABLE SECTION
   /**
    * ConstructTableFrame will construct the outer and inner table frames and
    * return them.  Unless aIsPseudo is PR_TRUE, it will put the inner frame in
    * the child list of the outer frame, and will put any pseudo frames it had
    * to create into aChildItems.  The newly-created outer frame will either be
@@ -749,17 +751,26 @@ private:
                         nsStyleContext*          aStyleContext,
                         PRBool                   aBuildCombobox,
                         nsFrameItems&            aFrameItems);
 
   nsresult MaybeRecreateFramesForContent(nsIContent*      aContent);
 
   nsresult RecreateFramesForContent(nsIContent*      aContent);
 
-  PRBool MaybeRecreateContainerForIBSplitterFrame(nsIFrame* aFrame, nsresult* aResult);
+  // If removal of aFrame from the frame tree requires reconstruction of some
+  // containing block (either of aFrame or of its parent) due to {ib} splits,
+  // recreate the relevant containing block.  The return value indicates
+  // whether this happened.  If this method returns true, *aResult is the
+  // return value of ReframeContainingBlock.  If this method returns false, the
+  // value of *aResult is no affected.  aFrame and aResult must not be null.
+  // aFrame must be the result of a GetPrimaryFrameFor() call (which means its
+  // parent is also not null).
+  PRBool MaybeRecreateContainerForIBSplitterFrame(nsIFrame* aFrame,
+                                                  nsresult* aResult);
 
   nsresult CreateContinuingOuterTableFrame(nsIPresShell*    aPresShell, 
                                            nsPresContext*  aPresContext,
                                            nsIFrame*        aFrame,
                                            nsIFrame*        aParentFrame,
                                            nsIContent*      aContent,
                                            nsStyleContext*  aStyleContext,
                                            nsIFrame**       aContinuingFrame);
@@ -823,37 +834,66 @@ private:
   nsresult ConstructInline(nsFrameConstructorState& aState,
                            const nsStyleDisplay*    aDisplay,
                            nsIContent*              aContent,
                            nsIFrame*                aParentFrame,
                            nsStyleContext*          aStyleContext,
                            PRBool                   aIsPositioned,
                            nsIFrame*                aNewFrame);
 
+  /**
+   * Move an already-constructed framelist into the inline frame at
+   * the tail end of an {ib} split.  Creates said inline if it doesn't
+   * already exist.
+   *
+   * @param aState the frame construction state we're using right now.
+   * @param aExistingEndFrame if non-null, the already-existing end frame.
+   * @param aIsPositioned Whether the end frame should be positioned.
+   * @param aContent the content node for this {ib} split.
+   * @param aStyleContext the style context to use for the new frame
+   * @param aFramesToMove The frame list to move over
+   * @param aBlockPart the block part of the {ib} split.
+   * @param aTargetState if non-null, the target state to pass to
+   *        MoveChildrenTo for float reparenting.
+   * XXXbz test float reparenting?
+   *
+   * @note aIsPositioned, aContent, aStyleContext, are
+   *       only used if aExistingEndFrame is null.
+   */
+  nsIFrame* MoveFramesToEndOfIBSplit(nsFrameConstructorState& aState,
+                                     nsIFrame* aExistingEndFrame,
+                                     PRBool aIsPositioned,
+                                     nsIContent* aContent,
+                                     nsStyleContext* aStyleContext,
+                                     nsIFrame* aFramesToMove,
+                                     nsIFrame* aBlockPart,
+                                     nsFrameConstructorState* aTargetState);
+
   nsresult ProcessInlineChildren(nsFrameConstructorState& aState,
                                  nsIContent*              aContent,
                                  nsIFrame*                aFrame,
                                  PRBool                   aCanHaveGeneratedContent,
                                  nsFrameItems&            aFrameItems,
                                  PRBool*                  aKidsAllInline);
 
   PRBool AreAllKidsInline(nsIFrame* aFrameList);
 
+  // Determine whether we need to wipe out what we just did and start over
+  // because we're doing something like adding block kids to an inline frame
+  // (and therefore need an {ib} split).  If aIsAppend is true, aPrevSibling is
+  // ignored.  Otherwise it may be used to determine whether to reframe when
+  // inserting into the block of an {ib} split.
+  // @return PR_TRUE if we reconstructed the containing block, PR_FALSE
+  // otherwise
   PRBool WipeContainingBlock(nsFrameConstructorState& aState,
-                             nsIFrame*                blockContent,
+                             nsIFrame*                aContainingBlock,
                              nsIFrame*                aFrame,
-                             nsIFrame*                aFrameList);
-
-  PRBool NeedSpecialFrameReframe(nsIContent*      aParent1,
-                                 nsIContent*      aParent2,
-                                 nsIFrame*&       aParentFrame,
-                                 nsIContent*      aChild,
-                                 PRInt32          aIndexInContainer,
-                                 nsIFrame*&       aPrevSibling,
-                                 nsIFrame*        aNextSibling);
+                             const nsFrameItems&      aFrameList,
+                             PRBool                   aIsAppend,
+                             nsIFrame*                aPrevSibling);
 
   nsresult ReframeContainingBlock(nsIFrame* aFrame);
 
   nsresult StyleChangeReflow(nsIFrame* aFrame);
 
   /** Helper function that searches the immediate child frames 
     * (and their children if the frames are "special")
     * for a frame that maps the specified content object
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -2361,18 +2361,17 @@ PresShell::InitialReflow(nscoord aWidth,
       // Have style sheet processor construct a frame for the
       // precursors to the root content object's frame
       mFrameConstructor->ConstructRootFrame(root, &rootFrame);
       FrameManager()->SetRootFrame(rootFrame);
     }
 
     // Have the style sheet processor construct frame for the root
     // content object down
-    mFrameConstructor->ContentInserted(nsnull, root, 0,
-                                       nsnull, PR_FALSE);
+    mFrameConstructor->ContentInserted(nsnull, root, 0, nsnull);
     VERIFY_STYLE_TREE;
     MOZ_TIMER_DEBUGLOG(("Stop: Frame Creation: PresShell::InitialReflow(), this=%p\n",
                         (void*)this));
     MOZ_TIMER_STOP(mFrameCreationWatch);
 
     // Something in mFrameConstructor->ContentInserted may have caused
     // Destroy() to get called, bug 337586.
     NS_ENSURE_STATE(!mHaveShutDown);
@@ -4534,17 +4533,17 @@ PresShell::ContentInserted(nsIDocument* 
   NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
 
   if (!mDidInitialReflow) {
     return;
   }
   
   WillCauseReflow();
   mFrameConstructor->ContentInserted(aContainer, aChild,
-                                     aIndexInContainer, nsnull, PR_FALSE);
+                                     aIndexInContainer, nsnull);
   VERIFY_STYLE_TREE;
   DidCauseReflow();
 }
 
 void
 PresShell::ContentRemoved(nsIDocument *aDocument,
                           nsIContent* aContainer,
                           nsIContent* aChild,
new file mode 100644
--- /dev/null
+++ b/layout/reftests/ib-split/insert-into-split-inline-10-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+ <head>
+  <style>
+   body > span { border: 3px solid blue }
+   body > span > span { border: 3px solid cyan }
+  </style>
+ </head>
+ <body>
+  <span><span
+  ><span>One</span
+  ><span>Two</span
+  ><span>Three</span
+  ><div>Four</div
+  ><div>Five</div
+  ><span>Six</span
+  ><div>Seven</div
+  ><div>Eight</div
+  ><span>Nine</span
+  ><span>Ten</span
+ ></span></span>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/ib-split/insert-into-split-inline-10.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+ <head>
+  <script>
+   function doit() {
+     var newNode = document.createElement("span");
+     newNode.appendChild(document.createTextNode("Nine"));
+     document.getElementById("target").appendChild(newNode);
+   }
+  </script>
+  <style>
+   body > span { border: 3px solid blue }
+   body > span > span { border: 3px solid cyan }
+   body > span > span::after { content: "Ten" }
+  </style>
+ </head>
+ <body onload='doit()'>
+  <span><span id="target"
+  ><span>One</span
+  ><span>Two</span
+  ><span>Three</span
+  ><div>Four</div
+  ><div>Five</div
+  ><span>Six</span
+  ><div>Seven</div
+  ><div>Eight</div
+ ></span></span>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/ib-split/insert-into-split-inline-11-ref.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+ <head>
+  <style>
+   body > span { border: 3px solid blue }
+   body > span > span { border: 3px solid cyan }
+  </style>
+ </head>
+ <body>
+  <span
+  ><span
+   ><span>One</span
+   ><span>Two</span
+   ><span>Three</span
+   ><div>Four</div
+   ><div>Five</div
+   ><span>Six</span
+   ><div>Seven</div
+   ><div>Eight</div
+   ><span>Nine</span
+  ></span
+  ><div>Ten</div
+ ></span>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/ib-split/insert-into-split-inline-11.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+ <head>
+  <script>
+   function doit() {
+     var newNode = document.createElement("span");
+     newNode.appendChild(document.createTextNode("Nine"));
+     document.getElementById("target").appendChild(newNode);
+   }
+  </script>
+  <style>
+   body > span { border: 3px solid blue }
+   body > span > span { border: 3px solid cyan }
+  </style>
+ </head>
+ <body onload='doit()'>
+  <span
+  ><span id="target"
+   ><span>One</span
+   ><span>Two</span
+   ><span>Three</span
+   ><div>Four</div
+   ><div>Five</div
+   ><span>Six</span
+   ><div>Seven</div
+   ><div>Eight</div
+  ></span
+  ><div>Ten</div
+ ></span>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/ib-split/insert-into-split-inline-8c.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+ <head>
+  <script>
+   function doit() {
+     var newNode = document.createElement("span");
+     newNode.appendChild(document.createTextNode("One"));
+     document.getElementById("target")
+             .insertBefore(newNode, document.getElementById("insertion"));
+   }
+  </script>
+  <style>
+   body > span { border: 3px solid blue }
+  </style>
+ </head>
+ <body onload='doit()'>
+  <span id="target"
+  ><div id="insertion">Two</div
+  ><span>Three</span
+  ><div>Four</div
+  ><span>Five</span
+ ></span>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/ib-split/insert-into-split-inline-9-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+ <head>
+  <style>
+   body > span { border: 3px solid blue }
+   body > span > span { border: 3px solid cyan }
+  </style>
+ </head>
+ <body>
+  <span><span
+  ><span>One</span
+  ><span>Two</span
+  ><span>Three</span
+  ><div>Four</div
+  ><div>Five</div
+  ><span>Six</span
+  ><div>Seven</div
+  ><div>Eight</div
+  ><span>Nine</span
+ ></span></span>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/ib-split/insert-into-split-inline-9.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+ <head>
+  <script>
+   function doit() {
+     var newNode = document.createElement("span");
+     newNode.appendChild(document.createTextNode("Nine"));
+     document.getElementById("target").appendChild(newNode);
+   }
+  </script>
+  <style>
+   body > span { border: 3px solid blue }
+   body > span > span { border: 3px solid cyan }
+  </style>
+ </head>
+ <body onload='doit()'>
+  <span><span id="target"
+  ><span>One</span
+  ><span>Two</span
+  ><span>Three</span
+  ><div>Four</div
+  ><div>Five</div
+  ><span>Six</span
+  ><div>Seven</div
+  ><div>Eight</div
+ ></span></span>
+ </body>
+</html>
--- a/layout/reftests/ib-split/reftest.list
+++ b/layout/reftests/ib-split/reftest.list
@@ -27,8 +27,12 @@
 == insert-into-split-inline-2i.html insert-into-split-inline-2-ref.html
 == insert-into-split-inline-3.html insert-into-split-inline-3-ref.html
 == insert-into-split-inline-4.html insert-into-split-inline-4-ref.html
 == insert-into-split-inline-5.html insert-into-split-inline-5-ref.html
 == insert-into-split-inline-6.html insert-into-split-inline-6-ref.html
 == insert-into-split-inline-7.html insert-into-split-inline-7-ref.html
 == insert-into-split-inline-8a.html insert-into-split-inline-8-ref.html
 == insert-into-split-inline-8b.html insert-into-split-inline-8-ref.html
+== insert-into-split-inline-8c.html insert-into-split-inline-8-ref.html
+== insert-into-split-inline-9.html insert-into-split-inline-9-ref.html
+== insert-into-split-inline-10.html insert-into-split-inline-10-ref.html
+== insert-into-split-inline-11.html insert-into-split-inline-11-ref.html
--- a/layout/reftests/reftest.list
+++ b/layout/reftests/reftest.list
@@ -58,9 +58,9 @@ include z-index/reftest.list
  
 # columns/
 include columns/reftest.list
 
 # image-region/
 include image-region/reftest.list
 
 # block-inside-inline splits
-#include ib-split/reftest.list
+include ib-split/reftest.list
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -2986,16 +2986,19 @@ nsRuleNode::ComputeDisplayData(nsStyleSt
   if (generatedContent) {
     // According to CSS2 section 12.1, :before and :after
     // pseudo-elements must not be positioned or floated (CSS2 12.1) and
     // must be limited to certain display types (depending on the
     // display type of the element to which they are attached).
     // XXX These restrictions are no longer present in CSS2.1.  We
     // should ensure that we support removing them before doing so,
     // though.
+    // XXXbz For example, the calls to WipeContainingBlock in the
+    // frame constructor will need to be changedif we allow
+    // block-level generated content inside inlines.
 
     if (display->mPosition != NS_STYLE_POSITION_STATIC)
       display->mPosition = NS_STYLE_POSITION_STATIC;
     if (display->mFloats != NS_STYLE_FLOAT_NONE)
       display->mFloats = NS_STYLE_FLOAT_NONE;
 
     PRUint8 displayValue = display->mDisplay;
     if (displayValue != NS_STYLE_DISPLAY_NONE &&