mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-12 17:22:04 +00:00
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:
parent
c50bd6b87c
commit
a268d55cd8
31
layout/generic/crashtests/786740-1.html
Normal file
31
layout/generic/crashtests/786740-1.html
Normal 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>
|
@ -392,3 +392,4 @@ load 737313-1.html
|
||||
load 737313-2.html
|
||||
load 737313-3.html
|
||||
load 762764-1.html
|
||||
load 786740-1.html
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
||||
// 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();
|
||||
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);
|
||||
}
|
||||
|
||||
nsIPresShell *shell = aPresContext->PresShell();
|
||||
|
||||
do {
|
||||
nsLineBox* line = aLines.front();
|
||||
#ifdef DEBUG
|
||||
numFrames -= line->GetChildCount();
|
||||
#endif
|
||||
aLines.pop_front();
|
||||
line->Destroy(shell);
|
||||
} while (! aLines.empty());
|
||||
#ifdef DEBUG
|
||||
NS_ASSERTION(numFrames == 0, "number of frames deleted does not match");
|
||||
#endif
|
||||
aLines.pop_front();
|
||||
line->Destroy(shell);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user