Bug 545465 - don't keep rejected accessible in the cache, r=ginn.chen, davidb, a=blockingBetaN
authorAlexander Surkov <surkov.alexander@gmail.com>
Fri, 12 Nov 2010 14:00:55 -0500
changeset 57413 b22e3d33e8b1b60d13f01ab1a1d36546f62cbf22
parent 57412 81f4de31f19e0aeb2343b07b4c7398805c147606
child 57414 3e941917e221c347d9c0fb4be2601afc1f7d135b
push id16913
push usersurkov.alexander@gmail.com
push dateFri, 12 Nov 2010 19:01:27 +0000
treeherdermozilla-central@3e941917e221 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersginn.chen, davidb, blockingBetaN
bugs545465
milestone2.0b8pre
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 545465 - don't keep rejected accessible in the cache, r=ginn.chen, davidb, a=blockingBetaN
accessible/src/base/nsAccDocManager.cpp
accessible/src/base/nsAccessibilityService.cpp
accessible/src/base/nsAccessibilityService.h
accessible/src/base/nsAccessible.cpp
accessible/src/base/nsAccessible.h
accessible/src/base/nsDocAccessible.cpp
accessible/src/base/nsDocAccessible.h
accessible/src/html/nsHTMLImageMapAccessible.cpp
accessible/src/html/nsHTMLSelectAccessible.cpp
accessible/src/html/nsHTMLTextAccessible.cpp
accessible/src/xul/nsXULColorPickerAccessible.cpp
accessible/src/xul/nsXULFormControlAccessible.cpp
accessible/src/xul/nsXULTreeAccessible.cpp
accessible/src/xul/nsXULTreeGridAccessible.cpp
--- a/accessible/src/base/nsAccDocManager.cpp
+++ b/accessible/src/base/nsAccDocManager.cpp
@@ -451,37 +451,38 @@ nsAccDocManager::CreateDocOrRootAccessib
   }
 
   if (!outerDocAcc)
     return nsnull;
 
   // We only create root accessibles for the true root, otherwise create a
   // doc accessible.
   nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(presShell));
-  nsDocAccessible *docAcc = isRootDoc ?
+  nsRefPtr<nsDocAccessible> docAcc = isRootDoc ?
     new nsRootAccessibleWrap(aDocument, rootElm, weakShell) :
     new nsDocAccessibleWrap(aDocument, rootElm, weakShell);
 
-  if (!docAcc)
+  // Cache the document accessible into document cache.
+  if (!docAcc || !mDocAccessibleCache.Put(aDocument, docAcc))
     return nsnull;
 
