Bug 607882 - shutdown document accessible may stay in cache, r=ginn.chen, a=blocking
authorAlexander Surkov <surkov.alexander@gmail.com>
Thu, 28 Oct 2010 18:34:26 +0900
changeset 56639 fe4898e97431be5e4f5f950df2258f93ff6eff38
parent 56638 eaefbdbc2f2d08ed03cac8c2a2fe2de72198ec34
child 56640 eefdc0e5e208c17553f7e2fb428a79ac40fabc62
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)
reviewersginn.chen, blocking
bugs607882
milestone2.0b8pre
first release with
nightly linux32
fe4898e97431 / 4.0b8pre / 20101028030917 / files
nightly linux64
fe4898e97431 / 4.0b8pre / 20101028030841 / files
nightly mac
fe4898e97431 / 4.0b8pre / 20101028030911 / files
nightly win32
fe4898e97431 / 4.0b8pre / 20101028042244 / files
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
Bug 607882 - shutdown document accessible may stay in cache, r=ginn.chen, a=blocking
accessible/src/base/nsAccDocManager.cpp
accessible/src/base/nsAccDocManager.h
accessible/src/base/nsAccessibilityService.cpp
accessible/src/base/nsDocAccessible.cpp
accessible/src/base/nsOuterDocAccessible.cpp
--- a/accessible/src/base/nsAccDocManager.cpp
+++ b/accessible/src/base/nsAccDocManager.cpp
@@ -86,24 +86,16 @@ nsAccDocManager::FindAccessibleInCache(n
   arg.mNode = aNode;
 
   mDocAccessibleCache.EnumerateRead(SearchAccessibleInDocCache,
                                     static_cast<void*>(&arg));
 
   return arg.mAccessible;
 }
 
-void
-nsAccDocManager::ShutdownDocAccessiblesInTree(nsIDocument *aDocument)
-{
-  nsCOMPtr<nsISupports> container = aDocument->GetContainer();
-  nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(container);
-  ShutdownDocAccessiblesInTree(treeItem, aDocument);
-}
-
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccDocManager protected
 
 PRBool
 nsAccDocManager::Init()
 {
   mDocAccessibleCache.Init(4);
@@ -127,31 +119,16 @@ nsAccDocManager::Shutdown()
     do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID);
 
   if (progress)
     progress->RemoveProgressListener(static_cast<nsIWebProgressListener*>(this));
 
   ClearDocCache();
 }
 
-void
-nsAccDocManager::ShutdownDocAccessible(nsIDocument *aDocument)
-{
-  nsDocAccessible* docAccessible = mDocAccessibleCache.GetWeak(aDocument);
-  if (!docAccessible)
-    return;
-
-  // We're allowed to not remove listeners when accessible document is shutdown
-  // since we don't keep strong reference on chrome event target and listeners
-  // are removed automatically when chrome event target goes away.
-
-  docAccessible->Shutdown();
-  mDocAccessibleCache.Remove(aDocument);
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // nsISupports
 
 NS_IMPL_THREADSAFE_ISUPPORTS3(nsAccDocManager,
                               nsIWebProgressListener,
                               nsIDOMEventListener,
                               nsISupportsWeakReference)
 
@@ -311,17 +288,24 @@ nsAccDocManager::HandleEvent(nsIDOMEvent
     NS_LOG_ACCDOCDESTROY("received 'pagehide' event", document)
 
     // Ignore 'pagehide' on temporary documents since we ignore them entirely in
     // accessibility.
     if (document->IsInitialDocument())
       return NS_OK;
 
     // Shutdown this one and sub document accessibles.
-    ShutdownDocAccessiblesInTree(document);
+
+    // We're allowed to not remove listeners when accessible document is
+    // shutdown since we don't keep strong reference on chrome event target and
+    // listeners are removed automatically when chrome event target goes away.
+    nsDocAccessible* docAccessible = mDocAccessibleCache.GetWeak(document);
+    if (docAccessible)
+      docAccessible->Shutdown();
+
     return NS_OK;
   }
 
   // XXX: handle error pages loading separately since they get neither
   // webprogress notifications nor 'pageshow' event.
   if (type.EqualsLiteral("DOMContentLoaded") &&
       nsCoreUtils::IsErrorPage(document)) {
     NS_LOG_ACCDOCLOAD2("handled 'DOMContentLoaded' event", document)
@@ -495,45 +479,16 @@ nsAccDocManager::CreateDocOrRootAccessib
   }
 
   NS_LOG_ACCDOCCREATE("document creation finished", aDocument)
 
   AddListeners(aDocument, isRootDoc);
   return docAcc;
 }
 
