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-20 02:46:28 +00:00
Родитель 95a79b473c
Коммит 3a1ec82b89
3 изменённых файлов: 101 добавлений и 49 удалений

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

@ -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<nsIContentViewer> 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;

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

@ -2480,29 +2480,40 @@ PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight)
return NS_OK;
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
// the way don't have region accumulation issues?
// Take this ref after viewManager so it'll make sure to go away first
nsCOMPtr<nsIPresShell> 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

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

@ -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<nsIDocShell> docShell;
GetDocShell(getter_AddRefs(docShell));
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);
}
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<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
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;
}