Bug 480979 part 5. Build up a tree of FrameConstructionItems so that we'll know which inlines might need splitting. r+sr=roc
authorBoris Zbarsky <bzbarsky@mit.edu>
Thu, 05 Mar 2009 08:09:02 -0500
changeset 25772 e6fb3c02435647a85dc6675aeed3bdc799fe0c4f
parent 25771 8abc0e906ed8068fc971c035176eb79a1281eaf3
child 25773 159168c61b02ced694aed3e00708a6bd2b9b47fa
push id5734
push userbzbarsky@mozilla.com
push dateThu, 05 Mar 2009 13:11:32 +0000
treeherdermozilla-central@fb254bab5a82 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs480979
milestone1.9.2a1pre
Bug 480979 part 5. Build up a tree of FrameConstructionItems so that we'll know which inlines might need splitting. r+sr=roc
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsCSSFrameConstructor.h
layout/reftests/ib-split/float-inside-inline-between-blocks-1-ref.html
layout/reftests/ib-split/float-inside-inline-between-blocks-1.html
layout/reftests/ib-split/reftest.list
layout/reftests/ib-split/split-inner-inline-1-ref.html
layout/reftests/ib-split/split-inner-inline-1.html
layout/reftests/ib-split/table-pseudo-in-part3-1-ref.html
layout/reftests/ib-split/table-pseudo-in-part3-1.html
layout/reftests/reftest-sanity/div-ref.html
layout/reftests/reftest-sanity/div.html
layout/reftests/reftest-sanity/reftest.list
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -4765,17 +4765,17 @@ FindAncestorWithGeneratedContentPseudo(n
 #define FULL_CTOR_FCDATA(_flags, _func)                     \
   { _flags | FCDATA_FUNC_IS_FULL_CTOR, { nsnull }, _func }
 
 /* static */
 const nsCSSFrameConstructor::FrameConstructionData*
 nsCSSFrameConstructor::FindTextData(nsIFrame* aParentFrame)
 {
 #ifdef MOZ_SVG
-  if (aParentFrame->IsFrameOfType(nsIFrame::eSVG)) {
+  if (aParentFrame && aParentFrame->IsFrameOfType(nsIFrame::eSVG)) {
     nsIFrame *ancestorFrame =
       nsSVGUtils::GetFirstNonAAncestorFrame(aParentFrame);
     if (ancestorFrame) {
       nsISVGTextContentMetrics* metrics = do_QueryFrame(ancestorFrame);
       if (metrics) {
         static const FrameConstructionData sSVGGlyphData =
           SIMPLE_FCDATA(NS_NewSVGGlyphFrame);
         return &sSVGGlyphData;
@@ -5082,17 +5082,16 @@ nsCSSFrameConstructor::ConstructFrameFro
   NS_ASSERTION(!(bits & FCDATA_FUNC_IS_DATA_GETTER),
                "Should have dealt with this inside the data finder");
 
   // Some sets of bits are not compatible with each other
 #define CHECK_ONLY_ONE_BIT(_bit1, _bit2)               \
   NS_ASSERTION(!(bits & _bit1) || !(bits & _bit2),     \
                "Only one of these bits should be set")
   CHECK_ONLY_ONE_BIT(FCDATA_SKIP_FRAMEMAP, FCDATA_MAY_NEED_SCROLLFRAME);
-  CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_DISALLOW_OUT_OF_FLOW);
   CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_FORCE_NULL_ABSPOS_CONTAINER);
 #ifdef MOZ_MATHML
   CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_WRAP_KIDS_IN_BLOCKS);
 #endif
   CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_MAY_NEED_SCROLLFRAME);
   CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_IS_POPUP);
   CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_SKIP_ABSPOS_PUSH);
   CHECK_ONLY_ONE_BIT(FCDATA_FUNC_IS_FULL_CTOR, FCDATA_FORCE_VIEW);
@@ -5123,22 +5122,17 @@ nsCSSFrameConstructor::ConstructFrameFro
 
     newFrame =
       (*data->mFunc.mCreationFunc)(mPresShell, styleContext);
     if (!newFrame) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     PRBool allowOutOfFlow = !(bits & FCDATA_DISALLOW_OUT_OF_FLOW);
-#ifdef MOZ_XUL
-    PRBool isPopup = (bits & FCDATA_IS_POPUP) &&
-                     aParentFrame->GetType() != nsGkAtoms::menuFrame;
-#else
-    PRBool isPopup = PR_FALSE;
-#endif
+    PRBool isPopup = aItem.mIsPopup;
     NS_ASSERTION(!isPopup ||
                  (aState.mPopupItems.containingBlock &&
                   aState.mPopupItems.containingBlock->GetType() ==
                     nsGkAtoms::popupSetFrame),
                  "Should have a containing block here!");
 
     nsIFrame* geometricParent =
       isPopup ? aState.mPopupItems.containingBlock :
@@ -5791,17 +5785,17 @@ nsCSSFrameConstructor::FindDisplayData(c
   // Handle various inlines
   if (NS_STYLE_DISPLAY_INLINE == aDisplay->mDisplay ||
       NS_STYLE_DISPLAY_MARKER == aDisplay->mDisplay) {
     // To keep the hash table small don't add inline frames (they're
     // typically things like FONT and B), because we can quickly
     // find them if we need to.
     // XXXbz the "quickly" part is a bald-faced lie!
     static const FrameConstructionData sInlineData =
-      FULL_CTOR_FCDATA(FCDATA_SKIP_FRAMEMAP,
+      FULL_CTOR_FCDATA(FCDATA_SKIP_FRAMEMAP | FCDATA_IS_INLINE,
                        &nsCSSFrameConstructor::ConstructInline);
     return &sInlineData;
   }
 
   if (NS_STYLE_DISPLAY_TABLE == aDisplay->mDisplay ||
       NS_STYLE_DISPLAY_INLINE_TABLE == aDisplay->mDisplay) {
     static const FrameConstructionData sTableData =
       FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable);
@@ -6030,28 +6024,34 @@ nsCSSFrameConstructor::ResolveStyleConte
       // context to use, and pass it the style context for the
       // previous page's fixed-pos frame?
     }
   } else {
     // This has got to be a call from ConstructDocElementTableFrame.
     // Not sure how best to assert that here.
   }
 
