Resize the subdocument off a post-reflow callback so that we don't run script during reflow, and a few related checks to make sure we can deal with script in reflow callbacks better. Bug 396587, r+sr+a=roc.

This commit is contained in:
bzbarsky@mit.edu 2007-09-19 19:46:28 -07:00
Родитель 0fa72586e5
Коммит acc3123915
3 изменённых файлов: 101 добавлений и 49 удалений

Просмотреть файл

@ -3624,9 +3624,11 @@ nsDocShell::SetPositionAndSize(PRInt32 x, PRInt32 y, PRInt32 cx,
mBounds.width = cx; mBounds.width = cx;
mBounds.height = cy; mBounds.height = cy;
if (mContentViewer) { // Hold strong ref, since SetBounds can make us null out mContentViewer
nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
if (viewer) {
//XXX Border figured in here or is that handled elsewhere? //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; return NS_OK;

Просмотреть файл

@ -2480,29 +2480,40 @@ PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight)
return NS_OK; return NS_OK;
NS_ASSERTION(mViewManager, "Must have view manager"); NS_ASSERTION(mViewManager, "Must have view manager");
mViewManager->BeginUpdateViewBatch(); nsCOMPtr<nsIViewManager> viewManager = mViewManager;
viewManager->BeginUpdateViewBatch();
// XXX Do a full invalidate at the beginning so that invalidates along // Take this ref after viewManager so it'll make sure to go away first
// the way don't have region accumulation issues? nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
WillCauseReflow(); // Make sure style is up to date
WillDoReflow(); mFrameConstructor->ProcessPendingRestyles();
if (!mIsDestroying) {
// XXX Do a full invalidate at the beginning so that invalidates along
// the way don't have region accumulation issues?
{ WillCauseReflow();
// Kick off a top-down reflow WillDoReflow();
AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
mIsReflowing = PR_TRUE;
mDirtyRoots.RemoveElement(rootFrame); {
DoReflow(rootFrame); // Kick off a top-down reflow
mIsReflowing = PR_FALSE; AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
mIsReflowing = PR_TRUE;
mDirtyRoots.RemoveElement(rootFrame);
DoReflow(rootFrame);
mIsReflowing = PR_FALSE;
}
DidCauseReflow();
DidDoReflow();
} }
DidCauseReflow(); viewManager->EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
DidDoReflow();
mViewManager->EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
CreateResizeEventTimer(); if (!mIsDestroying) {
CreateResizeEventTimer();
}
return NS_OK; //XXX this needs to be real. MMP return NS_OK; //XXX this needs to be real. MMP
} }
@ -6223,26 +6234,31 @@ PresShell::ProcessReflowCommands(PRBool aInterruptible)
DidDoReflow(); DidDoReflow();
// DidDoReflow might have killed us
if (!mIsDestroying) {
#ifdef DEBUG #ifdef DEBUG
if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) { if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {
printf("\nPresShell::ProcessReflowCommands() finished: this=%p\n", (void*)this); printf("\nPresShell::ProcessReflowCommands() finished: this=%p\n",
} (void*)this);
DoVerifyReflow(); }
DoVerifyReflow();
#endif #endif
// If any new reflow commands were enqueued during the reflow, schedule // If any new reflow commands were enqueued during the reflow, schedule
// another reflow event to process them. Note that we want to do this // another reflow event to process them. Note that we want to do this
// after DidDoReflow(), since that method can change whether there are // after DidDoReflow(), since that method can change whether there are
// dirty roots around by flushing, and there's no point in posting a reflow // dirty roots around by flushing, and there's no point in posting a
// event just to have the flush revoke it. // reflow event just to have the flush revoke it.
if (mDirtyRoots.Count()) if (mDirtyRoots.Count())
PostReflowEvent(); PostReflowEvent();
}
} }
MOZ_TIMER_DEBUGLOG(("Stop: Reflow: PresShell::ProcessReflowCommands(), this=%p\n", this)); MOZ_TIMER_DEBUGLOG(("Stop: Reflow: PresShell::ProcessReflowCommands(), this=%p\n", this));
MOZ_TIMER_STOP(mReflowWatch); 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 // We only unlock if we're out of reflows. It's pointless
// to unlock if reflows are still pending, since reflows // to unlock if reflows are still pending, since reflows
// are just going to thrash the frames around some more. By // are just going to thrash the frames around some more. By

Просмотреть файл