-  // Cache and addref document accessible.
-  if (!mDocAccessibleCache.Put(aDocument, docAcc)) {
-    delete docAcc;
+  // Bind the document accessible into tree.
+  if (!outerDocAcc->AppendChild(docAcc)) {
+    mDocAccessibleCache.Remove(aDocument);
     return nsnull;
   }
 
-  // XXX: ideally we should initialize an accessible and then put it into tree,
-  // we can't since document accessible fires reorder event on its container
-  // while initialized.
-  if (!outerDocAcc->AppendChild(docAcc) ||
-      !GetAccService()->InitAccessible(docAcc, nsAccUtils::GetRoleMapEntry(aDocument))) {
+  // Initialize the document accessible. Note, Init() should be called after
+  // the document accessible is bound to the tree.
+  if (!docAcc->Init()) {
+    docAcc->Shutdown();
     mDocAccessibleCache.Remove(aDocument);
     return nsnull;
   }
+  docAcc->SetRoleMapEntry(nsAccUtils::GetRoleMapEntry(aDocument));
 
   NS_LOG_ACCDOCCREATE("document creation finished", aDocument)
 
   AddListeners(aDocument, isRootDoc);
   return docAcc;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -832,38 +832,16 @@ nsAccessibilityService::GetCachedAccessi
 
   nsAccessible *accessible = nsnull;
   while (!(accessible = GetCachedAccessible(currNode, weakShell)) &&
          (currNode = currNode->GetNodeParent()));
 
   return accessible;
 }
 
-PRBool
-nsAccessibilityService::InitAccessible(nsAccessible *aAccessible,
-                                       nsRoleMapEntry *aRoleMapEntry)
-{
-  if (!aAccessible)
-    return PR_FALSE;
-
-  // Add to cache an accessible, etc.
-  if (!aAccessible->Init()) {
-    NS_ERROR("Failed to initialize an accessible!");
-
-    aAccessible->Shutdown();
-    return PR_FALSE;
-  }
-
-  NS_ASSERTION(aAccessible->IsInCache(),
-               "Initialized accessible not in the cache!");
-
-  aAccessible->SetRoleMapEntry(aRoleMapEntry);
-  return PR_TRUE;
-}
-
 static PRBool HasRelatedContent(nsIContent *aContent)
 {
   nsAutoString id;
   if (!aContent || !nsCoreUtils::GetID(aContent, id) || id.IsEmpty()) {
     return PR_FALSE;
   }
 
   nsIAtom *relationAttrs[] = {nsAccessibilityAtoms::aria_labelledby,
@@ -953,16 +931,23 @@ nsAccessibilityService::GetOrCreateAcces
     // frame or the node is not an area element then null is returned.
     // This setup will change when bug 135040 is fixed.
     nsAccessible* areaAcc = GetAreaAccessible(weakFrame.GetFrame(),
                                               aNode, aWeakShell);
     NS_IF_ADDREF(areaAcc);
     return areaAcc;
   }
 
+  nsDocAccessible* docAcc =
+    GetAccService()->GetDocAccessible(aNode->GetOwnerDoc());
+  if (!docAcc) {
+    NS_NOTREACHED("No document for accessible being created!");
+    return nsnull;
+  }
+
   // Attempt to create an accessible based on what we know.
   nsRefPtr<nsAccessible> newAcc;
   if (content->IsNodeOfType(nsINode::eTEXT)) {
     // --- Create HTML for visible text frames ---
     nsIFrame* f = weakFrame.GetFrame();
     if (f && f->IsEmpty()) {
       nsAutoString renderedWhitespace;
       f->GetRenderedText(&renderedWhitespace, nsnull, nsnull, 0, 1);
@@ -971,17 +956,17 @@ nsAccessibilityService::GetOrCreateAcces
         if (aIsHidden)
           *aIsHidden = PR_TRUE;
 
         return nsnull;
       }
     }
     if (weakFrame.IsAlive()) {
       newAcc = weakFrame.GetFrame()->CreateAccessible();
-      if (InitAccessible(newAcc, nsnull))
+      if (docAcc->BindToDocument(newAcc, nsnull))
         return newAcc.forget();
       return nsnull;
     }
 
     return nsnull;
   }
 
   PRBool isHTML = content->IsHTML();
@@ -999,17 +984,17 @@ nsAccessibilityService::GetOrCreateAcces
     if (!name.IsEmpty()) {
       if (aIsHidden)
         *aIsHidden = PR_TRUE;
 
       return nsnull;
     }
 
     newAcc = new nsHyperTextAccessibleWrap(content, aWeakShell);
-    if (InitAccessible(newAcc, nsAccUtils::GetRoleMapEntry(aNode)))
+    if (docAcc->BindToDocument(newAcc, nsAccUtils::GetRoleMapEntry(aNode)))
       return newAcc.forget();
     return nsnull;
   }
 
   nsRoleMapEntry *roleMapEntry = nsAccUtils::GetRoleMapEntry(aNode);
   if (roleMapEntry && !nsCRT::strcmp(roleMapEntry->roleString, "presentation") &&
       !content->IsFocusable()) { // For presentation only
     // Only create accessible for role of "presentation" if it is focusable --
@@ -1186,17 +1171,17 @@ nsAccessibilityService::GetOrCreateAcces
       newAcc = new nsHyperTextAccessibleWrap(content, aWeakShell);
     }
     else {  // XUL, SVG, MathML etc.
       // Interesting generic non-HTML container
       newAcc = new nsAccessibleWrap(content, aWeakShell);
     }
   }
 
-  if (InitAccessible(newAcc, roleMapEntry))
+  if (docAcc->BindToDocument(newAcc, roleMapEntry))
     return newAcc.forget();
   return nsnull;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessibilityService private
 
 PRBool
@@ -1343,32 +1328,39 @@ nsAccessibilityService::GetAreaAccessibl
     return nsnull;
 
   nsCOMPtr<nsIDOMHTMLAreaElement> areaElmt = do_QueryInterface(aAreaNode);
   if (!areaElmt)
     return nsnull;
 
   // Try to get image map accessible from the global cache or create it
   // if failed.
