diff --git a/mozilla/content/base/public/nsIDocument.h b/mozilla/content/base/public/nsIDocument.h index 72d48d55055..99b9a9e9a01 100644 --- a/mozilla/content/base/public/nsIDocument.h +++ b/mozilla/content/base/public/nsIDocument.h @@ -93,8 +93,8 @@ class nsILayoutHistoryState; // IID for the nsIDocument interface #define NS_IDOCUMENT_IID \ -{ 0x6a524f45, 0x4e21, 0x4049, \ - { 0xb3, 0x57, 0x2d, 0x29, 0x75, 0x76, 0x7a, 0x43 } } +{ 0x977a6eea, 0xd06f, 0x43fd, \ + { 0xa5, 0x7e, 0xe8, 0xad, 0x4d, 0x64, 0x02, 0x43 } } // The base value for the content ID counter. // This counter is used by the document to @@ -290,6 +290,7 @@ public: virtual PRBool DeleteShell(nsIPresShell* aShell) = 0; virtual PRUint32 GetNumberOfShells() const = 0; virtual nsIPresShell *GetShellAt(PRUint32 aIndex) const = 0; + virtual void SetShellsHidden(PRBool aHide) = 0; /** * Return the parent document of this document. Will return null diff --git a/mozilla/content/base/src/nsDocument.cpp b/mozilla/content/base/src/nsDocument.cpp index 3083a1d33e1..b5f7b9e8a40 100644 --- a/mozilla/content/base/src/nsDocument.cpp +++ b/mozilla/content/base/src/nsDocument.cpp @@ -1042,8 +1042,8 @@ nsDocument::ResetStylesheetsToURI(nsIURI* aURI) PRBool applicable; sheet->GetApplicable(applicable); if (applicable) { - for (PRInt32 i = 0, i_end = mPresShells.Count(); i < i_end; ++i) { - NS_STATIC_CAST(nsIPresShell*, mPresShells.ElementAt(i))->StyleSet()-> + for (PRInt32 i = 0, i_end = GetNumberOfShells(); i < i_end; ++i) { + GetShellAt(i)->StyleSet()-> RemoveStyleSheet(nsStyleSet::eAgentSheet, sheet); } } @@ -1063,9 +1063,9 @@ nsDocument::ResetStylesheetsToURI(nsIURI* aURI) nsStyleSet::sheetType attrSheetType = GetAttrSheetType(); if (mAttrStyleSheet) { // Remove this sheet from all style sets - PRInt32 count = mPresShells.Count(); + PRInt32 count = GetNumberOfShells(); for (indx = 0; indx < count; ++indx) { - NS_STATIC_CAST(nsIPresShell*, mPresShells.ElementAt(indx))->StyleSet()-> + GetShellAt(indx)->StyleSet()-> RemoveStyleSheet(attrSheetType, mAttrStyleSheet); } rv = mAttrStyleSheet->Reset(aURI); @@ -1080,9 +1080,9 @@ nsDocument::ResetStylesheetsToURI(nsIURI* aURI) if (mStyleAttrStyleSheet) { // Remove this sheet from all style sets - PRInt32 count = mPresShells.Count(); + PRInt32 count = GetNumberOfShells(); for (indx = 0; indx < count; ++indx) { - NS_STATIC_CAST(nsIPresShell*, mPresShells.ElementAt(indx))->StyleSet()-> + GetShellAt(indx)->StyleSet()-> RemoveStyleSheet(nsStyleSet::eStyleAttrSheet, mStyleAttrStyleSheet); } rv = mStyleAttrStyleSheet->Reset(aURI); @@ -1097,10 +1097,9 @@ nsDocument::ResetStylesheetsToURI(nsIURI* aURI) mStyleAttrStyleSheet->SetOwningDocument(this); // Now set up our style sets - PRInt32 count = mPresShells.Count(); + PRInt32 count = GetNumberOfShells(); for (indx = 0; indx < count; ++indx) { - FillStyleSet(NS_STATIC_CAST(nsIPresShell*, - mPresShells.ElementAt(indx))->StyleSet()); + FillStyleSet(GetShellAt(indx)->StyleSet()); } return rv; @@ -1485,7 +1484,9 @@ nsDocument::doCreateShell(nsPresContext* aContext, nsIPresShell** aInstancePtrResult) { *aInstancePtrResult = nsnull; - + + NS_ENSURE_FALSE(mShellsAreHidden, NS_ERROR_FAILURE); + FillStyleSet(aStyleSet); nsCOMPtr shell; @@ -1513,13 +1514,20 @@ nsDocument::DeleteShell(nsIPresShell* aShell) PRUint32 nsDocument::GetNumberOfShells() const { - return mPresShells.Count(); + return mShellsAreHidden ? 0 : mPresShells.Count(); } nsIPresShell * nsDocument::GetShellAt(PRUint32 aIndex) const { - return (nsIPresShell*)mPresShells.SafeElementAt(aIndex); + return mShellsAreHidden ? nsnull : + NS_STATIC_CAST(nsIPresShell*, mPresShells.SafeElementAt(aIndex)); +} + +void +nsDocument::SetShellsHidden(PRBool aHide) +{ + mShellsAreHidden = aHide; } PR_STATIC_CALLBACK(void) @@ -1738,11 +1746,10 @@ nsDocument::GetIndexOfStyleSheet(nsIStyleSheet* aSheet) const void nsDocument::AddStyleSheetToStyleSets(nsIStyleSheet* aSheet) { - PRInt32 count = mPresShells.Count(); + PRInt32 count = GetNumberOfShells(); PRInt32 indx; for (indx = 0; indx < count; ++indx) { - NS_STATIC_CAST(nsIPresShell*, mPresShells.ElementAt(indx))->StyleSet()-> - AddDocStyleSheet(aSheet, this); + GetShellAt(indx)->StyleSet()->AddDocStyleSheet(aSheet, this); } } @@ -1773,8 +1780,8 @@ nsDocument::AddStyleSheet(nsIStyleSheet* aSheet) void nsDocument::RemoveStyleSheetFromStyleSets(nsIStyleSheet* aSheet) { - for (PRInt32 i = 0, i_end = mPresShells.Count(); i < i_end; ++i) - NS_STATIC_CAST(nsIPresShell*, mPresShells.ElementAt(i))->StyleSet()-> + for (PRInt32 i = 0, i_end = GetNumberOfShells(); i < i_end; ++i) + GetShellAt(i)->StyleSet()-> RemoveStyleSheet(nsStyleSet::eDocSheet, aSheet); } @@ -1949,8 +1956,8 @@ nsDocument::AddCatalogStyleSheet(nsIStyleSheet* aSheet) if (applicable) { // This is like |AddStyleSheetToStyleSets|, but for an agent sheet. - for (PRInt32 i = 0, i_end = mPresShells.Count(); i < i_end; ++i) - NS_STATIC_CAST(nsIPresShell*, mPresShells.ElementAt(i))->StyleSet()-> + for (PRInt32 i = 0, i_end = GetNumberOfShells(); i < i_end; ++i) + GetShellAt(i)->StyleSet()-> AppendStyleSheet(nsStyleSet::eAgentSheet, aSheet); } @@ -3157,9 +3164,8 @@ nsDocument::GetTitle(nsAString& aTitle) NS_IMETHODIMP nsDocument::SetTitle(const nsAString& aTitle) { - for (PRInt32 i = mPresShells.Count() - 1; i >= 0; --i) { - nsCOMPtr shell = - NS_STATIC_CAST(nsIPresShell*, mPresShells[i]); + for (PRInt32 i = GetNumberOfShells() - 1; i >= 0; --i) { + nsCOMPtr shell = GetShellAt(i); nsCOMPtr container = shell->GetPresContext()->GetContainer(); if (!container) @@ -3312,7 +3318,7 @@ static const DirTable dirAttributes[] = { NS_IMETHODIMP nsDocument::GetDir(nsAString& aDirection) { - nsCOMPtr shell = (nsIPresShell*)mPresShells.SafeElementAt(0); + nsCOMPtr shell = GetShellAt(0); if (shell) { nsPresContext *context = shell->GetPresContext(); if (context) { @@ -3337,8 +3343,7 @@ nsDocument::GetDir(nsAString& aDirection) NS_IMETHODIMP nsDocument::SetDir(const nsAString& aDirection) { - nsIPresShell *shell = - NS_STATIC_CAST(nsIPresShell *, mPresShells.SafeElementAt(0)); + nsIPresShell *shell = GetShellAt(0); if (!shell) { return NS_OK; @@ -4283,11 +4288,10 @@ nsDocument::FlushPendingNotifications(mozFlushType aType) } } - PRInt32 i, count = mPresShells.Count(); + PRInt32 i, count = GetNumberOfShells(); for (i = 0; i < count; i++) { - nsCOMPtr shell = - NS_STATIC_CAST(nsIPresShell*, mPresShells[i]); + nsCOMPtr shell = GetShellAt(i); if (shell) { shell->FlushPendingNotifications(aType); @@ -4720,10 +4724,9 @@ PRBool nsDocument::IsSafeToFlush() const { PRBool isSafeToFlush = PR_TRUE; - PRInt32 i = 0, n = mPresShells.Count(); + PRInt32 i = 0, n = GetNumberOfShells(); while (i < n && isSafeToFlush) { - nsCOMPtr shell = - NS_STATIC_CAST(nsIPresShell*, mPresShells[i]); + nsCOMPtr shell = GetShellAt(i); if (shell) { shell->IsSafeToFlush(isSafeToFlush); @@ -4953,9 +4956,8 @@ nsDocument::Destroy() // content as well. This ensures that there aren't any accidental references // left in anonymous content keeping the document alive. (While not strictly // necessary -- the PresShell owns us -- it's tidy.) - for (count = mPresShells.Count() - 1; count >= 0; --count) { - nsCOMPtr shell = - NS_STATIC_CAST(nsIPresShell*, mPresShells[count]); + for (count = GetNumberOfShells() - 1; count >= 0; --count) { + nsCOMPtr shell = GetShellAt(count); if (!shell) continue; @@ -5116,7 +5118,7 @@ nsDocument::OnPageShow(PRBool aPersisted) } } - nsIPresShell *shell = NS_STATIC_CAST(nsIPresShell*, mPresShells[0]); + nsIPresShell *shell = GetShellAt(0); if (shell && mScriptGlobalObject) { nsPresContext *pc = shell->GetPresContext(); if (pc) { @@ -5152,7 +5154,7 @@ nsDocument::OnPageHide(PRBool aPersisted) } // Now send out a PageHide event. - nsIPresShell *shell = NS_STATIC_CAST(nsIPresShell*, mPresShells[0]); + nsIPresShell *shell = GetShellAt(0); if (shell && mScriptGlobalObject) { nsPresContext *pc = shell->GetPresContext(); if (pc) { diff --git a/mozilla/content/base/src/nsDocument.h b/mozilla/content/base/src/nsDocument.h index af3996ab7a6..0091a090aff 100644 --- a/mozilla/content/base/src/nsDocument.h +++ b/mozilla/content/base/src/nsDocument.h @@ -383,6 +383,7 @@ public: virtual PRBool DeleteShell(nsIPresShell* aShell); virtual PRUint32 GetNumberOfShells() const; virtual nsIPresShell *GetShellAt(PRUint32 aIndex) const; + virtual void SetShellsHidden(PRBool aHide); virtual nsresult SetSubDocumentFor(nsIContent *aContent, nsIDocument* aSubDoc); @@ -698,8 +699,6 @@ protected: PLDHashTable *mSubDocuments; - nsSmallVoidArray mPresShells; - // Array of owning references to all children nsAttrAndChildArray mChildren; @@ -734,6 +733,8 @@ protected: // True if the document "page" is not hidden PRPackedBool mVisible:1; + PRPackedBool mShellsAreHidden:1; + PRUint8 mXMLDeclarationBits; PRUint8 mDefaultElementType; @@ -762,6 +763,8 @@ private: nsDocument(const nsDocument& aOther); nsDocument& operator=(const nsDocument& aOther); + nsSmallVoidArray mPresShells; + nsXPathDocumentTearoff* mXPathDocument; // The layout history state that should be used by nodes in this diff --git a/mozilla/content/html/document/src/nsHTMLDocument.cpp b/mozilla/content/html/document/src/nsHTMLDocument.cpp index 60f8435f967..ef6527f2ada 100644 --- a/mozilla/content/html/document/src/nsHTMLDocument.cpp +++ b/mozilla/content/html/document/src/nsHTMLDocument.cpp @@ -1074,7 +1074,7 @@ nsHTMLDocument::SetCompatibilityMode(nsCompatibility aMode) mCompatMode = aMode; CSSLoader()->SetCompatibilityMode(mCompatMode); - nsCOMPtr shell = (nsIPresShell*)mPresShells.SafeElementAt(0); + nsCOMPtr shell = GetShellAt(0); if (shell) { nsPresContext *pc = shell->GetPresContext(); if (pc) { diff --git a/mozilla/content/xul/document/src/nsXULDocument.cpp b/mozilla/content/xul/document/src/nsXULDocument.cpp index 2b6034e7538..c23a88055a1 100644 --- a/mozilla/content/xul/document/src/nsXULDocument.cpp +++ b/mozilla/content/xul/document/src/nsXULDocument.cpp @@ -1055,10 +1055,9 @@ nsXULDocument::ExecuteOnBroadcastHandlerFor(nsIContent* aBroadcaster, // |onbroadcast| event handler nsEvent event(PR_TRUE, NS_XUL_BROADCAST); - PRInt32 j = mPresShells.Count(); + PRInt32 j = GetNumberOfShells(); while (--j >= 0) { - nsCOMPtr shell = - NS_STATIC_CAST(nsIPresShell*, mPresShells[j]); + nsCOMPtr shell = GetShellAt(j); nsCOMPtr aPresContext = shell->GetPresContext(); diff --git a/mozilla/docshell/shistory/src/nsSHEntry.cpp b/mozilla/docshell/shistory/src/nsSHEntry.cpp index 74122e47792..3f6741ce367 100644 --- a/mozilla/docshell/shistory/src/nsSHEntry.cpp +++ b/mozilla/docshell/shistory/src/nsSHEntry.cpp @@ -114,9 +114,12 @@ nsSHEntry::~nsSHEntry() // out the mParent pointers on all our kids. mChildren.EnumerateForwards(ClearParentPtr, nsnull); mChildren.Clear(); - RemoveDocumentObserver(); - if (mContentViewer) - mContentViewer->Destroy(); + + nsCOMPtr viewer = mContentViewer; + DropPresentationState(); + if (viewer) { + viewer->Destroy(); + } } //***************************************************************************** @@ -173,10 +176,14 @@ NS_IMETHODIMP nsSHEntry::SetReferrerURI(nsIURI *aReferrerURI) NS_IMETHODIMP nsSHEntry::SetContentViewer(nsIContentViewer *aViewer) { - RemoveDocumentObserver(); + NS_PRECONDITION(!aViewer || !mContentViewer, "SHEntry already contains viewer"); + + if (!aViewer) { + DropPresentationState(); + } + mContentViewer = aViewer; - mDocument = nsnull; if (mContentViewer) { nsCOMPtr domDoc; mContentViewer->GetDOMDocument(getter_AddRefs(domDoc)); @@ -184,6 +191,7 @@ nsSHEntry::SetContentViewer(nsIContentViewer *aViewer) // the contentviewer mDocument = do_QueryInterface(domDoc); if (mDocument) { + mDocument->SetShellsHidden(PR_TRUE); mDocument->AddObserver(this); } } @@ -606,12 +614,17 @@ nsSHEntry::SyncPresentationState() void nsSHEntry::DropPresentationState() { - RemoveDocumentObserver(); + nsRefPtr kungFuDeathGrip = this; + + if (mDocument) { + mDocument->SetShellsHidden(PR_FALSE); + mDocument->RemoveObserver(this); + mDocument = nsnull; + } if (mContentViewer) mContentViewer->ClearHistoryEntry(); mContentViewer = nsnull; - mDocument = nsnull; mSticky = PR_TRUE; mWindowState = nsnull; mViewerBounds.SetRect(0, 0, 0, 0); @@ -619,15 +632,6 @@ nsSHEntry::DropPresentationState() mRefreshURIList = nsnull; } -void -nsSHEntry::RemoveDocumentObserver() -{ - if (mDocument) { - mDocument->RemoveObserver(this); - mDocument = nsnull; - } -} - //***************************************************************************** // nsSHEntry: nsIDocumentObserver //***************************************************************************** @@ -682,39 +686,39 @@ nsSHEntry::ContentRemoved(nsIDocument* aDocument, DocumentMutated(); } -class DropPresentationEvent : public PLEvent +class DestroyViewerEvent : public PLEvent { public: - DropPresentationEvent(nsSHEntry* aSHEntry); + DestroyViewerEvent(nsIContentViewer* aViewer, nsIDocument* aDocument); - nsRefPtr mSHEntry; + nsCOMPtr mViewer; + nsCOMPtr mDocument; }; PR_STATIC_CALLBACK(void*) -HandleDropPresentationEvent(PLEvent *aEvent) +HandleDestroyViewerEvent(PLEvent *aEvent) { - nsSHEntry* entry = NS_STATIC_CAST(DropPresentationEvent*, aEvent)->mSHEntry; - nsCOMPtr viewer; - entry->GetContentViewer(getter_AddRefs(viewer)); + nsIContentViewer* viewer = NS_STATIC_CAST(DestroyViewerEvent*, aEvent)->mViewer; if (viewer) { viewer->Destroy(); } - entry->DropPresentationState(); return nsnull; } PR_STATIC_CALLBACK(void) -DestroyDropPresentationEvent(PLEvent *aEvent) +DestroyDestroyViewerEvent(PLEvent *aEvent) { - delete NS_STATIC_CAST(DropPresentationEvent*, aEvent); + delete NS_STATIC_CAST(DestroyViewerEvent*, aEvent); } -DropPresentationEvent::DropPresentationEvent(nsSHEntry* aSHEntry) - : mSHEntry(aSHEntry) +DestroyViewerEvent::DestroyViewerEvent(nsIContentViewer* aViewer, + nsIDocument* aDocument) + : mViewer(aViewer), + mDocument(aDocument) { - PL_InitEvent(this, mSHEntry, ::HandleDropPresentationEvent, - ::DestroyDropPresentationEvent); + PL_InitEvent(this, mViewer, ::HandleDestroyViewerEvent, + ::DestroyDestroyViewerEvent); } void @@ -731,7 +735,7 @@ nsSHEntry::DocumentMutated() return; } - PLEvent *evt = new DropPresentationEvent(this); + PLEvent *evt = new DestroyViewerEvent(mContentViewer, mDocument); if (!evt) { return; } @@ -740,7 +744,12 @@ nsSHEntry::DocumentMutated() if (NS_FAILED(rv)) { PL_DestroyEvent(evt); } - - // Ensure that we don't post more then one PLEvent - RemoveDocumentObserver(); + else { + // Drop presentation. Also ensures that we don't post more then one + // PLEvent. Only do this if we succeeded in posting the event since + // otherwise the document could be torn down mid mutation causing crashes. + DropPresentationState(); + } + // Warning! The call to DropPresentationState could have dropped the last + // reference to this nsSHEntry, so no accessing members beyond here. } diff --git a/mozilla/layout/base/nsDocumentViewer.cpp b/mozilla/layout/base/nsDocumentViewer.cpp index 7243960fee0..bd8f5a0326b 100644 --- a/mozilla/layout/base/nsDocumentViewer.cpp +++ b/mozilla/layout/base/nsDocumentViewer.cpp @@ -1344,7 +1344,7 @@ DocumentViewerImpl::Destroy() mSHEntry->SetSticky(mIsSticky); mIsSticky = PR_TRUE; - mSHEntry->SetContentViewer(this); + PRBool savePresentation = PR_TRUE; // Remove our root view from the view hierarchy. if (mPresShell) { @@ -1371,13 +1371,20 @@ DocumentViewerImpl::Destroy() if (mDocument) { nsresult rv = mDocument->Sanitize(); if (NS_FAILED(rv)) { - // If we failed to sanitize, remove the document immediately. - mSHEntry->SetContentViewer(nsnull); - mSHEntry->SyncPresentationState(); + // If we failed to sanitize, don't save presentation. + savePresentation = PR_FALSE; } } + // Reverse ownership. Do this *after* calling sanitize so that sanitize + // doesn't cause mutations that make the SHEntry drop the presentation + if (savePresentation) { + mSHEntry->SetContentViewer(this); + } + else { + mSHEntry->SyncPresentationState(); + } mSHEntry = nsnull; // Break the link from the document/presentation to the docshell, so that