--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -762,16 +762,33 @@ private:
// The name of the child list in which our frames would belong
nsIAtom* mChildListName;
nsFrameConstructorState* mState;
friend class nsFrameConstructorState;
};
+// Structure used to keep track of a list of bindings we need to call
+// AddToAttachedQueue on. These should be in post-order depth-first
+// flattened tree traversal order.
+struct PendingBinding : public PRCList
+{
+#ifdef NS_BUILD_REFCNT_LOGGING
+ PendingBinding() {
+ MOZ_COUNT_CTOR(PendingBinding);
+ }
+ ~PendingBinding() {
+ MOZ_COUNT_DTOR(PendingBinding);
+ }
+#endif
+
+ nsRefPtr<nsXBLBinding> mBinding;
+};
+
// Structure used for maintaining state information during the
// frame construction process
class NS_STACK_CLASS nsFrameConstructorState {
public:
nsPresContext *mPresContext;
nsIPresShell *mPresShell;
nsFrameManager *mFrameManager;
@@ -885,25 +902,69 @@ public:
{
return mFixedPosIsAbsPos ? mAbsoluteItems : mFixedItems;
}
const nsAbsoluteItems& GetFixedItems() const
{
return mFixedPosIsAbsPos ? mAbsoluteItems : mFixedItems;
}
+
+ /**
+ * class to automatically push and pop a pending binding in the frame
+ * constructor state. See nsCSSFrameConstructor::FrameConstructionItem
+ * mPendingBinding documentation.
+ */
+ class PendingBindingAutoPusher;
+ friend class PendingBindingAutoPusher;
+ class NS_STACK_CLASS PendingBindingAutoPusher {
+ public:
+ PendingBindingAutoPusher(nsFrameConstructorState& aState,
+ PendingBinding* aPendingBinding) :
+ mState(aState),
+ mPendingBinding(aState.mCurrentPendingBindingInsertionPoint)
+ {
+ NS_PRECONDITION(mPendingBinding, "how did that happen?");
+ if (aPendingBinding) {
+ aState.mCurrentPendingBindingInsertionPoint = aPendingBinding;
+ }
+ }
+
+ ~PendingBindingAutoPusher()
+ {
+ mState.mCurrentPendingBindingInsertionPoint = mPendingBinding;
+ }
+
+ private:
+ nsFrameConstructorState& mState;
+ PRCList* mPendingBinding;
+ };
+
+ /**
+ * Add a new pending binding to the list
+ */
+ void AddPendingBinding(PendingBinding* aPendingBinding) {
+ PR_INSERT_BEFORE(aPendingBinding, mCurrentPendingBindingInsertionPoint);
+ }
+
protected:
friend class nsFrameConstructorSaveState;
/**
* ProcessFrameInsertions takes the frames in aFrameItems and adds them as
* kids to the aChildListName child list of |aFrameItems.containingBlock|.
*/
void ProcessFrameInsertions(nsAbsoluteItems& aFrameItems,
nsIAtom* aChildListName);
+
+ // Our list of all pending bindings. When we're done, we need to call
+ // AddToAttachedQueue on all of them, in order.
+ PRCList mPendingBindings;
+
+ PRCList* mCurrentPendingBindingInsertionPoint;
};
nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShell,
nsIFrame* aFixedContainingBlock,
nsIFrame* aAbsoluteContainingBlock,
nsIFrame* aFloatContainingBlock,
nsILayoutHistoryState* aHistoryState)
: mPresContext(aPresShell->GetPresContext()),
@@ -916,25 +977,27 @@ nsFrameConstructorState::nsFrameConstruc
mAbsoluteItems(aAbsoluteContainingBlock),
mFloatedItems(aFloatContainingBlock),
// See PushAbsoluteContaningBlock below
mFrameState(aHistoryState),
mAdditionalStateBits(0),
mFixedPosIsAbsPos(aAbsoluteContainingBlock &&
aAbsoluteContainingBlock->GetStyleDisplay()->
HasTransform()),
- mHavePendingPopupgroup(PR_FALSE)
+ mHavePendingPopupgroup(PR_FALSE),
+ mCurrentPendingBindingInsertionPoint(&mPendingBindings)
{
#ifdef MOZ_XUL
nsIRootBox* rootBox = nsIRootBox::GetRootBox(aPresShell);
if (rootBox) {
mPopupItems.containingBlock = rootBox->GetPopupSetFrame();
}
#endif
MOZ_COUNT_CTOR(nsFrameConstructorState);
+ PR_INIT_CLIST(&mPendingBindings);
}
nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShell,
nsIFrame* aFixedContainingBlock,
nsIFrame* aAbsoluteContainingBlock,
nsIFrame* aFloatContainingBlock)
: mPresContext(aPresShell->GetPresContext()),
mPresShell(aPresShell),
@@ -945,26 +1008,28 @@ nsFrameConstructorState::nsFrameConstruc
mFixedItems(aFixedContainingBlock),
mAbsoluteItems(aAbsoluteContainingBlock),
mFloatedItems(aFloatContainingBlock),
// See PushAbsoluteContaningBlock below
mAdditionalStateBits(0),
mFixedPosIsAbsPos(aAbsoluteContainingBlock &&
aAbsoluteContainingBlock->GetStyleDisplay()->
HasTransform()),
- mHavePendingPopupgroup(PR_FALSE)
+ mHavePendingPopupgroup(PR_FALSE),
+ mCurrentPendingBindingInsertionPoint(&mPendingBindings)
{
#ifdef MOZ_XUL
nsIRootBox* rootBox = nsIRootBox::GetRootBox(aPresShell);
if (rootBox) {
mPopupItems.containingBlock = rootBox->GetPopupSetFrame();
}
#endif
MOZ_COUNT_CTOR(nsFrameConstructorState);
mFrameState = aPresShell->GetDocument()->GetLayoutHistoryState();
+ PR_INIT_CLIST(&mPendingBindings);
}
nsFrameConstructorState::~nsFrameConstructorState()
{
// Frame order comparison functions only work properly when the placeholders
// have been inserted into the frame tree. So for example if we have a new float
// containing the placeholder for a new abs-pos frame, and we process the abs-pos
// insertion first, then we won't be able to find the right place to insert in
@@ -978,16 +1043,26 @@ nsFrameConstructorState::~nsFrameConstru
ProcessFrameInsertions(mFixedItems, nsGkAtoms::fixedList);
#ifdef MOZ_XUL
ProcessFrameInsertions(mPopupItems, nsGkAtoms::popupList);
#endif
for (PRInt32 i = mGeneratedTextNodesWithInitializer.Count() - 1; i >= 0; --i) {
mGeneratedTextNodesWithInitializer[i]->
DeleteProperty(nsGkAtoms::genConInitializerProperty);
}
+ if (!PR_CLIST_IS_EMPTY(&mPendingBindings)) {
+ nsBindingManager* bindingManager = mPresShell->GetDocument()->BindingManager();
+ do {
+ PendingBinding* pendingBinding =
+ static_cast<PendingBinding*>(PR_NEXT_LINK(&mPendingBindings));
+ PR_REMOVE_LINK(pendingBinding);
+ bindingManager->AddToAttachedQueue(pendingBinding->mBinding);
+ delete pendingBinding;
+ } while (!PR_CLIST_IS_EMPTY(&mPendingBindings));
+ }
}
static nsIFrame*
AdjustAbsoluteContainingBlock(nsIFrame* aContainingBlockIn)
{
if (!aContainingBlockIn) {
return nsnull;
}
@@ -2021,17 +2096,17 @@ nsCSSFrameConstructor::ConstructTable(ns
}
nsFrameItems childItems;
if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
rv = ConstructFramesFromItemList(aState, aItem.mChildItems,
innerFrame, childItems);
} else {
rv = ProcessChildren(aState, content, styleContext, innerFrame,
- PR_TRUE, childItems, PR_FALSE);
+ PR_TRUE, childItems, PR_FALSE, aItem.mPendingBinding);
}
// XXXbz what about cleaning up?
if (NS_FAILED(rv)) return rv;
nsFrameItems captionItems;
PullOutCaptionFrames(childItems, captionItems);
// Set the inner table frame's initial primary list
@@ -2076,17 +2151,17 @@ nsCSSFrameConstructor::ConstructTableRow
nsFrameItems childItems;
nsresult rv;
if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
rv = ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame,
childItems);
} else {
rv = ProcessChildren(aState, content, styleContext, newFrame,
- PR_TRUE, childItems, PR_FALSE);
+ PR_TRUE, childItems, PR_FALSE, aItem.mPendingBinding);
}
if (NS_FAILED(rv)) return rv;
newFrame->SetInitialChildList(nsnull, childItems);
aFrameItems.AddChild(newFrame);
*aNewFrame = newFrame;
return NS_OK;
@@ -2216,17 +2291,17 @@ nsCSSFrameConstructor::ConstructTableCel
aState.PushFloatContainingBlock(cellInnerFrame, floatSaveState);
}
rv = ConstructFramesFromItemList(aState, aItem.mChildItems, cellInnerFrame,
childItems);
} else {
// Process the child content
rv = ProcessChildren(aState, content, styleContext, cellInnerFrame,
- PR_TRUE, childItems, isBlock);
+ PR_TRUE, childItems, isBlock, aItem.mPendingBinding);
}
if (NS_FAILED(rv)) {
// Clean up
// XXXbz kids of this stuff need to be cleaned up too!
cellInnerFrame->Destroy();
newFrame->Destroy();
return rv;
@@ -2390,36 +2465,43 @@ nsCSSFrameConstructor::ConstructDocEleme
// --------- CREATE AREA OR BOX FRAME -------
nsRefPtr<nsStyleContext> styleContext;
styleContext = mPresShell->StyleSet()->ResolveStyleFor(aDocElement,
nsnull);
const nsStyleDisplay* display = styleContext->GetStyleDisplay();
+ PendingBinding* pendingBinding = nsnull;
// Ensure that our XBL bindings are installed.
if (display->mBinding) {
// Get the XBL loader.
nsresult rv;
PRBool resolveStyle;
nsIXBLService * xblService = GetXBLService();
if (!xblService)
return NS_ERROR_FAILURE;
- nsRefPtr<nsXBLBinding> binding;
+ nsAutoPtr<PendingBinding> newPendingBinding(new PendingBinding());
+ if (!newPendingBinding) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
rv = xblService->LoadBindings(aDocElement, display->mBinding->mURI,
display->mBinding->mOriginPrincipal,
- PR_FALSE, getter_AddRefs(binding),
+ PR_FALSE,
+ getter_AddRefs(newPendingBinding->mBinding),
&resolveStyle);
if (NS_FAILED(rv))
return NS_OK; // Binding will load asynchronously.
- if (binding) {
- mDocument->BindingManager()->AddToAttachedQueue(binding);
+ if (newPendingBinding->mBinding) {
+ pendingBinding = newPendingBinding;
+ // state takes over owning newPendingBinding
+ state.AddPendingBinding(newPendingBinding.forget());
}
if (resolveStyle) {
styleContext = mPresShell->StyleSet()->ResolveStyleFor(aDocElement,
nsnull);
display = styleContext->GetStyleDisplay();
}
}
@@ -2515,17 +2597,17 @@ nsCSSFrameConstructor::ConstructDocEleme
// XXXbz on the other hand, if we converted this whole function to
// FrameConstructionData/Item, then we'd need the right function
// here... but would probably be able to get away with less code in this
// function in general.
static const FrameConstructionData rootTableData = FCDATA_DECL(0, nsnull);
nsRefPtr<nsStyleContext> extraRef(styleContext);
FrameConstructionItem item(&rootTableData, aDocElement,
aDocElement->Tag(), kNameSpaceID_None,
- -1, extraRef.forget());
+ -1, pendingBinding, extraRef.forget());
nsFrameItems frameItems;
// if the document is a table then just populate it.
rv = ConstructTable(state, item, mDocElementContainingBlock,
styleContext->GetStyleDisplay(),
frameItems, &contentFrame);
if (NS_FAILED(rv))
return rv;
@@ -2538,17 +2620,18 @@ nsCSSFrameConstructor::ConstructDocEleme
NS_BLOCK_FLOAT_MGR|NS_BLOCK_MARGIN_ROOT);
if (!contentFrame)
return NS_ERROR_OUT_OF_MEMORY;
nsFrameItems frameItems;
rv = ConstructBlock(state, display, aDocElement,
state.GetGeometricParent(display,
mDocElementContainingBlock),
mDocElementContainingBlock, styleContext,
- &contentFrame, frameItems, display->IsPositioned());
+ &contentFrame, frameItems, display->IsPositioned(),
+ pendingBinding);
if (NS_FAILED(rv) || frameItems.IsEmpty())
return rv;
*aNewFrame = frameItems.FirstChild();
NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
}
}
// set the primary frame
@@ -2571,17 +2654,17 @@ nsCSSFrameConstructor::ConstructDocEleme
if (processChildren) {
// Still need to process the child content
nsFrameItems childItems;
NS_ASSERTION(!nsLayoutUtils::GetAsBlock(contentFrame),
"Only XUL and SVG frames should reach here");
ProcessChildren(state, aDocElement, styleContext, contentFrame, PR_TRUE,
- childItems, PR_FALSE);
+ childItems, PR_FALSE, pendingBinding);
// Set the initial child lists
contentFrame->SetInitialChildList(nsnull, childItems);
}
SetInitialSingleChild(mDocElementContainingBlock, *aNewFrame);
return NS_OK;
@@ -3066,31 +3149,33 @@ nsCSSFrameConstructor::ConstructButtonFr
#ifdef DEBUG
// Make sure that anonymous child creation will have no effect in this case
nsIAnonymousContentCreator* creator = do_QueryFrame(blockFrame);
NS_ASSERTION(!creator, "Shouldn't be an anonymous content creator!");
#endif
rv = ProcessChildren(aState, content, styleContext, blockFrame, PR_TRUE,
- childItems, aStyleDisplay->IsBlockInside());
+ childItems, aStyleDisplay->IsBlockInside(),
+ aItem.mPendingBinding);
if (NS_FAILED(rv)) return rv;
// Set the areas frame's initial child lists
blockFrame->SetInitialChildList(nsnull, childItems);
}
SetInitialSingleChild(buttonFrame, blockFrame);
if (isLeaf) {
nsFrameItems anonymousChildItems;
// if there are any anonymous children create frames for them. Note that
// we're doing this using a different parent frame from the one we pass to
// ProcessChildren!
- CreateAnonymousFrames(aState, content, buttonFrame, anonymousChildItems);
+ CreateAnonymousFrames(aState, content, buttonFrame, aItem.mPendingBinding,
+ anonymousChildItems);
if (anonymousChildItems.NotEmpty()) {
// the anonymous content is already parented to the area frame
aState.mFrameManager->AppendFrames(blockFrame, nsnull,
anonymousChildItems);
}
}
// our new button frame returned is the top frame.
@@ -3176,30 +3261,32 @@ nsCSSFrameConstructor::ConstructSelectFr
NS_ASSERTION(!listStyle->GetStyleDisplay()->IsFloating(),
"Ended up with floating dropdown list somehow.");
// Initialize the scroll frame positioned. Note that it is NOT
// initialized as absolutely positioned.
nsIFrame* scrolledFrame = NS_NewSelectsAreaFrame(mPresShell, styleContext, flags);
InitializeSelectFrame(aState, listFrame, scrolledFrame, content,
- comboboxFrame, listStyle, PR_TRUE, aFrameItems);
+ comboboxFrame, listStyle, PR_TRUE,
+ aItem.mPendingBinding, aFrameItems);
// Set flag so the events go to the listFrame not child frames.
// XXX: We should replace this with a real widget manager similar
// to how the nsFormControlFrame works. Re-directing events is a temporary Kludge.
NS_ASSERTION(listFrame->GetView(), "ListFrame's view is nsnull");
//listFrame->GetView()->SetViewFlags(NS_VIEW_PUBLIC_FLAG_DONT_CHECK_CHILDREN);
// Create display and button frames from the combobox's anonymous content.
// The anonymous content is appended to existing anonymous content for this
// element (the scrollbars).
nsFrameItems childItems;
- CreateAnonymousFrames(aState, content, comboboxFrame, childItems);
+ CreateAnonymousFrames(aState, content, comboboxFrame,
+ aItem.mPendingBinding, childItems);
comboboxFrame->SetInitialChildList(nsnull, childItems);
// Initialize the additional popup child list which contains the
// dropdown list frame.
nsFrameItems popupItems;
popupItems.AddChild(listFrame);
comboboxFrame->SetInitialChildList(nsGkAtoms::selectPopupList,
@@ -3226,17 +3313,18 @@ nsCSSFrameConstructor::ConstructSelectFr
nsIFrame* scrolledFrame = NS_NewSelectsAreaFrame(
mPresShell, styleContext, NS_BLOCK_FLOAT_MGR);
// ******* this code stolen from Initialze ScrollFrame ********
// please adjust this code to use BuildScrollFrame.
InitializeSelectFrame(aState, listFrame, scrolledFrame, content,
- aParentFrame, styleContext, PR_FALSE, aFrameItems);
+ aParentFrame, styleContext, PR_FALSE,
+ aItem.mPendingBinding, aFrameItems);
*aNewFrame = listFrame;
}
}
return rv;
}
@@ -3248,16 +3336,17 @@ nsCSSFrameConstructor::ConstructSelectFr
nsresult
nsCSSFrameConstructor::InitializeSelectFrame(nsFrameConstructorState& aState,
nsIFrame* scrollFrame,
nsIFrame* scrolledFrame,
nsIContent* aContent,
nsIFrame* aParentFrame,
nsStyleContext* aStyleContext,
PRBool aBuildCombobox,
+ PendingBinding* aPendingBinding,
nsFrameItems& aFrameItems)
{
const nsStyleDisplay* display = aStyleContext->GetStyleDisplay();
// Initialize it
nsIFrame* geometricParent = aState.GetGeometricParent(display, aParentFrame);
// We don't call InitAndRestoreFrame for scrollFrame because we can only
@@ -3311,17 +3400,17 @@ nsCSSFrameConstructor::InitializeSelectF
if (display->IsPositioned()) {
// The area frame becomes a container for child frames that are
// absolutely positioned
aState.PushAbsoluteContainingBlock(scrolledFrame, absoluteSaveState);
}
ProcessChildren(aState, aContent, aStyleContext, scrolledFrame, PR_FALSE,
- childItems, PR_TRUE);
+ childItems, PR_TRUE, aPendingBinding);
// Set the scrolled frame's initial child lists
scrolledFrame->SetInitialChildList(nsnull, childItems);
return NS_OK;
}
nsresult
nsCSSFrameConstructor::ConstructFieldSetFrame(nsFrameConstructorState& aState,
@@ -3374,17 +3463,17 @@ nsCSSFrameConstructor::ConstructFieldSet
// The area frame becomes a container for child frames that are
// absolutely positioned
// XXXbz this is probably wrong, and once arbitrary frames can be absolute
// containing blocks we should fix this..
aState.PushAbsoluteContainingBlock(blockFrame, absoluteSaveState);
}
ProcessChildren(aState, content, styleContext, blockFrame, PR_TRUE,
- childItems, PR_TRUE);
+ childItems, PR_TRUE, aItem.mPendingBinding);
nsFrameItems fieldsetKids;
fieldsetKids.AddChild(blockFrame);
for (nsFrameList::Enumerator e(childItems); !e.AtEnd(); e.Next()) {
nsLegendFrame* legendFrame = do_QueryFrame(e.get());
if (legendFrame) {
// We want the legend to be the first frame in the fieldset child list.
@@ -3855,17 +3944,18 @@ nsCSSFrameConstructor::ConstructFrameFro
if (bits & FCDATA_USE_CHILD_ITEMS) {
rv = ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame,
childItems);
} else {
// Process the child frames.
rv = ProcessChildren(aState, content, styleContext, newFrame,
!(bits & FCDATA_DISALLOW_GENERATED_CONTENT),
childItems,
- (bits & FCDATA_ALLOW_BLOCK_STYLES) != 0);
+ (bits & FCDATA_ALLOW_BLOCK_STYLES) != 0,
+ aItem.mPendingBinding);
}
#ifdef MOZ_XUL
// More icky XUL stuff
if (aItem.mNameSpaceID == kNameSpaceID_XUL &&
(aItem.mTag == nsGkAtoms::treechildren || // trees always need titletips
content->HasAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext) ||
content->HasAttr(kNameSpaceID_None, nsGkAtoms::tooltip))) {
@@ -3926,27 +4016,31 @@ nsCSSFrameConstructor::ConstructFrameFro
}
// after the node has been constructed and initialized create any
// anonymous content a node needs.
nsresult
nsCSSFrameConstructor::CreateAnonymousFrames(nsFrameConstructorState& aState,
nsIContent* aParent,
nsIFrame* aParentFrame,
+ PendingBinding* aPendingBinding,
nsFrameItems& aChildItems)
{
nsAutoTArray<nsIContent*, 4> newAnonymousItems;
nsresult rv = GetAnonymousContent(aParent, aParentFrame, newAnonymousItems);
NS_ENSURE_SUCCESS(rv, rv);
PRUint32 count = newAnonymousItems.Length();
if (count == 0) {
return NS_OK;
}
+ nsFrameConstructorState::PendingBindingAutoPusher pusher(aState,
+ aPendingBinding);
+
nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame);
NS_ASSERTION(creator,
"How can that happen if we have nodes to construct frames for?");
for (PRUint32 i=0; i < count; i++) {
nsIContent* content = newAnonymousItems[i];
NS_ASSERTION(content, "null anonymous content?");
@@ -4299,17 +4393,21 @@ nsCSSFrameConstructor::BeginBuildingScro
InitAndRestoreFrame(aState, aContent, aParentFrame, nsnull, gfxScrollFrame);
// Create a view
nsHTMLContainerFrame::CreateViewForFrame(gfxScrollFrame, PR_FALSE);
}
// if there are any anonymous children for the scroll frame, create
// frames for them.
- CreateAnonymousFrames(aState, aContent, gfxScrollFrame, anonymousItems);
+ // Pass a null pending binding: we don't care how constructors for any of
+ // this anonymous content order with anything else. It's never been
+ // consistent anyway.
+ CreateAnonymousFrames(aState, aContent, gfxScrollFrame, nsnull,
+ anonymousItems);
aNewFrame = gfxScrollFrame;
// we used the style that was passed in. So resolve another one.
nsStyleSet *styleSet = mPresShell->StyleSet();
nsStyleContext* aScrolledChildStyle = styleSet->ResolvePseudoStyleFor(aContent,
aScrolledPseudo,
contentStyle).get();
@@ -4530,17 +4628,18 @@ nsCSSFrameConstructor::ConstructScrollab
// pass a temporary stylecontext, the correct one will be set later
nsIFrame* scrolledFrame =
NS_NewBlockFormattingContext(mPresShell, styleContext);
nsFrameItems blockItem;
nsresult rv = ConstructBlock(aState,
scrolledContentStyle->GetStyleDisplay(), content,
*aNewFrame, *aNewFrame, scrolledContentStyle,
- &scrolledFrame, blockItem, aDisplay->IsPositioned());
+ &scrolledFrame, blockItem, aDisplay->IsPositioned(),
+ aItem.mPendingBinding);
if (NS_UNLIKELY(NS_FAILED(rv))) {
// XXXbz any cleanup needed here?
return rv;
}
NS_ASSERTION(blockItem.FirstChild() == scrolledFrame,
"Scrollframe's frameItems should be exactly the scrolled frame");
FinishBuildingScrollFrame(*aNewFrame, scrolledFrame);
@@ -4566,17 +4665,18 @@ nsCSSFrameConstructor::ConstructNonScrol
*aNewFrame = NS_NewBlockFormattingContext(mPresShell, styleContext);
} else {
*aNewFrame = NS_NewBlockFrame(mPresShell, styleContext);
}
return ConstructBlock(aState, aDisplay, aItem.mContent,
aState.GetGeometricParent(aDisplay, aParentFrame),
aParentFrame, styleContext, aNewFrame,
- aFrameItems, aDisplay->IsPositioned());
+ aFrameItems, aDisplay->IsPositioned(),
+ aItem.mPendingBinding);
}
nsresult
nsCSSFrameConstructor::InitAndRestoreFrame(const nsFrameConstructorState& aState,
nsIContent* aContent,
nsIFrame* aParentFrame,
nsIFrame* aPrevInFlow,
@@ -4995,17 +5095,18 @@ nsCSSFrameConstructor::ConstructSVGForei
return NS_ERROR_OUT_OF_MEMORY;
}
nsFrameItems childItems;
// Claim to be relatively positioned so that we end up being the
// absolute containing block.
rv = ConstructBlock(aState, innerPseudoStyle->GetStyleDisplay(), content,
newFrame, newFrame, innerPseudoStyle,
- &blockFrame, childItems, PR_TRUE);
+ &blockFrame, childItems, PR_TRUE,
+ aItem.mPendingBinding);
// Give the blockFrame a view so that GetOffsetTo works for descendants
// of blockFrame with views...
nsHTMLContainerFrame::CreateViewForFrame(blockFrame, PR_TRUE);
newFrame->SetInitialChildList(nsnull, childItems);
*aNewFrame = newFrame;
@@ -5034,17 +5135,17 @@ nsCSSFrameConstructor::AddPageBreakItem(
NS_STYLE_DISPLAY_BLOCK, "Unexpected display");
static const FrameConstructionData sPageBreakData =
FCDATA_DECL(FCDATA_SKIP_FRAMEMAP, NS_NewPageBreakFrame);
// Lie about the tag and namespace so we don't trigger anything
// interesting during frame construction.
aItems.AppendItem(&sPageBreakData, aContent, nsCSSAnonBoxes::pageBreak,
- kNameSpaceID_None, -1, pseudoStyle.forget());
+ kNameSpaceID_None, -1, nsnull, pseudoStyle.forget());
}
nsresult
nsCSSFrameConstructor::ConstructFrame(nsFrameConstructorState& aState,
nsIContent* aContent,
nsIFrame* aParentFrame,
nsFrameItems& aFrameItems)
@@ -5128,35 +5229,45 @@ nsCSSFrameConstructor::AddFrameConstruct
aContent->GetParent()->GetChildAt(aContentIndex) == aContent,
"aContentIndex isn't the right content index");
// The following code allows the user to specify the base tag
// of an element using XBL. XUL and HTML objects (like boxes, menus, etc.)
// can then be extended arbitrarily.
const nsStyleDisplay* display = aStyleContext->GetStyleDisplay();
nsRefPtr<nsStyleContext> styleContext(aStyleContext);
- nsAutoEnqueueBinding binding(mDocument);
+ PendingBinding* pendingBinding = nsnull;
if ((aFlags & ITEM_ALLOW_XBL_BASE) && display->mBinding)
{
// Ensure that our XBL bindings are installed.
nsIXBLService * xblService = GetXBLService();
if (!xblService)
return;
PRBool resolveStyle;
+ nsAutoPtr<PendingBinding> newPendingBinding(new PendingBinding());
+ if (!newPendingBinding) {
+ return;
+ }
nsresult rv = xblService->LoadBindings(aContent, display->mBinding->mURI,
display->mBinding->mOriginPrincipal,
PR_FALSE,
- getter_AddRefs(binding.mBinding),
+ getter_AddRefs(newPendingBinding->mBinding),
&resolveStyle);
if (NS_FAILED(rv))
return;
+ if (newPendingBinding->mBinding) {
+ pendingBinding = newPendingBinding;
+ // aState takes over owning newPendingBinding
+ aState.AddPendingBinding(newPendingBinding.forget());
+ }
+
if (resolveStyle) {
styleContext = ResolveStyleContext(styleContext->GetParent(), aContent);
display = styleContext->GetStyleDisplay();
aStyleContext = styleContext;
}
aTag = mDocument->BindingManager()->ResolveTag(aContent, &aNameSpaceID);
}
@@ -5267,17 +5378,17 @@ nsCSSFrameConstructor::AddFrameConstruct
!(bits & FCDATA_IS_TABLE_PART);
if (canHavePageBreak && display->mBreakBefore) {
AddPageBreakItem(aContent, aStyleContext, aItems);
}
FrameConstructionItem* item =
aItems.AppendItem(data, aContent, aTag, aNameSpaceID, aContentIndex,
- styleContext.forget());
+ pendingBinding, styleContext.forget());
if (!item) {
if (isGeneratedContent) {
aContent->UnbindFromTree();
}
return;
}
item->mIsText = isText;
@@ -8158,18 +8269,21 @@ nsCSSFrameConstructor::CreateContinuingT
nsFrameConstructorState state(mPresShell, mFixedContainingBlock,
GetAbsoluteContainingBlock(newFrame),
nsnull);
headerFooterFrame = static_cast<nsTableRowGroupFrame*>
(NS_NewTableRowGroupFrame(aPresShell, rowGroupFrame->GetStyleContext()));
nsIContent* headerFooter = rowGroupFrame->GetContent();
headerFooterFrame->Init(headerFooter, newFrame, nsnull);
+ // No ancestor bindings to worry about ordering with, so null pending
+ // binding is ok.
ProcessChildren(state, headerFooter, rowGroupFrame->GetStyleContext(),
- headerFooterFrame, PR_TRUE, childItems, PR_FALSE);
+ headerFooterFrame, PR_TRUE, childItems, PR_FALSE,
+ nsnull);
NS_ASSERTION(state.mFloatedItems.IsEmpty(), "unexpected floated element");
headerFooterFrame->SetInitialChildList(nsnull, childItems);
headerFooterFrame->SetRepeatable(PR_TRUE);
// Table specific initialization
headerFooterFrame->InitRepeatedFrame(aPresContext, rowGroupFrame);
// XXX Deal with absolute and fixed frames...
@@ -9398,16 +9512,18 @@ nsCSSFrameConstructor::CreateNeededTable
parentContent,
// Lie about the tag; it doesn't matter anyway
pseudoType,
// The namespace does matter, however; it needs
// to match that of our first child item to
// match the old behavior
iter.item().mNameSpaceID,
-1,
+ // no pending binding
+ nsnull,
wrapperStyle.forget());
if (!newItem) {
return NS_ERROR_OUT_OF_MEMORY;
}
// Here we're cheating a tad... technically, table-internal items should be
// inline if aParentFrame is inline, but they'll get wrapped in an
@@ -9462,32 +9578,25 @@ nsCSSFrameConstructor::ConstructFramesFr
}
NS_ASSERTION(!aState.mHavePendingPopupgroup,
"Should have proccessed it by now");
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
- */
nsresult
nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState,
nsIContent* aContent,
nsStyleContext* aStyleContext,
nsIFrame* aFrame,
const PRBool aCanHaveGeneratedContent,
nsFrameItems& aFrameItems,
- const PRBool aAllowBlockStyles)
+ const PRBool aAllowBlockStyles,
+ PendingBinding* aPendingBinding)
{
NS_PRECONDITION(aFrame, "Must have parent frame here");
NS_PRECONDITION(aFrame->GetContentInsertionFrame() == aFrame,
"Parent frame in ProcessChildren should be its own "
"content insertion frame");
// XXXbz ideally, this would do all the pushing of various
// containing blocks as needed, so callers don't have to do it...
@@ -9502,16 +9611,19 @@ nsCSSFrameConstructor::ProcessChildren(n
nsFrameConstructorSaveState floatSaveState;
if (aFrame->IsFrameOfType(nsIFrame::eMathML) ||
aFrame->IsBoxFrame()) {
aState.PushFloatContainingBlock(nsnull, floatSaveState);
} else if (aFrame->IsFloatContainingBlock()) {
aState.PushFloatContainingBlock(aFrame, floatSaveState);
}
+ nsFrameConstructorState::PendingBindingAutoPusher pusher(aState,
+ aPendingBinding);
+
FrameConstructionItemList itemsToConstruct;
nsresult rv = NS_OK;
// If we have first-letter or first-line style then frames can get
// moved around so don't set these flags.
if (aAllowBlockStyles && !haveFirstLetterStyle && !haveFirstLineStyle) {
itemsToConstruct.SetLineBoundaryAtStart(PR_TRUE);
itemsToConstruct.SetLineBoundaryAtEnd(PR_TRUE);
@@ -10542,17 +10654,18 @@ nsresult
nsCSSFrameConstructor::ConstructBlock(nsFrameConstructorState& aState,
const nsStyleDisplay* aDisplay,
nsIContent* aContent,
nsIFrame* aParentFrame,
nsIFrame* aContentParentFrame,
nsStyleContext* aStyleContext,
nsIFrame** aNewFrame,
nsFrameItems& aFrameItems,
- PRBool aAbsPosContainer)
+ PRBool aAbsPosContainer,
+ PendingBinding* aPendingBinding)
{
// Create column wrapper if necessary
nsIFrame* blockFrame = *aNewFrame;
nsIFrame* parent = aParentFrame;
nsRefPtr<nsStyleContext> blockStyle = aStyleContext;
const nsStyleColumn* columns = aStyleContext->GetStyleColumn();
if (columns->mColumnCount != NS_STYLE_COLUMN_COUNT_AUTO
@@ -10606,17 +10719,17 @@ nsCSSFrameConstructor::ConstructBlock(ns
if (aAbsPosContainer) {
// NS_ASSERTION(aRelPos, "should have made area frame for this");
aState.PushAbsoluteContainingBlock(blockFrame, absoluteSaveState);
}
// Process the child content
nsFrameItems childItems;
rv = ProcessChildren(aState, aContent, aStyleContext, blockFrame, PR_TRUE,
- childItems, PR_TRUE);
+ childItems, PR_TRUE, aPendingBinding);
// Set the frame's initial child list
blockFrame->SetInitialChildList(nsnull, childItems);
return rv;
}
nsresult
@@ -10843,16 +10956,18 @@ nsCSSFrameConstructor::CreateIBSiblings(
}
void
nsCSSFrameConstructor::BuildInlineChildItems(nsFrameConstructorState& aState,
FrameConstructionItem& aParentItem)
{
// XXXbz should we preallocate aParentItem.mChildItems to some sane
// length? Maybe even to parentContent->GetChildCount()?
+ nsFrameConstructorState::PendingBindingAutoPusher
+ pusher(aState, aParentItem.mPendingBinding);
// Probe for generated content before
nsStyleContext* const parentStyleContext = aParentItem.mStyleContext;
nsIContent* const parentContent = aParentItem.mContent;
CreateGeneratedContentItem(aState, nsnull, parentContent,
parentStyleContext, nsCSSPseudoElements::before,
aParentItem.mChildItems);
@@ -11721,18 +11836,22 @@ nsCSSFrameConstructor::LazyGenerateChild
{
nsAutoScriptBlocker scriptBlocker;
nsCSSFrameConstructor* fc = mPresShell->FrameConstructor();
fc->BeginUpdate();
nsFrameItems childItems;
nsFrameConstructorState state(mPresShell, nsnull, nsnull, nsnull);
+ // We don't have a parent frame with a pending binding constructor here,
+ // so no need to worry about ordering of the kids' constructors with it.
+ // Pass null for the PendingBinding.
nsresult rv = fc->ProcessChildren(state, mContent, frame->GetStyleContext(),
- frame, PR_FALSE, childItems, PR_FALSE);
+ frame, PR_FALSE, childItems, PR_FALSE,
+ nsnull);
if (NS_FAILED(rv)) {
fc->EndUpdate();
return rv;
}
frame->SetInitialChildList(nsnull, childItems);
fc->EndUpdate();
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -64,16 +64,17 @@ class nsFrameManager;
class nsIDOMHTMLSelectElement;
class nsPresContext;
class nsStyleChangeList;
class nsIFrame;
struct nsGenConInitializer;
class ChildIterator;
class nsICSSAnonBoxPseudo;
class nsPageContentFrame;
+struct PendingBinding;
struct nsFindFrameHint
{
nsIFrame *mPrimaryFrameForPrevSibling; // weak ref to the primary frame for the content for which we need a frame
nsFindFrameHint() : mPrimaryFrameForPrevSibling(nsnull) { }
};
typedef void (nsLazyFrameConstructionCallback)
@@ -762,21 +763,22 @@ private:
// aContentIndex is the index of aContent in its parent's child list,
// or -1 if aContent is not in its parent's child list, or the index
// is not known.
FrameConstructionItem* AppendItem(const FrameConstructionData* aFCData,
nsIContent* aContent,
nsIAtom* aTag,
PRInt32 aNameSpaceID,
PRInt32 aContentIndex,
+ PendingBinding* aPendingBinding,
already_AddRefed<nsStyleContext> aStyleContext)
{
FrameConstructionItem* item =
new FrameConstructionItem(aFCData, aContent, aTag, aNameSpaceID,
- aContentIndex, aStyleContext);
+ aContentIndex, aPendingBinding, aStyleContext);
if (item) {
PR_APPEND_LINK(item, &mItems);
++mItemCount;
++mDesiredParentCounts[item->DesiredParentType()];
} else {
// Clean up the style context
nsRefPtr<nsStyleContext> sc(aStyleContext);
}
@@ -918,20 +920,21 @@ private:
struct FrameConstructionItem : public PRCList {
// No need to PR_INIT_CLIST in the constructor because the only
// place that creates us immediately appends us.
FrameConstructionItem(const FrameConstructionData* aFCData,
nsIContent* aContent,
nsIAtom* aTag,
PRInt32 aNameSpaceID,
PRInt32 aContentIndex,
+ PendingBinding* aPendingBinding,
already_AddRefed<nsStyleContext> aStyleContext) :
mFCData(aFCData), mContent(aContent), mTag(aTag),
mNameSpaceID(aNameSpaceID), mContentIndex(aContentIndex),
- mStyleContext(aStyleContext),
+ mPendingBinding(aPendingBinding), mStyleContext(aStyleContext),
mIsText(PR_FALSE), mIsGeneratedContent(PR_FALSE),
mIsRootPopupgroup(PR_FALSE), mIsAllInline(PR_FALSE), mIsBlock(PR_FALSE),
mHasInlineEnds(PR_FALSE), mIsPopup(PR_FALSE),
mIsLineParticipant(PR_FALSE)
{}
~FrameConstructionItem() {
if (mIsGeneratedContent) {
mContent->UnbindFromTree();
@@ -958,16 +961,25 @@ private:
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 index of mContent in its parent's child list, or -1 if it's
// not in the parent's child list or not known.
PRInt32 mContentIndex;
+ // The PendingBinding for this frame construction item, if any. May be
+ // null. We maintain a list of PendingBindings in the frame construction
+ // state in the order in which AddToAttachedQueue should be called on them:
+ // depth-first, post-order traversal order. Since we actually traverse the
+ // DOM in a mix of breadth-first and depth-first, it is the responsibility
+ // of whoever constructs FrameConstructionItem kids of a given
+ // FrameConstructionItem to push its mPendingBinding as the current
+ // insertion point before doing so and pop it afterward.
+ PendingBinding* mPendingBinding;
// The style context to use for creating the new frame.
nsRefPtr<nsStyleContext> mStyleContext;
// Whether this is a text content item.
PRPackedBool mIsText;
// Whether this is a generated content container.
// If it is, mContent is a strong pointer.
PRPackedBool mIsGeneratedContent;
// Whether this is an item for the root popupgroup.
@@ -1160,16 +1172,17 @@ private:
FCItemIterator& aItem,
nsIFrame* aParentFrame,
nsFrameItems& aFrameItems);
static PRBool AtLineBoundary(FCItemIterator& aIter);
nsresult CreateAnonymousFrames(nsFrameConstructorState& aState,
nsIContent* aParent,
nsIFrame* aParentFrame,
+ PendingBinding * aPendingBinding,
nsFrameItems& aChildItems);
nsresult GetAnonymousContent(nsIContent* aParent,
nsIFrame* aParentFrame,
nsTArray<nsIContent*>& aAnonContent);
//MathML Mod - RBS
#ifdef MOZ_MATHML
@@ -1290,27 +1303,27 @@ private:
* pushed as the float containing block, as needed. aFrame is also
* used to find the parent style context for the kids' style contexts
* (not necessary aFrame's style context).
* @param aCanHaveGeneratedContent Whether to allow :before and
* :after styles on the parent.
* @param aFrameItems the list in which we should place the in-flow children
* @param aAllowBlockStyles Whether to allow first-letter and first-line
* styles on the parent.
- * @param aTableCreator if non-null, will just make this method call
- * TableProcessChildren between constructing the ::before and ::after
- * content instead of doing whatever it would normally do.
+ * @param aPendingBinding Make sure to push this into aState before doing any
+ * child item construction.
*/
nsresult ProcessChildren(nsFrameConstructorState& aState,
nsIContent* aContent,
nsStyleContext* aStyleContext,
nsIFrame* aFrame,
const PRBool aCanHaveGeneratedContent,
nsFrameItems& aFrameItems,
- const PRBool aAllowBlockStyles);
+ const PRBool aAllowBlockStyles,
+ PendingBinding* aPendingBinding);
nsIFrame* GetFrameFor(nsIContent* aContent);
/**
* These two functions are used when we start frame creation from a non-root
* element. They should recreate the same state that we would have
* arrived at if we had built frames from the root frame to aFrame.
* Therefore, any calls to PushFloatContainingBlock and
@@ -1357,16 +1370,17 @@ private:
nsresult
InitializeSelectFrame(nsFrameConstructorState& aState,
nsIFrame* scrollFrame,
nsIFrame* scrolledFrame,
nsIContent* aContent,
nsIFrame* aParentFrame,
nsStyleContext* aStyleContext,
PRBool aBuildCombobox,
+ PendingBinding* aPendingBinding,
nsFrameItems& aFrameItems);
nsresult MaybeRecreateFramesForContent(nsIContent* aContent);
// If aAsyncInsert is true then a restyle event will be posted to handle the
// required ContentInserted call instead of doing it immediately.
nsresult RecreateFramesForContent(nsIContent* aContent, PRBool aAsyncInsert);
@@ -1430,25 +1444,28 @@ private:
// @param aNewFrame an in/out parameter. On input it is the block to be
// constructed. On output it is reset to the outermost
// frame constructed (e.g. if we need to wrap the block in an
// nsColumnSetFrame.
// @param aParentFrame is the desired parent for the (possibly wrapped)
// block
// @param aContentParent is the parent the block would have if it
// were in-flow
+ // @param aPendingBinding the pending binding from this block's frame
+ // construction item.
nsresult ConstructBlock(nsFrameConstructorState& aState,
const nsStyleDisplay* aDisplay,
nsIContent* aContent,
nsIFrame* aParentFrame,
nsIFrame* aContentParentFrame,
nsStyleContext* aStyleContext,
nsIFrame** aNewFrame,
nsFrameItems& aFrameItems,
- PRBool aAbsPosContainer);
+ PRBool aAbsPosContainer,
+ PendingBinding* aPendingBinding);
nsresult ConstructInline(nsFrameConstructorState& aState,
FrameConstructionItem& aItem,
nsIFrame* aParentFrame,
const nsStyleDisplay* aDisplay,
nsFrameItems& aFrameItems,
nsIFrame** aNewFrame);