From 2b1c90da3e849e1c9d7457658290aa8eb01d0fa9 Mon Sep 17 00:00:00 2001 From: Mats Palmgren Date: Thu, 16 Apr 2015 09:04:19 +0000 Subject: [PATCH] Bug 1153478 - Part 1: Add nsInlineFrame::StealFrame and make it deal with being called on the wrong parent for aChild (due to lazy reparenting). r=roc, a=sledru --- layout/generic/nsContainerFrame.cpp | 7 +++---- layout/generic/nsInlineFrame.cpp | 39 +++++++++++++++++++++++++++++++++++++ layout/generic/nsInlineFrame.h | 4 +++- 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/layout/generic/nsContainerFrame.cpp b/layout/generic/nsContainerFrame.cpp index 3ffcba7..34878af 100644 --- a/layout/generic/nsContainerFrame.cpp +++ b/layout/generic/nsContainerFrame.cpp @@ -172,13 +172,12 @@ nsContainerFrame::RemoveFrame(ChildListID aListID, nsIPresShell* shell = PresContext()->PresShell(); nsContainerFrame* lastParent = nullptr; while (aOldFrame) { - //XXXfr probably should use StealFrame here. I'm not sure if we need to - // check the overflow lists atm, but we'll need a prescontext lookup - // for overflow containers once we can split abspos elements with - // inline containing blocks. nsIFrame* oldFrameNextContinuation = aOldFrame->GetNextContinuation(); nsContainerFrame* parent = static_cast(aOldFrame->GetParent()); + // Please note that 'parent' may not actually be where 'aOldFrame' lives. + // We really MUST use StealFrame() and nothing else here. + // @see nsInlineFrame::StealFrame for details. parent->StealFrame(aOldFrame, true); aOldFrame->Destroy(); aOldFrame = oldFrameNextContinuation; diff --git a/layout/generic/nsInlineFrame.cpp b/layout/generic/nsInlineFrame.cpp index 526041e..a392a15 100644 --- a/layout/generic/nsInlineFrame.cpp +++ b/layout/generic/nsInlineFrame.cpp @@ -172,6 +172,45 @@ nsInlineFrame::PeekOffsetCharacter(bool aForward, int32_t* aOffset, return CONTINUE; } +nsresult +nsInlineFrame::StealFrame(nsIFrame* aChild, + bool aForceNormal) +{ + if (aChild->HasAnyStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER) && + !aForceNormal) { + return nsContainerFrame::StealFrame(aChild, aForceNormal); + } + + nsInlineFrame* parent = this; + bool removed = false; + do { + removed = parent->mFrames.StartRemoveFrame(aChild); + if (removed) { + break; + } + + // We didn't find the child in our principal child list. + // Maybe it's on the overflow list? + nsFrameList* frameList = parent->GetOverflowFrames(); + if (frameList) { + removed = frameList->ContinueRemoveFrame(aChild); + if (frameList->IsEmpty()) { + parent->DestroyOverflowList(); + } + if (removed) { + break; + } + } + + // Due to our "lazy reparenting" optimization 'aChild' might not actually + // be on any of our child lists, but instead in one of our next-in-flows. + parent = static_cast(parent->GetNextInFlow()); + } while (parent); + + MOZ_ASSERT(removed, "nsInlineFrame::StealFrame: can't find aChild"); + return removed ? NS_OK : NS_ERROR_UNEXPECTED; +} + void nsInlineFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, diff --git a/layout/generic/nsInlineFrame.h b/layout/generic/nsInlineFrame.h index 1a9899e..3e49241 100644 --- a/layout/generic/nsInlineFrame.h +++ b/layout/generic/nsInlineFrame.h @@ -61,7 +61,9 @@ public: virtual FrameSearchResult PeekOffsetCharacter(bool aForward, int32_t* aOffset, bool aRespectClusters = true) MOZ_OVERRIDE; - + + virtual nsresult StealFrame(nsIFrame* aChild, bool aForceNormal) MOZ_OVERRIDE; + // nsIHTMLReflow overrides virtual void AddInlineMinWidth(nsRenderingContext *aRenderingContext, InlineMinWidthData *aData) MOZ_OVERRIDE; -- 2.2.1