diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 8dd14bc8092e..aa51d969387f 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -3624,9 +3624,11 @@ nsDocShell::SetPositionAndSize(PRInt32 x, PRInt32 y, PRInt32 cx, mBounds.width = cx; mBounds.height = cy; - if (mContentViewer) { + // Hold strong ref, since SetBounds can make us null out mContentViewer + nsCOMPtr viewer = mContentViewer; + if (viewer) { //XXX Border figured in here or is that handled elsewhere? - NS_ENSURE_SUCCESS(mContentViewer->SetBounds(mBounds), NS_ERROR_FAILURE); + NS_ENSURE_SUCCESS(viewer->SetBounds(mBounds), NS_ERROR_FAILURE); } return NS_OK; diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index e8b37423f61d..f27d06a8bc4a 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -2480,29 +2480,40 @@ PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight) return NS_OK; NS_ASSERTION(mViewManager, "Must have view manager"); - mViewManager->BeginUpdateViewBatch(); + nsCOMPtr viewManager = mViewManager; + viewManager->BeginUpdateViewBatch(); - // XXX Do a full invalidate at the beginning so that invalidates along - // the way don't have region accumulation issues? + // Take this ref after viewManager so it'll make sure to go away first + nsCOMPtr kungFuDeathGrip(this); - WillCauseReflow(); - WillDoReflow(); + // Make sure style is up to date + mFrameConstructor->ProcessPendingRestyles(); + if (!mIsDestroying) { + // XXX Do a full invalidate at the beginning so that invalidates along + // the way don't have region accumulation issues? - { - // Kick off a top-down reflow - AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow); - mIsReflowing = PR_TRUE; + WillCauseReflow(); + WillDoReflow(); - mDirtyRoots.RemoveElement(rootFrame); - DoReflow(rootFrame); - mIsReflowing = PR_FALSE; + { + // Kick off a top-down reflow + AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow); + mIsReflowing = PR_TRUE; + + mDirtyRoots.RemoveElement(rootFrame); + DoReflow(rootFrame); + mIsReflowing = PR_FALSE; + } + + DidCauseReflow(); + DidDoReflow(); } - DidCauseReflow(); - DidDoReflow(); - mViewManager->EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC); + viewManager->EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC); - CreateResizeEventTimer(); + if (!mIsDestroying) { + CreateResizeEventTimer(); + } return NS_OK; //XXX this needs to be real. MMP } @@ -6223,26 +6234,31 @@ PresShell::ProcessReflowCommands(PRBool aInterruptible) DidDoReflow(); + // DidDoReflow might have killed us + if (!mIsDestroying) { #ifdef DEBUG - if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) { - printf("\nPresShell::ProcessReflowCommands() finished: this=%p\n", (void*)this); - } - DoVerifyReflow(); + if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) { + printf("\nPresShell::ProcessReflowCommands() finished: this=%p\n", + (void*)this); + } + DoVerifyReflow(); #endif - // If any new reflow commands were enqueued during the reflow, schedule - // another reflow event to process them. Note that we want to do this - // after DidDoReflow(), since that method can change whether there are - // dirty roots around by flushing, and there's no point in posting a reflow - // event just to have the flush revoke it. - if (mDirtyRoots.Count()) - PostReflowEvent(); + // If any new reflow commands were enqueued during the reflow, schedule + // another reflow event to process them. Note that we want to do this + // after DidDoReflow(), since that method can change whether there are + // dirty roots around by flushing, and there's no point in posting a + // reflow event just to have the flush revoke it. + if (mDirtyRoots.Count()) + PostReflowEvent(); + } } MOZ_TIMER_DEBUGLOG(("Stop: Reflow: PresShell::ProcessReflowCommands(), this=%p\n", this)); MOZ_TIMER_STOP(mReflowWatch); - if (mShouldUnsuppressPainting && mDirtyRoots.Count() == 0) { + if (!mIsDestroying && mShouldUnsuppressPainting && + mDirtyRoots.Count() == 0) { // We only unlock if we're out of reflows. It's pointless // to unlock if reflows are still pending, since reflows // are just going to thrash the frames around some more. By diff --git a/layout/generic/nsFrameFrame.cpp b/layout/generic/nsFrameFrame.cpp index a654fb0f0226..c6afff2a0f2d 100644 --- a/layout/generic/nsFrameFrame.cpp +++ b/layout/generic/nsFrameFrame.cpp @@ -89,6 +89,7 @@ #include "nsIDOMNSHTMLDocument.h" #include "nsDisplayList.h" #include "nsUnicharUtils.h" +#include "nsIReflowCallback.h" // For Accessibility #ifdef ACCESSIBILITY @@ -102,7 +103,8 @@ static NS_DEFINE_CID(kCChildCID, NS_CHILD_CID); * nsSubDocumentFrame *****************************************************************************/ class nsSubDocumentFrame : public nsLeafFrame, - public nsIFrameFrame + public nsIFrameFrame, + public nsIReflowCallback { public: nsSubDocumentFrame(nsStyleContext* aContext); @@ -159,6 +161,9 @@ public: NS_IMETHOD VerifyTree() const; + // nsIReflowCallback + virtual PRBool ReflowFinished(); + protected: nsSize GetMargin(); PRBool IsInline() { return mIsInline; } @@ -175,11 +180,12 @@ protected: PRPackedBool mDidCreateDoc; PRPackedBool mOwnsFrameLoader; PRPackedBool mIsInline; + PRPackedBool mPostedReflowCallback; }; nsSubDocumentFrame::nsSubDocumentFrame(nsStyleContext* aContext) : nsLeafFrame(aContext), mDidCreateDoc(PR_FALSE), mOwnsFrameLoader(PR_FALSE), - mIsInline(PR_FALSE) + mIsInline(PR_FALSE), mPostedReflowCallback(PR_FALSE) { } @@ -372,6 +378,9 @@ nsSubDocumentFrame::Reflow(nsPresContext* aPresContext, aStatus = NS_FRAME_COMPLETE; + NS_ASSERTION(aPresContext->GetPresShell()->GetPrimaryFrameFor(mContent) == this, + "Shouldn't happen"); + // "offset" is the offset of our content area from our frame's // top-left corner. nsPoint offset(0, 0); @@ -409,22 +418,9 @@ nsSubDocumentFrame::Reflow(nsPresContext* aPresContext, nsRect rect(nsPoint(0, 0), GetSize()); Invalidate(rect, PR_FALSE); - if (!aPresContext->IsPaginated()) { - nsCOMPtr docShell; - GetDocShell(getter_AddRefs(docShell)); - - nsCOMPtr baseWindow(do_QueryInterface(docShell)); - - // resize the sub document - if (baseWindow) { - PRInt32 x = 0; - PRInt32 y = 0; - - baseWindow->GetPositionAndSize(&x, &y, nsnull, nsnull); - PRInt32 cx = aPresContext->AppUnitsToDevPixels(innerSize.width); - PRInt32 cy = aPresContext->AppUnitsToDevPixels(innerSize.height); - baseWindow->SetPositionAndSize(x, y, cx, cy, PR_FALSE); - } + if (!aPresContext->IsPaginated() && !mPostedReflowCallback) { + PresContext()->PresShell()->PostReflowCallback(this); + mPostedReflowCallback = PR_TRUE; } // printf("OuterFrame::Reflow DONE %X (%d,%d)\n", this, @@ -438,6 +434,39 @@ nsSubDocumentFrame::Reflow(nsPresContext* aPresContext, return NS_OK; } +PRBool +nsSubDocumentFrame::ReflowFinished() +{ + mPostedReflowCallback = PR_FALSE; + + nsSize innerSize(GetSize()); + if (IsInline()) { + nsMargin usedBorderPadding = GetUsedBorderAndPadding(); + innerSize.width -= usedBorderPadding.LeftRight(); + innerSize.height -= usedBorderPadding.TopBottom(); + } + + nsCOMPtr docShell; + GetDocShell(getter_AddRefs(docShell)); + + nsCOMPtr baseWindow(do_QueryInterface(docShell)); + + // resize the sub document + if (baseWindow) { + PRInt32 x = 0; + PRInt32 y = 0; + + nsPresContext* presContext = PresContext(); + baseWindow->GetPositionAndSize(&x, &y, nsnull, nsnull); + PRInt32 cx = presContext->AppUnitsToDevPixels(innerSize.width); + PRInt32 cy = presContext->AppUnitsToDevPixels(innerSize.height); + baseWindow->SetPositionAndSize(x, y, cx, cy, PR_FALSE); + } + + return PR_FALSE; +} + + NS_IMETHODIMP nsSubDocumentFrame::VerifyTree() const { @@ -556,6 +585,11 @@ NS_NewSubDocumentFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) void nsSubDocumentFrame::Destroy() { + if (mPostedReflowCallback) { + PresContext()->PresShell()->CancelReflowCallback(this); + mPostedReflowCallback = PR_FALSE; + } + if (mFrameLoader && mDidCreateDoc) { // Get the content viewer through the docshell, but don't call // GetDocShell() since we don't want to create one if we don't @@ -684,7 +718,7 @@ nsSubDocumentFrame::ShowDocShell() if (presShell) { // The docshell is already showing, nothing left to do... - + NS_ASSERTION(mInnerView, "What's going on?"); return NS_OK; }