Bug 537624. Don't set up undisplayed entries until we're sure we're creating frames from the relevant FrameConstructionItemList. r=roc

This commit is contained in:
Boris Zbarsky 2012-03-19 18:22:02 -04:00
Родитель 21f5f2e536
Коммит 5c9ce7a9ee
5 изменённых файлов: 118 добавлений и 21 удалений

Просмотреть файл

@ -0,0 +1,18 @@
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript">
function boom()
{
var a = document.getElementById("a");
var b = document.getElementById("b");
a.insertBefore(b, a.firstChild);
}
</script>
</head>
<body onload="boom();"><span id="a"><div></div></span><span id="b"><span style="display: none;"></span><span style="display: none;"></span></span></body>
</html>

Просмотреть файл

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<script>
function boom()
{
var a = document.createElementNS("http://www.w3.org/1999/xhtml", "span");
var b = document.createElementNS("http://www.w3.org/1999/xhtml", "span");
var x = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
var y = document.createElementNS("http://www.w3.org/1999/xhtml", "basefont");
var z = document.createElementNS("http://www.w3.org/1999/xhtml", "body");
z.setAttributeNS(null, "link", "#333333");
document.documentElement.appendChild(a);
b.appendChild(x);
b.appendChild(y);
document.documentElement.offsetHeight;
a.appendChild(b);
document.documentElement.offsetHeight;
document.createElementNS("http://www.w3.org/1999/xhtml", "div").appendChild(y);
b.appendChild(z);
}
</script>
<body onload="boom();"></body>

Просмотреть файл

@ -299,6 +299,7 @@ load 536720.xul
load 537059-1.xhtml load 537059-1.xhtml
load 537141-1.xhtml load 537141-1.xhtml
load 537562-1.xhtml load 537562-1.xhtml
load 537624-1.html
load 537631-1.html load 537631-1.html
load 538082-1.xul load 538082-1.xul
load 538207-1.xhtml load 538207-1.xhtml
@ -352,3 +353,4 @@ load 722137.html
load 725535.html load 725535.html
load 727601.html load 727601.html
load 736389-1.xhtml load 736389-1.xhtml
load 736924-1.html

Просмотреть файл