+  return ResolveStyleContext(parentStyleContext, aContent);
+}
+
+already_AddRefed<nsStyleContext>
+nsCSSFrameConstructor::ResolveStyleContext(nsStyleContext* aParentStyleContext,
+                                           nsIContent* aContent)
+{
   nsStyleSet *styleSet = mPresShell->StyleSet();
 
   if (aContent->IsNodeOfType(nsINode::eELEMENT)) {
-    return styleSet->ResolveStyleFor(aContent, parentStyleContext);
-  } else {
-
-    NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
-                 "shouldn't waste time creating style contexts for "
-                 "comments and processing instructions");
-
-    return styleSet->ResolveStyleForNonElement(parentStyleContext);
-  }
+    return styleSet->ResolveStyleFor(aContent, aParentStyleContext);
+  }
+
+  NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
+               "shouldn't waste time creating style contexts for "
+               "comments and processing instructions");
+
+  return styleSet->ResolveStyleForNonElement(aParentStyleContext);
 }
 
 // MathML Mod - RBS
 #ifdef MOZ_MATHML
 nsresult
 nsCSSFrameConstructor::FlushAccumulatedBlock(nsFrameConstructorState& aState,
                                              nsIContent* aContent,
                                              nsIFrame* aParentFrame,
@@ -6241,37 +6241,40 @@ nsCSSFrameConstructor::FindSVGData(nsICo
                   FCDATA_SKIP_FRAMEMAP | FCDATA_DISALLOW_GENERATED_CONTENT,
                   NS_NewSVGOuterSVGFrame);
     return &sOuterSVGData;
   }
 
   // Special cases for text/tspan/textpath, because the kind of frame
   // they get depends on the parent frame.
   if (aTag == nsGkAtoms::text) {
+    NS_ASSERTION(aParentFrame, "Should have aParentFrame here");
     nsIFrame *ancestorFrame =
       nsSVGUtils::GetFirstNonAAncestorFrame(aParentFrame);
     if (ancestorFrame) {
       nsISVGTextContentMetrics* metrics = do_QueryFrame(ancestorFrame);
       // Text cannot be nested
       if (metrics) {
         return &sGenericContainerData;
       }
     }
   }
   else if (aTag == nsGkAtoms::tspan) {
+    NS_ASSERTION(aParentFrame, "Should have aParentFrame here");
     nsIFrame *ancestorFrame =
       nsSVGUtils::GetFirstNonAAncestorFrame(aParentFrame);
     if (ancestorFrame) {
       nsISVGTextContentMetrics* metrics = do_QueryFrame(ancestorFrame);
       if (!metrics) {
         return &sGenericContainerData;
       }
     }
   }
   else if (aTag == nsGkAtoms::textPath) {
+    NS_ASSERTION(aParentFrame, "Should have aParentFrame here");
     nsIFrame *ancestorFrame =
       nsSVGUtils::GetFirstNonAAncestorFrame(aParentFrame);
     if (!ancestorFrame ||
         ancestorFrame->GetType() != nsGkAtoms::svgTextFrame) {
       return &sGenericContainerData;
     }
   }
 
