diff --git a/mozilla/layout/generic/nsBlockFrame.cpp b/mozilla/layout/generic/nsBlockFrame.cpp index 686ed5a2759..8346b7ac8ca 100644 --- a/mozilla/layout/generic/nsBlockFrame.cpp +++ b/mozilla/layout/generic/nsBlockFrame.cpp @@ -1839,6 +1839,9 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) PRInt32 n = line->ChildCount(); while (--n >= 0) { frame->SetParent(this); + // When pushing and pulling frames we need to check for whether any + // views need to be reparented + nsHTMLContainerFrame::ReparentFrameView(frame, mNextInFlow, this); lastFrame = frame; frame->GetNextSibling(&frame); } @@ -2070,8 +2073,16 @@ nsBlockFrame::PullFrame(nsBlockReflowState& aState, // Change geometric parents if (aUpdateGeometricParent) { + // Before we set the new parent frame get the current parent + nsIFrame* oldParentFrame; + frame->GetParent(&oldParentFrame); frame->SetParent(this); + // When pushing and pulling frames we need to check for whether any + // views need to be reparented + NS_ASSERTION(oldParentFrame != this, "unexpected parent frame"); + nsHTMLContainerFrame::ReparentFrameView(frame, oldParentFrame, this); + // The frame is being pulled from a next-in-flow; therefore we // need to add it to our sibling list. if (nsnull != aState.mPrevChild) { @@ -3451,6 +3462,12 @@ nsBlockFrame::DrainOverflowLines() nsIFrame* frame = line->mFirstChild; while (nsnull != frame) { frame->SetParent(this); + + // When pushing and pulling frames we need to check for whether any + // views need to be reparented + nsHTMLContainerFrame::ReparentFrameView(frame, prevBlock, this); + + // Get the next frame lastFrame = frame; frame->GetNextSibling(&frame); } diff --git a/mozilla/layout/generic/nsBlockReflowState.cpp b/mozilla/layout/generic/nsBlockReflowState.cpp index 686ed5a2759..8346b7ac8ca 100644 --- a/mozilla/layout/generic/nsBlockReflowState.cpp +++ b/mozilla/layout/generic/nsBlockReflowState.cpp @@ -1839,6 +1839,9 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) PRInt32 n = line->ChildCount(); while (--n >= 0) { frame->SetParent(this); + // When pushing and pulling frames we need to check for whether any + // views need to be reparented + nsHTMLContainerFrame::ReparentFrameView(frame, mNextInFlow, this); lastFrame = frame; frame->GetNextSibling(&frame); } @@ -2070,8 +2073,16 @@ nsBlockFrame::PullFrame(nsBlockReflowState& aState, // Change geometric parents if (aUpdateGeometricParent) { + // Before we set the new parent frame get the current parent + nsIFrame* oldParentFrame; + frame->GetParent(&oldParentFrame); frame->SetParent(this); + // When pushing and pulling frames we need to check for whether any + // views need to be reparented + NS_ASSERTION(oldParentFrame != this, "unexpected parent frame"); + nsHTMLContainerFrame::ReparentFrameView(frame, oldParentFrame, this); + // The frame is being pulled from a next-in-flow; therefore we // need to add it to our sibling list. if (nsnull != aState.mPrevChild) { @@ -3451,6 +3462,12 @@ nsBlockFrame::DrainOverflowLines() nsIFrame* frame = line->mFirstChild; while (nsnull != frame) { frame->SetParent(this); + + // When pushing and pulling frames we need to check for whether any + // views need to be reparented + nsHTMLContainerFrame::ReparentFrameView(frame, prevBlock, this); + + // Get the next frame lastFrame = frame; frame->GetNextSibling(&frame); } diff --git a/mozilla/layout/generic/nsBlockReflowState.h b/mozilla/layout/generic/nsBlockReflowState.h index 686ed5a2759..8346b7ac8ca 100644 --- a/mozilla/layout/generic/nsBlockReflowState.h +++ b/mozilla/layout/generic/nsBlockReflowState.h @@ -1839,6 +1839,9 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) PRInt32 n = line->ChildCount(); while (--n >= 0) { frame->SetParent(this); + // When pushing and pulling frames we need to check for whether any + // views need to be reparented + nsHTMLContainerFrame::ReparentFrameView(frame, mNextInFlow, this); lastFrame = frame; frame->GetNextSibling(&frame); } @@ -2070,8 +2073,16 @@ nsBlockFrame::PullFrame(nsBlockReflowState& aState, // Change geometric parents if (aUpdateGeometricParent) { + // Before we set the new parent frame get the current parent + nsIFrame* oldParentFrame; + frame->GetParent(&oldParentFrame); frame->SetParent(this); + // When pushing and pulling frames we need to check for whether any + // views need to be reparented + NS_ASSERTION(oldParentFrame != this, "unexpected parent frame"); + nsHTMLContainerFrame::ReparentFrameView(frame, oldParentFrame, this); + // The frame is being pulled from a next-in-flow; therefore we // need to add it to our sibling list. if (nsnull != aState.mPrevChild) { @@ -3451,6 +3462,12 @@ nsBlockFrame::DrainOverflowLines() nsIFrame* frame = line->mFirstChild; while (nsnull != frame) { frame->SetParent(this); + + // When pushing and pulling frames we need to check for whether any + // views need to be reparented + nsHTMLContainerFrame::ReparentFrameView(frame, prevBlock, this); + + // Get the next frame lastFrame = frame; frame->GetNextSibling(&frame); } diff --git a/mozilla/layout/generic/nsHTMLContainerFrame.cpp b/mozilla/layout/generic/nsHTMLContainerFrame.cpp index 638f213e09b..36ab64ce51d 100644 --- a/mozilla/layout/generic/nsHTMLContainerFrame.cpp +++ b/mozilla/layout/generic/nsHTMLContainerFrame.cpp @@ -123,6 +123,91 @@ nsHTMLContainerFrame::CreateNextInFlow(nsIPresContext& aPresContext, return NS_OK; } +static nsresult +ReparentFrameViewTo(nsIFrame* aFrame, + nsIView* aNewParentView, + nsIView* aOldParentView) +{ + nsIView* view; + + // Does aFrame have a view? + aFrame->GetView(&view); + if (view) { + nsIViewManager* viewManager; + +#ifdef NS_DEBUG + // Verify that the current parent view is what we think it is + nsIView* parentView; + + view->GetParent(parentView); + NS_ASSERTION(parentView == aOldParentView, "unexpected parent view"); +#endif + + // Get the view manager + aNewParentView->GetViewManager(viewManager); + NS_ASSERTION(nsnull != viewManager, "null view manager"); + + // Change the parent view. + PRInt32 zIndex; + view->GetZIndex(zIndex); + viewManager->RemoveChild(aOldParentView, view); + + // XXX We need to insert this view in the correct place within its z-order... + viewManager->InsertChild(aNewParentView, view, zIndex); + NS_RELEASE(viewManager); + + } else { + // Iterate the child frames, and check each child frame to see if it has + // a view + nsIFrame* childFrame; + + aFrame->FirstChild(nsnull, &childFrame); + while (childFrame) { + ReparentFrameViewTo(childFrame, aNewParentView, aOldParentView); + childFrame->GetNextSibling(&childFrame); + } + } + + return NS_OK; +} + +static nsIView* +GetViewFor(nsIFrame* aFrame) +{ + nsIView* view; + + aFrame->GetView(&view); + if (!view) { + nsPoint offset; + aFrame->GetOffsetFromView(offset, &view); + } + + NS_POSTCONDITION(view, "no containing view"); + return view; +} + +nsresult +nsHTMLContainerFrame::ReparentFrameView(nsIFrame* aChildFrame, + nsIFrame* aOldParentFrame, + nsIFrame* aNewParentFrame) +{ + NS_PRECONDITION(aChildFrame, "null child frame pointer"); + NS_PRECONDITION(aOldParentFrame, "null old parent frame pointer"); + NS_PRECONDITION(aNewParentFrame, "null new parent frame pointer"); + NS_PRECONDITION(aOldParentFrame != aNewParentFrame, "same old and new parent frame"); + + // First see if the old parent frame and the new parent frame are in the + // same view sub-hierarchy + nsIView* oldParentView = GetViewFor(aOldParentFrame); + nsIView* newParentView = GetViewFor(aNewParentFrame); + + if (oldParentView != newParentView) { + return ReparentFrameViewTo(aChildFrame, newParentView, oldParentView); + } + + return NS_OK; +} + nsresult nsHTMLContainerFrame::CreateViewForFrame(nsIPresContext& aPresContext, nsIFrame* aFrame, diff --git a/mozilla/layout/generic/nsHTMLContainerFrame.h b/mozilla/layout/generic/nsHTMLContainerFrame.h index b8a5592d556..d4ac84b991a 100644 --- a/mozilla/layout/generic/nsHTMLContainerFrame.h +++ b/mozilla/layout/generic/nsHTMLContainerFrame.h @@ -62,6 +62,10 @@ public: nsIStyleContext* aStyleContext, PRBool aForce); + static nsresult ReparentFrameView(nsIFrame* aChildFrame, + nsIFrame* aOldParentFrame, + nsIFrame* aNewParentFrame); + protected: virtual PRIntn GetSkipSides() const = 0; }; diff --git a/mozilla/layout/generic/nsInlineFrame.cpp b/mozilla/layout/generic/nsInlineFrame.cpp index 9e3ffb997cf..064b4dd1c45 100644 --- a/mozilla/layout/generic/nsInlineFrame.cpp +++ b/mozilla/layout/generic/nsInlineFrame.cpp @@ -1284,6 +1284,14 @@ nsInlineFrame::DrainOverflow() nsInlineFrame* prevInFlow = (nsInlineFrame*)mPrevInFlow; if (nsnull != prevInFlow) { if (prevInFlow->mOverflowFrames.NotEmpty()) { + // When pushing and pulling frames we need to check for whether any + // views need to be reparented. + // XXX Doing it this way means an extra pass over the frames. We could + // change InsertFrames() to do this, but that's a general purpose + // function and it doesn't seem like this functionality belongs there... + for (nsIFrame* f = prevInFlow->mOverflowFrames.FirstChild(); f; f->GetNextSibling(&f)) { + nsHTMLContainerFrame::ReparentFrameView(f, prevInFlow, this); + } mFrames.InsertFrames(this, nsnull, prevInFlow->mOverflowFrames); changedFirstFrame = PR_TRUE; } diff --git a/mozilla/layout/html/base/src/nsBlockFrame.cpp b/mozilla/layout/html/base/src/nsBlockFrame.cpp index 686ed5a2759..8346b7ac8ca 100644 --- a/mozilla/layout/html/base/src/nsBlockFrame.cpp +++ b/mozilla/layout/html/base/src/nsBlockFrame.cpp @@ -1839,6 +1839,9 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) PRInt32 n = line->ChildCount(); while (--n >= 0) { frame->SetParent(this); + // When pushing and pulling frames we need to check for whether any + // views need to be reparented + nsHTMLContainerFrame::ReparentFrameView(frame, mNextInFlow, this); lastFrame = frame; frame->GetNextSibling(&frame); } @@ -2070,8 +2073,16 @@ nsBlockFrame::PullFrame(nsBlockReflowState& aState, // Change geometric parents if (aUpdateGeometricParent) { + // Before we set the new parent frame get the current parent + nsIFrame* oldParentFrame; + frame->GetParent(&oldParentFrame); frame->SetParent(this); + // When pushing and pulling frames we need to check for whether any + // views need to be reparented + NS_ASSERTION(oldParentFrame != this, "unexpected parent frame"); + nsHTMLContainerFrame::ReparentFrameView(frame, oldParentFrame, this); + // The frame is being pulled from a next-in-flow; therefore we // need to add it to our sibling list. if (nsnull != aState.mPrevChild) { @@ -3451,6 +3462,12 @@ nsBlockFrame::DrainOverflowLines() nsIFrame* frame = line->mFirstChild; while (nsnull != frame) { frame->SetParent(this); + + // When pushing and pulling frames we need to check for whether any + // views need to be reparented + nsHTMLContainerFrame::ReparentFrameView(frame, prevBlock, this); + + // Get the next frame lastFrame = frame; frame->GetNextSibling(&frame); } diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.cpp b/mozilla/layout/html/base/src/nsBlockReflowState.cpp index 686ed5a2759..8346b7ac8ca 100644 --- a/mozilla/layout/html/base/src/nsBlockReflowState.cpp +++ b/mozilla/layout/html/base/src/nsBlockReflowState.cpp @@ -1839,6 +1839,9 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) PRInt32 n = line->ChildCount(); while (--n >= 0) { frame->SetParent(this); + // When pushing and pulling frames we need to check for whether any + // views need to be reparented + nsHTMLContainerFrame::ReparentFrameView(frame, mNextInFlow, this); lastFrame = frame; frame->GetNextSibling(&frame); } @@ -2070,8 +2073,16 @@ nsBlockFrame::PullFrame(nsBlockReflowState& aState, // Change geometric parents if (aUpdateGeometricParent) { + // Before we set the new parent frame get the current parent + nsIFrame* oldParentFrame; + frame->GetParent(&oldParentFrame); frame->SetParent(this); + // When pushing and pulling frames we need to check for whether any + // views need to be reparented + NS_ASSERTION(oldParentFrame != this, "unexpected parent frame"); + nsHTMLContainerFrame::ReparentFrameView(frame, oldParentFrame, this); + // The frame is being pulled from a next-in-flow; therefore we // need to add it to our sibling list. if (nsnull != aState.mPrevChild) { @@ -3451,6 +3462,12 @@ nsBlockFrame::DrainOverflowLines() nsIFrame* frame = line->mFirstChild; while (nsnull != frame) { frame->SetParent(this); + + // When pushing and pulling frames we need to check for whether any + // views need to be reparented + nsHTMLContainerFrame::ReparentFrameView(frame, prevBlock, this); + + // Get the next frame lastFrame = frame; frame->GetNextSibling(&frame); } diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.h b/mozilla/layout/html/base/src/nsBlockReflowState.h index 686ed5a2759..8346b7ac8ca 100644 --- a/mozilla/layout/html/base/src/nsBlockReflowState.h +++ b/mozilla/layout/html/base/src/nsBlockReflowState.h @@ -1839,6 +1839,9 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) PRInt32 n = line->ChildCount(); while (--n >= 0) { frame->SetParent(this); + // When pushing and pulling frames we need to check for whether any + // views need to be reparented + nsHTMLContainerFrame::ReparentFrameView(frame, mNextInFlow, this); lastFrame = frame; frame->GetNextSibling(&frame); } @@ -2070,8 +2073,16 @@ nsBlockFrame::PullFrame(nsBlockReflowState& aState, // Change geometric parents if (aUpdateGeometricParent) { + // Before we set the new parent frame get the current parent + nsIFrame* oldParentFrame; + frame->GetParent(&oldParentFrame); frame->SetParent(this); + // When pushing and pulling frames we need to check for whether any + // views need to be reparented + NS_ASSERTION(oldParentFrame != this, "unexpected parent frame"); + nsHTMLContainerFrame::ReparentFrameView(frame, oldParentFrame, this); + // The frame is being pulled from a next-in-flow; therefore we // need to add it to our sibling list. if (nsnull != aState.mPrevChild) { @@ -3451,6 +3462,12 @@ nsBlockFrame::DrainOverflowLines() nsIFrame* frame = line->mFirstChild; while (nsnull != frame) { frame->SetParent(this); + + // When pushing and pulling frames we need to check for whether any + // views need to be reparented + nsHTMLContainerFrame::ReparentFrameView(frame, prevBlock, this); + + // Get the next frame lastFrame = frame; frame->GetNextSibling(&frame); } diff --git a/mozilla/layout/html/base/src/nsHTMLContainerFrame.cpp b/mozilla/layout/html/base/src/nsHTMLContainerFrame.cpp index 638f213e09b..36ab64ce51d 100644 --- a/mozilla/layout/html/base/src/nsHTMLContainerFrame.cpp +++ b/mozilla/layout/html/base/src/nsHTMLContainerFrame.cpp @@ -123,6 +123,91 @@ nsHTMLContainerFrame::CreateNextInFlow(nsIPresContext& aPresContext, return NS_OK; } +static nsresult +ReparentFrameViewTo(nsIFrame* aFrame, + nsIView* aNewParentView, + nsIView* aOldParentView) +{ + nsIView* view; + + // Does aFrame have a view? + aFrame->GetView(&view); + if (view) { + nsIViewManager* viewManager; + +#ifdef NS_DEBUG + // Verify that the current parent view is what we think it is + nsIView* parentView; + + view->GetParent(parentView); + NS_ASSERTION(parentView == aOldParentView, "unexpected parent view"); +#endif + + // Get the view manager + aNewParentView->GetViewManager(viewManager); + NS_ASSERTION(nsnull != viewManager, "null view manager"); + + // Change the parent view. + PRInt32 zIndex; + view->GetZIndex(zIndex); + viewManager->RemoveChild(aOldParentView, view); + + // XXX We need to insert this view in the correct place within its z-order... + viewManager->InsertChild(aNewParentView, view, zIndex); + NS_RELEASE(viewManager); + + } else { + // Iterate the child frames, and check each child frame to see if it has + // a view + nsIFrame* childFrame; + + aFrame->FirstChild(nsnull, &childFrame); + while (childFrame) { + ReparentFrameViewTo(childFrame, aNewParentView, aOldParentView); + childFrame->GetNextSibling(&childFrame); + } + } + + return NS_OK; +} + +static nsIView* +GetViewFor(nsIFrame* aFrame) +{ + nsIView* view; + + aFrame->GetView(&view); + if (!view) { + nsPoint offset; + aFrame->GetOffsetFromView(offset, &view); + } + + NS_POSTCONDITION(view, "no containing view"); + return view; +} + +nsresult +nsHTMLContainerFrame::ReparentFrameView(nsIFrame* aChildFrame, + nsIFrame* aOldParentFrame, + nsIFrame* aNewParentFrame) +{ + NS_PRECONDITION(aChildFrame, "null child frame pointer"); + NS_PRECONDITION(aOldParentFrame, "null old parent frame pointer"); + NS_PRECONDITION(aNewParentFrame, "null new parent frame pointer"); + NS_PRECONDITION(aOldParentFrame != aNewParentFrame, "same old and new parent frame"); + + // First see if the old parent frame and the new parent frame are in the + // same view sub-hierarchy + nsIView* oldParentView = GetViewFor(aOldParentFrame); + nsIView* newParentView = GetViewFor(aNewParentFrame); + + if (oldParentView != newParentView) { + return ReparentFrameViewTo(aChildFrame, newParentView, oldParentView); + } + + return NS_OK; +} + nsresult nsHTMLContainerFrame::CreateViewForFrame(nsIPresContext& aPresContext, nsIFrame* aFrame, diff --git a/mozilla/layout/html/base/src/nsHTMLContainerFrame.h b/mozilla/layout/html/base/src/nsHTMLContainerFrame.h index b8a5592d556..d4ac84b991a 100644 --- a/mozilla/layout/html/base/src/nsHTMLContainerFrame.h +++ b/mozilla/layout/html/base/src/nsHTMLContainerFrame.h @@ -62,6 +62,10 @@ public: nsIStyleContext* aStyleContext, PRBool aForce); + static nsresult ReparentFrameView(nsIFrame* aChildFrame, + nsIFrame* aOldParentFrame, + nsIFrame* aNewParentFrame); + protected: virtual PRIntn GetSkipSides() const = 0; }; diff --git a/mozilla/layout/html/base/src/nsInlineFrame.cpp b/mozilla/layout/html/base/src/nsInlineFrame.cpp index 9e3ffb997cf..064b4dd1c45 100644 --- a/mozilla/layout/html/base/src/nsInlineFrame.cpp +++ b/mozilla/layout/html/base/src/nsInlineFrame.cpp @@ -1284,6 +1284,14 @@ nsInlineFrame::DrainOverflow() nsInlineFrame* prevInFlow = (nsInlineFrame*)mPrevInFlow; if (nsnull != prevInFlow) { if (prevInFlow->mOverflowFrames.NotEmpty()) { + // When pushing and pulling frames we need to check for whether any + // views need to be reparented. + // XXX Doing it this way means an extra pass over the frames. We could + // change InsertFrames() to do this, but that's a general purpose + // function and it doesn't seem like this functionality belongs there... + for (nsIFrame* f = prevInFlow->mOverflowFrames.FirstChild(); f; f->GetNextSibling(&f)) { + nsHTMLContainerFrame::ReparentFrameView(f, prevInFlow, this); + } mFrames.InsertFrames(this, nsnull, prevInFlow->mOverflowFrames); changedFirstFrame = PR_TRUE; }