@ -89,6 +89,7 @@
#include "nsIDOMNSHTMLDocument.h" #include "nsIDOMNSHTMLDocument.h"
#include "nsDisplayList.h" #include "nsDisplayList.h"
#include "nsUnicharUtils.h" #include "nsUnicharUtils.h"
#include "nsIReflowCallback.h"
// For Accessibility // For Accessibility
#ifdef ACCESSIBILITY #ifdef ACCESSIBILITY
@ -102,7 +103,8 @@ static NS_DEFINE_CID(kCChildCID, NS_CHILD_CID);
* nsSubDocumentFrame * nsSubDocumentFrame
*****************************************************************************/ *****************************************************************************/
class nsSubDocumentFrame : public nsLeafFrame, class nsSubDocumentFrame : public nsLeafFrame,
public nsIFrameFrame public nsIFrameFrame,
public nsIReflowCallback
{ {
public: public:
nsSubDocumentFrame(nsStyleContext* aContext); nsSubDocumentFrame(nsStyleContext* aContext);
@ -159,6 +161,9 @@ public:
NS_IMETHOD VerifyTree() const; NS_IMETHOD VerifyTree() const;
// nsIReflowCallback
virtual PRBool ReflowFinished();
protected: protected:
nsSize GetMargin(); nsSize GetMargin();
PRBool IsInline() { return mIsInline; } PRBool IsInline() { return mIsInline; }
@ -175,11 +180,12 @@ protected:
PRPackedBool mDidCreateDoc; PRPackedBool mDidCreateDoc;
PRPackedBool mOwnsFrameLoader; PRPackedBool mOwnsFrameLoader;
PRPackedBool mIsInline; PRPackedBool mIsInline;
PRPackedBool mPostedReflowCallback;
}; };
nsSubDocumentFrame::nsSubDocumentFrame(nsStyleContext* aContext) nsSubDocumentFrame::nsSubDocumentFrame(nsStyleContext* aContext)
: nsLeafFrame(aContext), mDidCreateDoc(PR_FALSE), mOwnsFrameLoader(PR_FALSE), : 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; 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 // "offset" is the offset of our content area from our frame's
// top-left corner. // top-left corner.
nsPoint offset(0, 0); nsPoint offset(0, 0);
@ -409,22 +418,9 @@ nsSubDocumentFrame::Reflow(nsPresContext* aPresContext,
nsRect rect(nsPoint(0, 0), GetSize()); nsRect rect(nsPoint(0, 0), GetSize());
Invalidate(rect, PR_FALSE); Invalidate(rect, PR_FALSE);
if (!aPresContext->IsPaginated()) { if (!aPresContext->IsPaginated() && !mPostedReflowCallback) {
nsCOMPtr<nsIDocShell> docShell; PresContext()->PresShell()->PostReflowCallback(this);
GetDocShell(getter_AddRefs(docShell)); mPostedReflowCallback = PR_TRUE;
nsCOMPtr<nsIBaseWindow> 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);
}
} }
// printf("OuterFrame::Reflow DONE %X (%d,%d)\n", this, // printf("OuterFrame::Reflow DONE %X (%d,%d)\n", this,
@ -438,6 +434,39 @@ nsSubDocumentFrame::Reflow(nsPresContext* aPresContext,
return NS_OK; 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<nsIDocShell> docShell;
GetDocShell(getter_AddRefs(docShell));
nsCOMPtr<nsIBaseWindow> 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 NS_IMETHODIMP
nsSubDocumentFrame::VerifyTree() const nsSubDocumentFrame::VerifyTree() const
{ {
@ -556,6 +585,11 @@ NS_NewSubDocumentFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
void void
nsSubDocumentFrame::Destroy() nsSubDocumentFrame::Destroy()
{ {
if (mPostedReflowCallback) {
PresContext()->PresShell()->CancelReflowCallback(this);
mPostedReflowCallback = PR_FALSE;
}
if (mFrameLoader && mDidCreateDoc) { if (mFrameLoader && mDidCreateDoc) {
// Get the content viewer through the docshell, but don't call // Get the content viewer through the docshell, but don't call
// GetDocShell() since we don't want to create one if we don't // GetDocShell() since we don't want to create one if we don't
@ -684,7 +718,7 @@ nsSubDocumentFrame::ShowDocShell()
if (presShell) { if (presShell) {
// The docshell is already showing, nothing left to do... // The docshell is already showing, nothing left to do...
NS_ASSERTION(mInnerView, "What's going on?");
return NS_OK; return NS_OK;
} }