@@ -6281,18 +6284,19 @@ nsCSSFrameConstructor::FindSVGData(nsICo
     SIMPLE_SVG_CREATE(polygon, NS_NewSVGPathGeometryFrame),
     SIMPLE_SVG_CREATE(polyline, NS_NewSVGPathGeometryFrame),
     SIMPLE_SVG_CREATE(circle, NS_NewSVGPathGeometryFrame),
     SIMPLE_SVG_CREATE(ellipse, NS_NewSVGPathGeometryFrame),
     SIMPLE_SVG_CREATE(line, NS_NewSVGPathGeometryFrame),
     SIMPLE_SVG_CREATE(rect, NS_NewSVGPathGeometryFrame),
     SIMPLE_SVG_CREATE(path, NS_NewSVGPathGeometryFrame),
     SIMPLE_SVG_CREATE(defs, NS_NewSVGContainerFrame),
-    COMPLEX_TAG_CREATE(foreignObject,
-                       &nsCSSFrameConstructor::ConstructSVGForeignObjectFrame),
+    { &nsGkAtoms::foreignObject,
+      FULL_CTOR_FCDATA(FCDATA_DISALLOW_OUT_OF_FLOW,
+                       &nsCSSFrameConstructor::ConstructSVGForeignObjectFrame) },
     SIMPLE_SVG_CREATE(a, NS_NewSVGAFrame),
     SIMPLE_SVG_CREATE(text, NS_NewSVGTextFrame),
     SIMPLE_SVG_CREATE(tspan, NS_NewSVGTSpanFrame),
     SIMPLE_SVG_CREATE(linearGradient, NS_NewSVGLinearGradientFrame),
     SIMPLE_SVG_CREATE(radialGradient, NS_NewSVGRadialGradientFrame),
     SIMPLE_SVG_CREATE(stop, NS_NewSVGStopFrame),
     SIMPLE_SVG_CREATE(use, NS_NewSVGUseFrame),
     SIMPLE_SVG_CREATE(marker, NS_NewSVGMarkerFrame),
@@ -6403,16 +6407,20 @@ nsCSSFrameConstructor::AddPageBreakItem(
   // Use the same parent style context that |aMainStyleContext| has, since
   // that's easier to re-resolve and it doesn't matter in practice.
   // (Getting different parents can result in framechange hints, e.g.,
   // for user-modify.)
   pseudoStyle =
     mPresShell->StyleSet()->
       ResolvePseudoStyleFor(nsnull, nsCSSAnonBoxes::pageBreak,
                             aMainStyleContext->GetParent());
+
+  NS_ASSERTION(pseudoStyle->GetStyleDisplay()->mDisplay ==
+                 NS_STYLE_DISPLAY_BLOCK, "Unexpected display");
+
   FrameConstructionItem* item = aItems.AppendElement();
   if (!item) {
     return;
   }
 
   static const FrameConstructionData sPageBreakData =
     FCDATA_DECL(FCDATA_SKIP_FRAMEMAP, NS_NewPageBreakFrame);
 
@@ -6421,16 +6429,18 @@ nsCSSFrameConstructor::AddPageBreakItem(
   // Lie about the tag and namespace so we don't trigger anything
   // interesting during frame construction.
   item->mTag = nsCSSAnonBoxes::pageBreak;
   item->mNameSpaceID = kNameSpaceID_None;
   item->mStyleContext.swap(pseudoStyle);
   item->mIsText = PR_FALSE;
   item->mIsGeneratedContent = PR_FALSE;
   item->mIsRootPopupgroup = PR_FALSE;
+  item->mIsAllInline = PR_FALSE;
+  item->mIsPopup = PR_FALSE;
 }
 
 nsresult
 nsCSSFrameConstructor::ConstructFrame(nsFrameConstructorState& aState,
                                       nsIContent*              aContent,
                                       nsIFrame*                aParentFrame,
                                       nsFrameItems&            aFrameItems)
 
@@ -6505,32 +6515,33 @@ nsCSSFrameConstructor::AddFrameConstruct
                                            display->mBinding->mOriginPrincipal,
                                            PR_FALSE,
                                            getter_AddRefs(binding.mBinding),
                                            &resolveStyle);
     if (NS_FAILED(rv))
       return;
 
     if (resolveStyle) {
-      styleContext = ResolveStyleContext(aParentFrame, aContent);
+      styleContext = ResolveStyleContext(styleContext->GetParent(), aContent);
       display = styleContext->GetStyleDisplay();
       aStyleContext = styleContext;
     }
 
     aTag = mDocument->BindingManager()->ResolveTag(aContent, &aNameSpaceID);
   }
 
   // Pre-check for display "none" - if we find that, don't create
   // any frame at all
   if (NS_STYLE_DISPLAY_NONE == display->mDisplay) {
     aState.mFrameManager->SetUndisplayedContent(aContent, styleContext);
     return;
   }
 
   PRBool isText = aContent->IsNodeOfType(nsINode::eTEXT);