-  nsRefPtr<nsAccessible> imageAcc =
-    GetCachedAccessible(aImageFrame->GetContent(), aWeakShell);
-  if (!imageAcc) {
-    imageAcc = CreateHTMLImageAccessible(aImageFrame->GetContent(),
-                                         aImageFrame->PresContext()->PresShell());
+  nsRefPtr<nsAccessible> image = GetCachedAccessible(aImageFrame->GetContent(),
+                                                     aWeakShell);
+  if (!image) {
+    image = CreateHTMLImageAccessible(aImageFrame->GetContent(),
+                                      aImageFrame->PresContext()->PresShell());
 
-    if (!InitAccessible(imageAcc, nsnull))
+    nsDocAccessible* document =
+      GetAccService()->GetDocAccessible(aAreaNode->GetOwnerDoc());
+    if (!document) {
+      NS_NOTREACHED("No document for accessible being created!");
+      return nsnull;
+    }
+
+    if (!document->BindToDocument(image, nsnull))
       return nsnull;
   }
 
   if (aImageAccessible)
-    *aImageAccessible = imageAcc;
+    *aImageAccessible = image;
 
   // Make sure <area> accessible children of the image map are cached so
   // that they should be available in global cache.
-  imageAcc->EnsureChildren();
+  image->EnsureChildren();
 
   return GetCachedAccessible(aAreaNode, aWeakShell);
 }
 
 already_AddRefed<nsAccessible>
 nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
                                                nsIWeakReference* aWeakShell)
 {
@@ -1766,17 +1758,17 @@ nsAccessible*
 nsAccessibilityService::AddNativeRootAccessible(void* aAtkAccessible)
  {
 #ifdef MOZ_ACCESSIBILITY_ATK
   nsApplicationAccessible* applicationAcc =
     nsAccessNode::GetApplicationAccessible();
   if (!applicationAcc)
     return nsnull;
 
-  nsNativeRootAccessibleWrap* nativeRootAcc =
+  nsRefPtr<nsNativeRootAccessibleWrap> nativeRootAcc =
      new nsNativeRootAccessibleWrap((AtkObject*)aAtkAccessible);
   if (!nativeRootAcc)
     return nsnull;
 
   if (applicationAcc->AppendChild(nativeRootAcc))
     return nativeRootAcc;
 #endif
 
--- a/accessible/src/base/nsAccessibilityService.h
+++ b/accessible/src/base/nsAccessibilityService.h
@@ -197,29 +197,16 @@ public:
    * @param aDOMNode    [in] the DOM node to get an accessible for
    */
   inline nsAccessible* GetCachedContainerAccessible(nsINode *aNode)
   {
     return aNode ?
       GetCachedAccessibleOrContainer(aNode->GetNodeParent()) : nsnull;
   }
 
-  /**
-   * Initialize an accessible and cache it. The method should be called for
-   * every created accessible.
-   *
-   * @param  aAccessible    [in] accessible to initialize.
-   * @param  aRoleMapEntry  [in] the role map entry role the ARIA role or nsnull
-   *                          if none
-   *
-   * @return true if the accessible was initialized, otherwise false
-   */
-  PRBool InitAccessible(nsAccessible *aAccessible,
-                        nsRoleMapEntry *aRoleMapEntry);
-
 protected:
   /**
    * Return an accessible for the DOM node in the given presentation shell if
    * the accessible already exists, otherwise null.
    *
    * @param  aNode       [in] the DOM node to get an access node for
    * @param  aPresShell  [in] the presentation shell which contains layout info
    *                       for the DOM node
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -2616,29 +2616,16 @@ nsAccessible::AppendTextTo(nsAString& aT
   }
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessNode public methods
 
-PRBool
-nsAccessible::Init()
-{
-  if (!nsAccessNodeWrap::Init())
-    return PR_FALSE;
-
-  nsDocAccessible* document =
-    GetAccService()->GetDocAccessible(mContent->GetOwnerDoc());
-  NS_ASSERTION(document, "Cannot cache new nsAccessible!");
-
-  return document ? document->CacheAccessible(this) : PR_FALSE;
-}
-
 void
 nsAccessible::Shutdown()
 {
   // Invalidate the child count and pointers to other accessibles, also make
   // sure none of its children point to this parent
   InvalidateChildren();
   if (mParent)
     mParent->RemoveChild(this);
@@ -2907,30 +2894,16 @@ nsAccessible::GetIndexOfEmbeddedChild(ns
       mEmbeddedObjCollector = new EmbeddedObjCollector(this);
     return mEmbeddedObjCollector ?
       mEmbeddedObjCollector->GetIndexAt(aChild) : -1;
   }
 
   return GetIndexOf(aChild);
 }
 
-#ifdef DEBUG
-PRBool
-nsAccessible::IsInCache()
-{
-  nsDocAccessible *docAccessible =
-    GetAccService()->GetDocAccessible(mContent->GetOwnerDoc());
-  if (docAccessible)
-    return docAccessible->GetCachedAccessibleByUniqueID(UniqueID()) ? PR_TRUE : PR_FALSE;
-
-  return PR_FALSE;
-}
-#endif
-
-
 ////////////////////////////////////////////////////////////////////////////////
 // HyperLinkAccessible methods
 
 bool
 nsAccessible::IsHyperLink()
 {
   // Every embedded accessible within hypertext accessible implements
   // hyperlink interface.
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -108,17 +108,16 @@ public:
   NS_DECL_NSIACCESSIBLEHYPERLINK
   NS_DECL_NSIACCESSIBLESELECTABLE
   NS_DECL_NSIACCESSIBLEVALUE
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ACCESSIBLE_IMPL_IID)
 
   //////////////////////////////////////////////////////////////////////////////
   // nsAccessNode
 
-  virtual PRBool Init();
   virtual void Shutdown();
 
   //////////////////////////////////////////////////////////////////////////////
   // Public methods
 
   /**
    * Returns the accessible name specified by ARIA.
    */
@@ -293,23 +292,16 @@ public:
     return mParent ?
       mParent->mChildren.SafeElementAt(mIndexInParent - 1, nsnull).get() : nsnull;
   }
   PRUint32 GetCachedChildCount() const { return mChildren.Length(); }
   nsAccessible* GetCachedChildAt(PRUint32 aIndex) const { return mChildren.ElementAt(aIndex); }
   PRBool AreChildrenCached() const { return mChildrenFlags != eChildrenUninitialized; }
   bool IsBoundToParent() const { return mParent; }
 
-#ifdef DEBUG
-  /**
-   * Return true if the access node is cached.
-   */
-  PRBool IsInCache();
-#endif
-
   //////////////////////////////////////////////////////////////////////////////
   // Miscellaneous methods
 
   /**
    * Handle accessible event, i.e. process it, notifies observers and fires
    * platform specific event.
    */
   virtual nsresult HandleAccEvent(AccEvent* aAccEvent);
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -594,41 +594,16 @@ nsDocAccessible::GetCachedAccessible(nsI
   nsAccessible* parent(accessible->GetCachedParent());
   if (parent)
     parent->TestChildCache(accessible);
 #endif
 
   return accessible;
 }
 
-// nsDocAccessible public method
-PRBool
-nsDocAccessible::CacheAccessible(nsAccessible* aAccessible)
-{
-  if (aAccessible->IsPrimaryForNode() &&
-      !mNodeToAccessibleMap.Put(aAccessible->GetNode(), aAccessible))
-    return PR_FALSE;
-
-  return mAccessibleCache.Put(aAccessible->UniqueID(), aAccessible);
-}
-
-// nsDocAccessible public method
-void
-nsDocAccessible::ShutdownAccessible(nsAccessible *aAccessible)
-{
-  // Remove an accessible from node to accessible map if it is presented there.
-  if (aAccessible->IsPrimaryForNode() &&
-      mNodeToAccessibleMap.Get(aAccessible->GetNode()) == aAccessible)
-    mNodeToAccessibleMap.Remove(aAccessible->GetNode());
-
-  void* uniqueID = aAccessible->UniqueID();
-  aAccessible->Shutdown();
-  mAccessibleCache.Remove(uniqueID);
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessNode
 
 PRBool
 nsDocAccessible::Init()
 {
   NS_LOG_ACCDOCCREATE_FOR("document initialize", mDocument, this)
 
@@ -1340,16 +1315,65 @@ nsDocAccessible::GetCachedAccessibleByUn
     child = childDocument->GetCachedAccessibleByUniqueIDInSubtree(aUniqueID);
     if (child)
       return child;
   }
 
   return nsnull;
 }
 
+bool
+nsDocAccessible::BindToDocument(nsAccessible* aAccessible,
+                                nsRoleMapEntry* aRoleMapEntry)
+{
+  if (!aAccessible)
+    return false;
+
+  // Put into DOM node cache.
+  if (aAccessible->IsPrimaryForNode() &&
+      !mNodeToAccessibleMap.Put(aAccessible->GetNode(), aAccessible))
+    return false;
+
+  // Put into unique ID cache.
+  if (!mAccessibleCache.Put(aAccessible->UniqueID(), aAccessible)) {
+    if (aAccessible->IsPrimaryForNode())
+      mNodeToAccessibleMap.Remove(aAccessible->GetNode());
+    return false;
+  }
+
+  // Initialize the accessible.
+  if (!aAccessible->Init()) {
+    NS_ERROR("Failed to initialize an accessible!");
+
+    UnbindFromDocument(aAccessible);
+    return false;
+  }
+
+  aAccessible->SetRoleMapEntry(aRoleMapEntry);
+  return true;
+}
+
+void
+nsDocAccessible::UnbindFromDocument(nsAccessible* aAccessible)
+{
+  // Remove an accessible from node to accessible map if it is presented there.
+  if (aAccessible->IsPrimaryForNode() &&
+      mNodeToAccessibleMap.Get(aAccessible->GetNode()) == aAccessible)
+    mNodeToAccessibleMap.Remove(aAccessible->GetNode());
+
+#ifdef DEBUG
+  NS_ASSERTION(mAccessibleCache.GetWeak(aAccessible->UniqueID()),
+               "Illegitimate illegitimated accessible!");
+#endif
+
+  void* uniqueID = aAccessible->UniqueID();
+  aAccessible->Shutdown();
+  mAccessibleCache.Remove(uniqueID);
+}
+
 void
 nsDocAccessible::UpdateTree(nsIContent* aContainerNode,
                             nsIContent* aStartNode,
                             nsIContent* aEndNode,
                             PRBool aIsInsert)
 {
   // Content change notification mostly are async, thus we can't detect whether
   // these actions are from user. This information is used to fire or do not
@@ -1756,30 +1780,26 @@ nsDocAccessible::UncacheChildrenInSubtre
   if (aRoot->IsPrimaryForNode() &&
       mNodeToAccessibleMap.Get(aRoot->GetNode()) == aRoot)
     mNodeToAccessibleMap.Remove(aRoot->GetNode());
 }
 
 void
 nsDocAccessible::ShutdownChildrenInSubtree(nsAccessible* aAccessible)
 {
-#ifdef DEBUG
-  nsAccessible* incache = mAccessibleCache.GetWeak(aAccessible->UniqueID());
-#endif
-
   // Traverse through children and shutdown them before this accessible. When
   // child gets shutdown then it removes itself from children array of its
   //parent. Use jdx index to process the cases if child is not attached to the
   // parent and as result doesn't remove itself from its children.
   PRUint32 count = aAccessible->GetCachedChildCount();
   for (PRUint32 idx = 0, jdx = 0; idx < count; idx++) {
     nsAccessible* child = aAccessible->GetCachedChildAt(jdx);
     if (!child->IsBoundToParent()) {
       NS_ERROR("Parent refers to a child, child doesn't refer to parent!");
       jdx++;
     }
 
     ShutdownChildrenInSubtree(child);
   }
 
-  ShutdownAccessible(aAccessible);
+  UnbindFromDocument(aAccessible);
 }
 
--- a/accessible/src/base/nsDocAccessible.h
+++ b/accessible/src/base/nsDocAccessible.h
@@ -206,28 +206,28 @@ public:
 
   /**
    * Return the cached accessible by the given unique ID looking through
    * this and nested documents.
    */
   nsAccessible* GetCachedAccessibleByUniqueIDInSubtree(void* aUniqueID);
 
   /**
-   * Cache the accessible.
-   *
-   * @param  aAccessible  [in] accessible to cache
+   * Initialize the newly created accessible and put it into document caches.
    *
-   * @return true if accessible being cached, otherwise false
+   * @param  aAccessible    [in] created accessible
+   * @param  aRoleMapEntry  [in] the role map entry role the ARIA role or nsnull
+   *                          if none
    */
-  PRBool CacheAccessible(nsAccessible *aAccessible);
+  bool BindToDocument(nsAccessible* aAccessible, nsRoleMapEntry* aRoleMapEntry);
 
   /**
-   * Shutdown the accessible and remove it from document cache.
+   * Remove the existing accessible from document caches and shutdown it.
    */
-  void ShutdownAccessible(nsAccessible *aAccessible);
+  void UnbindFromDocument(nsAccessible* aAccessible);
 
   /**
    * Process the event when the queue of pending events is untwisted. Fire
    * accessible events as result of the processing.
    */
   void ProcessPendingEvent(AccEvent* aEvent);
 
   /**
--- a/accessible/src/html/nsHTMLImageMapAccessible.cpp
+++ b/accessible/src/html/nsHTMLImageMapAccessible.cpp
@@ -35,16 +35,17 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsHTMLImageMapAccessible.h"
 
 #include "nsAccUtils.h"
+#include "nsDocAccessible.h"
 
 #include "nsIDOMHTMLCollection.h"
 #include "nsIServiceManager.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMHTMLAreaElement.h"
 #include "nsIFrame.h"
 #include "nsIImageFrame.h"
 #include "nsIImageMap.h"
@@ -109,41 +110,35 @@ nsHTMLImageMapAccessible::CacheChildren(
   if (!mMapElement)
     return;
 
   nsCOMPtr<nsIDOMHTMLCollection> mapAreas;
   mMapElement->GetAreas(getter_AddRefs(mapAreas));
   if (!mapAreas)
     return;
 
+  nsDocAccessible* document = GetDocAccessible();
+
   PRUint32 areaCount = 0;
   mapAreas->GetLength(&areaCount);
 
   for (PRUint32 areaIdx = 0; areaIdx < areaCount; areaIdx++) {
     nsCOMPtr<nsIDOMNode> areaNode;
     mapAreas->Item(areaIdx, getter_AddRefs(areaNode));
     if (!areaNode)
       return;
 
     nsCOMPtr<nsIContent> areaContent(do_QueryInterface(areaNode));
-    nsRefPtr<nsAccessible> areaAcc =
+    nsRefPtr<nsAccessible> area =
       new nsHTMLAreaAccessible(areaContent, mWeakShell);
-    if (!areaAcc)
-      return;
 
-    if (!areaAcc->Init()) {
-      areaAcc->Shutdown();
+    if (!document->BindToDocument(area, nsAccUtils::GetRoleMapEntry(areaContent)) ||
+        !AppendChild(area)) {
       return;
     }
-
-    // We must respect ARIA on area elements (for the canvas map technique)
-    areaAcc->SetRoleMapEntry(nsAccUtils::GetRoleMapEntry(areaContent));
-
-    if (!AppendChild(areaAcc))
-      return;
   }
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLAreaAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
--- a/accessible/src/html/nsHTMLSelectAccessible.cpp
+++ b/accessible/src/html/nsHTMLSelectAccessible.cpp
@@ -687,31 +687,27 @@ nsHTMLComboboxAccessible::CacheChildren(
 
   nsIFrame *listFrame = comboFrame->GetDropDown();
   if (!listFrame)
     return;
 
   if (!mListAccessible) {
     mListAccessible = 
       new nsHTMLComboboxListAccessible(mParent, mContent, mWeakShell);
-    if (!mListAccessible)
-      return;
 
     // Initialize and put into cache.
-    if (!mListAccessible->Init()) {
-      mListAccessible->Shutdown();
+    if (!GetDocAccessible()->BindToDocument(mListAccessible, nsnull))
       return;
-    }
   }
 
-  AppendChild(mListAccessible);
-
-  // Cache combobox option accessibles so that we build complete accessible tree
-  // for combobox.
-  mListAccessible->EnsureChildren();
+  if (AppendChild(mListAccessible)) {
+    // Cache combobox option accessibles so that we build complete accessible
+    // tree for combobox.
+    mListAccessible->EnsureChildren();
+  }
 }
 
 void
 nsHTMLComboboxAccessible::Shutdown()
 {
   nsAccessibleWrap::Shutdown();
 
   if (mListAccessible) {
--- a/accessible/src/html/nsHTMLTextAccessible.cpp
+++ b/accessible/src/html/nsHTMLTextAccessible.cpp
@@ -254,18 +254,17 @@ nsHTMLOutputAccessible::GetAttributesInt
 
 nsHTMLLIAccessible::
   nsHTMLLIAccessible(nsIContent* aContent, nsIWeakReference* aShell) :
   nsHyperTextAccessibleWrap(aContent, aShell)
 {
   nsBlockFrame* blockFrame = do_QueryFrame(GetFrame());
   if (blockFrame && !blockFrame->BulletIsEmptyExternal()) {
     mBulletAccessible = new nsHTMLListBulletAccessible(mContent, mWeakShell);
-    if (mBulletAccessible)
-      mBulletAccessible->Init();
+    GetDocAccessible()->BindToDocument(mBulletAccessible, nsnull);
   }
 }
 
 NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLLIAccessible, nsHyperTextAccessible)
 
 void
 nsHTMLLIAccessible::Shutdown()
 {
--- a/accessible/src/xul/nsXULColorPickerAccessible.cpp
+++ b/accessible/src/xul/nsXULColorPickerAccessible.cpp
@@ -36,16 +36,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsXULColorPickerAccessible.h"
 
 #include "nsAccUtils.h"
 #include "nsAccTreeWalker.h"
 #include "nsCoreUtils.h"
+#include "nsDocAccessible.h"
 
 #include "nsIDOMElement.h"
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULColorPickerTileAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -166,10 +167,13 @@ nsXULColorPickerAccessible::CacheChildre
   while ((child = walker.GetNextChild())) {
     PRUint32 role = child->Role();
 
     // Get an accessbile for menupopup or panel elements.
     if (role == nsIAccessibleRole::ROLE_ALERT) {
       AppendChild(child);
       return;
     }
+
+    // Unbind rejected accessibles from the document.
+    GetDocAccessible()->UnbindFromDocument(child);
   }
 }
--- a/accessible/src/xul/nsXULFormControlAccessible.cpp
+++ b/accessible/src/xul/nsXULFormControlAccessible.cpp
@@ -38,16 +38,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsXULFormControlAccessible.h"
 
 #include "nsAccessibilityAtoms.h"
 #include "nsAccUtils.h"
 #include "nsAccTreeWalker.h"
 #include "nsCoreUtils.h"
+#include "nsDocAccessible.h"
 #include "nsRelUtils.h"
 
 // NOTE: alphabetically ordered
 #include "nsHTMLFormControlAccessible.h"
 #include "nsXULMenuAccessible.h"
 #include "nsIDOMHTMLInputElement.h"
 #include "nsIDOMNSEditableElement.h"
 #include "nsIDOMXULButtonElement.h"
@@ -217,16 +218,20 @@ nsXULButtonAccessible::CacheChildren()
       // Get an accessbile for menupopup or panel elements.
       menupopupAccessible.swap(child);
 
     } else if (isMenuButton && role == nsIAccessibleRole::ROLE_PUSHBUTTON) {
       // Button type="menu-button" contains a real button. Get an accessible
       // for it. Ignore dropmarker button what is placed as a last child.
       buttonAccessible.swap(child);
       break;
+
+    } else {
+      // Unbind rejected accessible from document.
+      GetDocAccessible()->UnbindFromDocument(child);
     }
   }
 
   if (!menupopupAccessible)
     return;
 
   AppendChild(menupopupAccessible);
   if (buttonAccessible)
--- a/accessible/src/xul/nsXULTreeAccessible.cpp
+++ b/accessible/src/xul/nsXULTreeAccessible.cpp
@@ -467,61 +467,58 @@ nsXULTreeAccessible::GetTreeItemAccessib
     return nsnull;
 
   PRInt32 rowCount = 0;
   nsresult rv = mTreeView->GetRowCount(&rowCount);
   if (NS_FAILED(rv) || aRow >= rowCount)
     return nsnull;
 
   void *key = reinterpret_cast<void*>(aRow);
-  nsRefPtr<nsAccessible> accessible = mAccessibleCache.GetWeak(key);
-
-  if (!accessible) {
-    accessible = CreateTreeItemAccessible(aRow);
-    if (!accessible)
-      return nsnull;
+  nsAccessible* cachedTreeItem = mAccessibleCache.GetWeak(key);
+  if (cachedTreeItem)
+    return cachedTreeItem;
 
-    if (!accessible->Init()) {
-      accessible->Shutdown();
-      return nsnull;
+  nsRefPtr<nsAccessible> treeItem = CreateTreeItemAccessible(aRow);
+  if (treeItem) {
+    if (mAccessibleCache.Put(key, treeItem)) {
+      if (GetDocAccessible()->BindToDocument(treeItem, nsnull))
+        return treeItem;
+
+      mAccessibleCache.Remove(key);
     }
-
-    if (!mAccessibleCache.Put(key, accessible))
-      return nsnull;
   }
 
-  return accessible;
+  return nsnull;
 }
 
 void
 nsXULTreeAccessible::InvalidateCache(PRInt32 aRow, PRInt32 aCount)
 {
   if (IsDefunct())
     return;
 
   // Do not invalidate the cache if rows have been inserted.
   if (aCount > 0)
     return;
 
+  nsDocAccessible* document = GetDocAccessible();
+
   // Fire destroy event for removed tree items and delete them from caches.
   for (PRInt32 rowIdx = aRow; rowIdx < aRow - aCount; rowIdx++) {
 
     void* key = reinterpret_cast<void*>(rowIdx);
-    nsAccessible *accessible = mAccessibleCache.GetWeak(key);
+    nsAccessible* treeItem = mAccessibleCache.GetWeak(key);
 
-    if (accessible) {
+    if (treeItem) {
       nsRefPtr<AccEvent> event =
-        new AccEvent(nsIAccessibleEvent::EVENT_HIDE, accessible);
+        new AccEvent(nsIAccessibleEvent::EVENT_HIDE, treeItem);
       nsEventShell::FireEvent(event);
 
-      // Shutdown and remove accessible from document cache and tree cache.
-      nsDocAccessible *docAccessible = GetDocAccessible();
-      if (docAccessible)
-        docAccessible->ShutdownAccessible(accessible);
-
+      // Unbind from document, shutdown and remove from tree cache.
+      document->UnbindFromDocument(treeItem);
       mAccessibleCache.Remove(key);
     }
   }
 
   // We dealt with removed tree items already however we may keep tree items
   // having row indexes greater than row count. We should remove these dead tree
   // items silently from caches.
   PRInt32 newRowCount = 0;
@@ -529,24 +526,21 @@ nsXULTreeAccessible::InvalidateCache(PRI
   if (NS_FAILED(rv))
     return;
 
   PRInt32 oldRowCount = newRowCount - aCount;
 
   for (PRInt32 rowIdx = newRowCount; rowIdx < oldRowCount; ++rowIdx) {
 
     void *key = reinterpret_cast<void*>(rowIdx);
-    nsAccessible *accessible = mAccessibleCache.GetWeak(key);
+    nsAccessible* treeItem = mAccessibleCache.GetWeak(key);
 
-    if (accessible) {
-      // Shutdown and remove accessible from document cache and tree cache.
-      nsDocAccessible *docAccessible = GetDocAccessible();
-      if (docAccessible)
-        docAccessible->ShutdownAccessible(accessible);
-
+    if (treeItem) {
+      // Unbind from document, shutdown and remove from tree cache.
+      document->UnbindFromDocument(treeItem);
       mAccessibleCache.Remove(key);
     }
   }
 }
 
 void
 nsXULTreeAccessible::TreeViewInvalidated(PRInt32 aStartRow, PRInt32 aEndRow,
                                          PRInt32 aStartCol, PRInt32 aEndCol)
--- a/accessible/src/xul/nsXULTreeGridAccessible.cpp
+++ b/accessible/src/xul/nsXULTreeGridAccessible.cpp
@@ -36,16 +36,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsXULTreeGridAccessibleWrap.h"
 
 #include "nsAccCache.h"
 #include "nsAccessibilityService.h"
 #include "nsAccUtils.h"
+#include "nsDocAccessible.h"
 #include "nsEventShell.h"
 
 #include "nsITreeSelection.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeGridAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -724,35 +725,33 @@ nsXULTreeGridRowAccessible::GetChildCoun
 // nsXULTreeGridRowAccessible: nsXULTreeItemAccessibleBase implementation
 
 nsAccessible*
 nsXULTreeGridRowAccessible::GetCellAccessible(nsITreeColumn* aColumn)
 {
   NS_PRECONDITION(aColumn, "No tree column!");
 
   void* key = static_cast<void*>(aColumn);
-  nsRefPtr<nsAccessible> accessible = mAccessibleCache.GetWeak(key);
+  nsAccessible* cachedCell = mAccessibleCache.GetWeak(key);
+  if (cachedCell)
+    return cachedCell;
 
-  if (!accessible) {
-    accessible =
-      new nsXULTreeGridCellAccessibleWrap(mContent, mWeakShell, this, mTree,
-                                          mTreeView, mRow, aColumn);
-    if (!accessible)
-      return nsnull;
+  nsRefPtr<nsAccessible> cell =
+    new nsXULTreeGridCellAccessibleWrap(mContent, mWeakShell, this, mTree,
+                                        mTreeView, mRow, aColumn);
+  if (cell) {
+    if (mAccessibleCache.Put(key, cell)) {
+      if (GetDocAccessible()->BindToDocument(cell, nsnull))
+        return cell;
 
-    if (!accessible->Init()) {
-      accessible->Shutdown();
-      return nsnull;
+      mAccessibleCache.Remove(key);
     }
-
-    if (!mAccessibleCache.Put(key, accessible))
-      return nsnull;
   }
 
-  return accessible;
+  return nsnull;
 }
 
 void
 nsXULTreeGridRowAccessible::RowInvalidated(PRInt32 aStartColIdx,
                                            PRInt32 aEndColIdx)
 {
   nsCOMPtr<nsITreeColumns> treeColumns;
   mTree->GetColumns(getter_AddRefs(treeColumns));