--- 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