+  PRBool isPopup = PR_FALSE;
   // Try to find frame construction data for this content
   const FrameConstructionData* data;
   if (isText) {
     data = FindTextData(aParentFrame);
 #ifdef MOZ_SVG
     if (!data) {
       // Nothing to do here; suppressed text inside SVG
       return;
@@ -6578,37 +6589,43 @@ nsCSSFrameConstructor::AddFrameConstruct
     NS_ASSERTION(data, "Should have frame construction data now");
 
     if (data->mBits & FCDATA_SUPPRESS_FRAME) {
       return;
     }
 
 #ifdef MOZ_XUL
     if ((data->mBits & FCDATA_IS_POPUP) &&
-        aParentFrame->GetType() != nsGkAtoms::menuFrame &&
-        !aState.mPopupItems.containingBlock &&
-        !aState.mHavePendingPopupgroup) {
-      return;
+        (!aParentFrame || // Parent is inline
+         aParentFrame->GetType() != nsGkAtoms::menuFrame)) {
+      if (!aState.mPopupItems.containingBlock &&
+          !aState.mHavePendingPopupgroup) {
+        return;
+      }
+
+      isPopup = PR_TRUE;
     }
 #endif /* MOZ_XUL */
   }
 
+  PRUint32 bits = data->mBits;
+
   // Inside colgroups, suppress everything except columns.
   if (aParentFrame &&
       aParentFrame->GetType() == nsGkAtoms::tableColGroupFrame &&
-      (!(data->mBits & FCDATA_IS_TABLE_PART) ||
+      (!(bits & FCDATA_IS_TABLE_PART) ||
        display->mDisplay != NS_STYLE_DISPLAY_TABLE_COLUMN)) {
     return;
   }
 
   PRBool canHavePageBreak =
     (aFlags & ITEM_ALLOW_PAGE_BREAK) &&
     aState.mPresContext->IsPaginated() &&
     !display->IsAbsolutelyPositioned() &&
-    !(data->mBits & FCDATA_IS_TABLE_PART);
+    !(bits & FCDATA_IS_TABLE_PART);
 
   if (canHavePageBreak && display->mBreakBefore) {
     AddPageBreakItem(aContent, aStyleContext, aItems);
   }
 
   PRBool isGeneratedContent = ((aFlags & ITEM_IS_GENERATED_CONTENT) != 0);
 
   FrameConstructionItem* item = aItems.AppendElement();
@@ -6630,20 +6647,51 @@ nsCSSFrameConstructor::AddFrameConstruct
     NS_ADDREF(item->mContent);
   }
   item->mIsRootPopupgroup =
     aNameSpaceID == kNameSpaceID_XUL && aTag == nsGkAtoms::popupgroup &&
     aContent->IsRootOfNativeAnonymousSubtree();
   if (item->mIsRootPopupgroup) {
     aState.mHavePendingPopupgroup = PR_TRUE;
   }
+  item->mIsPopup = isPopup;
 
   if (canHavePageBreak && display->mBreakAfter) {
     AddPageBreakItem(aContent, aStyleContext, aItems);
   }
+
+  if (bits & FCDATA_IS_INLINE) {
+    // To correctly set item->mIsAllInline we need to build up our child items
+    // right now.
+    BuildInlineChildItems(aState, *item);
+  } else {
+    item->mIsAllInline =
+      // Table-internal things are inline-outside if they're kids of
+      // inlines, since they'll trigger construction of inline-table
+      // pseudos.
+      ((bits & FCDATA_IS_TABLE_PART) &&
+       (!aParentFrame || // No aParentFrame means inline
+        aParentFrame->GetStyleDisplay()->mDisplay == NS_STYLE_DISPLAY_INLINE)) ||
+      // Things that are inline-outside but aren't inline frames are inline
+      display->IsInlineOutside() ||
+      // Things that we're guaranteed will end up out-of-flow are inline.  This
+      // is not a precise test, since one of our ancestor inlines might add an
+      // absolute containing block (if it's relatively positioned) or float
+      // containing block (the latter if it gets split by child blocks on both
+      // sides of us) when there wasn't such a containining block before.  But
+      // it's conservative in the sense that anything that will really end up
+      // as an in-flow non-inline will have false mIsAllInline.  It just might
+      // be that even an inline that has mIsAllInline false doesn't need an
+      // {ib} split.  So this is just an optimization to keep from doint to
+      // much work when that happens.
+      (!(bits & FCDATA_DISALLOW_OUT_OF_FLOW) &&
+       aState.GetGeometricParent(display, nsnull)) ||
+      // Popups that are certainly out of flow.
+      isPopup;
+  }
 }
 
 static void DestroyContent(void *aObject,
                            nsIAtom *aPropertyName,
                            void *aPropertyValue,
                            void *aData)
 {
   nsIContent* content = static_cast<nsIContent*>(aPropertyValue);
@@ -10167,16 +10215,51 @@ nsCSSFrameConstructor::ShouldHaveSpecial
                                                    PRBool* aHaveFirstLineStyle)
 {
   *aHaveFirstLetterStyle =
     ShouldHaveFirstLetterStyle(aContent, aStyleContext);
   *aHaveFirstLineStyle =
     ShouldHaveFirstLineStyle(aContent, aStyleContext);
 }
 
