Bug 786740. When destroying all the frames in a line list, keep the line list and frame list valid at each step in case someone tries to walk the frame tree during frame destruction. r=mats

--HG--
extra : rebase_source : 7045daffc35fdaca02a74caa52a93a270c94cf74
This commit is contained in:
Robert O'Callahan 2012-10-15 14:34:23 +13:00
parent c50bd6b87c
commit a268d55cd8
5 changed files with 55 additions and 35 deletions

View File

@ -0,0 +1,31 @@
<!DOCTYPE HTML>
<html class="reftest-wait">
<head>
<style>
#d {
transition:opacity 1s;
}
#p {
position:absolute;
}
</style>
</head>
<body>
<div id="d">
Hello
<span id="s"><div id="p">Kitty</div></span>
</div>
<script>
var d = document.getElementById("d");
d.getBoundingClientRect();
d.style.opacity = 0.3;
window.addEventListener("MozReftestInvalidate",
function() {
setTimeout(function() {
document.body.removeChild(d);
document.documentElement.removeAttribute("class");
}, 50);
}, false);
</script>
</body>
</html>

View File

@ -392,3 +392,4 @@ load 737313-1.html
load 737313-2.html
load 737313-3.html
load 762764-1.html
load 786740-1.html

View File

@ -279,10 +279,8 @@ nsBlockFrame::DestroyFrom(nsIFrame* aDestructRoot)
DestroyAbsoluteFrames(aDestructRoot);
mFloats.DestroyFramesFrom(aDestructRoot);
nsPresContext* presContext = PresContext();
nsLineBox::DeleteLineList(presContext, mLines, aDestructRoot);
// Now clear mFrames, since we've destroyed all the frames in it.
mFrames.Clear();
nsLineBox::DeleteLineList(presContext, mLines, aDestructRoot,
&mFrames);
nsFrameList* pushedFloats = RemovePushedFloats();
if (pushedFloats) {
@ -293,7 +291,7 @@ nsBlockFrame::DestroyFrom(nsIFrame* aDestructRoot)
FrameLines* overflowLines = RemoveOverflowLines();
if (overflowLines) {
nsLineBox::DeleteLineList(presContext, overflowLines->mLines,
aDestructRoot);
aDestructRoot, &overflowLines->mFrames);
delete overflowLines;
}

View File

@ -353,38 +353,28 @@ nsLineBox::CachedIsEmpty()
void
nsLineBox::DeleteLineList(nsPresContext* aPresContext, nsLineList& aLines,
nsIFrame* aDestructRoot)
nsIFrame* aDestructRoot, nsFrameList* aFrames)
{
if (! aLines.empty()) {
// Delete our child frames before doing anything else. In particular
// we do all of this before our base class releases it's hold on the
// view.
#ifdef DEBUG
int32_t numFrames = 0;
#endif
for (nsIFrame* child = aLines.front()->mFirstChild; child; ) {
nsIFrame* nextChild = child->GetNextSibling();
child->SetNextSibling(nullptr);
child->DestroyFrom((aDestructRoot) ? aDestructRoot : child);
child = nextChild;
#ifdef DEBUG
numFrames++;
#endif
}
nsIPresShell* shell = aPresContext->PresShell();
do {
// Keep our line list and frame list up to date as we
// remove frames, in case something wants to traverse the
// frame tree while we're destroying.
while (!aLines.empty()) {
nsLineBox* line = aLines.front();
#ifdef DEBUG
numFrames -= line->GetChildCount();
#endif
if (NS_UNLIKELY(line->mFlags.mHasHashedFrames)) {
line->SwitchToCounter(); // Avoid expensive has table removals.
}
while (line->GetChildCount() > 0) {
nsIFrame* child = aFrames->RemoveFirstChild();
MOZ_ASSERT(child == line->mFirstChild, "Lines out of sync");
line->mFirstChild = aFrames->FirstChild();
line->NoteFrameRemoved(child);
child->DestroyFrom(aDestructRoot);
}
aLines.pop_front();
line->Destroy(shell);
} while (! aLines.empty());
#ifdef DEBUG
NS_ASSERTION(numFrames == 0, "number of frames deleted does not match");
#endif
}
}

View File

@ -484,7 +484,7 @@ public:
}
static void DeleteLineList(nsPresContext* aPresContext, nsLineList& aLines,
nsIFrame* aDestructRoot);
nsIFrame* aDestructRoot, nsFrameList* aFrames);
// search from end to beginning of [aBegin, aEnd)
// Returns true if it found the line and false if not.