Bug 577607 part 1. Make sure resource documents don't have presshells when their display document doesn't. r=roc
authorBoris Zbarsky <bzbarsky@mit.edu>
Wed, 11 Aug 2010 17:05:26 -0400
changeset 49570 d07f35b7a38f0bbc102915a2ebcb608ecd82e979
parent 49569 fd26456949adf4a5f019c7b551a6e8ee7ce28c22
child 49571 0c4519d63a982f1e5943dcbd1320b516dd613957
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs577607
milestone2.0b4pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 577607 part 1. Make sure resource documents don't have presshells when their display document doesn't. r=roc
content/base/public/nsIDocument.h
content/base/src/nsDocument.cpp
content/base/src/nsDocument.h
layout/base/nsDocumentViewer.cpp
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -432,17 +432,17 @@ public:
    * shared among multiple presentation shells). The caller of this
    * method is responsible for calling BeginObservingDocument() on the
    * presshell if the presshell should observe document mutations.
    */
   virtual nsresult CreateShell(nsPresContext* aContext,
                                nsIViewManager* aViewManager,
                                nsStyleSet* aStyleSet,
                                nsIPresShell** aInstancePtrResult) = 0;
-  void DeleteShell() { mPresShell = nsnull; }
+  virtual void DeleteShell() = 0;
 
   nsIPresShell* GetShell() const
   {
     return mShellIsHidden ? nsnull : mPresShell;
   }
 
   void SetShellHidden(PRBool aHide) { mShellIsHidden = aHide; }
   PRBool ShellIsHidden() const { return mShellIsHidden; }
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -778,16 +778,46 @@ ExternalResourceTraverser(nsIURI* aKey,
 void
 nsExternalResourceMap::Traverse(nsCycleCollectionTraversalCallback* aCallback) const
 {
   // mPendingLoads will get cleared out as the requests complete, so
   // no need to worry about those here.
   mMap.EnumerateRead(ExternalResourceTraverser, aCallback);
 }
 
+static PLDHashOperator
+ExternalResourceHider(nsIURI* aKey,
+                      nsExternalResourceMap::ExternalResource* aData,
+                      void* aClosure)
+{
+  aData->mViewer->Hide();
+  return PL_DHASH_NEXT;
+}
+
+void
+nsExternalResourceMap::HideViewers()
+{
+  mMap.EnumerateRead(ExternalResourceHider, nsnull);
+}
+
+static PLDHashOperator
+ExternalResourceShower(nsIURI* aKey,
+                       nsExternalResourceMap::ExternalResource* aData,
+                       void* aClosure)
+{
+  aData->mViewer->Show();
+  return PL_DHASH_NEXT;
+}
+
+void
+nsExternalResourceMap::ShowViewers()
+{
+  mMap.EnumerateRead(ExternalResourceShower, nsnull);
+}
+
 nsresult
 nsExternalResourceMap::AddExternalResource(nsIURI* aURI,
                                            nsIDocumentViewer* aViewer,
                                            nsILoadGroup* aLoadGroup,
                                            nsIDocument* aDisplayDocument)
 {
   NS_PRECONDITION(aURI, "Unexpected call");
   NS_PRECONDITION((aViewer && aLoadGroup) || (!aViewer && !aLoadGroup),
@@ -806,16 +836,19 @@ nsExternalResourceMap::AddExternalResour
 
     nsCOMPtr<nsIXULDocument> xulDoc = do_QueryInterface(doc);
     if (xulDoc) {
       // We don't handle XUL stuff here yet.
       rv = NS_ERROR_NOT_AVAILABLE;
     } else {
       doc->SetDisplayDocument(aDisplayDocument);
 
+      // Make sure that hiding our viewer will tear down its presentation.
+      aViewer->SetSticky(PR_FALSE);
+
       rv = aViewer->Init(nsnull, nsIntRect(0, 0, 0, 0));
       if (NS_SUCCEEDED(rv)) {
         rv = aViewer->Open(nsnull, nsnull);
       }
     }
     
     if (NS_FAILED(rv)) {
       doc = nsnull;
@@ -3034,21 +3067,30 @@ nsDocument::doCreateShell(nsPresContext*
   }
 
   rv = shell->Init(this, aContext, aViewManager, aStyleSet, aCompatMode);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Note: we don't hold a ref to the shell (it holds a ref to us)
   mPresShell = shell;
 
+  mExternalResourceMap.ShowViewers();
+
   shell.swap(*aInstancePtrResult);
 
   return NS_OK;
 }
 
+void
+nsDocument::DeleteShell()
+{
+  mExternalResourceMap.HideViewers();
+  mPresShell = nsnull;
+}
+
 static void
 SubDocClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
 {
   SubDocMapEntry *e = static_cast<SubDocMapEntry *>(entry);
 
   NS_RELEASE(e->mKey);
   if (e->mSubDocument) {
     e->mSubDocument->SetParentDocument(nsnull);
@@ -7810,9 +7852,8 @@ nsIDocument::CreateStaticClone(nsISuppor
           }
         }
       }
     }
   }
   mCreatingStaticClone = PR_FALSE;
   return clonedDoc.forget();
 }
-
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -370,16 +370,22 @@ public:
   struct ExternalResource
   {
     ~ExternalResource();
     nsCOMPtr<nsIDocument> mDocument;
     nsCOMPtr<nsIContentViewer> mViewer;
     nsCOMPtr<nsILoadGroup> mLoadGroup;
   };
 
+  // Hide all our viewers
+  void HideViewers();
+
+  // Show all our viewers
+  void ShowViewers();
+
 protected:
   class PendingLoad : public ExternalResourceLoad,
                       public nsIStreamListener
   {
   public:
     PendingLoad(nsDocument* aDisplayDocument) :
       mDisplayDocument(aDisplayDocument)
     {}
@@ -583,16 +589,17 @@ public:
    * Create a new presentation shell that will use aContext for
    * its presentation context (presentation context's <b>must not</b> be
    * shared among multiple presentation shell's).
    */
   virtual nsresult CreateShell(nsPresContext* aContext,
                                nsIViewManager* aViewManager,
                                nsStyleSet* aStyleSet,
                                nsIPresShell** aInstancePtrResult);
+  virtual void DeleteShell();
 
   virtual nsresult SetSubDocumentFor(nsIContent *aContent,
                                      nsIDocument* aSubDoc);
   virtual nsIDocument* GetSubDocumentFor(nsIContent *aContent) const;
   virtual nsIContent* FindContentForSubDocument(nsIDocument *aDocument) const;
   virtual Element* GetRootElementInternal() const;
 
   /**
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -855,17 +855,19 @@ DocumentViewerImpl::InitInternal(nsIWidg
     nsresult rv = CreateDeviceContext(containerView);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // XXXbz this is a nasty hack to do with the fact that we create
     // presentations both in Init() and in Show()...  Ideally we would only do
     // it in one place (Show()) and require that callers call init(), open(),
     // show() in that order or something.
     if (!mPresContext &&
-        (aParentWidget || containerView || mDocument->GetDisplayDocument())) {
+        (aParentWidget || containerView ||
+         (mDocument->GetDisplayDocument() &&
+          mDocument->GetDisplayDocument()->GetShell()))) {
       // Create presentation context
       if (mIsPageMode) {
         //Presentation context already created in SetPageMode which is calling this method
       } else {
         mPresContext = CreatePresContext(mDocument,
             nsPresContext::eContext_Galley, containerView);
       }
       NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY);