Fix race condition where iframe's frame is created after document is loaded and body is parsed (bug 153815), kin@netscape.com's patch, r=jkeiser@netscape.com, sr=jst@netscape.com
git-svn-id: svn://10.0.0.236/trunk@128944 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -680,6 +680,19 @@ DocumentViewerImpl::InitPresentationStuff(PRBool aDoInitialReflow)
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aDoInitialReflow) {
|
||||
// Since InitialReflow() will create frames for *all* items
|
||||
// that are currently in the document tree, we need to flush
|
||||
// any pending notifications to prevent the content sink from
|
||||
// duplicating layout frames for content it has added to the tree
|
||||
// but hasn't notified the document about. (Bug 154018)
|
||||
//
|
||||
// Note that we are flushing before we add mPresShell as an observer
|
||||
// to avoid bogus notifications.
|
||||
|
||||
mDocument->FlushPendingNotifications(PR_FALSE);
|
||||
}
|
||||
|
||||
mPresShell->BeginObservingDocument();
|
||||
|
||||
// Initialize our view manager
|
||||
|
||||
@@ -2993,6 +2993,49 @@ HTMLContentSink::OpenBody(const nsIParserNode& aNode)
|
||||
|
||||
MOZ_TIMER_DEBUGLOG(("Stop: nsHTMLContentSink::OpenBody()\n"));
|
||||
MOZ_TIMER_STOP(mWatch);
|
||||
|
||||
|
||||
// Check to see if InitialReflow() has been called on any of our
|
||||
// presShells. If so, the InitialReflow() call inside StartLayout()
|
||||
// will be supressed, so we can't rely on it to construct the body
|
||||
// frame for us, so we'll have to manually call NotifyInsert() or
|
||||
// NotifyAppend() to make sure a body frame gets constructed. (Bug 153815)
|
||||
|
||||
PRBool didInitialReflow = PR_FALSE;
|
||||
|
||||
PRInt32 i, ns = mDocument->GetNumberOfShells();
|
||||
for (i = 0; i < ns; i++) {
|
||||
nsCOMPtr<nsIPresShell> shell;
|
||||
mDocument->GetShellAt(i, getter_AddRefs(shell));
|
||||
if (shell) {
|
||||
shell->GetDidInitialReflow(&didInitialReflow);
|
||||
if (didInitialReflow)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (didInitialReflow && mCurrentContext->mStackPos > 1) {
|
||||
PRInt32 parentIndex = mCurrentContext->mStackPos - 2;
|
||||
nsIHTMLContent *parent = mCurrentContext->mStack[parentIndex].mContent;
|
||||
PRInt32 numFlushed = mCurrentContext->mStack[parentIndex].mNumFlushed;
|
||||
PRInt32 insertionPoint = mCurrentContext->mStack[parentIndex].mInsertionPoint;
|
||||
|
||||
// XXX: I have yet to see a case where numFlushed is non-zero and
|
||||
// insertionPoint is not -1, but this code will try to handle
|
||||
// those cases too.
|
||||
|
||||
if (insertionPoint != -1) {
|
||||
NotifyInsert(parent, mBody, insertionPoint - 1);
|
||||
}
|
||||
else {
|
||||
// XXX: Would it be better to use |parent->ChildCount() - 1| so that
|
||||
// we don't cause notifications for the <head> element and it's
|
||||
// children?
|
||||
|
||||
NotifyAppend(parent, numFlushed);
|
||||
}
|
||||
}
|
||||
|
||||
StartLayout();
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -3755,6 +3798,24 @@ HTMLContentSink::StartLayout()
|
||||
nsCOMPtr<nsIPresShell> shell;
|
||||
mDocument->GetShellAt(i, getter_AddRefs(shell));
|
||||
if (shell) {
|
||||
|
||||
// Make sure we don't call InitialReflow() for a shell that has
|
||||
// already called it. This can happen when the layout frame for
|
||||
// an iframe is constructed *between* the Embed() call for the
|
||||
// docshell in the iframe, and the content sink's call to OpenBody().
|
||||
// (Bug 153815)
|
||||
|
||||
PRBool didInitialReflow = PR_FALSE;
|
||||
shell->GetDidInitialReflow(&didInitialReflow);
|
||||
if (didInitialReflow) {
|
||||
// XXX: The assumption here is that if something already called
|
||||
// InitialReflow() on this shell, it also did some of the
|
||||
// setup below, so we do nothing and just move on to the next
|
||||
// shell in the list.
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Make shell an observer for next time
|
||||
shell->BeginObservingDocument();
|
||||
|
||||
|
||||
@@ -680,6 +680,19 @@ DocumentViewerImpl::InitPresentationStuff(PRBool aDoInitialReflow)
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aDoInitialReflow) {
|
||||
// Since InitialReflow() will create frames for *all* items
|
||||
// that are currently in the document tree, we need to flush
|
||||
// any pending notifications to prevent the content sink from
|
||||
// duplicating layout frames for content it has added to the tree
|
||||
// but hasn't notified the document about. (Bug 154018)
|
||||
//
|
||||
// Note that we are flushing before we add mPresShell as an observer
|
||||
// to avoid bogus notifications.
|
||||
|
||||
mDocument->FlushPendingNotifications(PR_FALSE);
|
||||
}
|
||||
|
||||
mPresShell->BeginObservingDocument();
|
||||
|
||||
// Initialize our view manager
|
||||
|
||||
@@ -206,6 +206,13 @@ public:
|
||||
// Make shell stop being a document observer
|
||||
NS_IMETHOD EndObservingDocument() = 0;
|
||||
|
||||
/**
|
||||
* Determine if InitialReflow() was previously called.
|
||||
* @param aDidInitialReflow PR_TRUE if InitalReflow() was previously called,
|
||||
* PR_FALSE otherwise.
|
||||
*/
|
||||
NS_IMETHOD GetDidInitialReflow(PRBool *aDidInitialReflow) = 0;
|
||||
|
||||
/**
|
||||
* Perform the initial reflow. Constructs the frame for the root content
|
||||
* object and then reflows the frame model into the specified width and
|
||||
|
||||
@@ -1042,6 +1042,7 @@ public:
|
||||
|
||||
NS_IMETHOD BeginObservingDocument();
|
||||
NS_IMETHOD EndObservingDocument();
|
||||
NS_IMETHOD GetDidInitialReflow(PRBool *aDidInitialReflow);
|
||||
NS_IMETHOD InitialReflow(nscoord aWidth, nscoord aHeight);
|
||||
NS_IMETHOD ResizeReflow(nscoord aWidth, nscoord aHeight);
|
||||
NS_IMETHOD StyleChangeReflow();
|
||||
@@ -2712,6 +2713,17 @@ GetRootScrollFrame(nsIPresContext* aPresContext, nsIFrame* aRootFrame, nsIFrame*
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresShell::GetDidInitialReflow(PRBool *aDidInitialReflow)
|
||||
{
|
||||
if (!aDidInitialReflow)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
*aDidInitialReflow = mDidInitialReflow;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresShell::InitialReflow(nscoord aWidth, nscoord aHeight)
|
||||
{
|
||||
|
||||
@@ -206,6 +206,13 @@ public:
|
||||
// Make shell stop being a document observer
|
||||
NS_IMETHOD EndObservingDocument() = 0;
|
||||
|
||||
/**
|
||||
* Determine if InitialReflow() was previously called.
|
||||
* @param aDidInitialReflow PR_TRUE if InitalReflow() was previously called,
|
||||
* PR_FALSE otherwise.
|
||||
*/
|
||||
NS_IMETHOD GetDidInitialReflow(PRBool *aDidInitialReflow) = 0;
|
||||
|
||||
/**
|
||||
* Perform the initial reflow. Constructs the frame for the root content
|
||||
* object and then reflows the frame model into the specified width and
|
||||
|
||||
@@ -1042,6 +1042,7 @@ public:
|
||||
|
||||
NS_IMETHOD BeginObservingDocument();
|
||||
NS_IMETHOD EndObservingDocument();
|
||||
NS_IMETHOD GetDidInitialReflow(PRBool *aDidInitialReflow);
|
||||
NS_IMETHOD InitialReflow(nscoord aWidth, nscoord aHeight);
|
||||
NS_IMETHOD ResizeReflow(nscoord aWidth, nscoord aHeight);
|
||||
NS_IMETHOD StyleChangeReflow();
|
||||
@@ -2712,6 +2713,17 @@ GetRootScrollFrame(nsIPresContext* aPresContext, nsIFrame* aRootFrame, nsIFrame*
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresShell::GetDidInitialReflow(PRBool *aDidInitialReflow)
|
||||
{
|
||||
if (!aDidInitialReflow)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
*aDidInitialReflow = mDidInitialReflow;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresShell::InitialReflow(nscoord aWidth, nscoord aHeight)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user