From 656b35d352ea0dbe87e12c039035400a155d58cc Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Wed, 5 May 2010 14:18:05 -0400 Subject: [PATCH] Bug 563837. Don't set primary frames when doing paginated replication of frames for whatever reason, and loosen up some asserts accordingly. r=roc --- layout/base/nsCSSFrameConstructor.cpp | 54 ++++++++++++++++++--------- layout/base/nsCSSFrameConstructor.h | 9 +++-- 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 55d092147454..609de6d4c8b4 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -747,6 +747,14 @@ public: // we have not yet created the relevant frame. PRPackedBool mHavePendingPopupgroup; + // If true (which is the default) then call SetPrimaryFrame() as needed + // during frame construction. If false, don't make any SetPrimaryFrame() + // calls. The mSetPrimaryFrames == PR_FALSE mode is meant to be used for + // construction of random "extra" frames for elements via normal frame + // construction APIs (e.g. replication of things across pages in paginated + // mode). + PRPackedBool mSetPrimaryFrames; + nsCOMArray mGeneratedTextNodesWithInitializer; // Constructor @@ -910,6 +918,7 @@ nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShe aAbsoluteContainingBlock->GetStyleDisplay()-> HasTransform()), mHavePendingPopupgroup(PR_FALSE), + mSetPrimaryFrames(PR_TRUE), mCurrentPendingBindingInsertionPoint(&mPendingBindings) { #ifdef MOZ_XUL @@ -941,6 +950,7 @@ nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShell, aAbsoluteContainingBlock->GetStyleDisplay()-> HasTransform()), mHavePendingPopupgroup(PR_FALSE), + mSetPrimaryFrames(PR_TRUE), mCurrentPendingBindingInsertionPoint(&mPendingBindings) { #ifdef MOZ_XUL @@ -2167,13 +2177,15 @@ nsCSSFrameConstructor::ConstructTableCell(nsFrameConstructorState& aState, return NS_OK; } -static PRBool -NeedFrameFor(nsIFrame* aParentFrame, +static inline PRBool +NeedFrameFor(const nsFrameConstructorState& aState, + nsIFrame* aParentFrame, nsIContent* aChildContent) { // XXX the GetContent() != aChildContent check is needed due to bug 135040. // Remove it once that's fixed. NS_PRECONDITION(!aChildContent->GetPrimaryFrame() || + !aState.mSetPrimaryFrames || aChildContent->GetPrimaryFrame()->GetContent() != aChildContent, "Why did we get called?"); @@ -3433,7 +3445,8 @@ nsCSSFrameConstructor::ConstructTextFrame(const FrameConstructionData* aData, // Add the newly constructed frame to the flow aFrameItems.AddChild(newFrame); - aContent->SetPrimaryFrame(newFrame); + if (aState.mSetPrimaryFrames) + aContent->SetPrimaryFrame(newFrame); return rv; } @@ -3859,7 +3872,7 @@ nsCSSFrameConstructor::ConstructFrameFromItemInternal(FrameConstructionItem& aIt ((bits & FCDATA_IS_LINE_PARTICIPANT) != 0), "Incorrectly set FCDATA_IS_LINE_PARTICIPANT bits"); - if (!(bits & FCDATA_SKIP_FRAMESET)) { + if (aState.mSetPrimaryFrames && !(bits & FCDATA_SKIP_FRAMESET)) { aItem.mContent->SetPrimaryFrame(primaryFrame); } @@ -5008,7 +5021,7 @@ nsCSSFrameConstructor::AddFrameConstructionItems(nsFrameConstructorState& aState aContent->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME); // don't create a whitespace frame if aParent doesn't want it - if (!NeedFrameFor(aParentFrame, aContent)) { + if (!NeedFrameFor(aState, aParentFrame, aContent)) { return; } @@ -5409,7 +5422,7 @@ nsCSSFrameConstructor::ConstructFramesFromItem(nsFrameConstructorState& aState, aIter.List()->ParentHasNoXBLChildren() && !(aState.mAdditionalStateBits & NS_FRAME_GENERATED_CONTENT) && (item.mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT) && - item.IsWhitespace()) + item.IsWhitespace(aState)) return NS_OK; return ConstructTextFrame(item.mFCData, aState, item.mContent, @@ -8410,6 +8423,7 @@ nsCSSFrameConstructor::CreateContinuingTableFrame(nsIPresShell* aPresShell, nsFrameConstructorState state(mPresShell, mFixedContainingBlock, GetAbsoluteContainingBlock(newFrame), nsnull); + state.mSetPrimaryFrames = PR_FALSE; headerFooterFrame = static_cast (NS_NewTableRowGroupFrame(aPresShell, rowGroupFrame->GetStyleContext())); @@ -8736,6 +8750,7 @@ nsCSSFrameConstructor::ReplicateFixedFrames(nsPageContentFrame* aParentFrame) nsFrameConstructorState state(mPresShell, aParentFrame, nsnull, mRootElementFrame); + state.mSetPrimaryFrames = PR_FALSE; // Iterate across fixed frames and replicate each whose placeholder is a // descendant of aFrame. (We don't want to explicitly copy placeholders that @@ -9272,7 +9287,8 @@ nsCSSFrameConstructor::sPseudoParentData[eParentTypeCount] = { * contain only items for frames that can be direct kids of aParentFrame. */ nsresult -nsCSSFrameConstructor::CreateNeededTablePseudos(FrameConstructionItemList& aItems, +nsCSSFrameConstructor::CreateNeededTablePseudos(nsFrameConstructorState& aState, + FrameConstructionItemList& aItems, nsIFrame* aParentFrame) { ParentType ourParentType = GetParentType(aParentFrame); @@ -9322,8 +9338,8 @@ nsCSSFrameConstructor::CreateNeededTablePseudos(FrameConstructionItemList& aItem FCItemIterator spaceEndIter(endIter); if (prevParentType != eTypeBlock && !aParentFrame->IsGeneratedContentFrame() && - spaceEndIter.item().IsWhitespace()) { - PRBool trailingSpaces = spaceEndIter.SkipWhitespace(); + spaceEndIter.item().IsWhitespace(aState)) { + PRBool trailingSpaces = spaceEndIter.SkipWhitespace(aState); // See whether we can drop the whitespace if (trailingSpaces || @@ -9469,13 +9485,13 @@ nsCSSFrameConstructor::CreateNeededTablePseudos(FrameConstructionItemList& aItem return NS_OK; } -nsresult +inline nsresult nsCSSFrameConstructor::ConstructFramesFromItemList(nsFrameConstructorState& aState, FrameConstructionItemList& aItems, nsIFrame* aParentFrame, nsFrameItems& aFrameItems) { - nsresult rv = CreateNeededTablePseudos(aItems, aParentFrame); + nsresult rv = CreateNeededTablePseudos(aState, aItems, aParentFrame); NS_ENSURE_SUCCESS(rv, rv); #ifdef DEBUG @@ -11040,7 +11056,7 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState, // iter points to an item that wants a different parent. If it's not // whitespace, we're done; no more point scanning the list. - if (!iter.item().IsWhitespace()) { + if (!iter.item().IsWhitespace(aState)) { break; } @@ -11072,7 +11088,7 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState, FCItemIterator spaceEndIter(iter); // Advance spaceEndIter past any whitespace - PRBool trailingSpaces = spaceEndIter.SkipWhitespace(); + PRBool trailingSpaces = spaceEndIter.SkipWhitespace(aState); PRBool okToDrop; if (trailingSpaces) { @@ -11841,9 +11857,11 @@ nsCSSFrameConstructor::LazyGenerateChildrenEvent::Run() // nsCSSFrameConstructor::FrameConstructionItem methods // ////////////////////////////////////////////////////////// PRBool -nsCSSFrameConstructor::FrameConstructionItem::IsWhitespace() const +nsCSSFrameConstructor:: +FrameConstructionItem::IsWhitespace(nsFrameConstructorState& aState) const { - NS_PRECONDITION(!mContent->GetPrimaryFrame(), "How did that happen?"); + NS_PRECONDITION(!aState.mSetPrimaryFrames || + !mContent->GetPrimaryFrame(), "How did that happen?"); if (!mIsText) { return PR_FALSE; } @@ -11892,16 +11910,16 @@ Iterator::SkipItemsWantingParentType(ParentType aParentType) inline PRBool nsCSSFrameConstructor::FrameConstructionItemList:: -Iterator::SkipWhitespace() +Iterator::SkipWhitespace(nsFrameConstructorState& aState) { NS_PRECONDITION(!IsDone(), "Shouldn't be done yet"); - NS_PRECONDITION(item().IsWhitespace(), "Not pointing to whitespace?"); + NS_PRECONDITION(item().IsWhitespace(aState), "Not pointing to whitespace?"); do { Next(); if (IsDone()) { return PR_TRUE; } - } while (item().IsWhitespace()); + } while (item().IsWhitespace(aState)); return PR_FALSE; } diff --git a/layout/base/nsCSSFrameConstructor.h b/layout/base/nsCSSFrameConstructor.h index e24b05b579e7..7652c7b4705f 100644 --- a/layout/base/nsCSSFrameConstructor.h +++ b/layout/base/nsCSSFrameConstructor.h @@ -964,7 +964,7 @@ private: // Skip over whitespace. Return whether the iterator is done after doing // that. The iterator must not be done, and must be pointing to a // whitespace item when this is called. - inline PRBool SkipWhitespace(); + inline PRBool SkipWhitespace(nsFrameConstructorState& aState); // Remove the item pointed to by this iterator from its current list and // Append it to aTargetList. This iterator is advanced to point to the @@ -1064,7 +1064,7 @@ private: // Don't call this unless the frametree really depends on the answer! // Especially so for generated content, where we don't want to reframe // things. - PRBool IsWhitespace() const; + PRBool IsWhitespace(nsFrameConstructorState& aState) const; PRBool IsLineBoundary() const { return mIsBlock || (mFCData->mBits & FCDATA_IS_LINE_BREAK); @@ -1133,8 +1133,9 @@ private: * @param aItems the child frame construction items before pseudo creation * @param aParentFrame the parent frame we're creating pseudos for */ - nsresult CreateNeededTablePseudos(FrameConstructionItemList& aItems, - nsIFrame* aParentFrame); + inline nsresult CreateNeededTablePseudos(nsFrameConstructorState& aState, + FrameConstructionItemList& aItems, + nsIFrame* aParentFrame); /** * Function to adjust aParentFrame to deal with captions.