Bug 1429961: Destroy continuations last-to-first. r?mats
MozReview-Commit-ID: Ftc8NJLTaAw
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -147,36 +147,42 @@ nsContainerFrame::InsertFrames(ChildList
void
nsContainerFrame::RemoveFrame(ChildListID aListID,
nsIFrame* aOldFrame)
{
MOZ_ASSERT(aListID == kPrincipalList || aListID == kNoReflowPrincipalList,
"unexpected child list");
- // Loop and destroy aOldFrame and all of its continuations.
- // Request a reflow on the parent frames involved unless we were explicitly
- // told not to (kNoReflowPrincipalList).
- bool generateReflowCommand = true;
- if (kNoReflowPrincipalList == aListID) {
- generateReflowCommand = false;
+ AutoTArray<nsIFrame*, 10> continuations;
+ {
+ nsIFrame* continuation = aOldFrame;
+ while (continuation) {
+ continuations.AppendElement(continuation);
+ continuation = continuation->GetNextContinuation();
+ }
}
+
nsIPresShell* shell = PresShell();
nsContainerFrame* lastParent = nullptr;
- AutoPostDestroyData data(PresContext());
- while (aOldFrame) {
- nsIFrame* oldFrameNextContinuation = aOldFrame->GetNextContinuation();
- nsContainerFrame* parent = aOldFrame->GetParent();
- // Please note that 'parent' may not actually be where 'aOldFrame' lives.
+
+ // Loop and destroy aOldFrame and all of its continuations.
+ //
+ // Request a reflow on the parent frames involved unless we were explicitly
+ // told not to (kNoReflowPrincipalList).
+ const bool generateReflowCommand = (kNoReflowPrincipalList != aListID);
+ for (nsIFrame* continuation : Reversed(continuations)) {
+ nsContainerFrame* parent = continuation->GetParent();
+
+ // Please note that 'parent' may not actually be where 'continuation' lives.
// We really MUST use StealFrame() and nothing else here.
// @see nsInlineFrame::StealFrame for details.
- parent->StealFrame(aOldFrame);
- aOldFrame->Destroy(data.mData);
- aOldFrame = oldFrameNextContinuation;
- if (parent != lastParent && generateReflowCommand) {
+ parent->StealFrame(continuation);
+ continuation->Destroy();
+ if (generateReflowCommand && parent != lastParent) {
shell->FrameNeedsReflow(parent, nsIPresShell::eTreeChange,
NS_FRAME_HAS_DIRTY_CHILDREN);
lastParent = parent;
}
}
}
void
@@ -1405,18 +1411,17 @@ nsContainerFrame::DeleteNextInFlowChild(
// Do this in a loop so we don't overflow the stack for frames
// with very many next-in-flows
nsIFrame* nextNextInFlow = aNextInFlow->GetNextInFlow();
if (nextNextInFlow) {
AutoTArray<nsIFrame*, 8> frames;
for (nsIFrame* f = nextNextInFlow; f; f = f->GetNextInFlow()) {
frames.AppendElement(f);
}
- for (int32_t i = frames.Length() - 1; i >= 0; --i) {
- nsIFrame* delFrame = frames.ElementAt(i);
+ for (nsIFrame* delFrame : Reversed(frames)) {
delFrame->GetParent()->
DeleteNextInFlowChild(delFrame, aDeletingEmptyFrames);
}
}
// Take the next-in-flow out of the parent's child list
DebugOnly<nsresult> rv = StealFrame(aNextInFlow);
NS_ASSERTION(NS_SUCCEEDED(rv), "StealFrame failure");
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -679,25 +679,17 @@ public:
* Destroy() for each child). If this frame is a first-continuation, this
* also removes the frame from the primary frame map and clears undisplayed
* content for its content node.
* If the frame is a placeholder, it also ensures the out-of-flow frame's
* removal and destruction.
*/
void Destroy() {
AutoPostDestroyData data(PresContext());
- Destroy(data.mData);
- // Note that |this| is deleted at this point.
- }
-
- /**
- * Pretty much like Destroy() but with a provided PostDestroyData.
- */
- void Destroy(PostDestroyData& aPostDestroyData) {
- DestroyFrom(this, aPostDestroyData);
+ DestroyFrom(this, data.mData);
// Note that |this| is deleted at this point.
}
/** Flags for PeekOffsetCharacter, PeekOffsetNoAmount, PeekOffsetWord return values.
*/
enum FrameSearchResult {
// Peek found a appropriate offset within frame.
FOUND = 0x00,