diff --git a/layout/base/crashtests/537624-1.html b/layout/base/crashtests/537624-1.html new file mode 100644 index 00000000000..a6c19516eed --- /dev/null +++ b/layout/base/crashtests/537624-1.html @@ -0,0 +1,18 @@ + + + + + + +
+ + diff --git a/layout/base/crashtests/736924-1.html b/layout/base/crashtests/736924-1.html new file mode 100644 index 00000000000..b9274bd78cb --- /dev/null +++ b/layout/base/crashtests/736924-1.html @@ -0,0 +1,23 @@ + + + + diff --git a/layout/base/crashtests/crashtests.list b/layout/base/crashtests/crashtests.list index 69e5c2bf6e2..52b4f0fb134 100644 --- a/layout/base/crashtests/crashtests.list +++ b/layout/base/crashtests/crashtests.list @@ -299,6 +299,7 @@ load 536720.xul load 537059-1.xhtml load 537141-1.xhtml load 537562-1.xhtml +load 537624-1.html load 537631-1.html load 538082-1.xul load 538207-1.xhtml @@ -352,3 +353,4 @@ load 722137.html load 725535.html load 727601.html load 736389-1.xhtml +load 736924-1.html diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 4d1e54ca7db..4ad3b8b4137 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -4933,6 +4933,7 @@ nsCSSFrameConstructor::ConstructFrame(nsFrameConstructorState& aState, NS_PRECONDITION(nsnull != aParentFrame, "no parent frame"); FrameConstructionItemList items; AddFrameConstructionItems(aState, aContent, true, aParentFrame, items); + items.SetTriedConstructingFrames(); for (FCItemIterator iter(items); !iter.IsDone(); iter.Next()) { NS_ASSERTION(iter.item().DesiredParentType() == GetParentType(aParentFrame), @@ -4995,16 +4996,11 @@ nsCSSFrameConstructor::AddFrameConstructionItems(nsFrameConstructorState& aState aItems); } -/** - * Set aContent as undisplayed content with style context aStyleContext. This - * method enforces the invariant that all style contexts in the undisplayed - * content map must be non-pseudo contexts and also handles unbinding - * undisplayed generated content as needed. - */ -static void -SetAsUndisplayedContent(nsFrameManager* aFrameManager, nsIContent* aContent, - nsStyleContext* aStyleContext, - bool aIsGeneratedContent) +/* static */ void +nsCSSFrameConstructor::SetAsUndisplayedContent(FrameConstructionItemList& aList, + nsIContent* aContent, + nsStyleContext* aStyleContext, + bool aIsGeneratedContent) { if (aStyleContext->GetPseudo()) { if (aIsGeneratedContent) { @@ -5014,7 +5010,7 @@ SetAsUndisplayedContent(nsFrameManager* aFrameManager, nsIContent* aContent, } NS_ASSERTION(!aIsGeneratedContent, "Should have had pseudo type"); - aFrameManager->SetUndisplayedContent(aContent, aStyleContext); + aList.AppendUndisplayedItem(aContent, aStyleContext); } void @@ -5079,7 +5075,7 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState // Pre-check for display "none" - if we find that, don't create // any frame at all if (NS_STYLE_DISPLAY_NONE == display->mDisplay) { - SetAsUndisplayedContent(this, aContent, styleContext, isGeneratedContent); + SetAsUndisplayedContent(aItems, aContent, styleContext, isGeneratedContent); return; } @@ -5103,7 +5099,8 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState !aContent->IsRootOfNativeAnonymousSubtree()) { // No frame for aContent if (!isText) { - SetAsUndisplayedContent(this, aContent, styleContext, isGeneratedContent); + SetAsUndisplayedContent(aItems, aContent, styleContext, + isGeneratedContent); } return; } @@ -5127,7 +5124,7 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState aParentFrame->IsFrameOfType(nsIFrame::eSVG) && !aParentFrame->IsFrameOfType(nsIFrame::eSVGForeignObject) ) { - SetAsUndisplayedContent(this, element, styleContext, + SetAsUndisplayedContent(aItems, element, styleContext, isGeneratedContent); return; } @@ -5158,7 +5155,7 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState NS_ASSERTION(data, "Should have frame construction data now"); if (data->mBits & FCDATA_SUPPRESS_FRAME) { - SetAsUndisplayedContent(this, element, styleContext, isGeneratedContent); + SetAsUndisplayedContent(aItems, element, styleContext, isGeneratedContent); return; } @@ -5168,7 +5165,7 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState aParentFrame->GetType() != nsGkAtoms::menuFrame)) { if (!aState.mPopupItems.containingBlock && !aState.mHavePendingPopupgroup) { - SetAsUndisplayedContent(this, element, styleContext, + SetAsUndisplayedContent(aItems, element, styleContext, isGeneratedContent); return; } @@ -5185,7 +5182,7 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState aParentFrame->GetType() == nsGkAtoms::tableColGroupFrame && (!(bits & FCDATA_IS_TABLE_PART) || display->mDisplay != NS_STYLE_DISPLAY_TABLE_COLUMN)) { - SetAsUndisplayedContent(this, aContent, styleContext, isGeneratedContent); + SetAsUndisplayedContent(aItems, aContent, styleContext, isGeneratedContent); return; } @@ -8717,6 +8714,7 @@ nsCSSFrameConstructor::ReplicateFixedFrames(nsPageContentFrame* aParentFrame) ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_PAGE_BREAK, items); + items.SetTriedConstructingFrames(); for (FCItemIterator iter(items); !iter.IsDone(); iter.Next()) { NS_ASSERTION(iter.item().DesiredParentType() == GetParentType(canvasFrame), @@ -9442,6 +9440,8 @@ nsCSSFrameConstructor::ConstructFramesFromItemList(nsFrameConstructorState& aSta nsIFrame* aParentFrame, nsFrameItems& aFrameItems) { + aItems.SetTriedConstructingFrames(); + nsresult rv = CreateNeededTablePseudos(aState, aItems, aParentFrame); NS_ENSURE_SUCCESS(rv, rv); @@ -11832,7 +11832,10 @@ Iterator::AppendItemsToList(const Iterator& aEnd, NS_ASSERTION(&aTargetList != &mList, "Unexpected call"); NS_PRECONDITION(mEnd == aEnd.mEnd, "end iterator for some other list?"); - if (!AtStart() || !aEnd.IsDone() || !aTargetList.IsEmpty()) { + // We can't just move our guts to the other list if it already has + // some information or if we're not moving our entire list. + if (!AtStart() || !aEnd.IsDone() || !aTargetList.IsEmpty() || + !aTargetList.mUndisplayedItems.IsEmpty()) { do { AppendItemToList(aTargetList); } while (*this != aEnd); @@ -11841,7 +11844,8 @@ Iterator::AppendItemsToList(const Iterator& aEnd, // move over the list of items PR_INSERT_AFTER(&aTargetList.mItems, &mList.mItems); - PR_REMOVE_LINK(&mList.mItems); + // Need to init when we remove to makd ~FrameConstructionItemList work right. + PR_REMOVE_AND_INIT_LINK(&mList.mItems); // Copy over the various counters aTargetList.mInlineCount = mList.mInlineCount; @@ -11851,7 +11855,11 @@ Iterator::AppendItemsToList(const Iterator& aEnd, memcpy(aTargetList.mDesiredParentCounts, mList.mDesiredParentCounts, sizeof(aTargetList.mDesiredParentCounts)); + // Swap out undisplayed item arrays, before we nuke the array on our end + aTargetList.mUndisplayedItems.SwapElements(mList.mUndisplayedItems); + // reset mList + mList.~FrameConstructionItemList(); new (&mList) FrameConstructionItemList(); // Point ourselves to aEnd, as advertised diff --git a/layout/base/nsCSSFrameConstructor.h b/layout/base/nsCSSFrameConstructor.h index 8ed7849bce4..5423657b0e0 100644 --- a/layout/base/nsCSSFrameConstructor.h +++ b/layout/base/nsCSSFrameConstructor.h @@ -816,7 +816,8 @@ private: mItemCount(0), mLineBoundaryAtStart(false), mLineBoundaryAtEnd(false), - mParentHasNoXBLChildren(false) + mParentHasNoXBLChildren(false), + mTriedConstructingFrames(false) { PR_INIT_CLIST(&mItems); memset(mDesiredParentCounts, 0, sizeof(mDesiredParentCounts)); @@ -832,6 +833,20 @@ private: // Leaves our mItems pointing to deleted memory in both directions, // but that's OK at this point. + + // Create the undisplayed entries for our mUndisplayedItems, if any, but + // only if we have tried constructing frames for this item list. If we + // haven't, then we're just throwing it away and will probably try again. + if (!mUndisplayedItems.IsEmpty() && mTriedConstructingFrames) { + // We could store the frame manager in a member, but just + // getting it off the style context is not too bad. + nsFrameManager *mgr = + mUndisplayedItems[0].mStyleContext->PresContext()->FrameManager(); + for (PRUint32 i = 0; i < mUndisplayedItems.Length(); ++i) { + UndisplayedItem& item = mUndisplayedItems[i]; + mgr->SetUndisplayedContent(item.mContent, item.mStyleContext); + } + } } void SetLineBoundaryAtStart(bool aBoundary) { mLineBoundaryAtStart = aBoundary; } @@ -839,6 +854,7 @@ private: void SetParentHasNoXBLChildren(bool aHasNoXBLChildren) { mParentHasNoXBLChildren = aHasNoXBLChildren; } + void SetTriedConstructingFrames() { mTriedConstructingFrames = true; } bool HasLineBoundaryAtStart() { return mLineBoundaryAtStart; } bool HasLineBoundaryAtEnd() { return mLineBoundaryAtEnd; } bool ParentHasNoXBLChildren() { return mParentHasNoXBLChildren; } @@ -871,6 +887,11 @@ private: return item; } + void AppendUndisplayedItem(nsIContent* aContent, + nsStyleContext* aStyleContext) { + mUndisplayedItems.AppendElement(UndisplayedItem(aContent, aStyleContext)); + } + void InlineItemAdded() { ++mInlineCount; } void BlockItemAdded() { ++mBlockCount; } void LineParticipantItemAdded() { ++mLineParticipantCount; } @@ -977,6 +998,15 @@ private: return static_cast(item); } + struct UndisplayedItem { + UndisplayedItem(nsIContent* aContent, nsStyleContext* aStyleContext) : + mContent(aContent), mStyleContext(aStyleContext) + {} + + nsIContent * const mContent; + nsRefPtr mStyleContext; + }; + // Adjust our various counts for aItem being added or removed. aDelta // should be either +1 or -1 depending on which is happening. void AdjustCountsForItem(FrameConstructionItem* aItem, PRInt32 aDelta); @@ -995,6 +1025,10 @@ private: bool mLineBoundaryAtEnd; // True if the parent is guaranteed to have no XBL anonymous children bool mParentHasNoXBLChildren; + // True if we have tried constructing frames from this list + bool mTriedConstructingFrames; + + nsTArray mUndisplayedItems; }; typedef FrameConstructionItemList::Iterator FCItemIterator; @@ -1097,7 +1131,7 @@ private: FrameConstructionItemList mChildItems; private: - FrameConstructionItem(const FrameConstructionItem& aOther); /* not implemented */ + FrameConstructionItem(const FrameConstructionItem& aOther) MOZ_DELETE; /* not implemented */ }; /** @@ -1779,6 +1813,18 @@ private: mDocument->SetNeedLayoutFlush(); } + /** + * Add the pair (aContent, aStyleContext) to the undisplayed items + * in aList as needed. This method enforces the invariant that all + * style contexts in the undisplayed content map must be non-pseudo + * contexts and also handles unbinding undisplayed generated content + * as needed. + */ + static void SetAsUndisplayedContent(FrameConstructionItemList& aList, + nsIContent* aContent, + nsStyleContext* aStyleContext, + bool aIsGeneratedContent); + public: friend class nsFrameConstructorState;