Bug 480979 part 1. Introduce FrameConstructionItem and restructure existing ConstructFrame and ProcessChildren code to use it internally without any other behavior changes. r+sr=roc

This commit is contained in:
Boris Zbarsky 2009-03-05 08:09:01 -05:00
parent cf0aeb9e0d
commit 0189933479
2 changed files with 364 additions and 164 deletions

View File

@ -1045,17 +1045,17 @@ nsPseudoFrames::Dump()
// Structure for saving the existing state when pushing/poping containing // Structure for saving the existing state when pushing/poping containing
// blocks. The destructor restores the state to its previous state // blocks. The destructor restores the state to its previous state
class nsFrameConstructorSaveState { class NS_STACK_CLASS nsFrameConstructorSaveState {
public: public:
nsFrameConstructorSaveState(); nsFrameConstructorSaveState();
~nsFrameConstructorSaveState(); ~nsFrameConstructorSaveState();
private: private:
nsAbsoluteItems* mItems; // pointer to struct whose data we save/restore nsAbsoluteItems* mItems; // pointer to struct whose data we save/restore
PRBool* mFixedPosIsAbsPos; PRPackedBool* mFixedPosIsAbsPos;
nsAbsoluteItems mSavedItems; // copy of original data nsAbsoluteItems mSavedItems; // copy of original data
PRBool mSavedFixedPosIsAbsPos; PRPackedBool mSavedFixedPosIsAbsPos;
// The name of the child list in which our frames would belong // The name of the child list in which our frames would belong
nsIAtom* mChildListName; nsIAtom* mChildListName;
@ -1087,7 +1087,12 @@ public:
// elements are fixed-pos containing blocks. This flag determines // elements are fixed-pos containing blocks. This flag determines
// whether or not we want to wire the fixed-pos and abs-pos lists // whether or not we want to wire the fixed-pos and abs-pos lists
// together. // together.
PRBool mFixedPosIsAbsPos; PRPackedBool mFixedPosIsAbsPos;
// A boolean to indicate whether we have a "pending" popupgroup. That is, we
// have already created the FrameConstructionItem for the root popupgroup but
// we have not yet created the relevant frame.
PRPackedBool mHavePendingPopupgroup;
nsCOMPtr<nsILayoutHistoryState> mFrameState; nsCOMPtr<nsILayoutHistoryState> mFrameState;
nsPseudoFrames mPseudoFrames; nsPseudoFrames mPseudoFrames;
@ -1210,6 +1215,7 @@ nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShe
mFixedPosIsAbsPos(aAbsoluteContainingBlock && mFixedPosIsAbsPos(aAbsoluteContainingBlock &&
aAbsoluteContainingBlock->GetStyleDisplay()-> aAbsoluteContainingBlock->GetStyleDisplay()->
HasTransform()), HasTransform()),
mHavePendingPopupgroup(PR_FALSE),
mFrameState(aHistoryState), mFrameState(aHistoryState),
mPseudoFrames(), mPseudoFrames(),
mAdditionalStateBits(0) mAdditionalStateBits(0)
@ -1240,6 +1246,7 @@ nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShell,
mFixedPosIsAbsPos(aAbsoluteContainingBlock && mFixedPosIsAbsPos(aAbsoluteContainingBlock &&
aAbsoluteContainingBlock->GetStyleDisplay()-> aAbsoluteContainingBlock->GetStyleDisplay()->
HasTransform()), HasTransform()),
mHavePendingPopupgroup(PR_FALSE),
mPseudoFrames(), mPseudoFrames(),
mAdditionalStateBits(0) mAdditionalStateBits(0)
{ {
@ -2085,23 +2092,12 @@ nsCSSFrameConstructor::CreateGeneratedContent(nsIContent* aParentContent,
return nsnull; return nsnull;
} }
static void DestroyContent(void *aObject,
nsIAtom *aPropertyName,
void *aPropertyValue,
void *aData)
{
nsIContent* content = static_cast<nsIContent*>(aPropertyValue);
content->UnbindFromTree();
NS_RELEASE(content);
}
/* /*
* aParentFrame - the frame that should be the parent of the generated * aParentFrame - the frame that should be the parent of the generated
* content. This is the frame for the corresponding content node, * content. This is the frame for the corresponding content node,
* which must not be a leaf frame. * which must not be a leaf frame.
* *
* Any frames created are added to aFrameItems (or possibly left * Any items created are added to aItems.
* in the table pseudoframe state in aState).
* *
* We create an XML element (tag _moz_generated_content_before or * We create an XML element (tag _moz_generated_content_before or
* _moz_generated_content_after) representing the pseudoelement. We * _moz_generated_content_after) representing the pseudoelement. We
@ -2112,13 +2108,14 @@ static void DestroyContent(void *aObject,
* ::after style. * ::after style.
*/ */
void void
nsCSSFrameConstructor::CreateGeneratedContentFrame(nsFrameConstructorState& aState, nsCSSFrameConstructor::CreateGeneratedContentItem(nsFrameConstructorState& aState,
nsIFrame* aParentFrame, nsIFrame* aParentFrame,
nsIContent* aParentContent, nsIContent* aParentContent,
nsStyleContext* aStyleContext, nsStyleContext* aStyleContext,
nsIAtom* aPseudoElement, nsIAtom* aPseudoElement,
nsFrameItems& aFrameItems) nsTArray<FrameConstructionItem>& aItems)
{ {
// XXXbz is this ever true?
if (!aParentContent->IsNodeOfType(nsINode::eELEMENT)) if (!aParentContent->IsNodeOfType(nsINode::eELEMENT))
return; return;
@ -2138,13 +2135,11 @@ nsCSSFrameConstructor::CreateGeneratedContentFrame(nsFrameConstructorState& aSta
nsGkAtoms::mozgeneratedcontentbefore : nsGkAtoms::mozgeneratedcontentafter; nsGkAtoms::mozgeneratedcontentbefore : nsGkAtoms::mozgeneratedcontentafter;
nodeInfo = mDocument->NodeInfoManager()->GetNodeInfo(elemName, nsnull, nodeInfo = mDocument->NodeInfoManager()->GetNodeInfo(elemName, nsnull,
kNameSpaceID_None); kNameSpaceID_None);
nsIContent* container; nsCOMPtr<nsIContent> container;
nsresult rv = NS_NewXMLElement(&container, nodeInfo); nsresult rv = NS_NewXMLElement(getter_AddRefs(container), nodeInfo);
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return; return;
container->SetNativeAnonymous(); container->SetNativeAnonymous();
// Transfer ownership to the frame
aParentFrame->SetProperty(aPseudoElement, container, DestroyContent);
rv = container->BindToTree(mDocument, aParentContent, aParentContent, PR_TRUE); rv = container->BindToTree(mDocument, aParentContent, aParentContent, PR_TRUE);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
@ -2161,16 +2156,9 @@ nsCSSFrameConstructor::CreateGeneratedContentFrame(nsFrameConstructorState& aSta
} }
} }
nsFrameState savedStateBits = aState.mAdditionalStateBits; AddFrameConstructionItemInternal(aState, container, aParentFrame, elemName,
// Ensure that frames created here are all tagged with kNameSpaceID_None, pseudoStyleContext,
// NS_FRAME_GENERATED_CONTENT. ITEM_IS_GENERATED_CONTENT, aItems);
aState.mAdditionalStateBits |= NS_FRAME_GENERATED_CONTENT;
// XXXbz should we actually allow page-break frames here?
ConstructFrameInternal(aState, container, aParentFrame,
elemName, kNameSpaceID_None, pseudoStyleContext,
aFrameItems, PR_FALSE, PR_FALSE);
aState.mAdditionalStateBits = savedStateBits;
} }
static PRBool static PRBool
@ -3062,13 +3050,13 @@ nsCSSFrameConstructor::AdjustParentFrame(nsFrameConstructorState& aState,
nsIFrame* & aParentFrame, nsIFrame* & aParentFrame,
const FrameConstructionData* aFCData, const FrameConstructionData* aFCData,
PRInt32 aNameSpaceID, PRInt32 aNameSpaceID,
const nsStyleDisplay* aDisplay, nsStyleContext* aStyleContext,
nsFrameItems* & aFrameItems, nsFrameItems* & aFrameItems,
nsFrameConstructorSaveState& aSaveState, nsFrameConstructorSaveState& aSaveState,
PRBool& aSuppressFrame, PRBool& aSuppressFrame,
PRBool& aCreatedPseudo) PRBool& aCreatedPseudo)
{ {
NS_PRECONDITION(aDisplay, "Must have child's style context"); NS_PRECONDITION(aStyleContext, "Must have child's style context");
NS_PRECONDITION(aFrameItems, "Must have frame items to work with"); NS_PRECONDITION(aFrameItems, "Must have frame items to work with");
NS_PRECONDITION(aFCData, "Must have frame construction data"); NS_PRECONDITION(aFCData, "Must have frame construction data");
@ -3088,7 +3076,9 @@ nsCSSFrameConstructor::AdjustParentFrame(nsFrameConstructorState& aState,
NS_ASSERTION(parentType != nsGkAtoms::tableOuterFrame, NS_ASSERTION(parentType != nsGkAtoms::tableOuterFrame,
"Shouldn't be happening"); "Shouldn't be happening");
if (parentType == nsGkAtoms::tableColGroupFrame) { if (parentType == nsGkAtoms::tableColGroupFrame) {
if (!tablePart || aDisplay->mDisplay != NS_STYLE_DISPLAY_TABLE_COLUMN) { if (!tablePart ||
aStyleContext->GetStyleDisplay()->mDisplay !=
NS_STYLE_DISPLAY_TABLE_COLUMN) {
aSuppressFrame = PR_TRUE; aSuppressFrame = PR_TRUE;
return NS_OK; return NS_OK;
} }
@ -5200,14 +5190,17 @@ nsCSSFrameConstructor::ConstructFrameFromData(const FrameConstructionData* aData
#ifdef MOZ_XUL #ifdef MOZ_XUL
// Icky XUL stuff, sadly // Icky XUL stuff, sadly
// XXXbz if we had the FrameConstructionItem in here, we could probably
// just flag this info on the item.
if (isXUL && aTag == nsGkAtoms::popupgroup && if (isXUL && aTag == nsGkAtoms::popupgroup &&
aContent->IsRootOfNativeAnonymousSubtree()) { aContent->IsRootOfNativeAnonymousSubtree()) {
nsIRootBox* rootBox = nsIRootBox::GetRootBox(mPresShell); NS_ASSERTION(nsIRootBox::GetRootBox(mPresShell) &&
if (rootBox) { nsIRootBox::GetRootBox(mPresShell)->GetPopupSetFrame() ==
NS_ASSERTION(rootBox->GetPopupSetFrame() == newFrame, newFrame,
"Unexpected PopupSetFrame"); "Unexpected PopupSetFrame");
aState.mPopupItems.containingBlock = rootBox->GetPopupSetFrame(); aState.mPopupItems.containingBlock = newFrame;
} aState.mHavePendingPopupgroup = PR_FALSE;
} }
#endif /* MOZ_XUL */ #endif /* MOZ_XUL */
@ -5294,14 +5287,8 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsFrameConstructorState& aState,
nsIFrame* aParentFrame, nsIFrame* aParentFrame,
nsFrameItems& aChildItems) nsFrameItems& aChildItems)
{ {
nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame);
if (!creator)
return NS_OK;
nsresult rv;
nsAutoTArray<nsIContent*, 4> newAnonymousItems; nsAutoTArray<nsIContent*, 4> newAnonymousItems;
rv = creator->CreateAnonymousContent(newAnonymousItems); nsresult rv = GetAnonymousContent(aParent, aParentFrame, newAnonymousItems);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
PRUint32 count = newAnonymousItems.Length(); PRUint32 count = newAnonymousItems.Length();
@ -5309,16 +5296,58 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsFrameConstructorState& aState,
return NS_OK; return NS_OK;
} }
nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame);
NS_ASSERTION(creator,
"How can that happen if we have nodes to construct frames for?");
// save the incoming pseudo frame state, so that we don't end up // save the incoming pseudo frame state, so that we don't end up
// with those pseudoframes in aChildItems // with those pseudoframes in aChildItems
nsPseudoFrames priorPseudoFrames; nsPseudoFrames priorPseudoFrames;
aState.mPseudoFrames.Reset(&priorPseudoFrames); aState.mPseudoFrames.Reset(&priorPseudoFrames);
for (PRUint32 i=0; i < count; i++) { for (PRUint32 i=0; i < count; i++) {
// get our child's content and set its parent to our content
nsIContent* content = newAnonymousItems[i]; nsIContent* content = newAnonymousItems[i];
NS_ASSERTION(content, "null anonymous content?"); NS_ASSERTION(content, "null anonymous content?");
nsIFrame* newFrame = creator->CreateFrameFor(content);
if (newFrame) {
aChildItems.AddChild(newFrame);
}
else {
// create the frame and attach it to our frame
ConstructFrame(aState, content, aParentFrame, aChildItems);
}
}
// process the current pseudo frame state
if (!aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aState, aChildItems);
}
// restore the incoming pseudo frame state
aState.mPseudoFrames = priorPseudoFrames;
return NS_OK;
}
nsresult
nsCSSFrameConstructor::GetAnonymousContent(nsIContent* aParent,
nsIFrame* aParentFrame,
nsTArray<nsIContent*>& aContent)
{
nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame);
if (!creator)
return NS_OK;
nsresult rv = creator->CreateAnonymousContent(aContent);
NS_ENSURE_SUCCESS(rv, rv);
PRUint32 count = aContent.Length();
for (PRUint32 i=0; i < count; i++) {
// get our child's content and set its parent to our content
nsIContent* content = aContent[i];
NS_ASSERTION(content, "null anonymous content?");
#ifdef MOZ_SVG #ifdef MOZ_SVG
// least-surprise CSS binding until we do the SVG specified // least-surprise CSS binding until we do the SVG specified
// cascading rules for <svg:use> - bug 265894 // cascading rules for <svg:use> - bug 265894
@ -5336,25 +5365,8 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsFrameConstructorState& aState,
content->UnbindFromTree(); content->UnbindFromTree();
return rv; return rv;
} }
nsIFrame* newFrame = creator->CreateFrameFor(content);
if (newFrame) {
aChildItems.AddChild(newFrame);
}
else {
// create the frame and attach it to our frame
ConstructFrame(aState, content, aParentFrame, aChildItems);
}
} }
// process the current pseudo frame state
if (!aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aState, aChildItems);
}
// restore the incoming pseudo frame state
aState.mPseudoFrames = priorPseudoFrames;
return NS_OK; return NS_OK;
} }
@ -6470,39 +6482,53 @@ nsCSSFrameConstructor::ConstructFrame(nsFrameConstructorState& aState,
{ {
NS_PRECONDITION(nsnull != aParentFrame, "no parent frame"); NS_PRECONDITION(nsnull != aParentFrame, "no parent frame");
nsAutoTArray<FrameConstructionItem, 1> items;
AddFrameConstructionItem(aState, aContent, aParentFrame, items);
nsresult rv = NS_OK; NS_ASSERTION(items.Length() <= 1, "Unexpected number of items");
if (items.Length() == 0) {
return NS_OK;
}
return ConstructFramesFromItem(aState, items[0], aParentFrame, aFrameItems);
}
void
nsCSSFrameConstructor::AddFrameConstructionItem(nsFrameConstructorState& aState,
nsIContent* aContent,
nsIFrame* aParentFrame,
nsTArray<FrameConstructionItem>& aItems)
{
// don't create a whitespace frame if aParent doesn't want it // don't create a whitespace frame if aParent doesn't want it
if (!NeedFrameFor(aParentFrame, aContent)) { if (!NeedFrameFor(aParentFrame, aContent)) {
return rv; return;
} }
// never create frames for comments or PIs // never create frames for comments or PIs
if (aContent->IsNodeOfType(nsINode::eCOMMENT) || if (aContent->IsNodeOfType(nsINode::eCOMMENT) ||
aContent->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) aContent->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION))
return rv; return;
nsRefPtr<nsStyleContext> styleContext; nsRefPtr<nsStyleContext> styleContext;
styleContext = ResolveStyleContext(aParentFrame, aContent); styleContext = ResolveStyleContext(aParentFrame, aContent);
// construct the frame AddFrameConstructionItemInternal(aState, aContent, aParentFrame,
return ConstructFrameInternal(aState, aContent, aParentFrame, aContent->Tag(), aContent->GetNameSpaceID(),
aContent->Tag(), aContent->GetNameSpaceID(), styleContext,
styleContext, aFrameItems, PR_TRUE, PR_TRUE); ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK,
aItems);
} }
nsresult void
nsCSSFrameConstructor::ConstructFrameInternal(nsFrameConstructorState& aState, nsCSSFrameConstructor::AddFrameConstructionItemInternal(nsFrameConstructorState& aState,
nsIContent* aContent, nsIContent* aContent,
nsIFrame* aParentFrame, nsIFrame* aParentFrame,
nsIAtom* aTag, nsIAtom* aTag,
PRInt32 aNameSpaceID, PRInt32 aNameSpaceID,
nsStyleContext* aStyleContext, nsStyleContext* aStyleContext,
nsFrameItems& aFrameItems, PRUint32 aFlags,
PRBool aAllowXBLBase, nsTArray<FrameConstructionItem>& aItems)
PRBool aAllowPageBreaks)
{ {
// The following code allows the user to specify the base tag // The following code allows the user to specify the base tag
// of an element using XBL. XUL and HTML objects (like boxes, menus, etc.) // of an element using XBL. XUL and HTML objects (like boxes, menus, etc.)
@ -6510,13 +6536,13 @@ nsCSSFrameConstructor::ConstructFrameInternal(nsFrameConstructorState& aState,
const nsStyleDisplay* display = aStyleContext->GetStyleDisplay(); const nsStyleDisplay* display = aStyleContext->GetStyleDisplay();
nsRefPtr<nsStyleContext> styleContext(aStyleContext); nsRefPtr<nsStyleContext> styleContext(aStyleContext);
nsAutoEnqueueBinding binding(mDocument); nsAutoEnqueueBinding binding(mDocument);
if (aAllowXBLBase && display->mBinding) if ((aFlags & ITEM_ALLOW_XBL_BASE) && display->mBinding)
{ {
// Ensure that our XBL bindings are installed. // Ensure that our XBL bindings are installed.
nsIXBLService * xblService = GetXBLService(); nsIXBLService * xblService = GetXBLService();
if (!xblService) if (!xblService)
return NS_ERROR_FAILURE; return;
PRBool resolveStyle; PRBool resolveStyle;
@ -6526,7 +6552,7 @@ nsCSSFrameConstructor::ConstructFrameInternal(nsFrameConstructorState& aState,
getter_AddRefs(binding.mBinding), getter_AddRefs(binding.mBinding),
&resolveStyle); &resolveStyle);
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return NS_OK; return;
if (resolveStyle) { if (resolveStyle) {
styleContext = ResolveStyleContext(aParentFrame, aContent); styleContext = ResolveStyleContext(aParentFrame, aContent);
@ -6541,7 +6567,7 @@ nsCSSFrameConstructor::ConstructFrameInternal(nsFrameConstructorState& aState,
// any frame at all // any frame at all
if (NS_STYLE_DISPLAY_NONE == display->mDisplay) { if (NS_STYLE_DISPLAY_NONE == display->mDisplay) {
aState.mFrameManager->SetUndisplayedContent(aContent, styleContext); aState.mFrameManager->SetUndisplayedContent(aContent, styleContext);
return NS_OK; return;
} }
PRBool isText = aContent->IsNodeOfType(nsINode::eTEXT); PRBool isText = aContent->IsNodeOfType(nsINode::eTEXT);
@ -6552,7 +6578,7 @@ nsCSSFrameConstructor::ConstructFrameInternal(nsFrameConstructorState& aState,
#ifdef MOZ_SVG #ifdef MOZ_SVG
if (!data) { if (!data) {
// Nothing to do here; suppressed text inside SVG // Nothing to do here; suppressed text inside SVG
return NS_OK; return;
} }
#endif /* MOZ_SVG */ #endif /* MOZ_SVG */
} else { } else {
@ -6563,7 +6589,7 @@ nsCSSFrameConstructor::ConstructFrameInternal(nsFrameConstructorState& aState,
aParentFrame->IsFrameOfType(nsIFrame::eSVG) && aParentFrame->IsFrameOfType(nsIFrame::eSVG) &&
!aParentFrame->IsFrameOfType(nsIFrame::eSVGForeignObject) !aParentFrame->IsFrameOfType(nsIFrame::eSVGForeignObject)
) { ) {
return NS_OK; return;
} }
#endif /* MOZ_SVG */ #endif /* MOZ_SVG */
@ -6597,33 +6623,76 @@ nsCSSFrameConstructor::ConstructFrameInternal(nsFrameConstructorState& aState,
NS_ASSERTION(data, "Should have frame construction data now"); NS_ASSERTION(data, "Should have frame construction data now");
if (data->mBits & FCDATA_SUPPRESS_FRAME) { if (data->mBits & FCDATA_SUPPRESS_FRAME) {
return NS_OK; return;
} }
#ifdef MOZ_XUL #ifdef MOZ_XUL
if ((data->mBits & FCDATA_IS_POPUP) && if ((data->mBits & FCDATA_IS_POPUP) &&
aParentFrame->GetType() != nsGkAtoms::menuFrame && aParentFrame->GetType() != nsGkAtoms::menuFrame &&
!aState.mPopupItems.containingBlock) { !aState.mPopupItems.containingBlock &&
return NS_OK; !aState.mHavePendingPopupgroup) {
return;
} }
#endif /* MOZ_XUL */ #endif /* MOZ_XUL */
} }
PRBool isGeneratedContent = ((aFlags & ITEM_IS_GENERATED_CONTENT) != 0);
FrameConstructionItem* item = aItems.AppendElement();
if (!item) {
if (isGeneratedContent) {
aContent->UnbindFromTree();
}
return;
}
item->mFCData = data;
item->mContent = aContent;
item->mTag = aTag;
item->mNameSpaceID = aNameSpaceID;
item->mStyleContext.swap(styleContext);
item->mAllowPageBreaks = ((aFlags & ITEM_ALLOW_PAGE_BREAK) != 0);
item->mIsText = isText;
item->mIsGeneratedContent = isGeneratedContent;
if (isGeneratedContent) {
NS_ADDREF(item->mContent);
}
}
static void DestroyContent(void *aObject,
nsIAtom *aPropertyName,
void *aPropertyValue,
void *aData)
{
nsIContent* content = static_cast<nsIContent*>(aPropertyValue);
content->UnbindFromTree();
NS_RELEASE(content);
}
nsresult
nsCSSFrameConstructor::ConstructFramesFromItem(nsFrameConstructorState& aState,
FrameConstructionItem& aItem,
nsIFrame* aParentFrame,
nsFrameItems& aFrameItems)
{
nsIFrame* adjParentFrame = aParentFrame; nsIFrame* adjParentFrame = aParentFrame;
nsFrameItems* frameItems = &aFrameItems; nsFrameItems* frameItems = &aFrameItems;
PRBool pseudoParent = PR_FALSE; PRBool pseudoParent = PR_FALSE;
PRBool suppressFrame = PR_FALSE; PRBool suppressFrame = PR_FALSE;
nsStyleContext* styleContext = aItem.mStyleContext;
nsFrameConstructorSaveState pseudoSaveState; nsFrameConstructorSaveState pseudoSaveState;
nsresult rv = AdjustParentFrame(aState, aContent, adjParentFrame, nsresult rv = AdjustParentFrame(aState, aItem.mContent, adjParentFrame,
data, aNameSpaceID, display, frameItems, aItem.mFCData, aItem.mNameSpaceID,
pseudoSaveState, suppressFrame, pseudoParent); styleContext, frameItems, pseudoSaveState,
suppressFrame, pseudoParent);
if (NS_FAILED(rv) || suppressFrame) { if (NS_FAILED(rv) || suppressFrame) {
return rv; return rv;
} }
if (isText) { if (aItem.mIsText) {
return ConstructTextFrame(data, aState, aContent, adjParentFrame, return ConstructTextFrame(aItem.mFCData, aState, aItem.mContent,
styleContext, *frameItems, pseudoParent); adjParentFrame, styleContext,
*frameItems, pseudoParent);
} }
// If the page contains markup that overrides text direction, and // If the page contains markup that overrides text direction, and
@ -6642,24 +6711,42 @@ nsCSSFrameConstructor::ConstructFrameInternal(nsFrameConstructorState& aState,
styleContext->GetStyleBackground(); styleContext->GetStyleBackground();
} }
nsFrameState savedStateBits = aState.mAdditionalStateBits;
if (aItem.mIsGeneratedContent) {
// Ensure that frames created here are all tagged with
// NS_FRAME_GENERATED_CONTENT.
aState.mAdditionalStateBits |= NS_FRAME_GENERATED_CONTENT;
aParentFrame->SetProperty(styleContext->GetPseudoType(),
aItem.mContent, DestroyContent);
// Now that we've passed ownership of aItem.mContent to the frame, unset
// our generated content flag so we don't release or unbind it ourselves.
aItem.mIsGeneratedContent = PR_FALSE;
}
// Construct a page break frame for page-break-before, if needed, and // Construct a page break frame for page-break-before, if needed, and
// remember whether we need one for page-break-after. // remember whether we need one for page-break-after.
PRBool pageBreakAfter = PRBool pageBreakAfter =
aAllowPageBreaks && aItem.mAllowPageBreaks &&
aState.mPresContext->IsPaginated() && aState.mPresContext->IsPaginated() &&
PageBreakBefore(aState, aContent, adjParentFrame, styleContext, data, PageBreakBefore(aState, aItem.mContent, adjParentFrame,
*frameItems); styleContext, aItem.mFCData, *frameItems);
rv = ConstructFrameFromData(data, aState, aContent, adjParentFrame, aTag, // XXXbz maybe just inline ConstructFrameFromData here or something?
aNameSpaceID, styleContext, *frameItems, rv = ConstructFrameFromData(aItem.mFCData, aState, aItem.mContent,
pseudoParent); adjParentFrame, aItem.mTag,
aItem.mNameSpaceID, styleContext,
*frameItems, pseudoParent);
if (NS_SUCCEEDED(rv) && pageBreakAfter) { if (NS_SUCCEEDED(rv) && pageBreakAfter) {
// Construct the page break after // Construct the page break after
ConstructPageBreakFrame(aState, aContent, adjParentFrame, styleContext, ConstructPageBreakFrame(aState, aItem.mContent, adjParentFrame,
*frameItems); styleContext, *frameItems);
} }
aState.mAdditionalStateBits = savedStateBits;
return rv; return rv;
} }
@ -10133,9 +10220,9 @@ nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState,
nsIContent* aContent, nsIContent* aContent,
nsStyleContext* aStyleContext, nsStyleContext* aStyleContext,
nsIFrame* aFrame, nsIFrame* aFrame,
PRBool aCanHaveGeneratedContent, const PRBool aCanHaveGeneratedContent,
nsFrameItems& aFrameItems, nsFrameItems& aFrameItems,
PRBool aAllowBlockStyles) const PRBool aAllowBlockStyles)
{ {
NS_PRECONDITION(aFrame, "Must have parent frame here"); NS_PRECONDITION(aFrame, "Must have parent frame here");
NS_PRECONDITION(aFrame->GetContentInsertionFrame() == aFrame, NS_PRECONDITION(aFrame->GetContentInsertionFrame() == aFrame,
@ -10164,14 +10251,38 @@ nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState,
nsPseudoFrames priorPseudoFrames; nsPseudoFrames priorPseudoFrames;
aState.mPseudoFrames.Reset(&priorPseudoFrames); aState.mPseudoFrames.Reset(&priorPseudoFrames);
nsAutoTArray<FrameConstructionItem, 16> itemsToConstruct;
nsresult rv = NS_OK;
if (aFrame == mRootElementFrame) { if (aFrame == mRootElementFrame) {
// Create any anonymous frames the initial containing block frame requires. // Create any anonymous frames the initial containing block frame requires.
// This must happen before the rest of ProcessChildren to ensure that // This must happen before the rest of ProcessChildren to ensure that
// popups are never constructed before the popupset. // popups are never constructed before the popupset.
CreateAnonymousFrames(aState, aContent, aFrame, aFrameItems); nsAutoTArray<nsIContent*, 4> anonymousItems;
GetAnonymousContent(aContent, aFrame, anonymousItems);
for (PRUint32 i = 0; i < anonymousItems.Length(); ++i) {
#ifdef DEBUG
nsIAnonymousContentCreator* creator = do_QueryFrame(aFrame);
NS_ASSERTION(!creator || !creator->CreateFrameFor(anonymousItems[i]),
"If you need to use CreateFrameFor, you need to call "
"CreateAnonymousFrames manually and not follow the standard "
"ProcessChildren() codepath for this frame");
#endif
PRUint32 c = itemsToConstruct.Length();
AddFrameConstructionItem(aState, anonymousItems[i], aFrame,
itemsToConstruct);
// Bit of a hack here to make sure that the popup stuff actually works
if (itemsToConstruct.Length() != c) {
NS_ASSERTION(itemsToConstruct.Length() == c + 1, "Unexpected length");
if (itemsToConstruct[c].mNameSpaceID == kNameSpaceID_XUL &&
itemsToConstruct[c].mTag == nsGkAtoms::popupgroup) {
aState.mHavePendingPopupgroup = PR_TRUE;
}
}
}
} }
nsresult rv = NS_OK;
if (!aFrame->IsLeaf() && if (!aFrame->IsLeaf() &&
mDocument->BindingManager()->ShouldBuildChildFrames(aContent)) { mDocument->BindingManager()->ShouldBuildChildFrames(aContent)) {
// :before/:after content should have the same style context parent // :before/:after content should have the same style context parent
@ -10179,37 +10290,57 @@ nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState,
// Note that we don't use this style context for looking up things like // Note that we don't use this style context for looking up things like
// special block styles because in some cases involving table pseudo-frames // special block styles because in some cases involving table pseudo-frames
// it has nothing to do with the parent frame's desired behavior. // it has nothing to do with the parent frame's desired behavior.
nsStyleContext* styleContext = nsStyleContext* styleContext;
nsFrame::CorrectStyleParentFrame(aFrame, nsnull)->GetStyleContext();
if (aCanHaveGeneratedContent) { if (aCanHaveGeneratedContent) {
styleContext =
nsFrame::CorrectStyleParentFrame(aFrame, nsnull)->GetStyleContext();
// Probe for generated content before // Probe for generated content before
CreateGeneratedContentFrame(aState, aFrame, aContent, CreateGeneratedContentItem(aState, aFrame, aContent,
styleContext, nsCSSPseudoElements::before, styleContext, nsCSSPseudoElements::before,
aFrameItems); itemsToConstruct);
} }
ChildIterator iter, last; ChildIterator iter, last;
for (ChildIterator::Init(aContent, &iter, &last); for (ChildIterator::Init(aContent, &iter, &last);
iter != last; iter != last;
++iter) { ++iter) {
rv = ConstructFrame(aState, *iter, aFrame, aFrameItems); AddFrameConstructionItem(aState, *iter, aFrame, itemsToConstruct);
if (NS_FAILED(rv))
return rv;
} }
if (aCanHaveGeneratedContent) { if (aCanHaveGeneratedContent) {
// Probe for generated content after // Probe for generated content after
CreateGeneratedContentFrame(aState, aFrame, aContent, CreateGeneratedContentItem(aState, aFrame, aContent,
styleContext, nsCSSPseudoElements::after, styleContext, nsCSSPseudoElements::after,
aFrameItems); itemsToConstruct);
} }
} }
if (aFrame != mRootElementFrame) { if (aFrame != mRootElementFrame) {
CreateAnonymousFrames(aState, aContent, aFrame, aFrameItems); nsAutoTArray<nsIContent*, 4> anonymousItems;
GetAnonymousContent(aContent, aFrame, anonymousItems);
for (PRUint32 i = 0; i < anonymousItems.Length(); ++i) {
#ifdef DEBUG
nsIAnonymousContentCreator* creator = do_QueryFrame(aFrame);
NS_ASSERTION(!creator || !creator->CreateFrameFor(anonymousItems[i]),
"If you need to use CreateFrameFor, you need to call "
"CreateAnonymousFrames manually and not follow the standard "
"ProcessChildren() codepath for this frame");
#endif
AddFrameConstructionItem(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 // process the current pseudo frame state
if (!aState.mPseudoFrames.IsEmpty()) { if (!aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aState, aFrameItems); ProcessPseudoFrames(aState, aFrameItems);
@ -11228,9 +11359,15 @@ nsCSSFrameConstructor::CreateListBoxContent(nsPresContext* aPresContext,
BeginUpdate(); BeginUpdate();
rv = ConstructFrameInternal(state, aChild, aParentFrame, aChild->Tag(), nsAutoTArray<FrameConstructionItem, 1> items;
aChild->GetNameSpaceID(), styleContext, AddFrameConstructionItemInternal(state, aChild, aParentFrame, aChild->Tag(),
frameItems, PR_TRUE, PR_FALSE); aChild->GetNameSpaceID(), styleContext,
ITEM_ALLOW_XBL_BASE, items);
if (items.Length() > 0) {
NS_ASSERTION(items.Length() == 1, "Unexpected count");
ConstructFramesFromItem(state, items[0], aParentFrame, frameItems);
}
if (!state.mPseudoFrames.IsEmpty()) { if (!state.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(state, frameItems); ProcessPseudoFrames(state, frameItems);
} }
@ -11588,12 +11725,14 @@ nsCSSFrameConstructor::ProcessInlineChildren(nsFrameConstructorState& aState,
nsPseudoFrames prevPseudoFrames; nsPseudoFrames prevPseudoFrames;
aState.mPseudoFrames.Reset(&prevPseudoFrames); aState.mPseudoFrames.Reset(&prevPseudoFrames);
nsAutoTArray<FrameConstructionItem, 16> itemsToConstruct;
if (aCanHaveGeneratedContent) { if (aCanHaveGeneratedContent) {
// Probe for generated content before // Probe for generated content before
styleContext = aFrame->GetStyleContext(); styleContext = aFrame->GetStyleContext();
CreateGeneratedContentFrame(aState, aFrame, aContent, CreateGeneratedContentItem(aState, aFrame, aContent,
styleContext, nsCSSPseudoElements::before, styleContext, nsCSSPseudoElements::before,
aFrameItems); itemsToConstruct);
} }
// Iterate the child content objects and construct frames // Iterate the child content objects and construct frames
@ -11603,12 +11742,22 @@ nsCSSFrameConstructor::ProcessInlineChildren(nsFrameConstructorState& aState,
iter != last; iter != last;
++iter) { ++iter) {
// Construct a child frame // Construct a child frame
nsIFrame* oldLastChild = aFrameItems.lastChild; AddFrameConstructionItem(aState, *iter, aFrame, itemsToConstruct);
rv = ConstructFrame(aState, *iter, aFrame, aFrameItems); }
if (NS_FAILED(rv)) { if (aCanHaveGeneratedContent) {
return rv; // 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 // Examine newly added children (we may have added more than one
// child if the child was another inline frame that ends up // child if the child was another inline frame that ends up
@ -11631,13 +11780,6 @@ nsCSSFrameConstructor::ProcessInlineChildren(nsFrameConstructorState& aState,
} }
} }
if (aCanHaveGeneratedContent) {
// Probe for generated content after
CreateGeneratedContentFrame(aState, aFrame, aContent,
styleContext, nsCSSPseudoElements::after,
aFrameItems);
}
// process the current pseudo frame state // process the current pseudo frame state
if (!aState.mPseudoFrames.IsEmpty()) { if (!aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aState, aFrameItems); ProcessPseudoFrames(aState, aFrameItems);

View File

@ -282,6 +282,7 @@ public:
PRBool IsDestroyingFrameTree() { return mIsDestroyingFrameTree; } PRBool IsDestroyingFrameTree() { return mIsDestroyingFrameTree; }
private: private:
struct FrameConstructionItem;
nsresult ReconstructDocElementHierarchyInternal(); nsresult ReconstructDocElementHierarchyInternal();
@ -321,6 +322,11 @@ private:
nsIFrame* aParentFrame, nsIFrame* aParentFrame,
nsFrameItems& aFrameItems); nsFrameItems& aFrameItems);
void AddFrameConstructionItem(nsFrameConstructorState& aState,
nsIContent* aContent,
nsIFrame* aParentFrame,
nsTArray<FrameConstructionItem>& aItems);
nsresult ConstructDocElementFrame(nsFrameConstructorState& aState, nsresult ConstructDocElementFrame(nsFrameConstructorState& aState,
nsIContent* aDocElement, nsIContent* aDocElement,
nsIFrame* aParentFrame, nsIFrame* aParentFrame,
@ -375,12 +381,12 @@ private:
nsStyleContext* aStyleContext, nsStyleContext* aStyleContext,
PRUint32 aContentIndex); PRUint32 aContentIndex);
void CreateGeneratedContentFrame(nsFrameConstructorState& aState, void CreateGeneratedContentItem(nsFrameConstructorState& aState,
nsIFrame* aFrame, nsIFrame* aFrame,
nsIContent* aContent, nsIContent* aContent,
nsStyleContext* aStyleContext, nsStyleContext* aStyleContext,
nsIAtom* aPseudoElement, nsIAtom* aPseudoElement,
nsFrameItems& aFrameItems); nsTArray<FrameConstructionItem>& aItems);
// This method can change aFrameList: it can chop off the end and // This method can change aFrameList: it can chop off the end and
// put it in a special sibling of aParentFrame. It can also change // put it in a special sibling of aParentFrame. It can also change
@ -719,6 +725,42 @@ private:
const FrameConstructionDataByTag* aDataPtr, const FrameConstructionDataByTag* aDataPtr,
PRUint32 aDataLength); PRUint32 aDataLength);
/* A struct representing an item for which frames might need to be
* constructed. This contains all the information needed to construct the
* frame other than the parent frame and whatever would be stored in the
* frame constructor state. */
struct FrameConstructionItem {
FrameConstructionItem() :
mIsGeneratedContent(PR_FALSE) {}
~FrameConstructionItem() {
if (mIsGeneratedContent) {
mContent->UnbindFromTree();
NS_RELEASE(mContent);
}
}
// The FrameConstructionData to use.
const FrameConstructionData* mFCData;
// The nsIContent node to use when initializing the new frame.
nsIContent* mContent;
// The XBL-resolved tag name to use for frame construction.
nsIAtom* mTag;
// The XBL-resolved namespace to use for frame construction.
PRInt32 mNameSpaceID;
// The style context to use for creating the new frame.
nsRefPtr<nsStyleContext> mStyleContext;
// Whether to allow page-break stuff around this frame.
PRPackedBool mAllowPageBreaks;
// Whether this is a text content item.
PRPackedBool mIsText;
// Whether this is generated content. If it is, mContent is a strong
// pointer.
PRPackedBool mIsGeneratedContent;
private:
FrameConstructionItem(const FrameConstructionItem& aOther); /* not implemented */
};
/** /**
* Function to adjust aParentFrame and aFrameItems to deal with table * Function to adjust aParentFrame and aFrameItems to deal with table
* pseudo-frames that may have to be inserted. * pseudo-frames that may have to be inserted.
@ -729,7 +771,7 @@ private:
* @param aFCData the FrameConstructionData that would be used for frame * @param aFCData the FrameConstructionData that would be used for frame
* construction. * construction.
* @param aNameSpaceID namespace that will be used for frame construction * @param aNameSpaceID namespace that will be used for frame construction
* @param aDisplay the display style struct for aChildContent * @param aStyleContext the style context for aChildContent
* @param aFrameItems the framelist we think we need to put the child frame * @param aFrameItems the framelist we think we need to put the child frame
* into. If we have to construct pseudo-frames, we'll modify the * into. If we have to construct pseudo-frames, we'll modify the
* pointer to point to the list the child frame should go into. * pointer to point to the list the child frame should go into.
@ -749,7 +791,7 @@ private:
nsIFrame* & aParentFrame, nsIFrame* & aParentFrame,
const FrameConstructionData* aFCData, const FrameConstructionData* aFCData,
PRInt32 aNameSpaceID, PRInt32 aNameSpaceID,
const nsStyleDisplay* aDisplay, nsStyleContext* aStyleContext,
nsFrameItems* & aFrameItems, nsFrameItems* & aFrameItems,
nsFrameConstructorSaveState& aSaveState, nsFrameConstructorSaveState& aSaveState,
PRBool& aSuppressFrame, PRBool& aSuppressFrame,
@ -872,21 +914,37 @@ private:
nsFrameItems& aFrameItems, nsFrameItems& aFrameItems,
PRBool aHasPseudoParent); PRBool aHasPseudoParent);
nsresult ConstructFrameInternal(nsFrameConstructorState& aState, // possible flags for AddFrameConstructionItemInternal's aFlags argument
nsIContent* aContent, /* Allow xbl:base to affect the tag/namespace used. */
nsIFrame* aParentFrame, #define ITEM_ALLOW_XBL_BASE 0x1
nsIAtom* aTag, /* Allow page-break before and after items to be created if the
PRInt32 aNameSpaceID, style asks for them. */
nsStyleContext* aStyleContext, #define ITEM_ALLOW_PAGE_BREAK 0x2
nsFrameItems& aFrameItems, /* The item is a generated content item. */
PRBool aAllowXBLBase, #define ITEM_IS_GENERATED_CONTENT 0x4
PRBool aAllowPageBreaks); void AddFrameConstructionItemInternal(nsFrameConstructorState& aState,
nsIContent* aContent,
nsIFrame* aParentFrame,
nsIAtom* aTag,
PRInt32 aNameSpaceID,
nsStyleContext* aStyleContext,
PRUint32 aFlags,
nsTArray<FrameConstructionItem>& aItems);
nsresult ConstructFramesFromItem(nsFrameConstructorState& aState,
FrameConstructionItem& aItem,
nsIFrame* aParentFrame,
nsFrameItems& aFrameItems);
nsresult CreateAnonymousFrames(nsFrameConstructorState& aState, nsresult CreateAnonymousFrames(nsFrameConstructorState& aState,
nsIContent* aParent, nsIContent* aParent,
nsIFrame* aParentFrame, nsIFrame* aParentFrame,
nsFrameItems& aChildItems); nsFrameItems& aChildItems);
nsresult GetAnonymousContent(nsIContent* aParent,
nsIFrame* aParentFrame,
nsTArray<nsIContent*>& aAnonContent);
//MathML Mod - RBS //MathML Mod - RBS
#ifdef MOZ_MATHML #ifdef MOZ_MATHML
/** /**
@ -1027,9 +1085,9 @@ private:
nsIContent* aContent, nsIContent* aContent,
nsStyleContext* aStyleContext, nsStyleContext* aStyleContext,
nsIFrame* aFrame, nsIFrame* aFrame,
PRBool aCanHaveGeneratedContent, const PRBool aCanHaveGeneratedContent,
nsFrameItems& aFrameItems, nsFrameItems& aFrameItems,
PRBool aAllowBlockStyles); const PRBool aAllowBlockStyles);
nsIFrame* GetFrameFor(nsIContent* aContent); nsIFrame* GetFrameFor(nsIContent* aContent);