@ -4933,6 +4933,7 @@ nsCSSFrameConstructor::ConstructFrame(nsFrameConstructorState& aState,
NS_PRECONDITION(nsnull != aParentFrame, "no parent frame"); NS_PRECONDITION(nsnull != aParentFrame, "no parent frame");
FrameConstructionItemList items; FrameConstructionItemList items;
AddFrameConstructionItems(aState, aContent, true, aParentFrame, items); AddFrameConstructionItems(aState, aContent, true, aParentFrame, items);
items.SetTriedConstructingFrames();
for (FCItemIterator iter(items); !iter.IsDone(); iter.Next()) { for (FCItemIterator iter(items); !iter.IsDone(); iter.Next()) {
NS_ASSERTION(iter.item().DesiredParentType() == GetParentType(aParentFrame), NS_ASSERTION(iter.item().DesiredParentType() == GetParentType(aParentFrame),
@ -4995,16 +4996,11 @@ nsCSSFrameConstructor::AddFrameConstructionItems(nsFrameConstructorState& aState
aItems); aItems);
} }
/** /* static */ void
* Set aContent as undisplayed content with style context aStyleContext. This nsCSSFrameConstructor::SetAsUndisplayedContent(FrameConstructionItemList& aList,
* method enforces the invariant that all style contexts in the undisplayed nsIContent* aContent,
* content map must be non-pseudo contexts and also handles unbinding nsStyleContext* aStyleContext,
* undisplayed generated content as needed. bool aIsGeneratedContent)
*/
static void
SetAsUndisplayedContent(nsFrameManager* aFrameManager, nsIContent* aContent,
nsStyleContext* aStyleContext,
bool aIsGeneratedContent)
{ {
if (aStyleContext->GetPseudo()) { if (aStyleContext->GetPseudo()) {
if (aIsGeneratedContent) { if (aIsGeneratedContent) {
@ -5014,7 +5010,7 @@ SetAsUndisplayedContent(nsFrameManager* aFrameManager, nsIContent* aContent,
} }
NS_ASSERTION(!aIsGeneratedContent, "Should have had pseudo type"); NS_ASSERTION(!aIsGeneratedContent, "Should have had pseudo type");
aFrameManager->SetUndisplayedContent(aContent, aStyleContext); aList.AppendUndisplayedItem(aContent, aStyleContext);
} }
void void
@ -5079,7 +5075,7 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState
// Pre-check for display "none" - if we find that, don't create // Pre-check for display "none" - if we find that, don't create
// any frame at all // any frame at all
if (NS_STYLE_DISPLAY_NONE == display->mDisplay) { if (NS_STYLE_DISPLAY_NONE == display->mDisplay) {
SetAsUndisplayedContent(this, aContent, styleContext, isGeneratedContent); SetAsUndisplayedContent(aItems, aContent, styleContext, isGeneratedContent);
return; return;
} }
@ -5103,7 +5099,8 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState
!aContent->IsRootOfNativeAnonymousSubtree()) { !aContent->IsRootOfNativeAnonymousSubtree()) {
// No frame for aContent // No frame for aContent
if (!isText) { if (!isText) {
SetAsUndisplayedContent(this, aContent, styleContext, isGeneratedContent); SetAsUndisplayedContent(aItems, aContent, styleContext,
isGeneratedContent);
} }
return; return;
} }
@ -5127,7 +5124,7 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState
aParentFrame->IsFrameOfType(nsIFrame::eSVG) && aParentFrame->IsFrameOfType(nsIFrame::eSVG) &&
!aParentFrame->IsFrameOfType(nsIFrame::eSVGForeignObject) !aParentFrame->IsFrameOfType(nsIFrame::eSVGForeignObject)
) { ) {
SetAsUndisplayedContent(this, element, styleContext, SetAsUndisplayedContent(aItems, element, styleContext,
isGeneratedContent); isGeneratedContent);
return; return;
} }
@ -5158,7 +5155,7 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState
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) {
SetAsUndisplayedContent(this, element, styleContext, isGeneratedContent); SetAsUndisplayedContent(aItems, element, styleContext, isGeneratedContent);
return; return;
} }
@ -5168,7 +5165,7 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState
aParentFrame->GetType() != nsGkAtoms::menuFrame)) { aParentFrame->GetType() != nsGkAtoms::menuFrame)) {
if (!aState.mPopupItems.containingBlock && if (!aState.mPopupItems.containingBlock &&
!aState.mHavePendingPopupgroup) { !aState.mHavePendingPopupgroup) {
SetAsUndisplayedContent(this, element, styleContext, SetAsUndisplayedContent(aItems, element, styleContext,
isGeneratedContent); isGeneratedContent);
return; return;
} }
@ -5185,7 +5182,7 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState
aParentFrame->GetType() == nsGkAtoms::tableColGroupFrame && aParentFrame->GetType() == nsGkAtoms::tableColGroupFrame &&
(!(bits & FCDATA_IS_TABLE_PART) || (!(bits & FCDATA_IS_TABLE_PART) ||
display->mDisplay != NS_STYLE_DISPLAY_TABLE_COLUMN)) { display->mDisplay != NS_STYLE_DISPLAY_TABLE_COLUMN)) {
SetAsUndisplayedContent(this, aContent, styleContext, isGeneratedContent); SetAsUndisplayedContent(aItems, aContent, styleContext, isGeneratedContent);
return; return;
} }
@ -8717,6 +8714,7 @@ nsCSSFrameConstructor::ReplicateFixedFrames(nsPageContentFrame* aParentFrame)
ITEM_ALLOW_XBL_BASE | ITEM_ALLOW_XBL_BASE |
ITEM_ALLOW_PAGE_BREAK, ITEM_ALLOW_PAGE_BREAK,
items); items);
items.SetTriedConstructingFrames();
for (FCItemIterator iter(items); !iter.IsDone(); iter.Next()) { for (FCItemIterator iter(items); !iter.IsDone(); iter.Next()) {
NS_ASSERTION(iter.item().DesiredParentType() == NS_ASSERTION(iter.item().DesiredParentType() ==
GetParentType(canvasFrame), GetParentType(canvasFrame),
@ -9442,6 +9440,8 @@ nsCSSFrameConstructor::ConstructFramesFromItemList(nsFrameConstructorState& aSta
nsIFrame* aParentFrame, nsIFrame* aParentFrame,
nsFrameItems& aFrameItems) nsFrameItems& aFrameItems)
{ {
aItems.SetTriedConstructingFrames();
nsresult rv = CreateNeededTablePseudos(aState, aItems, aParentFrame); nsresult rv = CreateNeededTablePseudos(aState, aItems, aParentFrame);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
@ -11832,7 +11832,10 @@ Iterator::AppendItemsToList(const Iterator& aEnd,
NS_ASSERTION(&aTargetList != &mList, "Unexpected call"); NS_ASSERTION(&aTargetList != &mList, "Unexpected call");
NS_PRECONDITION(mEnd == aEnd.mEnd, "end iterator for some other list?"); 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 { do {
AppendItemToList(aTargetList); AppendItemToList(aTargetList);
} while (*this != aEnd); } while (*this != aEnd);
@ -11841,7 +11844,8 @@ Iterator::AppendItemsToList(const Iterator& aEnd,
// move over the list of items // move over the list of items
PR_INSERT_AFTER(&aTargetList.mItems, &mList.mItems); 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 // Copy over the various counters
aTargetList.mInlineCount = mList.mInlineCount; aTargetList.mInlineCount = mList.mInlineCount;
@ -11851,7 +11855,11 @@ Iterator::AppendItemsToList(const Iterator& aEnd,
memcpy(aTargetList.mDesiredParentCounts, mList.mDesiredParentCounts, memcpy(aTargetList.mDesiredParentCounts, mList.mDesiredParentCounts,
sizeof(aTargetList.mDesiredParentCounts)); sizeof(aTargetList.mDesiredParentCounts));
// Swap out undisplayed item arrays, before we nuke the array on our end
aTargetList.mUndisplayedItems.SwapElements(mList.mUndisplayedItems);
// reset mList // reset mList
mList.~FrameConstructionItemList();
new (&mList) FrameConstructionItemList(); new (&mList) FrameConstructionItemList();
// Point ourselves to aEnd, as advertised // Point ourselves to aEnd, as advertised

Просмотреть файл

@ -816,7 +816,8 @@ private:
mItemCount(0), mItemCount(0),
mLineBoundaryAtStart(false), mLineBoundaryAtStart(false),
mLineBoundaryAtEnd(false), mLineBoundaryAtEnd(false),
mParentHasNoXBLChildren(false) mParentHasNoXBLChildren(false),
mTriedConstructingFrames(false)
{ {
PR_INIT_CLIST(&mItems); PR_INIT_CLIST(&mItems);
memset(mDesiredParentCounts, 0, sizeof(mDesiredParentCounts)); memset(mDesiredParentCounts, 0, sizeof(mDesiredParentCounts));
@ -832,6 +833,20 @@ private:
// Leaves our mItems pointing to deleted memory in both directions, // Leaves our mItems pointing to deleted memory in both directions,
// but that's OK at this point. // 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; } void SetLineBoundaryAtStart(bool aBoundary) { mLineBoundaryAtStart = aBoundary; }
@ -839,6 +854,7 @@ private:
void SetParentHasNoXBLChildren(bool aHasNoXBLChildren) { void SetParentHasNoXBLChildren(bool aHasNoXBLChildren) {
mParentHasNoXBLChildren = aHasNoXBLChildren; mParentHasNoXBLChildren = aHasNoXBLChildren;
} }
void SetTriedConstructingFrames() { mTriedConstructingFrames = true; }
bool HasLineBoundaryAtStart() { return mLineBoundaryAtStart; } bool HasLineBoundaryAtStart() { return mLineBoundaryAtStart; }
bool HasLineBoundaryAtEnd() { return mLineBoundaryAtEnd; } bool HasLineBoundaryAtEnd() { return mLineBoundaryAtEnd; }
bool ParentHasNoXBLChildren() { return mParentHasNoXBLChildren; } bool ParentHasNoXBLChildren() { return mParentHasNoXBLChildren; }
@ -871,6 +887,11 @@ private:
return item; return item;
} }
void AppendUndisplayedItem(nsIContent* aContent,
nsStyleContext* aStyleContext) {
mUndisplayedItems.AppendElement(UndisplayedItem(aContent, aStyleContext));
}
void InlineItemAdded() { ++mInlineCount; } void InlineItemAdded() { ++mInlineCount; }
void BlockItemAdded() { ++mBlockCount; } void BlockItemAdded() { ++mBlockCount; }
void LineParticipantItemAdded() { ++mLineParticipantCount; } void LineParticipantItemAdded() { ++mLineParticipantCount; }
@ -977,6 +998,15 @@ private:
return static_cast<FrameConstructionItem*>(item); return static_cast<FrameConstructionItem*>(item);
} }
struct UndisplayedItem {
UndisplayedItem(nsIContent* aContent, nsStyleContext* aStyleContext) :
mContent(aContent), mStyleContext(aStyleContext)
{}
nsIContent * const mContent;
nsRefPtr<nsStyleContext> mStyleContext;
};
// Adjust our various counts for aItem being added or removed. aDelta // Adjust our various counts for aItem being added or removed. aDelta
// should be either +1 or -1 depending on which is happening. // should be either +1 or -1 depending on which is happening.
void AdjustCountsForItem(FrameConstructionItem* aItem, PRInt32 aDelta); void AdjustCountsForItem(FrameConstructionItem* aItem, PRInt32 aDelta);
@ -995,6 +1025,10 @@ private:
bool mLineBoundaryAtEnd; bool mLineBoundaryAtEnd;
// True if the parent is guaranteed to have no XBL anonymous children // True if the parent is guaranteed to have no XBL anonymous children
bool mParentHasNoXBLChildren; bool mParentHasNoXBLChildren;
// True if we have tried constructing frames from this list
bool mTriedConstructingFrames;
nsTArray<UndisplayedItem> mUndisplayedItems;
}; };
typedef FrameConstructionItemList::Iterator FCItemIterator; typedef FrameConstructionItemList::Iterator FCItemIterator;
@ -1097,7 +1131,7 @@ private:
FrameConstructionItemList mChildItems; FrameConstructionItemList mChildItems;
private: private:
FrameConstructionItem(const FrameConstructionItem& aOther); /* not implemented */ FrameConstructionItem(const FrameConstructionItem& aOther) MOZ_DELETE; /* not implemented */
}; };
/** /**
@ -1779,6 +1813,18 @@ private:
mDocument->SetNeedLayoutFlush(); 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: public:
friend class nsFrameConstructorState; friend class nsFrameConstructorState;