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 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

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

@ -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

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

@ -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<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
// 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<UndisplayedItem> 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;