-void
-nsAccDocManager::ShutdownDocAccessiblesInTree(nsIDocShellTreeItem *aTreeItem,
-                                              nsIDocument *aDocument)
-{
-  nsCOMPtr<nsIDocShellTreeNode> treeNode(do_QueryInterface(aTreeItem));
-
-  if (treeNode) {
-    PRInt32 subDocumentsCount = 0;
-    treeNode->GetChildCount(&subDocumentsCount);
-    for (PRInt32 idx = 0; idx < subDocumentsCount; idx++) {
-      nsCOMPtr<nsIDocShellTreeItem> treeItemChild;
-      treeNode->GetChildAt(idx, getter_AddRefs(treeItemChild));
-      NS_ASSERTION(treeItemChild, "No tree item when there should be");
-      if (!treeItemChild)
-        continue;
-
-      nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(treeItemChild));
-      nsCOMPtr<nsIContentViewer> contentViewer;
-      docShell->GetContentViewer(getter_AddRefs(contentViewer));
-      if (!contentViewer)
-        continue;
-
-      ShutdownDocAccessiblesInTree(treeItemChild, contentViewer->GetDocument());
-    }
-  }
-
-  ShutdownDocAccessible(aDocument);
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccDocManager static
 
 PLDHashOperator
 nsAccDocManager::ClearDocCacheEntry(const nsIDocument* aKey,
                                     nsRefPtr<nsDocAccessible>& aDocAccessible,
                                     void* aUserArg)
 {
--- a/accessible/src/base/nsAccDocManager.h
+++ b/accessible/src/base/nsAccDocManager.h
@@ -71,48 +71,44 @@ public:
 
   /**
    * Search through all document accessibles for an accessible with the given
    * unique id.
    */
   nsAccessible* FindAccessibleInCache(nsINode* aNode) const;
 
   /**
-   * Shutdown document accessibles in the tree starting from the given one.
-   *
-   * @param  aDocument  [in] the DOM document of start document accessible
-   */
-  void ShutdownDocAccessiblesInTree(nsIDocument *aDocument);
-
-  /**
    * Return document accessible from the cache. Convenient method for testing.
    */
   inline nsDocAccessible* GetDocAccessibleFromCache(nsIDocument* aDocument) const
   {
     return mDocAccessibleCache.GetWeak(aDocument);
   }
 
+  /**
+   * Called by document accessible when it gets shutdown.
+   */
+  inline void NotifyOfDocumentShutdown(nsIDocument* aDocument)
+  {
+    mDocAccessibleCache.Remove(aDocument);
+  }
+
 protected:
   nsAccDocManager() { };
 
   /**
    * Initialize the manager.
    */
   PRBool Init();
 
   /**
    * Shutdown the manager.
    */
   void Shutdown();
 
-  /**
-   * Shutdown the document accessible.
-   */
-  void ShutdownDocAccessible(nsIDocument* aDocument);
-
 private:
   nsAccDocManager(const nsAccDocManager&);
   nsAccDocManager& operator =(const nsAccDocManager&);
 
 private:
   /**
    * Create an accessible document if it was't created and fire accessibility
    * events if needed.
@@ -151,22 +147,16 @@ private:
    */
   void AddListeners(nsIDocument *aDocument, PRBool aAddPageShowListener);
 
   /**
    * Create document or root accessible.
    */
   nsDocAccessible *CreateDocOrRootAccessible(nsIDocument *aDocument);
 
-  /**
-   * Shutdown document accessibles in the tree starting from given tree item.
-   */
-  void ShutdownDocAccessiblesInTree(nsIDocShellTreeItem *aTreeItem,
-                                    nsIDocument *aDocument);
-
   typedef nsRefPtrHashtable<nsPtrHashKey<const nsIDocument>, nsDocAccessible>
     nsDocAccessibleHashtable;
 
   /**
    * Shutdown and remove the document accessible from cache.
    */
   static PLDHashOperator
     ClearDocCacheEntry(const nsIDocument* aKey,
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -538,17 +538,20 @@ nsAccessibilityService::PresShellDestroy
   // pagehide event for the iframe's underlying document and its presshell is
   // destroyed before we're notified styles were changed. Shutdown the document
   // accessible early.
   nsIDocument* doc = aPresShell->GetDocument();
   if (!doc)
     return;
 
   NS_LOG_ACCDOCDESTROY("presshell destroyed", doc)
-  ShutdownDocAccessible(doc);
+
+  nsDocAccessible* docAccessible = GetDocAccessibleFromCache(doc);
+  if (docAccessible)
+    docAccessible->Shutdown();
 }
 
 void
 nsAccessibilityService::RecreateAccessible(nsIPresShell* aPresShell,
                                            nsIContent* aContent)
 {
   nsDocAccessible* document = GetDocAccessible(aPresShell->GetDocument());
   if (document)
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -670,27 +670,33 @@ nsDocAccessible::Shutdown()
   if (mParent) {
     nsDocAccessible* parentDocument = mParent->GetDocAccessible();
     if (parentDocument)
       parentDocument->RemoveChildDocument(this);
 
     mParent->RemoveChild(this);
   }
 
+  PRUint32 childDocCount = mChildDocuments.Length();
+  for (PRUint32 idx = 0; idx < childDocCount; idx++)
+    mChildDocuments[idx]->Shutdown();
+
   mChildDocuments.Clear();
 
   mWeakShell = nsnull;  // Avoid reentrancy
 
   mNodeToAccessibleMap.Clear();
   ClearCache(mAccessibleCache);
 
   nsCOMPtr<nsIDocument> kungFuDeathGripDoc = mDocument;
   mDocument = nsnull;
 
   nsHyperTextAccessibleWrap::Shutdown();
+
+  GetAccService()->NotifyOfDocumentShutdown(kungFuDeathGripDoc);
 }
 
 nsIFrame*
 nsDocAccessible::GetFrame()
 {
   nsCOMPtr<nsIPresShell> shell(do_QueryReferent(mWeakShell));
 
   nsIFrame* root = nsnull;
--- a/accessible/src/base/nsOuterDocAccessible.cpp
+++ b/accessible/src/base/nsOuterDocAccessible.cpp
@@ -164,17 +164,17 @@ nsOuterDocAccessible::Shutdown()
   // any to avoid hanging document accessible.
   NS_LOG_ACCDOCDESTROY_MSG("A11y outerdoc shutdown")
   NS_LOG_ACCDOCDESTROY_ACCADDRESS("outerdoc", this)
 
   nsAccessible *childAcc = mChildren.SafeElementAt(0, nsnull);
   if (childAcc) {
     NS_LOG_ACCDOCDESTROY("outerdoc's child document shutdown",
                          childAcc->GetDocumentNode())
-    GetAccService()->ShutdownDocAccessiblesInTree(childAcc->GetDocumentNode());
+    childAcc->Shutdown();
   }
 
   nsAccessibleWrap::Shutdown();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessible public