From d73bc69f1aa3f4a07bdd5ab6b2a282eddd85ade4 Mon Sep 17 00:00:00 2001 From: "jkeiser%netscape.com" Date: Fri, 6 Sep 2002 05:44:31 +0000 Subject: [PATCH] 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 --- mozilla/content/base/src/nsDocumentViewer.cpp | 13 ++++ .../html/document/src/nsHTMLContentSink.cpp | 61 +++++++++++++++++++ mozilla/layout/base/nsDocumentViewer.cpp | 13 ++++ mozilla/layout/base/nsIPresShell.h | 7 +++ mozilla/layout/base/nsPresShell.cpp | 12 ++++ mozilla/layout/base/public/nsIPresShell.h | 7 +++ mozilla/layout/html/base/src/nsPresShell.cpp | 12 ++++ 7 files changed, 125 insertions(+) diff --git a/mozilla/content/base/src/nsDocumentViewer.cpp b/mozilla/content/base/src/nsDocumentViewer.cpp index 34b25bbdb01..f68b351c4b3 100644 --- a/mozilla/content/base/src/nsDocumentViewer.cpp +++ b/mozilla/content/base/src/nsDocumentViewer.cpp @@ -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 diff --git a/mozilla/content/html/document/src/nsHTMLContentSink.cpp b/mozilla/content/html/document/src/nsHTMLContentSink.cpp index 5d95f414f8b..92e330caeb2 100644 --- a/mozilla/content/html/document/src/nsHTMLContentSink.cpp +++ b/mozilla/content/html/document/src/nsHTMLContentSink.cpp @@ -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 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 element and it's + // children? + + NotifyAppend(parent, numFlushed); + } + } + StartLayout(); return NS_OK; } @@ -3755,6 +3798,24 @@ HTMLContentSink::StartLayout() nsCOMPtr 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(); diff --git a/mozilla/layout/base/nsDocumentViewer.cpp b/mozilla/layout/base/nsDocumentViewer.cpp index 34b25bbdb01..f68b351c4b3 100644 --- a/mozilla/layout/base/nsDocumentViewer.cpp +++ b/mozilla/layout/base/nsDocumentViewer.cpp @@ -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 diff --git a/mozilla/layout/base/nsIPresShell.h b/mozilla/layout/base/nsIPresShell.h index 1b175238a88..cdec023f12f 100644 --- a/mozilla/layout/base/nsIPresShell.h +++ b/mozilla/layout/base/nsIPresShell.h @@ -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 diff --git a/mozilla/layout/base/nsPresShell.cpp b/mozilla/layout/base/nsPresShell.cpp index 7c3959918f9..b5980f4c9fe 100644 --- a/mozilla/layout/base/nsPresShell.cpp +++ b/mozilla/layout/base/nsPresShell.cpp @@ -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) { diff --git a/mozilla/layout/base/public/nsIPresShell.h b/mozilla/layout/base/public/nsIPresShell.h index 1b175238a88..cdec023f12f 100644 --- a/mozilla/layout/base/public/nsIPresShell.h +++ b/mozilla/layout/base/public/nsIPresShell.h @@ -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 diff --git a/mozilla/layout/html/base/src/nsPresShell.cpp b/mozilla/layout/html/base/src/nsPresShell.cpp index 7c3959918f9..b5980f4c9fe 100644 --- a/mozilla/layout/html/base/src/nsPresShell.cpp +++ b/mozilla/layout/html/base/src/nsPresShell.cpp @@ -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) {