diff --git a/layout/generic/nsHTMLContainerFrame.cpp b/layout/generic/nsHTMLContainerFrame.cpp index d9b14fde0f6d..9e3a244557b9 100644 --- a/layout/generic/nsHTMLContainerFrame.cpp +++ b/layout/generic/nsHTMLContainerFrame.cpp @@ -156,18 +156,6 @@ NS_METHOD nsHTMLContainerFrame::ContentAppended(nsIPresShell* aShell, return NS_OK; } -static PRBool -HasSameMapping(nsIFrame* aFrame, nsIContent* aContent) -{ - nsIContent* content; - PRBool result; - - aFrame->GetContent(content); - result = content == aContent; - NS_RELEASE(content); - return result; -} - NS_IMETHODIMP nsHTMLContainerFrame::ContentInserted(nsIPresShell* aShell, nsIPresContext* aPresContext, @@ -247,6 +235,128 @@ nsHTMLContainerFrame::ContentInserted(nsIPresShell* aShell, return rv; } +NS_IMETHODIMP +nsHTMLContainerFrame::ContentDeleted(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInParent) +{ + NS_ASSERTION(!IsPseudoFrame(), "pseudos not supported here"); + + // Find the frame that precedes the deletion point + nsHTMLContainerFrame* flow; + nsIFrame* deadFrame; + nsIFrame* prevSibling; + if (aIndexInParent > 0) { + nsIContent* precedingContent = aContainer->ChildAt(aIndexInParent - 1); + prevSibling = aShell->FindFrameWithContent(precedingContent); + NS_RELEASE(precedingContent); + + // The frame may have a next-in-flow. Get the last-in-flow + nsIFrame* nextInFlow; + do { + prevSibling->GetNextInFlow(nextInFlow); + if (nsnull != nextInFlow) { + prevSibling = nextInFlow; + } + } while (nsnull != nextInFlow); + + // Get the dead frame (maybe) + prevSibling->GetGeometricParent((nsIFrame*&)flow); + prevSibling->GetNextSibling(deadFrame); + if (nsnull == deadFrame) { + // The deadFrame must be prevSibling's parent's next-in-flows + // first frame. Therefore it doesn't have a prevSibling. + flow = (nsHTMLContainerFrame*) flow->mNextInFlow; + if (nsnull != flow) { + deadFrame = flow->mFirstChild; + } + prevSibling = nsnull; + } + } + else { + prevSibling = nsnull; + flow = this; + deadFrame = flow->mFirstChild; + } + NS_ASSERTION(nsnull != deadFrame, "yikes! couldn't find frame"); + if (nsnull == deadFrame) { + return NS_OK; + } + + // Generate a reflow command + nsIReflowCommand* cmd; + nsresult rv = NS_NewHTMLReflowCommand(&cmd, flow, + nsIReflowCommand::FrameDeleted); + if (NS_OK != rv) { + return rv; + } + aShell->AppendReflowCommand(cmd); + NS_RELEASE(cmd); + + // Take the frame away; Note that we also have to take away any + // continuations so we loop here until deadFrame is nsnull. + while (nsnull != deadFrame) { + // If the last frame for the flow is the frame we are deleting + // then the flow will become complete. + if (!flow->mLastContentIsComplete) { + nsIFrame* lastFrame; + flow->LastChild(lastFrame); + if (lastFrame == deadFrame) { + flow->mLastContentIsComplete = PR_TRUE; + } + } + + // Remove frame from sibling list + nsIFrame* nextSib; + deadFrame->GetNextSibling(nextSib); + if (nsnull != prevSibling) { + prevSibling->SetNextSibling(nextSib); + } + else { + flow->mFirstChild = nextSib; + } + + // Update flows child count and last-content-offset. Note that + // only the last content needs updating when a deadFrame is + // removed from flow (because only the children that follow the + // deletion need renumbering). + flow->mChildCount--; + flow->mLastContentOffset--; + + // Break frame out of its flow and then destroy it + nsIFrame* nextInFlow; + deadFrame->GetNextInFlow(nextInFlow); + deadFrame->BreakFromNextFlow(); + deadFrame->DeleteFrame(); + deadFrame = nextInFlow; + + if (nsnull != deadFrame) { + // Get the parent of deadFrame's continuation + deadFrame->GetGeometricParent((nsIFrame*&) flow); + + // When we move to a next-in-flow then the deadFrame will be the + // first child of the new parent. Therefore we know that + // prevSibling will be null. + prevSibling = nsnull; + } + } + + // Repair any remaining next-in-flows content offsets; these are the + // next-in-flows the follow the last flow container that contained + // one of the deadFrame's. Therefore both content offsets need + // updating (because all the children are following the deletion). + flow = (nsHTMLContainerFrame*) flow->mNextInFlow; + while (nsnull != flow) { + flow->mFirstContentOffset--; + flow->mLastContentOffset--; + flow = (nsHTMLContainerFrame*) flow->mNextInFlow; + } + + return rv; +} + nsresult nsHTMLContainerFrame::ProcessInitialReflow(nsIPresContext* aPresContext) { diff --git a/layout/generic/nsHTMLContainerFrame.h b/layout/generic/nsHTMLContainerFrame.h index c7d4a11a2329..52d886fb8561 100644 --- a/layout/generic/nsHTMLContainerFrame.h +++ b/layout/generic/nsHTMLContainerFrame.h @@ -31,25 +31,26 @@ public: NS_IMETHOD Paint(nsIPresContext& aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect); - NS_IMETHOD HandleEvent(nsIPresContext& aPresContext, nsGUIEvent* aEvent, nsEventStatus& aEventStatus); - NS_IMETHOD GetCursorAt(nsIPresContext& aPresContext, const nsPoint& aPoint, nsIFrame** aFrame, PRInt32& aCursor); - NS_IMETHOD ContentAppended(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer); - NS_IMETHOD ContentInserted(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer, nsIContent* aChild, PRInt32 aIndexInParent); + NS_IMETHOD ContentDeleted(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInParent); protected: virtual ~nsHTMLContainerFrame(); diff --git a/layout/html/base/src/nsHTMLContainerFrame.cpp b/layout/html/base/src/nsHTMLContainerFrame.cpp index d9b14fde0f6d..9e3a244557b9 100644 --- a/layout/html/base/src/nsHTMLContainerFrame.cpp +++ b/layout/html/base/src/nsHTMLContainerFrame.cpp @@ -156,18 +156,6 @@ NS_METHOD nsHTMLContainerFrame::ContentAppended(nsIPresShell* aShell, return NS_OK; } -static PRBool -HasSameMapping(nsIFrame* aFrame, nsIContent* aContent) -{ - nsIContent* content; - PRBool result; - - aFrame->GetContent(content); - result = content == aContent; - NS_RELEASE(content); - return result; -} - NS_IMETHODIMP nsHTMLContainerFrame::ContentInserted(nsIPresShell* aShell, nsIPresContext* aPresContext, @@ -247,6 +235,128 @@ nsHTMLContainerFrame::ContentInserted(nsIPresShell* aShell, return rv; } +NS_IMETHODIMP +nsHTMLContainerFrame::ContentDeleted(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInParent) +{ + NS_ASSERTION(!IsPseudoFrame(), "pseudos not supported here"); + + // Find the frame that precedes the deletion point + nsHTMLContainerFrame* flow; + nsIFrame* deadFrame; + nsIFrame* prevSibling; + if (aIndexInParent > 0) { + nsIContent* precedingContent = aContainer->ChildAt(aIndexInParent - 1); + prevSibling = aShell->FindFrameWithContent(precedingContent); + NS_RELEASE(precedingContent); + + // The frame may have a next-in-flow. Get the last-in-flow + nsIFrame* nextInFlow; + do { + prevSibling->GetNextInFlow(nextInFlow); + if (nsnull != nextInFlow) { + prevSibling = nextInFlow; + } + } while (nsnull != nextInFlow); + + // Get the dead frame (maybe) + prevSibling->GetGeometricParent((nsIFrame*&)flow); + prevSibling->GetNextSibling(deadFrame); + if (nsnull == deadFrame) { + // The deadFrame must be prevSibling's parent's next-in-flows + // first frame. Therefore it doesn't have a prevSibling. + flow = (nsHTMLContainerFrame*) flow->mNextInFlow; + if (nsnull != flow) { + deadFrame = flow->mFirstChild; + } + prevSibling = nsnull; + } + } + else { + prevSibling = nsnull; + flow = this; + deadFrame = flow->mFirstChild; + } + NS_ASSERTION(nsnull != deadFrame, "yikes! couldn't find frame"); + if (nsnull == deadFrame) { + return NS_OK; + } + + // Generate a reflow command + nsIReflowCommand* cmd; + nsresult rv = NS_NewHTMLReflowCommand(&cmd, flow, + nsIReflowCommand::FrameDeleted); + if (NS_OK != rv) { + return rv; + } + aShell->AppendReflowCommand(cmd); + NS_RELEASE(cmd); + + // Take the frame away; Note that we also have to take away any + // continuations so we loop here until deadFrame is nsnull. + while (nsnull != deadFrame) { + // If the last frame for the flow is the frame we are deleting + // then the flow will become complete. + if (!flow->mLastContentIsComplete) { + nsIFrame* lastFrame; + flow->LastChild(lastFrame); + if (lastFrame == deadFrame) { + flow->mLastContentIsComplete = PR_TRUE; + } + } + + // Remove frame from sibling list + nsIFrame* nextSib; + deadFrame->GetNextSibling(nextSib); + if (nsnull != prevSibling) { + prevSibling->SetNextSibling(nextSib); + } + else { + flow->mFirstChild = nextSib; + } + + // Update flows child count and last-content-offset. Note that + // only the last content needs updating when a deadFrame is + // removed from flow (because only the children that follow the + // deletion need renumbering). + flow->mChildCount--; + flow->mLastContentOffset--; + + // Break frame out of its flow and then destroy it + nsIFrame* nextInFlow; + deadFrame->GetNextInFlow(nextInFlow); + deadFrame->BreakFromNextFlow(); + deadFrame->DeleteFrame(); + deadFrame = nextInFlow; + + if (nsnull != deadFrame) { + // Get the parent of deadFrame's continuation + deadFrame->GetGeometricParent((nsIFrame*&) flow); + + // When we move to a next-in-flow then the deadFrame will be the + // first child of the new parent. Therefore we know that + // prevSibling will be null. + prevSibling = nsnull; + } + } + + // Repair any remaining next-in-flows content offsets; these are the + // next-in-flows the follow the last flow container that contained + // one of the deadFrame's. Therefore both content offsets need + // updating (because all the children are following the deletion). + flow = (nsHTMLContainerFrame*) flow->mNextInFlow; + while (nsnull != flow) { + flow->mFirstContentOffset--; + flow->mLastContentOffset--; + flow = (nsHTMLContainerFrame*) flow->mNextInFlow; + } + + return rv; +} + nsresult nsHTMLContainerFrame::ProcessInitialReflow(nsIPresContext* aPresContext) { diff --git a/layout/html/base/src/nsHTMLContainerFrame.h b/layout/html/base/src/nsHTMLContainerFrame.h index c7d4a11a2329..52d886fb8561 100644 --- a/layout/html/base/src/nsHTMLContainerFrame.h +++ b/layout/html/base/src/nsHTMLContainerFrame.h @@ -31,25 +31,26 @@ public: NS_IMETHOD Paint(nsIPresContext& aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect); - NS_IMETHOD HandleEvent(nsIPresContext& aPresContext, nsGUIEvent* aEvent, nsEventStatus& aEventStatus); - NS_IMETHOD GetCursorAt(nsIPresContext& aPresContext, const nsPoint& aPoint, nsIFrame** aFrame, PRInt32& aCursor); - NS_IMETHOD ContentAppended(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer); - NS_IMETHOD ContentInserted(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer, nsIContent* aChild, PRInt32 aIndexInParent); + NS_IMETHOD ContentDeleted(nsIPresShell* aShell, + nsIPresContext* aPresContext, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInParent); protected: virtual ~nsHTMLContainerFrame();