+nsresult
+nsCSSFrameConstructor::ConstructFramesFromItemSublist(nsFrameConstructorState& aState,
+                                                      nsTArray<FrameConstructionItem>& aItems,
+                                                      PRUint32 aStart,
+                                                      PRUint32 aEnd,
+                                                      nsIFrame* aParentFrame,
+                                                      nsFrameItems& aFrameItems)
+{
+  NS_PRECONDITION(aStart <= aEnd, "Bogus start or end");
+  NS_PRECONDITION(aEnd <= aItems.Length(), "Bogus end");
+
+  // save the incoming pseudo frame state
+  nsPseudoFrames priorPseudoFrames;
+  aState.mPseudoFrames.Reset(&priorPseudoFrames);
+
+  for (PRUint32 i = aStart; i < aEnd; ++i) {
+    nsresult rv =
+      ConstructFramesFromItem(aState, aItems[i], aParentFrame, aFrameItems);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  NS_ASSERTION(!aState.mHavePendingPopupgroup,
+               "Should have proccessed it by now");
+
+  // process the current pseudo frame state
+  if (!aState.mPseudoFrames.IsEmpty()) {
+    ProcessPseudoFrames(aState, aFrameItems);
+  }
+
+  // restore the incoming pseudo frame state
+  aState.mPseudoFrames = priorPseudoFrames;
+
+  return NS_OK;
+}
+
 /**
  * Request to process the child content elements and create frames.
  *
  * @param   aContent the content object whose child elements to process
  * @param   aFrame the frame associated with aContent. This will be the
  *            parent frame (both content and geometric) for the flowed
  *            child frames
  */
@@ -10207,20 +10290,16 @@ nsCSSFrameConstructor::ProcessChildren(n
   nsFrameConstructorSaveState floatSaveState;
   if (aFrame->IsFrameOfType(nsIFrame::eMathML) ||
       aFrame->IsBoxFrame()) {
     aState.PushFloatContainingBlock(nsnull, floatSaveState);
   } else if (aFrame->IsFloatContainingBlock()) {
     aState.PushFloatContainingBlock(aFrame, floatSaveState);
   }
 
-  // save the incoming pseudo frame state
-  nsPseudoFrames priorPseudoFrames;
-  aState.mPseudoFrames.Reset(&priorPseudoFrames);
-
   nsAutoTArray<FrameConstructionItem, 16> itemsToConstruct;
   nsresult rv = NS_OK;
 
   if (aFrame == mRootElementFrame) {
     // Create any anonymous frames the initial containing block frame requires.
     // This must happen before the rest of ProcessChildren to ensure that
     // popups are never constructed before the popupset.
     nsAutoTArray<nsIContent*, 4> anonymousItems;
@@ -10282,32 +10361,20 @@ nsCSSFrameConstructor::ProcessChildren(n
                    "CreateAnonymousFrames manually and not follow the standard "
                    "ProcessChildren() codepath for this frame");
 #endif
       AddFrameConstructionItems(aState, anonymousItems[i], aFrame,
                                 itemsToConstruct);
     }
   }
 
-  for (PRUint32 i = 0; i < itemsToConstruct.Length(); ++i) {
-    rv = ConstructFramesFromItem(aState, itemsToConstruct[i], aFrame,
-                                 aFrameItems);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  NS_ASSERTION(!aState.mHavePendingPopupgroup,
-               "Should have proccessed it by now");
-
-  // process the current pseudo frame state
-  if (!aState.mPseudoFrames.IsEmpty()) {
-    ProcessPseudoFrames(aState, aFrameItems);
-  }
-
-  // restore the incoming pseudo frame state
-  aState.mPseudoFrames = priorPseudoFrames;
+  rv = ConstructFramesFromItemSublist(aState, itemsToConstruct, 0,
+                                      itemsToConstruct.Length(), aFrame,
+                                      aFrameItems);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ASSERTION(!aAllowBlockStyles || !aFrame->IsBoxFrame(),
                "can't be both block and box");
 
   if (haveFirstLetterStyle) {
     rv = WrapFramesInFirstLetterFrame(aContent, aFrame, aFrameItems);
   }
   if (haveFirstLineStyle) {
@@ -11479,23 +11546,38 @@ nsCSSFrameConstructor::ConstructInline(n
   if (positioned) {                            
     // Relatively positioned frames becomes a container for child
     // frames that are positioned
     aState.PushAbsoluteContainingBlock(newFrame, absoluteSaveState);
   }
 
   // Process the child content
   nsFrameItems childItems;
-  PRBool kidsAllInline;
-  nsresult rv = ProcessInlineChildren(aState, content, newFrame, PR_TRUE,
-                                      childItems, &kidsAllInline);
-  if (kidsAllInline) {
-    // Set the inline frame's initial child list
-    CreateAnonymousFrames(aState, content, newFrame, childItems);
-
+  nsresult rv = ConstructFramesFromItemSublist(aState, aItem.mChildItems, 0,
+                                               aItem.mChildItems.Length(),
+                                               newFrame, childItems);
+  if (NS_FAILED(rv)) {
+    // Clean up?
+    return rv;
+  }
+
+  nsIFrame* list1 = childItems.childList;
+  nsIFrame* prevToFirstBlock;
+  nsIFrame* list2;
+
+  if (aItem.mIsAllInline ||
+      // Note: This really is meant to be an assignment to list2 followed by a
+      // test of !list2.
+      !(list2 = FindFirstBlock(list1, &prevToFirstBlock))) {
+    // This part is easy.  We either already know we have no non-inline kids,
+    // or haven't found any when constructing actual frames (the latter can
+    // happen only if out-of-flows that we thought had no containing block
+    // acquired one when ancestor inline frames and {ib} splits got
+    // constructed).  Just put all the kids into the single inline frame and
+    // bail.
     newFrame->SetInitialChildList(nsnull, childItems.childList);
     if (NS_SUCCEEDED(rv)) {
       aState.AddChild(newFrame, aFrameItems, content, styleContext, aParentFrame);
       *aNewFrame = newFrame;
     }
     return rv;
   }
 
@@ -11504,19 +11586,16 @@ nsCSSFrameConstructor::ConstructInline(n
   // as a result of this 3 lists of children. The first list contains
   // all of the inline children that precede the first block child
   // (and may be empty). The second list contains all of the block
   // children and any inlines that are between them (and must not be
   // empty, otherwise - why are we here?). The final list contains all
   // of the inline children that follow the final block child.
 
   // Find the first block child which defines list1 and list2
-  nsIFrame* list1 = childItems.childList;
-  nsIFrame* prevToFirstBlock;
-  nsIFrame* list2 = FindFirstBlock(list1, &prevToFirstBlock);
   if (prevToFirstBlock) {
     prevToFirstBlock->SetNextSibling(nsnull);
   }
   else {
     list1 = nsnull;
   }
 
   // Find the last block child which defines the end of list2 and the
@@ -11659,102 +11738,66 @@ nsCSSFrameConstructor::MoveFramesToEndOf
     aExistingEndFrame->SetInitialChildList(nsnull, aFramesToMove);
   } else {
     aExistingEndFrame->InsertFrames(nsnull, nsnull, aFramesToMove);
   }
   nsFrameConstructorState* startState = aTargetState ? &aState : nsnull;
   MoveChildrenTo(aState.mFrameManager, aExistingEndFrame, aFramesToMove,
                  existingFirstChild, aTargetState, startState);
 }
- 
-nsresult
-nsCSSFrameConstructor::ProcessInlineChildren(nsFrameConstructorState& aState,
-                                             nsIContent*              aContent,
-                                             nsIFrame*                aFrame,
-                                             PRBool                   aCanHaveGeneratedContent,
-                                             nsFrameItems&            aFrameItems,
-                                             PRBool*                  aKidsAllInline)
-{
-  nsresult rv = NS_OK;
-  nsStyleContext* styleContext = nsnull;
-
-  // save the pseudo frame state 
-  nsPseudoFrames prevPseudoFrames; 
-  aState.mPseudoFrames.Reset(&prevPseudoFrames);
-
-  nsAutoTArray<FrameConstructionItem, 16> itemsToConstruct;
-
-  if (aCanHaveGeneratedContent) {
-    // Probe for generated content before
-    styleContext = aFrame->GetStyleContext();
-    CreateGeneratedContentItem(aState, aFrame, aContent,
-                               styleContext, nsCSSPseudoElements::before,
-                               itemsToConstruct);
-  }
-
-  // Iterate the child content objects and construct frames
-  PRBool allKidsInline = PR_TRUE;
+
+void
+nsCSSFrameConstructor::BuildInlineChildItems(nsFrameConstructorState& aState,
+                                             FrameConstructionItem& aParentItem)
+{
+  // XXXbz should we preallocate aParentItem.mChildItems to some sane
+  // length?  Maybe even to parentContent->GetChildCount()?
+
+  // Probe for generated content before
+  nsStyleContext* const parentStyleContext = aParentItem.mStyleContext;
+  nsIContent* const parentContent = aParentItem.mContent;
+  CreateGeneratedContentItem(aState, nsnull, parentContent,
+                             parentStyleContext, nsCSSPseudoElements::before,
+                             aParentItem.mChildItems);
+
   ChildIterator iter, last;
-  for (ChildIterator::Init(aContent, &iter, &last);
+  for (ChildIterator::Init(parentContent, &iter, &last);
        iter != last;
        ++iter) {
-    // Construct a child frame
-    AddFrameConstructionItems(aState, *iter, aFrame, itemsToConstruct);
-  }
-
-  if (aCanHaveGeneratedContent) {
-    // Probe for generated content after
-    CreateGeneratedContentItem(aState, aFrame, aContent,
-                               styleContext, nsCSSPseudoElements::after,
-                               itemsToConstruct);
-  }
-
-  for (PRUint32 i = 0; i < itemsToConstruct.Length(); ++i) {
-    nsIFrame* oldLastChild = aFrameItems.lastChild;
-
-    rv = ConstructFramesFromItem(aState, itemsToConstruct[i], aFrame,
-                                 aFrameItems);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // Examine newly added children (we may have added more than one
-    // child if the child was another inline frame that ends up
-    // being carved in 3 pieces) to maintain the allKidsInline flag.
-    if (allKidsInline) {
-      nsIFrame* kid;
-      if (oldLastChild) {
-        kid = oldLastChild->GetNextSibling();
-      }
-      else {
-        kid = aFrameItems.childList;
-      }
-      while (kid) {
-        if (!IsInlineOutside(kid)) {
-          allKidsInline = PR_FALSE;
-          break;
-        }
-        kid = kid->GetNextSibling();
-      }
-    }
-  }
-
-  // process the current pseudo frame state
-  if (!aState.mPseudoFrames.IsEmpty()) {
-    ProcessPseudoFrames(aState, aFrameItems);
-    // recompute allKidsInline to take into account new child frames
-    // XXX we DON'T do this yet because anonymous table children should
-    // be accepted as inline children, until we turn on inline-table.
-    // See bug 297537.
-    // allKidsInline = AreAllKidsInline(aFrameItems.childList);
-  }
-  // restore the pseudo frame state
-  aState.mPseudoFrames = prevPseudoFrames;
-
-  *aKidsAllInline = allKidsInline;
-
-  return rv;
+    // Manually check for comments/PIs, since we do't have a frame to pass to
+    // AddFrameConstructionItems.  We know our parent is a non-replaced inline,
+    // so there is no need to do the NeedFrameFor check.
+    nsIContent* content = *iter;
+    if (content->IsNodeOfType(nsINode::eCOMMENT) ||
+        content->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
+      continue;
+    }
+
+    nsRefPtr<nsStyleContext> childContext =
+      ResolveStyleContext(parentStyleContext, content);
+
+    AddFrameConstructionItemsInternal(aState, content, nsnull, content->Tag(),
+                                      content->GetNameSpaceID(), childContext,
+                                      ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK,
+                                      aParentItem.mChildItems);
+  }
+
+  // Probe for generated content after
+  CreateGeneratedContentItem(aState, nsnull, parentContent,
+                             parentStyleContext, nsCSSPseudoElements::after,
+                             aParentItem.mChildItems);
+
+  aParentItem.mIsAllInline = PR_TRUE;
+  for (PRUint32 i = 0, count = aParentItem.mChildItems.Length();
+       i < count; ++i) {
+    if (!aParentItem.mChildItems[i].mIsAllInline) {
+      aParentItem.mIsAllInline = PR_FALSE;
+      break;
+    }
+  }
 }
 
 static void
 DestroyNewlyCreatedFrames(nsFrameConstructorState& aState,
                           nsIFrame* aParentFrame,
                           const nsFrameItems& aFrameList)
 {
   // Ok, reverse tracks: wipe out the frames we just created
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -311,16 +311,19 @@ private:
                                 nsIFrame*                      aParentFrame,
                                 nsIFrame*                      aPrevInFlow,
                                 nsIFrame*                      aNewFrame,
                                 PRBool                         aAllowCounters = PR_TRUE);
 
   already_AddRefed<nsStyleContext>
   ResolveStyleContext(nsIFrame*         aParentFrame,
                       nsIContent*       aContent);
+  already_AddRefed<nsStyleContext>
+  ResolveStyleContext(nsStyleContext* aParentStyleContext,
+                      nsIContent* aContent);
 
   nsresult ConstructFrame(nsFrameConstructorState& aState,
                           nsIContent*              aContent,
                           nsIFrame*                aParentFrame,
                           nsFrameItems&            aFrameItems);
 
   // Add the frame construction items for the given aContent and aParentFrame
   // to the list.  This might add more than one item in some rare cases.
@@ -378,16 +381,17 @@ private:
    * @param aStyleContext is the 'before' or 'after' pseudo-element
    * style context
    * @param aContentIndex is the index of the content item to create
    */
   already_AddRefed<nsIContent> CreateGeneratedContent(nsIContent*     aParentContent,
                                                       nsStyleContext* aStyleContext,
                                                       PRUint32        aContentIndex);
 
+  // aFrame may be null; this method doesn't use it directly in any case.
   void CreateGeneratedContentItem(nsFrameConstructorState& aState,
                                   nsIFrame*                aFrame,
                                   nsIContent*              aContent,
                                   nsStyleContext*          aStyleContext,
                                   nsIAtom*                 aPseudoElement,
                                   nsTArray<FrameConstructionItem>& aItems);
 
   // This method can change aFrameList: it can chop off the end and
@@ -606,18 +610,19 @@ private:
      FrameConstructionData is a getter function that can be used to get the
      actual FrameConstructionData to use. */
 #define FCDATA_FUNC_IS_DATA_GETTER 0x2
   /* If the FCDATA_FUNC_IS_FULL_CTOR bit is set, then the FrameConstructionData
      has an mFullConstructor.  In this case, there is no relevant mData or
      mFunc */
 #define FCDATA_FUNC_IS_FULL_CTOR 0x4
   /* If FCDATA_DISALLOW_OUT_OF_FLOW is set, do not allow the frame to
-     float or be absolutely positioned.  This cannot be used with
-     FCDATA_FUNC_IS_FULL_CTOR */
+     float or be absolutely positioned.  This can also be used with
+     FCDATA_FUNC_IS_FULL_CTOR to indicate what the full-constructor
+     function will do. */
 #define FCDATA_DISALLOW_OUT_OF_FLOW 0x8
   /* If FCDATA_FORCE_NULL_ABSPOS_CONTAINER is set, make sure to push a
      null absolute containing block before processing children for this
      frame.  If this is not set, the frame will be pushed as the
      absolute containing block as needed, based on its style */
 #define FCDATA_FORCE_NULL_ABSPOS_CONTAINER 0x10
 #ifdef MOZ_MATHML
   /* If FCDATA_WRAP_KIDS_IN_BLOCKS is set, the inline kids of the frame
@@ -650,16 +655,19 @@ private:
   /* If FCDATA_DISALLOW_GENERATED_CONTENT is set, then don't allow generated
      content when processing kids of this frame.  This should not be used with
      FCDATA_FUNC_IS_FULL_CTOR */
 #define FCDATA_DISALLOW_GENERATED_CONTENT 0x800
   /* If FCDATA_IS_TABLE_PART is set, then the frame is some sort of
      table-related thing and we should not attempt to fetch a table-cell parent
      for it if it's inside another table-related frame. */
 #define FCDATA_IS_TABLE_PART 0x1000
+  /* If FCDATA_IS_INLINE is set, then the frame is a non-replaced CSS
+     inline box. */
+#define FCDATA_IS_INLINE 0x2000
 
   /* Structure representing information about how a frame should be
      constructed.  */
   struct FrameConstructionData {
     // Flag bits that can modify the way the construction happens
     PRUint32 mBits;
     // We have exactly one of three types of functions, so use a union for
     // better cache locality for the ones that aren't pointer-to-member.  That
@@ -742,16 +750,28 @@ private:
     nsRefPtr<nsStyleContext> mStyleContext;
     // Whether this is a text content item.
     PRPackedBool mIsText;
     // Whether this is generated content.  If it is, mContent is a strong
     // pointer.
     PRPackedBool mIsGeneratedContent;
     // Whether this is an item for the root popupgroup.
     PRPackedBool mIsRootPopupgroup;
+    // Whether construction from this item will create only frames that are
+    // IsInlineOutside() in the principal child list.
+    PRPackedBool mIsAllInline;
+    // Whether construction from this item will create a popup that needs to
+    // go into the global popup items.
+    PRPackedBool mIsPopup;
+
+    // Child frame construction items.
+    // Can't be an auto array, since we don't know our size yet, and
+    // in any case it would be bad if someone tried to do that...
+    // Only used for inline frame items.
+    nsTArray<FrameConstructionItem> mChildItems;
 
   private:
     FrameConstructionItem(const FrameConstructionItem& aOther); /* not implemented */
   };
 
   /**
    * Function to adjust aParentFrame and aFrameItems to deal with table
    * pseudo-frames that may have to be inserted.
@@ -819,32 +839,36 @@ private:
   // handles the kids of the fieldset
   nsresult ConstructFieldSetFrame(nsFrameConstructorState& aState,
                                   FrameConstructionItem&   aItem,
                                   nsIFrame*                aParentFrame,
                                   const nsStyleDisplay*    aStyleDisplay,
                                   nsFrameItems&            aFrameItems,
                                   nsIFrame**               aNewFrame);
 
+  // aParentFrame might be null.  If it is, that means it was an
+  // inline frame.
   static const FrameConstructionData* FindTextData(nsIFrame* aParentFrame);
 
   nsresult ConstructTextFrame(const FrameConstructionData* aData,
                               nsFrameConstructorState& aState,
                               nsIContent*              aContent,
                               nsIFrame*                aParentFrame,
                               nsStyleContext*          aStyleContext,
                               nsFrameItems&            aFrameItems,
                               PRBool                   aPseudoParent);
 
   void AddPageBreakItem(nsIContent* aContent,
                         nsStyleContext* aMainStyleContext,
                         nsTArray<FrameConstructionItem>& aItems);
 
   // Function to find FrameConstructionData for aContent.  Will return
   // null if aContent is not HTML.
+  // aParentFrame might be null.  If it is, that means it was an
+  // inline frame.
   static const FrameConstructionData* FindHTMLData(nsIContent* aContent,
                                                    nsIAtom* aTag,
                                                    PRInt32 aNameSpaceID,
                                                    nsIFrame* aParentFrame,
                                                    nsStyleContext* aStyleContext);
   // HTML data-finding helper functions
   static const FrameConstructionData*
     FindImgData(nsIContent* aContent, nsStyleContext* aStyleContext);
@@ -877,16 +901,18 @@ private:
   /* Allow xbl:base to affect the tag/namespace used. */
 #define ITEM_ALLOW_XBL_BASE 0x1
   /* Allow page-break before and after items to be created if the
      style asks for them. */
 #define ITEM_ALLOW_PAGE_BREAK 0x2
   /* The item is a generated content item. */
 #define ITEM_IS_GENERATED_CONTENT 0x4
   // The guts of AddFrameConstructionItems
+  // aParentFrame might be null.  If it is, that means it was an
+  // inline frame.
   void AddFrameConstructionItemsInternal(nsFrameConstructorState& aState,
                                          nsIContent*              aContent,
                                          nsIFrame*                aParentFrame,
                                          nsIAtom*                 aTag,
                                          PRInt32                  aNameSpaceID,
                                          nsStyleContext*          aStyleContext,
                                          PRUint32                 aFlags,
                                          nsTArray<FrameConstructionItem>& aItems);
@@ -1197,22 +1223,35 @@ private:
    * XXXbz test float reparenting?
    */
   void MoveFramesToEndOfIBSplit(nsFrameConstructorState& aState,
                                 nsIFrame* aExistingEndFrame,
                                 nsIFrame* aFramesToMove,
                                 nsIFrame* aBlockPart,
                                 nsFrameConstructorState* aTargetState);
 
-  nsresult ProcessInlineChildren(nsFrameConstructorState& aState,
-                                 nsIContent*              aContent,
-                                 nsIFrame*                aFrame,
-                                 PRBool                   aCanHaveGeneratedContent,
-                                 nsFrameItems&            aFrameItems,
-                                 PRBool*                  aKidsAllInline);
+  /**
+   * For an inline aParentItem, construct its list of child
+   * FrameConstructionItems and set its mIsAllInline flag appropriately.
+   */
+  void BuildInlineChildItems(nsFrameConstructorState& aState,
+                             FrameConstructionItem& aParentItem);
+
+  /**
+   * Construct frames for the indicated range of aItems (half-open; closed on
+   * the aStart end, open on the aEnd end), and put the resulting frames in
+   * aFrameItems.  This function will save pseudoframes on entry and restore on
+   * exit.
+   */
+  nsresult ConstructFramesFromItemSublist(nsFrameConstructorState& aState,
+                                          nsTArray<FrameConstructionItem>& aItems,
+                                          PRUint32 aStart,
+                                          PRUint32 aEnd,
+                                          nsIFrame* aParentFrame,
+                                          nsFrameItems& aFrameItems);
 
   // 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
new file mode 100644
--- /dev/null
+++ b/layout/reftests/ib-split/float-inside-inline-between-blocks-1-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <div style="position: relative; left: 100px">
+      <div>
+        aaa
+      </div>
+      <span style="float: left">bbb</span>
+      <div>
+        aaa
+      </div>
+    </div>
+  </body>
+</html> 
new file mode 100644
--- /dev/null
+++ b/layout/reftests/ib-split/float-inside-inline-between-blocks-1.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <span style="position: relative; left: 100px">
+      <span style="display: block">
+        aaa
+      </span>
+      <span style="float: left">bbb</span>
+      <span style="display: block">
+        aaa
+      </span>
+    </span>
+  </body>
+</html> 
--- a/layout/reftests/ib-split/reftest.list
+++ b/layout/reftests/ib-split/reftest.list
@@ -31,8 +31,11 @@
 == 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
+== float-inside-inline-between-blocks-1.html float-inside-inline-between-blocks-1-ref.html
+== table-pseudo-in-part3-1.html table-pseudo-in-part3-1-ref.html
+== split-inner-inline-1.html split-inner-inline-1-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/ib-split/split-inner-inline-1-ref.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <span>First line</span>
+    <div>Second line</div>
+    <span>Third line, yes</span>
+  </body>
+</html> 
new file mode 100644
--- /dev/null
+++ b/layout/reftests/ib-split/split-inner-inline-1.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <span>
+      First
+      <span>
+        line
+        <span style="display: block">
+          Second line
+        </span>
+        Third
+      </span>
+      line, yes
+    </span>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/ib-split/table-pseudo-in-part3-1-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <head>
+  </head>
+  <body>
+    <div>
+      aaa
+      <div>bbb</div>
+    </div>
+  </body>
+</html> 
new file mode 100644
--- /dev/null
+++ b/layout/reftests/ib-split/table-pseudo-in-part3-1.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+  <head>
+  </head>
+  <body>
+    <span style="display: table-row">
+      <span>
+        aaa
+        <span style="display: block"></span>
+        <span style="display: table-cell">bbb</span>
+      </span>
+    </span>
+  </body>
+</html> 
new file mode 100644
--- /dev/null
+++ b/layout/reftests/reftest-sanity/div-ref.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <span style="display:block">aaa</span>
+    <span style="display:block">bbb</span>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/reftest-sanity/div.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <div>aaa</div>
+    <div>bbb</div>
+  </body>
+</html>
+  
--- a/layout/reftests/reftest-sanity/reftest.list
+++ b/layout/reftests/reftest-sanity/reftest.list
@@ -47,8 +47,11 @@ fails-if(xulRuntime.OS!="Darwin") == dat
 
 # test parsing of asserts() expressions
 asserts(0) load about:blank
 asserts(0-5) load about:blank
 asserts-if(true,0) load about:blank
 asserts-if(false,7) load about:blank
 asserts-if(true,0-4) load about:blank
 asserts-if(false,6-8) load about:blank
+
+# test that <div> is display:block
+== div.html div-ref.html