Add assertions that the frame tree is safe to destroy (i.e., doesn't contain any first-in-flows or other things we should never destroy) when we call DeleteNextInFlowChild. (Bug 619021) r=roc a2.0=blocking

This commit is contained in:
L. David Baron 2011-01-11 17:09:22 -08:00
parent a056e87fc8
commit a572c4fbef
4 changed files with 61 additions and 0 deletions

View File

@ -3811,6 +3811,49 @@ nsLayoutUtils::AssertNoDuplicateContinuations(nsIFrame* aContainer,
}
}
}
// Is one of aFrame's ancestors a letter frame?
static bool
IsInLetterFrame(nsIFrame *aFrame)
{
for (nsIFrame *f = aFrame->GetParent(); f; f = f->GetParent()) {
if (f->GetType() == nsGkAtoms::letterFrame) {
return true;
}
}
return false;
}
/* static */ void
nsLayoutUtils::AssertTreeOnlyEmptyNextInFlows(nsIFrame *aSubtreeRoot)
{
NS_ASSERTION(aSubtreeRoot->GetPrevInFlow(),
"frame tree not empty, but caller reported complete status");
// Also assert that text frames map no text.
PRInt32 start, end;
nsresult rv = aSubtreeRoot->GetOffsets(start, end);
NS_ASSERTION(NS_SUCCEEDED(rv), "GetOffsets failed");
// In some cases involving :first-letter, we'll partially unlink a
// continuation in the middle of a continuation chain from its
// previous and next continuations before destroying it, presumably so
// that we don't also destroy the later continuations. Once we've
// done this, GetOffsets returns incorrect values.
// For examples, see list of tests in
// https://bugzilla.mozilla.org/show_bug.cgi?id=619021#c29
NS_ASSERTION(start == end || IsInLetterFrame(aSubtreeRoot),
"frame tree not empty, but caller reported complete status");
PRInt32 listIndex = 0;
nsIAtom* childList = nsnull;
do {
for (nsIFrame* child = aSubtreeRoot->GetFirstChild(childList); child;
child = child->GetNextSibling()) {
nsLayoutUtils::AssertTreeOnlyEmptyNextInFlows(child);
}
childList = aSubtreeRoot->GetAdditionalChildListName(listIndex++);
} while (childList);
}
#endif
nsSetAttrRunnable::nsSetAttrRunnable(nsIContent* aContent, nsIAtom* aAttrName,

View File

@ -1273,6 +1273,13 @@ public:
static void
AssertNoDuplicateContinuations(nsIFrame* aContainer,
const nsFrameList& aFrameList);
/**
* Assert that the frame tree rooted at |aSubtreeRoot| is empty, i.e.,
* that it contains no first-in-flows.
*/
static void
AssertTreeOnlyEmptyNextInFlows(nsIFrame *aSubtreeRoot);
#endif
};

View File

@ -5642,6 +5642,11 @@ nsBlockFrame::DeleteNextInFlowChild(nsPresContext* aPresContext,
aNextInFlow, aDeletingEmptyFrames);
}
else {
#ifdef DEBUG
if (aDeletingEmptyFrames) {
nsLayoutUtils::AssertTreeOnlyEmptyNextInFlows(aNextInFlow);
}
#endif
DoRemoveFrame(aNextInFlow,
aDeletingEmptyFrames ? FRAMES_ARE_EMPTY : 0);
}

View File

@ -1140,6 +1140,12 @@ nsContainerFrame::DeleteNextInFlowChild(nsPresContext* aPresContext,
StealFrame(aPresContext, aNextInFlow);
NS_ASSERTION(NS_SUCCEEDED(rv), "StealFrame failure");
#ifdef DEBUG
if (aDeletingEmptyFrames) {
nsLayoutUtils::AssertTreeOnlyEmptyNextInFlows(aNextInFlow);
}
#endif
// Delete the next-in-flow frame and its descendants. This will also
// remove it from its next-in-flow/prev-in-flow chain.
aNextInFlow->Destroy();