Bug 566103- reorganize accessible document handling, r=marcoz, davidb
authorAlexander Surkov <surkov.alexander@gmail.com>
Wed, 09 Jun 2010 01:39:58 +0900
changeset 43310 a2ba3a7cec03945d4e0301f59f9dbb44f5e22582
parent 43309 3347c14893e2ecef7ea0ce388fe1fba21203d510
child 43311 47b178e787914e32d524b07f52b0c93b1ddbbe99
push id13648
push usersurkov.alexander@gmail.com
push dateTue, 08 Jun 2010 16:40:53 +0000
treeherderautoland@a2ba3a7cec03 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmarcoz, davidb
bugs566103
milestone1.9.3a5pre
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 566103- reorganize accessible document handling, r=marcoz, davidb
accessible/public/nsIAccessibleEvent.idl
accessible/src/atk/nsApplicationAccessibleWrap.cpp
accessible/src/base/Makefile.in
accessible/src/base/nsAccDocManager.cpp
accessible/src/base/nsAccDocManager.h
accessible/src/base/nsAccEvent.cpp
accessible/src/base/nsAccTreeWalker.cpp
accessible/src/base/nsAccUtils.h
accessible/src/base/nsAccessNode.cpp
accessible/src/base/nsAccessNode.h
accessible/src/base/nsAccessibilityService.cpp
accessible/src/base/nsAccessibilityService.h
accessible/src/base/nsAccessible.h
accessible/src/base/nsApplicationAccessible.cpp
accessible/src/base/nsCaretAccessible.cpp
accessible/src/base/nsCoreUtils.cpp
accessible/src/base/nsCoreUtils.h
accessible/src/base/nsDocAccessible.cpp
accessible/src/base/nsDocAccessible.h
accessible/src/base/nsOuterDocAccessible.cpp
accessible/src/base/nsOuterDocAccessible.h
accessible/src/base/nsRelUtils.cpp
accessible/src/base/nsRootAccessible.cpp
accessible/src/base/nsRootAccessible.h
accessible/src/msaa/nsDocAccessibleWrap.cpp
accessible/src/msaa/nsEventMap.h
accessible/src/xul/nsXULComboboxAccessible.cpp
accessible/tests/mochitest/common.js
accessible/tests/mochitest/events.js
accessible/tests/mochitest/events/Makefile.in
accessible/tests/mochitest/events/docload_wnd.xul
accessible/tests/mochitest/events/test_doc.html
accessible/tests/mochitest/events/test_docload.html
accessible/tests/mochitest/events/test_docload.xul
--- a/accessible/public/nsIAccessibleEvent.idl
+++ b/accessible/public/nsIAccessibleEvent.idl
@@ -56,17 +56,17 @@ interface nsIDOMNode;
  * using code something like this:
  *   nsCOMPtr<nsIObserverService> observerService = 
  *     do_GetService("@mozilla.org/observer-service;1", &rv);
  *   if (NS_SUCCEEDED(rv)) 
  *     rv = observerService->AddObserver(this, "accessible-event", PR_TRUE);
  *
  * @status UNDER_REVIEW
  */
-[scriptable, uuid(5713f093-1d67-4666-b9e2-516f410976bc)]
+[scriptable, uuid(c68b4386-dca7-4b88-8988-7a95ce7be92f)]
 interface nsIAccessibleEvent : nsISupports
 {
   /**
    * An object has been created.
    */
   const unsigned long EVENT_SHOW = 0x0001;
 
   /**
@@ -252,217 +252,207 @@ interface nsIAccessibleEvent : nsISuppor
   const unsigned long EVENT_MINIMIZE_START = 0x0025;
 
   /**
    * A window object has been minimized or maximized
    */
   const unsigned long EVENT_MINIMIZE_END = 0x0026;
 
   /**
-   * XXX:
-   */
-  const unsigned long EVENT_DOCUMENT_LOAD_START = 0x0027;
-
-  /**
    * The loading of the document has completed.
    */
-  const unsigned long EVENT_DOCUMENT_LOAD_COMPLETE = 0x0028;
+  const unsigned long EVENT_DOCUMENT_LOAD_COMPLETE = 0x0027;
 
   /**
    * The document contents are being reloaded.
    */
-  const unsigned long EVENT_DOCUMENT_RELOAD = 0x0029;
+  const unsigned long EVENT_DOCUMENT_RELOAD = 0x0028;
 
   /**
    * The loading of the document was interrupted.
    */
-  const unsigned long EVENT_DOCUMENT_LOAD_STOPPED = 0x002A;
+  const unsigned long EVENT_DOCUMENT_LOAD_STOPPED = 0x0029;
 
   /**
    * The document wide attributes of the document object have changed.
    */
-  const unsigned long EVENT_DOCUMENT_ATTRIBUTES_CHANGED = 0x002B;
+  const unsigned long EVENT_DOCUMENT_ATTRIBUTES_CHANGED = 0x002A;
 
   /**
    * The contents of the document have changed.
    */
-  const unsigned long EVENT_DOCUMENT_CONTENT_CHANGED = 0x002C;
+  const unsigned long EVENT_DOCUMENT_CONTENT_CHANGED = 0x002B;
 
-  const unsigned long EVENT_PROPERTY_CHANGED = 0x002D;
-  const unsigned long EVENT_SELECTION_CHANGED = 0x002E;
+  const unsigned long EVENT_PROPERTY_CHANGED = 0x002C;
+  const unsigned long EVENT_SELECTION_CHANGED = 0x002D;
 
   /**
    * A text object's attributes changed.
    * Also see EVENT_OBJECT_ATTRIBUTE_CHANGED.
    */
-  const unsigned long EVENT_TEXT_ATTRIBUTE_CHANGED = 0x002F;
+  const unsigned long EVENT_TEXT_ATTRIBUTE_CHANGED = 0x002E;
 
   /**
    * The caret has moved to a new position.
    */
-  const unsigned long EVENT_TEXT_CARET_MOVED = 0x0030;
+  const unsigned long EVENT_TEXT_CARET_MOVED = 0x002F;
 
   /**
    * This event indicates general text changes, i.e. changes to text that is
    * exposed through the IAccessibleText and IAccessibleEditableText interfaces.
    */
-  const unsigned long EVENT_TEXT_CHANGED = 0x0031;
+  const unsigned long EVENT_TEXT_CHANGED = 0x0030;
 
   /**
    * Text was inserted.
    */
-  const unsigned long EVENT_TEXT_INSERTED = 0x0032;
+  const unsigned long EVENT_TEXT_INSERTED = 0x0031;
 
   /**
    * Text was removed.
    */
-  const unsigned long EVENT_TEXT_REMOVED = 0x0033;
+  const unsigned long EVENT_TEXT_REMOVED = 0x0032;
 
   /**
    * Text was updated.
    */
-  const unsigned long EVENT_TEXT_UPDATED = 0x0034;
+  const unsigned long EVENT_TEXT_UPDATED = 0x0033;
 
   /**
    * The text selection changed.
    */
-  const unsigned long EVENT_TEXT_SELECTION_CHANGED = 0x0035;
+  const unsigned long EVENT_TEXT_SELECTION_CHANGED = 0x0034;
 
   /**
    * A visibile data event indicates the change of the visual appearance
    * of an accessible object.  This includes for example most of the
    * attributes available via the IAccessibleComponent interface.
    */
-  const unsigned long EVENT_VISIBLE_DATA_CHANGED = 0x0036;
+  const unsigned long EVENT_VISIBLE_DATA_CHANGED = 0x0035;
 
   /**
    * The caret moved from one column to the next.
    */
-  const unsigned long EVENT_TEXT_COLUMN_CHANGED = 0x0037;
+  const unsigned long EVENT_TEXT_COLUMN_CHANGED = 0x0036;
 
   /**
    * The caret moved from one section to the next.
    */
-  const unsigned long EVENT_SECTION_CHANGED = 0x0038;
+  const unsigned long EVENT_SECTION_CHANGED = 0x0037;
 
   /**
    * A table caption changed.
    */
-  const unsigned long EVENT_TABLE_CAPTION_CHANGED = 0x0039;
+  const unsigned long EVENT_TABLE_CAPTION_CHANGED = 0x0038;
 
   /**
    * A table's data changed.
    */
-  const unsigned long EVENT_TABLE_MODEL_CHANGED = 0x003A;
+  const unsigned long EVENT_TABLE_MODEL_CHANGED = 0x0039;
 
   /**
    * A table's summary changed.
    */
-  const unsigned long EVENT_TABLE_SUMMARY_CHANGED = 0x003B;
+  const unsigned long EVENT_TABLE_SUMMARY_CHANGED = 0x003A;
 
   /**
    * A table's row description changed.
    */
-  const unsigned long EVENT_TABLE_ROW_DESCRIPTION_CHANGED = 0x003C;
+  const unsigned long EVENT_TABLE_ROW_DESCRIPTION_CHANGED = 0x003B;
 
   /**
    * A table's row header changed.
    */
-  const unsigned long EVENT_TABLE_ROW_HEADER_CHANGED = 0x003D;
+  const unsigned long EVENT_TABLE_ROW_HEADER_CHANGED = 0x003C;
 
-  const unsigned long EVENT_TABLE_ROW_INSERT = 0x003E;
-  const unsigned long EVENT_TABLE_ROW_DELETE = 0x003F;
-  const unsigned long EVENT_TABLE_ROW_REORDER = 0x0040;
+  const unsigned long EVENT_TABLE_ROW_INSERT = 0x003D;
+  const unsigned long EVENT_TABLE_ROW_DELETE = 0x003E;
+  const unsigned long EVENT_TABLE_ROW_REORDER = 0x003F;
 
   /**
    * A table's column description changed.
    */
-  const unsigned long EVENT_TABLE_COLUMN_DESCRIPTION_CHANGED = 0x0041;
+  const unsigned long EVENT_TABLE_COLUMN_DESCRIPTION_CHANGED = 0x0040;
 
   /**
    * A table's column header changed.
    */
-  const unsigned long EVENT_TABLE_COLUMN_HEADER_CHANGED = 0x0042;
+  const unsigned long EVENT_TABLE_COLUMN_HEADER_CHANGED = 0x0041;
 
-  const unsigned long EVENT_TABLE_COLUMN_INSERT = 0x0043;
-  const unsigned long EVENT_TABLE_COLUMN_DELETE = 0x0044;
-  const unsigned long EVENT_TABLE_COLUMN_REORDER = 0x0045;
+  const unsigned long EVENT_TABLE_COLUMN_INSERT = 0x0042;
+  const unsigned long EVENT_TABLE_COLUMN_DELETE = 0x0043;
+  const unsigned long EVENT_TABLE_COLUMN_REORDER = 0x0044;
 
-  const unsigned long EVENT_WINDOW_ACTIVATE = 0x0046;
-  const unsigned long EVENT_WINDOW_CREATE = 0x0047;
-  const unsigned long EVENT_WINDOW_DEACTIVATE = 0x0048;
-  const unsigned long EVENT_WINDOW_DESTROY = 0x0049;
-  const unsigned long EVENT_WINDOW_MAXIMIZE = 0x004A;
-  const unsigned long EVENT_WINDOW_MINIMIZE = 0x004B;
-  const unsigned long EVENT_WINDOW_RESIZE = 0x004C;
-  const unsigned long EVENT_WINDOW_RESTORE = 0x004D;
+  const unsigned long EVENT_WINDOW_ACTIVATE = 0x0045;
+  const unsigned long EVENT_WINDOW_CREATE = 0x0046;
+  const unsigned long EVENT_WINDOW_DEACTIVATE = 0x0047;
+  const unsigned long EVENT_WINDOW_DESTROY = 0x0048;
+  const unsigned long EVENT_WINDOW_MAXIMIZE = 0x0049;
+  const unsigned long EVENT_WINDOW_MINIMIZE = 0x004A;
+  const unsigned long EVENT_WINDOW_RESIZE = 0x004B;
+  const unsigned long EVENT_WINDOW_RESTORE = 0x004C;
 
   /**
    * The ending index of this link within the containing string has changed.
    */
-  const unsigned long EVENT_HYPERLINK_END_INDEX_CHANGED = 0x004E;
+  const unsigned long EVENT_HYPERLINK_END_INDEX_CHANGED = 0x004D;
 
   /**
    * The number of anchors assoicated with this hyperlink object has changed.
    */
-  const unsigned long EVENT_HYPERLINK_NUMBER_OF_ANCHORS_CHANGED = 0x004F;
+  const unsigned long EVENT_HYPERLINK_NUMBER_OF_ANCHORS_CHANGED = 0x004E;
 
   /**
    * The hyperlink selected state changed from selected to unselected or
    * from unselected to selected.
    */
-  const unsigned long EVENT_HYPERLINK_SELECTED_LINK_CHANGED = 0x0050;
+  const unsigned long EVENT_HYPERLINK_SELECTED_LINK_CHANGED = 0x004F;
 
   /**
    * One of the links associated with the hypertext object has been activated.
    */
-  const unsigned long EVENT_HYPERTEXT_LINK_ACTIVATED = 0x0051;
+  const unsigned long EVENT_HYPERTEXT_LINK_ACTIVATED = 0x0050;
 
   /**
    * One of the links associated with the hypertext object has been selected.
    */
-  const unsigned long EVENT_HYPERTEXT_LINK_SELECTED = 0x0052;
+  const unsigned long EVENT_HYPERTEXT_LINK_SELECTED = 0x0051;
 
   /**
    * The starting index of this link within the containing string has changed.
    */
-  const unsigned long EVENT_HYPERLINK_START_INDEX_CHANGED = 0x0053;
+  const unsigned long EVENT_HYPERLINK_START_INDEX_CHANGED = 0x0052;
 
   /**
    * Focus has changed from one hypertext object to another, or focus moved
    * from a non-hypertext object to a hypertext object, or focus moved from a
    * hypertext object to a non-hypertext object.
    */
-  const unsigned long EVENT_HYPERTEXT_CHANGED = 0x0054;
+  const unsigned long EVENT_HYPERTEXT_CHANGED = 0x0053;
 
   /**
    * The number of hyperlinks associated with a hypertext object changed.
    */
-  const unsigned long EVENT_HYPERTEXT_NLINKS_CHANGED = 0x0055;
+  const unsigned long EVENT_HYPERTEXT_NLINKS_CHANGED = 0x0054;
 
   /**
    * An object's attributes changed. Also see EVENT_TEXT_ATTRIBUTE_CHANGED.
    */
-  const unsigned long EVENT_OBJECT_ATTRIBUTE_CHANGED = 0x0056;
+  const unsigned long EVENT_OBJECT_ATTRIBUTE_CHANGED = 0x0055;
 
   /**
    * A slide changed in a presentation document or a page boundary was
    * crossed in a word processing document.
    */
-  const unsigned long EVENT_PAGE_CHANGED = 0x0057;
-
-  /**
-   * Used internally in Gecko.
-   */
-  const unsigned long EVENT_INTERNAL_LOAD = 0x0058;
+  const unsigned long EVENT_PAGE_CHANGED = 0x0056;
 
   /**
    * Help make sure event map does not get out-of-line.
    */
-  const unsigned long EVENT_LAST_ENTRY = 0x0059;
+  const unsigned long EVENT_LAST_ENTRY = 0x0057;
 
   /**
    * The type of event, based on the enumerated event values
    * defined in this interface.
    */
   readonly attribute unsigned long eventType;
   
   /**
--- a/accessible/src/atk/nsApplicationAccessibleWrap.cpp
+++ b/accessible/src/atk/nsApplicationAccessibleWrap.cpp
@@ -432,17 +432,17 @@ mai_util_remove_key_event_listener (guin
     if (g_hash_table_size(key_listener_list) == 0) {
         gtk_key_snooper_remove(key_snooper_id);
     }
 }
 
 AtkObject *
 mai_util_get_root(void)
 {
-    if (nsAccessibilityService::gIsShutdown) {
+    if (nsAccessibilityService::IsShutdown()) {
         // We've shutdown, try to use gail instead
         // (to avoid assert in spi_atk_tidy_windows())
         if (gail_get_root)
             return gail_get_root();
 
         return nsnull;
     }
 
--- a/accessible/src/base/Makefile.in
+++ b/accessible/src/base/Makefile.in
@@ -43,16 +43,17 @@ VPATH = @srcdir@
 include $(DEPTH)/config/autoconf.mk
 
 MODULE = accessibility
 LIBRARY_NAME = accessibility_base_s
 LIBXUL_LIBRARY = 1
 
 
 CPPSRCS = \
+  nsAccDocManager.cpp \
   nsAccessNode.cpp \
   nsAccEvent.cpp \
   nsAccIterator.cpp \
   nsARIAGridAccessible.cpp \
   nsARIAMap.cpp \
   nsDocAccessible.cpp \
   nsOuterDocAccessible.cpp \
   nsAccessibilityAtoms.cpp \
new file mode 100644
--- /dev/null
+++ b/accessible/src/base/nsAccDocManager.cpp
@@ -0,0 +1,610 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Alexander Surkov <surkov.alexander@gmail.com> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * 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 "nsAccDocManager.h"
+
+#include "nsAccessibilityService.h"
+#include "nsAccUtils.h"
+#include "nsOuterDocAccessible.h"
+#include "nsRootAccessibleWrap.h"
+
+#include "nsCURILoader.h"
+#include "nsDocShellLoadTypes.h"
+#include "nsIChannel.h"
+#include "nsIContentViewer.h"
+#include "nsIDOMDocument.h"
+#include "nsIEventListenerManager.h"
+#include "nsIDOMEventTarget.h"
+#include "nsIDOMWindow.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsIWebNavigation.h"
+#include "nsServiceManagerUtils.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// nsAccDocManager
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+// nsAccDocManager public
+
+nsDocAccessible*
+nsAccDocManager::GetDocAccessible(nsIDocument *aDocument)
+{
+  if (!aDocument)
+    return nsnull;
+
+  nsDocAccessible *docAcc =
+    mDocAccessibleCache.GetWeak(static_cast<void*>(aDocument));
+  if (docAcc)
+    return docAcc;
+
+  return CreateDocOrRootAccessible(aDocument);
+}
+
+nsAccessible*
+nsAccDocManager::FindAccessibleInCache(void *aUniqueID) const
+{
+  nsSearchAccessibleInCacheArg arg;
+    arg.mUniqueID = aUniqueID;
+
+  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);
+
+  nsCOMPtr<nsIWebProgress> progress =
+    do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID);
+
+  if (!progress)
+    return PR_FALSE;
+
+  progress->AddProgressListener(static_cast<nsIWebProgressListener*>(this),
+                                nsIWebProgress::NOTIFY_STATE_DOCUMENT);
+
+  return PR_TRUE;
+}
+
+void
+nsAccDocManager::Shutdown()
+{
+  nsCOMPtr<nsIWebProgress> progress =
+    do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID);
+
+  if (progress)
+    progress->RemoveProgressListener(static_cast<nsIWebProgressListener*>(this));
+
+  ClearDocCache();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsISupports
+
+NS_IMPL_THREADSAFE_ISUPPORTS3(nsAccDocManager,
+                              nsIWebProgressListener,
+                              nsIDOMEventListener,
+                              nsISupportsWeakReference)
+
+////////////////////////////////////////////////////////////////////////////////
+// nsIWebProgressListener
+
+NS_IMETHODIMP
+nsAccDocManager::OnStateChange(nsIWebProgress *aWebProgress,
+                               nsIRequest *aRequest, PRUint32 aStateFlags,
+                               nsresult aStatus)
+{
+  NS_ASSERTION(aStateFlags & STATE_IS_DOCUMENT, "Other notifications excluded");
+
+  if (nsAccessibilityService::IsShutdown() || !aWebProgress ||
+      (aStateFlags & (STATE_START | STATE_STOP)) == 0)
+    return NS_OK;
+
+  nsCOMPtr<nsIDOMWindow> DOMWindow;
+  aWebProgress->GetDOMWindow(getter_AddRefs(DOMWindow));
+  NS_ENSURE_STATE(DOMWindow);
+
+  nsCOMPtr<nsIDOMDocument> DOMDocument;
+  DOMWindow->GetDocument(getter_AddRefs(DOMDocument));
+  NS_ENSURE_STATE(DOMDocument);
+
+  nsCOMPtr<nsIDocument> document(do_QueryInterface(DOMDocument));
+
+  // Document was loaded.
+  if (aStateFlags & STATE_STOP) {
+    NS_LOG_ACCDOCLOAD("document loaded", aWebProgress, aRequest, aStateFlags)
+
+    // Figure out an event type to notify the document has been loaded.
+    PRUint32 eventType = nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED;
+
+    // Some XUL documents get start state and then stop state with failure
+    // status when everything is ok. Fire document load complete event in this
+    // case.
+    if (NS_SUCCEEDED(aStatus) || !nsCoreUtils::IsContentDocument(document))
+      eventType = nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE;
+
+    // If end consumer has been retargeted for loaded content then do not fire
+    // any event because it means no new document has been loaded, for example,
+    // it happens when user clicks on file link.
+    if (aRequest) {
+      PRUint32 loadFlags = 0;
+      aRequest->GetLoadFlags(&loadFlags);
+      if (loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI)
+        eventType = 0;
+    }
+
+    HandleDOMDocumentLoad(document, eventType);
+    return NS_OK;
+  }
+
+  // Document loading was started.
+  NS_LOG_ACCDOCLOAD("start document loading", aWebProgress, aRequest,
+                    aStateFlags)
+
+  if (!IsEventTargetDocument(document))
+    return NS_OK;
+
+  nsDocAccessible *docAcc =
+    mDocAccessibleCache.GetWeak(static_cast<void*>(document));
+  if (!docAcc)
+    return NS_OK;
+
+  nsCOMPtr<nsIWebNavigation> webNav(do_GetInterface(DOMWindow));
+  nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(webNav));
+  NS_ENSURE_STATE(docShell);
+
+  nsCOMPtr<nsIDOMNode> DOMNode = do_QueryInterface(document);
+
+  // Fire reload and state busy events on existing document accessible while
+  // event from user input flag can be calculated properly and accessible
+  // is alive. When new document gets loaded then this one is destroyed.
+  PRUint32 loadType;
+  docShell->GetLoadType(&loadType);
+  if (loadType == LOAD_RELOAD_NORMAL ||
+      loadType == LOAD_RELOAD_BYPASS_CACHE ||
+      loadType == LOAD_RELOAD_BYPASS_PROXY ||
+      loadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE) {
+
+    // Fire reload event.
+    nsRefPtr<nsAccEvent> reloadEvent =
+      new nsAccEvent(nsIAccessibleEvent::EVENT_DOCUMENT_RELOAD, docAcc);
+    nsEventShell::FireEvent(reloadEvent);
+  }
+
+  // Fire state busy change event. Use delayed event since we don't care
+  // actually if event isn't delivered when the document goes away like a shot.
+  nsRefPtr<nsAccEvent> stateEvent =
+    new nsAccStateChangeEvent(DOMNode, nsIAccessibleStates::STATE_BUSY,
+                              PR_FALSE, PR_TRUE);
+  docAcc->FireDelayedAccessibleEvent(stateEvent);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsAccDocManager::OnProgressChange(nsIWebProgress *aWebProgress,
+                                  nsIRequest *aRequest,
+                                  PRInt32 aCurSelfProgress,
+                                  PRInt32 aMaxSelfProgress,
+                                  PRInt32 aCurTotalProgress,
+                                  PRInt32 aMaxTotalProgress)
+{
+  NS_NOTREACHED("notification excluded in AddProgressListener(...)");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsAccDocManager::OnLocationChange(nsIWebProgress *aWebProgress,
+                                  nsIRequest *aRequest, nsIURI *aLocation)
+{
+  NS_NOTREACHED("notification excluded in AddProgressListener(...)");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsAccDocManager::OnStatusChange(nsIWebProgress *aWebProgress,
+                                nsIRequest *aRequest, nsresult aStatus,
+                                const PRUnichar *aMessage)
+{
+  NS_NOTREACHED("notification excluded in AddProgressListener(...)");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsAccDocManager::OnSecurityChange(nsIWebProgress *aWebProgress,
+                                  nsIRequest *aRequest,
+                                  PRUint32 aState)
+{
+  NS_NOTREACHED("notification excluded in AddProgressListener(...)");
+  return NS_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsIDOMEventListener
+
+NS_IMETHODIMP
+nsAccDocManager::HandleEvent(nsIDOMEvent *aEvent)
+{
+  nsAutoString type;
+  aEvent->GetType(type);
+
+  nsCOMPtr<nsIDOMEventTarget> target;
+  aEvent->GetTarget(getter_AddRefs(target));
+
+  nsCOMPtr<nsIDocument> document(do_QueryInterface(target));
+  NS_ASSERTION(document, "pagehide or DOMContentLoaded for non document!");
+  if (!document)
+    return NS_OK;
+
+  if (type.EqualsLiteral("pagehide")) {
+    // 'pagehide' event is registered on every DOM document we create an
+    // accessible for, process the event for the target. This document
+    // accessible and all its sub document accessible are shutdown as result of
+    // processing.
+
+    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);
+    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)
+    HandleDOMDocumentLoad(document,
+                          nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE,
+                          PR_TRUE);
+  }
+
+  return NS_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsAccDocManager private
+
+void
+nsAccDocManager::HandleDOMDocumentLoad(nsIDocument *aDocument,
+                                       PRUint32 aLoadEventType,
+                                       PRBool aMarkAsLoaded)
+{
+  // Document accessible can be created before we were notified the DOM document
+  // was loaded completely. However if it's not created yet then create it.
+  nsDocAccessible *docAcc =
+    mDocAccessibleCache.GetWeak(static_cast<void*>(aDocument));
+
+  if (!docAcc) {
+    docAcc = CreateDocOrRootAccessible(aDocument);
+    NS_ASSERTION(docAcc, "Can't create document accessible!");
+    if (!docAcc)
+      return;
+  }
+
+  if (aMarkAsLoaded)
+    docAcc->MarkAsLoaded();
+
+  // Do not fire document complete/stop events for root chrome document
+  // accessibles and for frame/iframe documents because
+  // a) screen readers start working on focus event in the case of root chrome
+  // documents
+  // b) document load event on sub documents causes screen readers to act is if
+  // entire page is reloaded.
+  if (!IsEventTargetDocument(aDocument)) {
+    // XXX: AT doesn't update their virtual buffer once frame is loaded and it
+    // has dynamic content added after frame load. There's something wrong how
+    // we handle this changes.
+    if (!nsCoreUtils::IsRootDocument(aDocument)) {
+      docAcc->InvalidateCacheSubtree(nsnull,
+                                     nsIAccessibilityService::NODE_SIGNIFICANT_CHANGE);
+    }
+    return;
+  }
+
+  // Fire complete/load stopped if the load event type is given.
+  nsCOMPtr<nsIDOMNode> DOMNode = do_QueryInterface(aDocument);
+  if (aLoadEventType) {
+    nsRefPtr<nsAccEvent> loadEvent = new nsAccEvent(aLoadEventType, DOMNode);
+    docAcc->FireDelayedAccessibleEvent(loadEvent);
+  }
+
+  // Fire busy state change event.
+  nsRefPtr<nsAccEvent> stateEvent =
+    new nsAccStateChangeEvent(DOMNode, nsIAccessibleStates::STATE_BUSY,
+                              PR_FALSE, PR_FALSE);
+  docAcc->FireDelayedAccessibleEvent(stateEvent);
+}
+
+PRBool
+nsAccDocManager::IsEventTargetDocument(nsIDocument *aDocument) const
+{
+  nsCOMPtr<nsISupports> container = aDocument->GetContainer();
+  nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem =
+    do_QueryInterface(container);
+  NS_ASSERTION(docShellTreeItem, "No document shell for document!");
+
+  nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
+  docShellTreeItem->GetParent(getter_AddRefs(parentTreeItem));
+
+  // It's not a root document.
+  if (parentTreeItem) {
+    nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
+    docShellTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
+
+    // It's not a sub document, i.e. a frame or iframe.
+    return (sameTypeRoot == docShellTreeItem);
+  }
+
+  // It's not chrome root document.
+  PRInt32 contentType;
+  docShellTreeItem->GetItemType(&contentType);
+  return (contentType == nsIDocShellTreeItem::typeContent);
+}
+
+void
+nsAccDocManager::AddListeners(nsIDocument *aDocument,
+                              PRBool aAddDOMContentLoadedListener)
+{
+  nsPIDOMWindow *window = aDocument->GetWindow();
+  nsPIDOMEventTarget *target = window->GetChromeEventHandler();
+  nsIEventListenerManager* elm = target->GetListenerManager(PR_TRUE);
+  elm->AddEventListenerByType(this, NS_LITERAL_STRING("pagehide"),
+                              NS_EVENT_FLAG_CAPTURE, nsnull);
+
+  NS_LOG_ACCDOCCREATE_TEXT("  added 'pagehide' listener")
+
+  if (aAddDOMContentLoadedListener) {
+    elm->AddEventListenerByType(this, NS_LITERAL_STRING("DOMContentLoaded"),
+                                NS_EVENT_FLAG_CAPTURE, nsnull);
+    NS_LOG_ACCDOCCREATE_TEXT("  added 'DOMContentLoaded' listener")
+  }
+}
+
+void
+nsAccDocManager::RemoveListeners(nsIDocument *aDocument)
+{
+  // Document has no window when application shuts down. The document can still
+  // exist because we didn't receive a "pagehide" event.
+  nsPIDOMWindow *window = aDocument->GetWindow();
+  if (!window)
+    return;
+
+  nsPIDOMEventTarget *target = window->GetChromeEventHandler();
+  nsIEventListenerManager* elm = target->GetListenerManager(PR_TRUE);
+  elm->RemoveEventListenerByType(this, NS_LITERAL_STRING("pagehide"),
+                                 NS_EVENT_FLAG_CAPTURE, nsnull);
+
+  NS_LOG_ACCDOCDESTROY("removed 'pagehide' listener", aDocument)
+
+  if (nsCoreUtils::IsRootDocument(aDocument)) {
+    elm->RemoveEventListenerByType(this, NS_LITERAL_STRING("DOMContentLoaded"),
+                                     NS_EVENT_FLAG_CAPTURE, nsnull);
+
+    NS_LOG_ACCDOCDESTROY("removed 'DOMContentLoaded' listener", aDocument)
+  }
+}
+
+nsDocAccessible*
+nsAccDocManager::CreateDocOrRootAccessible(nsIDocument *aDocument)
+{
+  // Ignore temporary and hiding documents.
+  if (aDocument->IsInitialDocument() || !aDocument->IsVisible())
+    return nsnull;
+
+  // Ignore documents without presshell.
+  nsIPresShell *presShell = aDocument->GetPrimaryShell();
+  if (!presShell)
+    return nsnull;
+
+  // Do not create document accessible until role content is loaded, otherwise
+  // we get accessible document with wrong role.
+  nsCOMPtr<nsIDOMNode> DOMNode(do_QueryInterface(aDocument));
+  if (!nsCoreUtils::GetRoleContent(DOMNode))
+    return NS_OK;
+
+  PRBool isRootDoc = nsCoreUtils::IsRootDocument(aDocument);
+
+  // Ensure the document container node is accessible, otherwise do not create
+  // document accessible.
+  nsAccessible *outerDocAcc = nsnull;
+  if (!isRootDoc) {
+    nsIDocument* parentDoc = aDocument->GetParentDocument();
+    if (!parentDoc)
+      return nsnull;
+
+    nsIContent* ownerContent = parentDoc->FindContentForSubDocument(aDocument);
+    nsCOMPtr<nsIDOMNode> ownerNode(do_QueryInterface(ownerContent));
+    if (!ownerNode)
+      return nsnull;
+
+    // XXXaaronl: ideally we would traverse the presshell chain. Since there's
+    // no easy way to do that, we cheat and use the document hierarchy.
+    // GetAccessible() is bad because it doesn't support our concept of multiple
+    // presshells per doc. It should be changed to use
+    // GetAccessibleInWeakShell().
+    outerDocAcc = GetAccService()->GetAccessible(ownerNode);
+    if (!outerDocAcc)
+      return nsnull;
+  }
+
+  nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(presShell));
+
+  // We only create root accessibles for the true root, otherwise create a
+  // doc accessible.
+  nsDocAccessible *docAcc = isRootDoc ?
+    new nsRootAccessibleWrap(DOMNode, weakShell) :
+    new nsDocAccessibleWrap(DOMNode, weakShell);
+
+  if (!docAcc)
+    return nsnull;
+
+  // Cache and addref document accessible.
+  if (!mDocAccessibleCache.Put(static_cast<void*>(aDocument), docAcc)) {
+    delete docAcc;
+    return nsnull;
+  }
+
+  // XXX: ideally we should initialize an accessible and then put it into tree,
+  // also this code should be shared between doc and root accessibles.
+  if (outerDocAcc) {
+    // Root document accessible doesn't have associated outerdoc accessible, it
+    // adds itself to application accessible instead.
+    NS_LOG_ACCDOCCREATE("append document to outerdoc", aDocument)
+    outerDocAcc->AppendChild(docAcc);
+  }
+
+  if (!GetAccService()->InitAccessible(docAcc,
+                                       nsAccUtils::GetRoleMapEntry(DOMNode))) {
+    mDocAccessibleCache.Remove(static_cast<void*>(aDocument));
+    return nsnull;
+  }
+
+  NS_LOG_ACCDOCCREATE("document created", aDocument)
+
+  AddListeners(aDocument, isRootDoc);
+  return docAcc;
+}
+
+void
+nsAccDocManager::ShutdownDocAccessiblesInTree(nsIDocShellTreeItem *aTreeItem,
+                                              nsIDocument *aDocument)
+{
+  nsCOMPtr<nsIDocShellTreeNode> treeNode(do_QueryInterface(aTreeItem));
+  if (!treeNode)
+    return;
+
+  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);
+}
+
+void
+nsAccDocManager::ShutdownDocAccessible(nsIDocument *aDocument)
+{
+  RemoveListeners(aDocument);
+
+  nsDocAccessible *docAccessible =
+    mDocAccessibleCache.GetWeak(static_cast<void*>(aDocument));
+  if (docAccessible)
+    docAccessible->Shutdown();
+
+  mDocAccessibleCache.Remove(static_cast<void*>(aDocument));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsAccDocManager static
+
+PLDHashOperator
+nsAccDocManager::ClearDocCacheEntry(const void* aKey,
+                                    nsRefPtr<nsDocAccessible>& aDocAccessible,
+                                    void* aUserArg)
+{
+  nsAccDocManager *accDocMgr = static_cast<nsAccDocManager*>(aUserArg);
+
+  NS_ASSERTION(aDocAccessible,
+               "Calling ClearDocCacheEntry with a NULL pointer!");
+
+  if (aDocAccessible) {
+    nsCOMPtr<nsIDocument> document = aDocAccessible->GetDOMDocument();
+    NS_ASSERTION(document, "Document accessible was shutdown already!");
+    if (document)
+      accDocMgr->RemoveListeners(document);
+
+    aDocAccessible->Shutdown();
+  }
+
+  return PL_DHASH_REMOVE;
+}
+
+PLDHashOperator
+nsAccDocManager::SearchAccessibleInDocCache(const void* aKey,
+                                            nsDocAccessible* aDocAccessible,
+                                            void* aUserArg)
+{
+  NS_ASSERTION(aDocAccessible,
+               "No doc accessible for the object in doc accessible cache!");
+
+  if (aDocAccessible) {
+    nsSearchAccessibleInCacheArg* arg =
+      static_cast<nsSearchAccessibleInCacheArg*>(aUserArg);
+    nsAccessNode* accessNode =
+      aDocAccessible->GetCachedAccessNode(arg->mUniqueID);
+    if (accessNode) {
+      arg->mAccessible = do_QueryObject(accessNode);
+      return PL_DHASH_STOP;
+    }
+  }
+
+  return PL_DHASH_NEXT;
+}
new file mode 100644
--- /dev/null
+++ b/accessible/src/base/nsAccDocManager.h
@@ -0,0 +1,552 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Alexander Surkov <surkov.alexander@gmail.com> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * 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 ***** */
+
+#ifndef nsAccDocManager_h_
+#define nsAccDocManager_h_
+
+#include "nsAccessible.h"
+
+#include "nsIDocument.h"
+#include "nsIDOMEventListener.h"
+#include "nsIWebProgress.h"
+#include "nsIWebProgressListener.h"
+#include "nsWeakReference.h"
+
+class nsDocAccessible;
+
+/**
+ * Manage the document accessible life cycle.
+ */
+class nsAccDocManager : public nsIWebProgressListener,
+                        public nsIDOMEventListener,
+                        public nsSupportsWeakReference
+{
+public:
+  virtual ~nsAccDocManager() { };
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIWEBPROGRESSLISTENER
+  NS_DECL_NSIDOMEVENTLISTENER
+
+  /**
+   * Return document accessible for the given DOM node.
+   */
+  nsDocAccessible *GetDocAccessible(nsIDocument *aDocument);
+
+  /**
+   * Search through all document accessibles for an accessible with the given
+   * unique id.
+   */
+  nsAccessible *FindAccessibleInCache(void *aUniqueID) 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);
+
+protected:
+  nsAccDocManager() { };
+
+  /**
+   * Initialize the manager.
+   */
+  PRBool Init();
+
+  /**
+   * Shutdown the manager.
+   */
+  void Shutdown();
+
+private:
+  nsAccDocManager(const nsAccDocManager&);
+  nsAccDocManager& operator =(const nsAccDocManager&);
+
+private:
+  /**
+   * Create an accessible document if it was't created and fire accessibility
+   * events if needed.
+   *
+   * @param  aDocument       [in] loaded DOM document
+   * @param  aLoadEventType  [in] specifies the event type to fire load event,
+   *                           if 0 then no event is fired
+   * @param  aMarkAsLoaded   [in] indicates whether we should mark forcedly
+   *                           an accessible document as loaded (used for error
+   *                           pages only which do not get 'pageshow' event)
+   */
+  void HandleDOMDocumentLoad(nsIDocument *aDocument,
+                             PRUint32 aLoadEventType,
+                             PRBool aMarkAsLoaded = PR_FALSE);
+
+  /**
+   * Return true if accessibility events accompanying document accessible
+   * loading should be fired.
+   *
+   * The rules are: do not fire events for root chrome document accessibles and
+   * for sub document accessibles (like HTML frame of iframe) of the loading
+   * document accessible.
+   *
+   * XXX: in general AT expect events for document accessible loading into
+   * tabbrowser, events from other document accessibles may break AT. We need to
+   * figure out what AT wants to know about loading page (for example, some of
+   * them have separate processing of iframe documents on the page and therefore
+   * they need a way to distinguish sub documents from page document). Ideally
+   * we should make events firing for any loaded document and provide additional
+   * info AT are needing.
+   */
+  PRBool IsEventTargetDocument(nsIDocument *aDocument) const;
+
+  /**
+   * Add/remove 'pagehide' and 'DOMContentLoaded' event listeners.
+   */
+  void AddListeners(nsIDocument *aDocument, PRBool aAddPageShowListener);
+  void RemoveListeners(nsIDocument *aDocument);
+
+  /**
+   * 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);
+
+  /**
+   * Shutdown the document accessible.
+   */
+  void ShutdownDocAccessible(nsIDocument *aDocument);
+
+  typedef nsRefPtrHashtable<nsVoidPtrHashKey, nsDocAccessible>
+    nsDocAccessibleHashtable;
+
+  /**
+   * Shutdown and remove the document accessible from cache.
+   */
+  static PLDHashOperator
+    ClearDocCacheEntry(const void* aKey,
+                       nsRefPtr<nsDocAccessible>& aDocAccessible,
+                       void* aUserArg);
+
+  /**
+   * Clear the cache and shutdown the document accessibles.
+   */
+  void ClearDocCache()
+  {
+    mDocAccessibleCache.Enumerate(ClearDocCacheEntry, static_cast<void*>(this));
+  }
+
+  struct nsSearchAccessibleInCacheArg
+  {
+    nsRefPtr<nsAccessible> mAccessible;
+    void *mUniqueID;
+  };
+
+  static PLDHashOperator
+    SearchAccessibleInDocCache(const void* aKey,
+                               nsDocAccessible* aDocAccessible,
+                               void* aUserArg);
+
+  nsDocAccessibleHashtable mDocAccessibleCache;
+};
+
+/**
+ * nsAccDocManager debugging macros.
+ */
+//#define DEBUG_ACCDOCMGR
+
+#ifdef DEBUG_ACCDOCMGR
+
+// Enable these to log accessible document loading, creation or destruction.
+#define DEBUG_ACCDOCMGR_DOCLOAD
+#define DEBUG_ACCDOCMGR_DOCCREATE
+#define DEBUG_ACCDOCMGR_DOCDESTROY
+
+// Common macros, do not use directly.
+#define NS_LOG_ACCDOC_ADDRESS(aDocument, aDocAcc)                              \
+  printf("DOM id: 0x%x, acc id: 0x%x",                                         \
+         reinterpret_cast<PRInt32>(static_cast<void*>(aDocument)),             \
+         reinterpret_cast<PRInt32>(aDocAcc));
+
+#define NS_LOG_ACCDOC_URI(aDocument)                                           \
+  nsIURI *uri = aDocument->GetDocumentURI();                                   \
+  nsCAutoString spec;                                                          \
+  uri->GetSpec(spec);                                                          \
+  printf("uri: %s", spec);
+
+#define NS_LOG_ACCDOC_TYPE(aDocument)                                          \
+  PRBool isContent = nsCoreUtils::IsContentDocument(aDocument);                \
+  printf("%s document", (isContent ? "content" : "chrome"));
+
+#define NS_LOG_ACCDOC_SHELLSTATE(aDocument)                                    \
+  nsCOMPtr<nsISupports> container = aDocument->GetContainer();                 \
+  nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);               \
+  PRUint32 busyFlags = nsIDocShell::BUSY_FLAGS_NONE;                           \
+  docShell->GetBusyFlags(&busyFlags);                                          \
+  nsCAutoString docShellBusy;                                                  \
+  if (busyFlags == nsIDocShell::BUSY_FLAGS_NONE)                               \
+    docShellBusy.AppendLiteral("'none'");                                      \
+  if (busyFlags & nsIDocShell::BUSY_FLAGS_BUSY)                                \
+    docShellBusy.AppendLiteral("'busy'");                                      \
+  if (busyFlags & nsIDocShell::BUSY_FLAGS_BEFORE_PAGE_LOAD)                    \
+    docShellBusy.AppendLiteral(", 'before page load'");                        \
+  if (busyFlags & nsIDocShell::BUSY_FLAGS_PAGE_LOADING)                        \
+    docShellBusy.AppendLiteral(", 'page loading'");                            \
+  printf("docshell busy: %s", docShellBusy.get());
+
+#define NS_LOG_ACCDOC_DOCSTATES(aDocument)                                     \
+  const char *docState = 0;                                                    \
+  nsIDocument::ReadyState docStateFlag = aDocument->GetReadyStateEnum();       \
+  switch (docStateFlag) {                                                      \
+    case nsIDocument::READYSTATE_UNINITIALIZED:                                \
+     docState = "uninitialized";                                               \
+      break;                                                                   \
+    case nsIDocument::READYSTATE_LOADING:                                      \
+      docState = "loading";                                                    \
+      break;                                                                   \
+    case nsIDocument::READYSTATE_INTERACTIVE:                                  \
+      docState = "interactive";                                                \
+      break;                                                                   \
+    case nsIDocument::READYSTATE_COMPLETE:                                     \
+      docState = "complete";                                                   \
+      break;                                                                   \
+  }                                                                            \
+  printf("doc state: %s", docState);                                           \
+  printf(", %sinitial", aDocument->IsInitialDocument() ? "" : "not ");         \
+  printf(", %sshowing", aDocument->IsShowing() ? "" : "not ");                 \
+  printf(", %svisible", aDocument->IsVisible() ? "" : "not ");                 \
+  printf(", %sactive", aDocument->IsActive() ? "" : "not ");
+
+#define NS_LOG_ACCDOC_DOCPRESSHELL(aDocument)                                  \
+  nsIPresShell *ps = aDocument->GetPrimaryShell();                             \
+  printf("presshell: 0x%x", reinterpret_cast<PRInt32>(ps));                    \
+  nsIScrollableFrame *sf = ps ?                                                \
+    ps->GetRootScrollFrameAsScrollableExternal() : nsnull;                     \
+  printf(", root scroll frame: 0x%x", reinterpret_cast<PRInt32>(sf));
+
+#define NS_LOG_ACCDOC_DOCLOADGROUP(aDocument)                                  \
+  nsCOMPtr<nsILoadGroup> loadGroup = aDocument->GetDocumentLoadGroup();        \
+  printf("load group: 0x%x", reinterpret_cast<PRInt32>(loadGroup.get()));
+
+#define NS_LOG_ACCDOC_DOCPARENT(aDocument)                                     \
+  nsIDocument *parentDoc = aDocument->GetParentDocument();                     \
+  printf("parent id: 0x%x",                                                    \
+         reinterpret_cast<PRInt32>(parentDoc));                                \
+  if (parentDoc) {                                                             \
+    printf("\n    parent ");                                                   \
+    NS_LOG_ACCDOC_URI(parentDoc)                                               \
+    printf("\n");                                                              \
+  }
+
+#define NS_LOG_ACCDOC_SHELLLOADTYPE(aDocShell)                                 \
+  {                                                                            \
+    printf("load type: ");                                                     \
+    PRUint32 loadType;                                                         \
+    docShell->GetLoadType(&loadType);                                          \
+    switch (loadType) {                                                        \
+      case LOAD_NORMAL:                                                        \
+        printf("normal; ");                                                    \
+        break;                                                                 \
+      case LOAD_NORMAL_REPLACE:                                                \
+        printf("normal replace; ");                                            \
+        break;                                                                 \
+      case LOAD_NORMAL_EXTERNAL:                                               \
+        printf("normal external; ");                                           \
+        break;                                                                 \
+      case LOAD_HISTORY:                                                       \
+        printf("history; ");                                                   \
+        break;                                                                 \
+      case LOAD_NORMAL_BYPASS_CACHE:                                           \
+        printf("normal bypass cache; ");                                       \
+        break;                                                                 \
+      case LOAD_NORMAL_BYPASS_PROXY:                                           \
+        printf("normal bypass proxy; ");                                       \
+        break;                                                                 \
+      case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:                                 \
+        printf("normal bypass proxy and cache; ");                             \
+        break;                                                                 \
+      case LOAD_RELOAD_NORMAL:                                                 \
+        printf("reload normal; ");                                             \
+        break;                                                                 \
+      case LOAD_RELOAD_BYPASS_CACHE:                                           \
+        printf("reload bypass cache; ");                                       \
+        break;                                                                 \
+      case LOAD_RELOAD_BYPASS_PROXY:                                           \
+        printf("reload bypass proxy; ");                                       \
+        break;                                                                 \
+      case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:                                 \
+        printf("reload bypass proxy and cache; ");                             \
+        break;                                                                 \
+      case LOAD_LINK:                                                          \
+        printf("link; ");                                                      \
+        break;                                                                 \
+      case LOAD_REFRESH:                                                       \
+        printf("refresh; ");                                                   \
+        break;                                                                 \
+      case LOAD_RELOAD_CHARSET_CHANGE:                                         \
+        printf("reload charset change; ");                                     \
+        break;                                                                 \
+      case LOAD_BYPASS_HISTORY:                                                \
+        printf("bypass history; ");                                            \
+        break;                                                                 \
+      case LOAD_STOP_CONTENT:                                                  \
+        printf("stop content; ");                                              \
+        break;                                                                 \
+      case LOAD_STOP_CONTENT_AND_REPLACE:                                      \
+        printf("stop content and replace; ");                                  \
+        break;                                                                 \
+      case LOAD_PUSHSTATE:                                                     \
+        printf("load pushstate; ");                                            \
+        break;                                                                 \
+      case LOAD_ERROR_PAGE:                                                    \
+        printf("error page;");                                                 \
+        break;                                                                 \
+      default:                                                                 \
+        printf("unknown");                                                     \
+    }                                                                          \
+  }
+
+#define NS_LOG_ACCDOC_DOCINFO_BEGIN                                            \
+  printf("  {\n");
+#define NS_LOG_ACCDOC_DOCINFO_BODY(aDocument, aDocAcc)                         \
+  {                                                                            \
+    printf("    ");                                                            \
+    NS_LOG_ACCDOC_ADDRESS(aDocument, aDocAcc)                                  \
+    printf("\n    ");                                                          \
+    NS_LOG_ACCDOC_URI(aDocument)                                               \
+    printf("\n    ");                                                          \
+    NS_LOG_ACCDOC_SHELLSTATE(aDocument)                                        \
+    printf("; ");                                                              \
+    NS_LOG_ACCDOC_TYPE(aDocument)                                              \
+    printf("\n    ");                                                          \
+    NS_LOG_ACCDOC_DOCSTATES(aDocument)                                         \
+    printf("\n    ");                                                          \
+    NS_LOG_ACCDOC_DOCPRESSHELL(aDocument)                                      \
+    printf("\n    ");                                                          \
+    NS_LOG_ACCDOC_DOCLOADGROUP(aDocument)                                      \
+    printf(", ");                                                              \
+    NS_LOG_ACCDOC_DOCPARENT(aDocument)                                         \
+    printf("\n");                                                              \
+  }
+#define NS_LOG_ACCDOC_DOCINFO_END                                              \
+  printf("  }\n");
+
+#define NS_LOG_ACCDOC_DOCINFO(aDocument, aDocAcc)                              \
+  NS_LOG_ACCDOC_DOCINFO_BEGIN                                                  \
+  NS_LOG_ACCDOC_DOCINFO_BODY(aDocument, aDocAcc)                               \
+  NS_LOG_ACCDOC_DOCINFO_END
+
+#define NS_GET_ACCDOC_EVENTTYPE(aEvent)                                        \
+  nsCAutoString strEventType;                                                  \
+  PRUint32 type = aEvent->GetEventType();                                      \
+  if (type == nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED) {               \
+    strEventType.AssignLiteral("load stopped");                                \
+  } else if (type == nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE) {       \
+    strEventType.AssignLiteral("load complete");                               \
+  } else if (type == nsIAccessibleEvent::EVENT_DOCUMENT_RELOAD) {              \
+      strEventType.AssignLiteral("reload");                                    \
+  } else if (type == nsIAccessibleEvent::EVENT_STATE_CHANGE) {                 \
+    nsCOMPtr<nsIAccessibleStateChangeEvent> event(do_QueryObject(aEvent));     \
+    PRUint32 state = 0;                                                        \
+    event->GetState(&state);                                                   \
+    if (state == nsIAccessibleStates::STATE_BUSY) {                            \
+      PRBool isEnabled;                                                        \
+      event->IsEnabled(&isEnabled);                                            \
+      strEventType.AssignLiteral("busy ");                                     \
+      if (isEnabled)                                                           \
+        strEventType.AppendLiteral("true");                                    \
+      else                                                                     \
+        strEventType.AppendLiteral("false");                                   \
+    }                                                                          \
+  }
+
+#define NS_LOG_ACCDOC_TEXT(aMsg)                                               \
+  printf("  " aMsg "\n");
+
+// Accessible document loading macros.
+#ifdef DEBUG_ACCDOCMGR_DOCLOAD
+
+#define NS_LOG_ACCDOCLOAD_REQUEST(aRequest)                                    \
+  if (aRequest) {                                                              \
+    nsCAutoString name;                                                        \
+    aRequest->GetName(name);                                                   \
+    printf("    request spec: %s\n", name.get());                              \
+    PRUint32 loadFlags = 0;                                                    \
+    aRequest->GetLoadFlags(&loadFlags);                                        \
+    printf("    request load flags: %x; ", loadFlags);                         \
+    if (loadFlags & nsIChannel::LOAD_DOCUMENT_URI)                             \
+      printf("document uri; ");                                                \
+    if (loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI)                  \
+      printf("retargeted document uri; ");                                     \
+    if (loadFlags & nsIChannel::LOAD_REPLACE)                                  \
+      printf("replace; ");                                                     \
+    if (loadFlags & nsIChannel::LOAD_INITIAL_DOCUMENT_URI)                     \
+      printf("initial document uri; ");                                        \
+    if (loadFlags & nsIChannel::LOAD_TARGETED)                                 \
+      printf("targeted; ");                                                    \
+    if (loadFlags & nsIChannel::LOAD_CALL_CONTENT_SNIFFERS)                    \
+      printf("call content sniffers; ");                                       \
+    if (loadFlags & nsIChannel::LOAD_CLASSIFY_URI)                             \
+      printf("classify uri; ");                                                \
+  } else {                                                                     \
+    printf("    no request");                                                  \
+  }
+
+#define NS_LOG_ACCDOCLOAD(aMsg, aWebProgress, aRequest, aStateFlags)           \
+  {                                                                            \
+    printf("\nA11Y DOCLOAD: " aMsg "\n");                                      \
+                                                                               \
+    nsCOMPtr<nsIDOMWindow> DOMWindow;                                          \
+    aWebProgress->GetDOMWindow(getter_AddRefs(DOMWindow));                     \
+    if (DOMWindow) {                                                           \
+      nsCOMPtr<nsIDOMDocument> DOMDocument;                                    \
+      DOMWindow->GetDocument(getter_AddRefs(DOMDocument));                     \
+      if (DOMDocument) {                                                       \
+        nsCOMPtr<nsIDocument> document(do_QueryInterface(DOMDocument));        \
+        nsDocAccessible *docAcc =                                              \
+          mDocAccessibleCache.GetWeak(static_cast<void*>(document));           \
+        NS_LOG_ACCDOC_DOCINFO(document, docAcc)                                \
+                                                                               \
+        printf("  {\n");                                                       \
+        nsCOMPtr<nsIWebNavigation> webNav(do_GetInterface(DOMWindow));         \
+        nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(webNav));             \
+        printf("    ");                                                        \
+        NS_LOG_ACCDOC_SHELLLOADTYPE(docShell)                                  \
+        printf("\n");                                                          \
+        NS_LOG_ACCDOCLOAD_REQUEST(aRequest)                                    \
+        printf("\n");                                                          \
+        printf("    state flags: %x", aStateFlags);                            \
+        PRBool isDocLoading;                                                   \
+        aWebProgress->GetIsLoadingDocument(&isDocLoading);                     \
+        printf(", document is %sloading\n", (isDocLoading ? "" : "not "));     \
+        printf("  }\n");                                                       \
+      }                                                                        \
+    }                                                                          \
+  }
+
+#define NS_LOG_ACCDOCLOAD2(aMsg, aDocument)                                    \
+  {                                                                            \
+    printf("\nA11Y DOCLOAD: " aMsg "\n");                                      \
+    nsDocAccessible *docAcc =                                                  \
+      mDocAccessibleCache.GetWeak(static_cast<void*>(aDocument));              \
+    NS_LOG_ACCDOC_DOCINFO(aDocument, docAcc)                                   \
+  }
+
+#define NS_LOG_ACCDOCLOAD_FIREEVENT(aEvent)                                    \
+  {                                                                            \
+    NS_GET_ACCDOC_EVENTTYPE(aEvent)                                            \
+    if (!strEventType.IsEmpty())                                               \
+      printf("  fire: %s\n", strEventType.get());                              \
+  }
+
+#define NS_LOG_ACCDOCLOAD_HANDLEEVENT(aEvent)                                  \
+  {                                                                            \
+    NS_GET_ACCDOC_EVENTTYPE(aEvent)                                            \
+    nsCOMPtr<nsIDocument> doc(do_QueryInterface(aEvent->GetNode()));           \
+    if (doc && !strEventType.IsEmpty()) {                                      \
+      printf("\nA11Y DOCEVENT: handled '%s' event ", strEventType.get());      \
+      nsDocAccessible *docAcc = aEvent->GetDocAccessible();                    \
+      NS_LOG_ACCDOC_DOCINFO(doc, docAcc)                                       \
+      printf("\n");                                                            \
+    }                                                                          \
+  }
+
+#define NS_LOG_ACCDOCLOAD_TEXT(aMsg)                                           \
+    NS_LOG_ACCDOC_TEXT(aMsg)
+
+#endif // DEBUG_ACCDOCMGR_DOCLOAD
+
+// Accessible document creation macros.
+#ifdef DEBUG_ACCDOCMGR_DOCCREATE
+#define NS_LOG_ACCDOCCREATE_FOR(aMsg, aDocument, aDocAcc)                      \
+  printf("\nA11Y DOCCREATE: " aMsg "\n");                                      \
+  NS_LOG_ACCDOC_DOCINFO(aDocument, aDocAcc)
+
+#define NS_LOG_ACCDOCCREATE(aMsg, aDocument)                                   \
+  {                                                                            \
+    nsDocAccessible *docAcc =                                                  \
+      mDocAccessibleCache.GetWeak(static_cast<void*>(aDocument));              \
+    NS_LOG_ACCDOCCREATE_FOR(aMsg, aDocument, docAcc)                           \
+  }
+
+#define NS_LOG_ACCDOCCREATE_TEXT(aMsg)                                         \
+    NS_LOG_ACCDOC_TEXT(aMsg)
+
+#endif // DEBUG_ACCDOCMGR_DOCCREATE
+
+// Accessible document destruction macros.
+#ifdef DEBUG_ACCDOCMGR_DOCDESTROY
+#define NS_LOG_ACCDOCDESTROY_FOR(aMsg, aDocument, aDocAcc)                     \
+  printf("\nA11Y DOCDESTROY: " aMsg "\n");                                     \
+  NS_LOG_ACCDOC_DOCINFO(aDocument, aDocAcc)
+
+#define NS_LOG_ACCDOCDESTROY(aMsg, aDocument)                                  \
+  nsDocAccessible *docAcc =                                                    \
+    mDocAccessibleCache.GetWeak(static_cast<void*>(aDocument));                \
+  NS_LOG_ACCDOCDESTROY_FOR(aMsg, aDocument, docAcc)
+
+#define NS_LOG_ACCDOCDESTROY_TEXT(aMsg)                                       \
+    NS_LOG_ACCDOC_TEXT(aMsg)
+
+#endif // DEBUG_ACCDOCMGR_DOCDESTROY
+
+#endif // DEBUG_ACCDOCMGR
+
+#ifndef DEBUG_ACCDOCMGR_DOCLOAD
+#define NS_LOG_ACCDOCLOAD(aMsg, aWebProgress, aRequest, aStateFlags)
+#define NS_LOG_ACCDOCLOAD2(aMsg, aDocument)
+#define NS_LOG_ACCDOCLOAD_EVENT(aMsg, aEvent)
+#define NS_LOG_ACCDOCLOAD_FIREEVENT(aEvent)
+#define NS_LOG_ACCDOCLOAD_HANDLEEVENT(aEvent)
+#define NS_LOG_ACCDOCLOAD_TEXT(aMsg)
+#endif
+
+#ifndef DEBUG_ACCDOCMGR_DOCCREATE
+#define NS_LOG_ACCDOCCREATE_FOR(aMsg, aDocument, aDocAcc)
+#define NS_LOG_ACCDOCCREATE(aMsg, aDocument)
+#define NS_LOG_ACCDOCCREATE_TEXT(aMsg)
+#endif
+
+#ifndef DEBUG_ACCDOCMGR_DOCDESTROY
+#define NS_LOG_ACCDOCDESTROY_FOR(aMsg, aDocument, aDocAcc)
+#define NS_LOG_ACCDOCDESTROY(aMsg, aDocument)
+#define NS_LOG_ACCDOCDESTROY_TEXT(aMsg)
+#endif
+
+#endif // nsAccDocManager_h_
--- a/accessible/src/base/nsAccEvent.cpp
+++ b/accessible/src/base/nsAccEvent.cpp
@@ -178,17 +178,17 @@ nsAccEvent::GetNode()
   return mNode;
 }
 
 nsDocAccessible*
 nsAccEvent::GetDocAccessible()
 {
   nsINode *node = GetNode();
   if (node)
-    return nsAccessNode::GetDocAccessibleFor(node->GetOwnerDoc());
+    return GetAccService()->GetDocAccessible(node->GetOwnerDoc());
 
   return nsnull;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccEvent: protected methods
 
 already_AddRefed<nsIAccessible>
--- a/accessible/src/base/nsAccTreeWalker.cpp
+++ b/accessible/src/base/nsAccTreeWalker.cpp
@@ -37,16 +37,19 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsAccTreeWalker.h"
 
 #include "nsAccessible.h"
 #include "nsAccessibilityService.h"
 
+#include "nsINodeList.h"
+#include "nsIPresShell.h"
+
 ////////////////////////////////////////////////////////////////////////////////
 // WalkState
 ////////////////////////////////////////////////////////////////////////////////
 
 struct WalkState
 {
   WalkState(nsIContent *aContent) :
     content(aContent), childIdx(0), prevState(nsnull) {}
--- a/accessible/src/base/nsAccUtils.h
+++ b/accessible/src/base/nsAccUtils.h
@@ -40,21 +40,26 @@
 #define nsAccUtils_h_
 
 #include "nsIAccessible.h"
 #include "nsIAccessNode.h"
 #include "nsIAccessibleDocument.h"
 #include "nsIAccessibleRole.h"
 #include "nsIAccessibleText.h"
 #include "nsIAccessibleTable.h"
+
 #include "nsARIAMap.h"
+#include "nsAccessibilityService.h"
+#include "nsCoreUtils.h"
 
+#include "nsIContent.h"
+#include "nsIDocShell.h"
 #include "nsIDOMNode.h"
 #include "nsIPersistentProperties2.h"
-#include "nsIContent.h"
+#include "nsIPresShell.h"
 #include "nsPoint.h"
 
 class nsAccessNode;
 class nsAccessible;
 class nsHTMLTableAccessible;
 class nsDocAccessible;
 #ifdef MOZ_XUL
 class nsXULTreeAccessible;
@@ -140,16 +145,48 @@ public:
    * property is not present, or is "" or "undefined". Do not call 
    * this method for properties of type string, decimal, IDREF or IDREFS.
    * 
    * Return PR_TRUE if the ARIA property is defined, otherwise PR_FALSE
    */
   static PRBool HasDefinedARIAToken(nsIContent *aContent, nsIAtom *aAtom);
 
   /**
+   * Return document accessible for the given presshell.
+   */
+  static nsDocAccessible *GetDocAccessibleFor(nsIWeakReference *aWeakShell)
+  {
+    nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(aWeakShell));
+    return presShell ?
+      GetAccService()->GetDocAccessible(presShell->GetDocument()) : nsnull;
+  }
+
+  /**
+   * Return document accessible for the given DOM node.
+   */
+  static nsDocAccessible *GetDocAccessibleFor(nsIDOMNode *aNode)
+  {
+    nsIPresShell *presShell = nsCoreUtils::GetPresShellFor(aNode);
+    return presShell ?
+      GetAccService()->GetDocAccessible(presShell->GetDocument()) : nsnull;
+  }
+
+  /**
+   * Return document accessible for the given docshell.
+   */
+  static nsDocAccessible *GetDocAccessibleFor(nsIDocShellTreeItem *aContainer)
+  {
+    nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aContainer));
+    nsCOMPtr<nsIPresShell> presShell;
+    docShell->GetPresShell(getter_AddRefs(presShell));
+    return presShell ?
+      GetAccService()->GetDocAccessible(presShell->GetDocument()) : nsnull;
+  }
+
+  /**
    * Return true if the given DOM node contains accessible children.
    */
   static PRBool HasAccessibleChildren(nsIDOMNode *aNode);
 
   /**
     * If an ancestor in this document exists with the given role, return it
     * @param aDescendant Descendant to start search with
     * @param aRole Role to find matching ancestor for
--- a/accessible/src/base/nsAccessNode.cpp
+++ b/accessible/src/base/nsAccessNode.cpp
@@ -79,18 +79,16 @@
  */
 
 nsIStringBundle *nsAccessNode::gStringBundle = 0;
 nsIStringBundle *nsAccessNode::gKeyStringBundle = 0;
 nsIDOMNode *nsAccessNode::gLastFocusedNode = 0;
 
 PRBool nsAccessNode::gIsCacheDisabled = PR_FALSE;
 PRBool nsAccessNode::gIsFormFillEnabled = PR_FALSE;
-nsRefPtrHashtable<nsVoidPtrHashKey, nsDocAccessible>
-  nsAccessNode::gGlobalDocAccessibleCache;
 
 nsApplicationAccessible *nsAccessNode::gApplicationAccessible = nsnull;
 
 /*
  * Class nsAccessNode
  */
  
 ////////////////////////////////////////////////////////////////////////////////
@@ -143,35 +141,27 @@ nsAccessNode::Init()
 {
   // We have to put this here, instead of constructor, otherwise
   // we don't have the virtual GetUniqueID() method for the hash key.
   // We need that for accessibles that don't have DOM nodes
 
 #ifdef DEBUG_A11Y
   NS_ASSERTION(!mIsInitialized, "Initialized twice!");
 #endif
-  nsRefPtr<nsDocAccessible> docAcc = GetDocAccessible();
+  nsDocAccessible *docAcc = nsnull;
+  nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(mWeakShell));
+  if (presShell)
+    docAcc = GetAccService()->GetDocAccessible(presShell->GetDocument());
+
+  NS_ASSERTION(docAcc, "Cannot cache new nsAccessNode");
   if (!docAcc) {
-    // No doc accessible yet for this node's document. 
-    // There was probably an accessible event fired before the 
-    // current document was ever asked for by the assistive technology.
-    // Create a doc accessible so we can cache this node
-    nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(mWeakShell));
-    if (presShell) {
-      nsCOMPtr<nsIDOMNode> docNode(do_QueryInterface(presShell->GetDocument()));
-      if (docNode) {
-        nsAccessible *accessible =
-          GetAccService()->GetAccessibleInWeakShell(docNode, mWeakShell);
-        docAcc = do_QueryObject(accessible);
-      }
-    }
-    NS_ASSERTION(docAcc, "Cannot cache new nsAccessNode");
-    if (!docAcc) {
-      return NS_ERROR_FAILURE;
-    }
+#ifdef DEBUG
+    docAcc = GetAccService()->GetDocAccessible(presShell->GetDocument());
+#endif
+    return NS_ERROR_FAILURE;
   }
 
   void* uniqueID;
   GetUniqueID(&uniqueID);
 
   if (!docAcc->CacheAccessNode(uniqueID, this))
     return NS_ERROR_OUT_OF_MEMORY;
 
@@ -219,17 +209,17 @@ NS_IMETHODIMP nsAccessNode::GetOwnerWind
   if (!docAccessible)
     return NS_ERROR_FAILURE; // This node or doc accessible is shut down
   return docAccessible->GetWindowHandle(aWindow);
 }
 
 nsApplicationAccessible*
 nsAccessNode::GetApplicationAccessible()
 {
-  NS_ASSERTION(!nsAccessibilityService::gIsShutdown,
+  NS_ASSERTION(!nsAccessibilityService::IsShutdown(),
                "Accessibility wasn't initialized!");
 
   if (!gApplicationAccessible) {
     nsApplicationAccessibleWrap::PreCreate();
 
     gApplicationAccessible = new nsApplicationAccessibleWrap();
     if (!gApplicationAccessible)
       return nsnull;
@@ -257,18 +247,16 @@ void nsAccessNode::InitXPAccessibility()
     stringBundleService->CreateBundle(ACCESSIBLE_BUNDLE_URL, 
                                       &gStringBundle);
     stringBundleService->CreateBundle(PLATFORM_KEYS_BUNDLE_URL, 
                                       &gKeyStringBundle);
   }
 
   nsAccessibilityAtoms::AddRefAtoms();
 
-  gGlobalDocAccessibleCache.Init(4);
-
   nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
   if (prefBranch) {
     prefBranch->GetBoolPref("accessibility.disablecache", &gIsCacheDisabled);
     prefBranch->GetBoolPref("browser.formfill.enable", &gIsFormFillEnabled);
   }
 
   NotifyA11yInitOrShutdown(PR_TRUE);
 }
@@ -293,18 +281,16 @@ void nsAccessNode::ShutdownXPAccessibili
   // Called by nsAccessibilityService::Shutdown()
   // which happens when xpcom is shutting down
   // at exit of program
 
   NS_IF_RELEASE(gStringBundle);
   NS_IF_RELEASE(gKeyStringBundle);
   NS_IF_RELEASE(gLastFocusedNode);
 
-  ClearCache(gGlobalDocAccessibleCache);
-
   // Release gApplicationAccessible after everything else is shutdown
   // so we don't accidently create it again while tearing down root accessibles
   nsApplicationAccessibleWrap::Unload();
   if (gApplicationAccessible) {
     gApplicationAccessible->Shutdown();
     NS_RELEASE(gApplicationAccessible);
   }
 
@@ -359,49 +345,39 @@ already_AddRefed<nsRootAccessible> nsAcc
   }
   nsCOMPtr<nsIDocShellTreeItem> root;
   docShellTreeItem->GetRootTreeItem(getter_AddRefs(root));
   NS_ASSERTION(root, "No root content tree item");
   if (!root) {
     return nsnull;
   }
 
-  nsCOMPtr<nsIAccessibleDocument> accDoc = GetDocAccessibleFor(root);
-  if (!accDoc) {
-    return nsnull;
-  }
-
-  // nsRootAccessible has a special QI
-  // that let us get that concrete type directly.
-  nsRootAccessible* rootAccessible;
-  accDoc->QueryInterface(NS_GET_IID(nsRootAccessible), (void**)&rootAccessible); // addrefs
-  return rootAccessible;
+  nsDocAccessible *docAcc = nsAccUtils::GetDocAccessibleFor(root);
+  nsRefPtr<nsRootAccessible> rootAcc = do_QueryObject(docAcc);
+  return rootAcc.forget();
 }
 
 nsIFrame*
 nsAccessNode::GetFrame()
 {
   nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
   return content ? content->GetPrimaryFrame() : nsnull;
 }
 
 #ifdef DEBUG
 PRBool
 nsAccessNode::IsInCache()
 {
-  nsCOMPtr<nsIAccessibleDocument> accessibleDoc =
-    nsAccessNode::GetDocAccessibleFor(mWeakShell);
-
-  if (!accessibleDoc)
+  nsDocAccessible *docAccessible = nsAccUtils::GetDocAccessibleFor(mWeakShell);
+  if (!docAccessible)
     return nsnull;
 
   void* uniqueID = nsnull;
   GetUniqueID(&uniqueID);
 
-  nsRefPtr<nsDocAccessible> docAccessible = do_QueryObject(accessibleDoc);
   return docAccessible->GetCachedAccessNode(uniqueID) ? PR_TRUE : PR_FALSE;
 }
 #endif
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsIAccessNode
 
 NS_IMETHODIMP
@@ -427,17 +403,17 @@ nsAccessNode::GetNumChildren(PRInt32 *aN
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAccessNode::GetDocument(nsIAccessibleDocument **aDocument)
 {
   NS_ENSURE_ARG_POINTER(aDocument);
 
-  NS_IF_ADDREF(*aDocument = GetDocAccessibleFor(mWeakShell));
+  NS_IF_ADDREF(*aDocument = nsAccUtils::GetDocAccessibleFor(mWeakShell));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAccessNode::GetRootDocument(nsIAccessibleDocument **aRootDocument)
 {
   NS_ENSURE_ARG_POINTER(aRootDocument);
 
@@ -638,83 +614,17 @@ nsAccessNode::GetComputedStyleCSSValue(c
 
   nsCOMPtr<nsIDOMCSSValue> cssValue;
   styleDecl->GetPropertyCSSValue(aPropertyName, getter_AddRefs(cssValue));
   NS_ENSURE_TRUE(cssValue, NS_ERROR_FAILURE);
 
   return CallQueryInterface(cssValue, aCSSValue);
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// nsAccessNode public static
-
-nsDocAccessible*
-nsAccessNode::GetDocAccessibleFor(nsIDocument *aDocument)
-{
-  return aDocument ?
-    gGlobalDocAccessibleCache.GetWeak(static_cast<void*>(aDocument)) : nsnull;
-}
-
-nsDocAccessible*
-nsAccessNode::GetDocAccessibleFor(nsIWeakReference *aWeakShell)
-{
-  nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(aWeakShell));
-  if (!presShell) {
-    return nsnull;
-  }
-
-  return GetDocAccessibleFor(presShell->GetDocument());
-}
-
-already_AddRefed<nsIAccessibleDocument>
-nsAccessNode::GetDocAccessibleFor(nsIDocShellTreeItem *aContainer,
-                                  PRBool aCanCreate)
-{
-  if (!aCanCreate) {
-    nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aContainer));
-    NS_ASSERTION(docShell, "This method currently only supports docshells");
-    nsCOMPtr<nsIPresShell> presShell;
-    docShell->GetPresShell(getter_AddRefs(presShell));
-    if (!presShell)
-      return nsnull;
-
-    nsDocAccessible *docAcc = GetDocAccessibleFor(presShell->GetDocument());
-    NS_IF_ADDREF(docAcc);
-    return docAcc;
-  }
-
-  nsCOMPtr<nsIDOMNode> node = nsCoreUtils::GetDOMNodeForContainer(aContainer);
-  if (!node) {
-    return nsnull;
-  }
-
-  nsCOMPtr<nsIAccessible> accessible;
-  GetAccService()->GetAccessibleFor(node, getter_AddRefs(accessible));
-  nsIAccessibleDocument *docAccessible = nsnull;
-  if (accessible) {
-    CallQueryInterface(accessible, &docAccessible);
-  }
-  return docAccessible;
-}
- 
-nsDocAccessible*
-nsAccessNode::GetDocAccessibleFor(nsIDOMNode *aNode)
-{
-  nsIPresShell *presShell = nsCoreUtils::GetPresShellFor(aNode);
-  if (presShell)
-    return GetDocAccessibleFor(presShell->GetDocument());
-
-  nsCOMPtr<nsIDocument> doc(do_QueryInterface(aNode));
-  if (doc) {
-    return GetDocAccessibleFor(doc);
-  }
-
-  return nsnull;
-}
-
+// nsAccessNode public
 already_AddRefed<nsIDOMNode> nsAccessNode::GetCurrentFocus()
 {
   nsIPresShell *shell = nsCoreUtils::GetPresShellFor(mDOMNode);
   NS_ENSURE_TRUE(shell, nsnull);
   nsCOMPtr<nsIDocument> doc = shell->GetDocument();
   NS_ENSURE_TRUE(doc, nsnull);
 
   nsIDOMWindow* win = doc->GetWindow();
@@ -735,17 +645,16 @@ already_AddRefed<nsIDOMNode> nsAccessNod
     focusedWindow->GetDocument(getter_AddRefs(doc));
     if (doc)
       CallQueryInterface(doc, &focusedNode);
   }
 
   return focusedNode;
 }
 
-// nsIAccessNode
 NS_IMETHODIMP
 nsAccessNode::GetLanguage(nsAString& aLanguage)
 {
   aLanguage.Truncate();
   nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
   if (!content) {
     // For documents make sure we look for lang attribute on
     // document element
@@ -782,10 +691,10 @@ nsAccessNode::GetLanguage(nsAString& aLa
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessNode protected
 
 nsDocAccessible*
 nsAccessNode::GetDocAccessible() const
 {
-  return GetDocAccessibleFor(mWeakShell);
+  return nsAccUtils::GetDocAccessibleFor(mWeakShell);
 }
--- a/accessible/src/base/nsAccessNode.h
+++ b/accessible/src/base/nsAccessNode.h
@@ -152,30 +152,16 @@ class nsAccessNode: public nsIAccessNode
 
 #ifdef DEBUG
   /**
    * Return true if the access node is cached.
    */
   PRBool IsInCache();
 #endif
 
-  /**
-   * Return cached document accessible.
-   */
-  static nsDocAccessible* GetDocAccessibleFor(nsIDocument *aDocument);
-  static nsDocAccessible* GetDocAccessibleFor(nsIWeakReference *aWeakShell);
-  static nsDocAccessible* GetDocAccessibleFor(nsIDOMNode *aNode);
-
-  /**
-   * Return document accessible.
-   */
-  static already_AddRefed<nsIAccessibleDocument>
-    GetDocAccessibleFor(nsIDocShellTreeItem *aContainer,
-                        PRBool aCanCreate = PR_FALSE);
-
 protected:
     nsresult MakeAccessNode(nsIDOMNode *aNode, nsIAccessNode **aAccessNode);
 
     nsPresContext* GetPresContext();
 
     void LastRelease();
 
     nsCOMPtr<nsIDOMNode> mDOMNode;
@@ -192,19 +178,16 @@ protected:
 
     // Static data, we do our own refcounting for our static data
     static nsIStringBundle *gStringBundle;
     static nsIStringBundle *gKeyStringBundle;
 
     static PRBool gIsCacheDisabled;
     static PRBool gIsFormFillEnabled;
 
-  static nsRefPtrHashtable<nsVoidPtrHashKey, nsDocAccessible>
-    gGlobalDocAccessibleCache;
-
 private:
   static nsApplicationAccessible *gApplicationAccessible;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsAccessNode,
                               NS_ACCESSNODE_IMPL_CID)
 
 #endif
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -57,39 +57,34 @@
 #include "nsIAccessibleProvider.h"
 
 #include "nsIDOMDocument.h"
 #include "nsIDOMHTMLAreaElement.h"
 #include "nsIDOMHTMLLegendElement.h"
 #include "nsIDOMHTMLObjectElement.h"
 #include "nsIDOMHTMLOptGroupElement.h"
 #include "nsIDOMHTMLOptionElement.h"
-#include "nsIDOMWindow.h"
 #include "nsIDOMXULElement.h"
 #include "nsIHTMLDocument.h"
 #include "nsIDocShell.h"
 #include "nsIFrame.h"
-#include "nsIInterfaceRequestorUtils.h"
 #include "nsIImageFrame.h"
 #include "nsILink.h"
 #include "nsINameSpaceManager.h"
 #include "nsIObserverService.h"
 #include "nsIPluginInstance.h"
 #include "nsIPresShell.h"
 #include "nsISupportsUtils.h"
-#include "nsIWebNavigation.h"
 #include "nsObjectFrame.h"
 #include "nsOuterDocAccessible.h"
 #include "nsRootAccessibleWrap.h"
 #include "nsTextFragment.h"
 #include "nsServiceManagerUtils.h"
 #include "nsUnicharUtils.h"
-#include "nsIWebProgress.h"
 #include "nsNetError.h"
-#include "nsDocShellLoadTypes.h"
 #include "mozilla/Services.h"
 
 #ifdef MOZ_XUL
 #include "nsXULAlertAccessible.h"
 #include "nsXULColorPickerAccessible.h"
 #include "nsXULComboboxAccessible.h"
 #include "nsXULFormControlAccessible.h"
 #include "nsXULListboxAccessibleWrap.h"
@@ -114,236 +109,95 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessibilityService
 ////////////////////////////////////////////////////////////////////////////////
 
 nsAccessibilityService *nsAccessibilityService::gAccessibilityService = nsnull;
 PRBool nsAccessibilityService::gIsShutdown = PR_TRUE;
 
-nsAccessibilityService::nsAccessibilityService()
+nsAccessibilityService::nsAccessibilityService() : nsAccDocManager()
 {
   NS_TIME_FUNCTION;
-
-  // Add observers.
-  nsCOMPtr<nsIObserverService> observerService =
-    mozilla::services::GetObserverService();
-  if (!observerService)
-    return;
-
-  observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
-  nsCOMPtr<nsIWebProgress> progress(do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID));
-  if (progress) {
-    progress->AddProgressListener(static_cast<nsIWebProgressListener*>(this),
-                                  nsIWebProgress::NOTIFY_STATE_DOCUMENT);
-  }
-
-  // Initialize accessibility.
-  nsAccessNodeWrap::InitAccessibility();
 }
 
 nsAccessibilityService::~nsAccessibilityService()
 {
   NS_ASSERTION(gIsShutdown, "Accessibility wasn't shutdown!");
   gAccessibilityService = nsnull;
 }
 
-NS_IMPL_THREADSAFE_ISUPPORTS5(nsAccessibilityService, nsIAccessibilityService, nsIAccessibleRetrieval,
-                              nsIObserver, nsIWebProgressListener, nsISupportsWeakReference)
+////////////////////////////////////////////////////////////////////////////////
+// nsISupports
 
+NS_IMPL_ISUPPORTS_INHERITED3(nsAccessibilityService,
+                             nsAccDocManager,
+                             nsIAccessibilityService,
+                             nsIAccessibleRetrieval,
+                             nsIObserver)
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsIObserver
 
 NS_IMETHODIMP
 nsAccessibilityService::Observe(nsISupports *aSubject, const char *aTopic,
                          const PRUnichar *aData)
 {
-  if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
-
-    // Remove observers.
-    nsCOMPtr<nsIObserverService> observerService =
-      mozilla::services::GetObserverService();
-    if (observerService)
-      observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
-
-    nsCOMPtr<nsIWebProgress> progress(do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID));
-    if (progress)
-      progress->RemoveProgressListener(static_cast<nsIWebProgressListener*>(this));
-
-    // Application is going to be closed, shutdown accessibility and mark
-    // accessibility service as shutdown to prevent calls of its methods.
-    // Don't null accessibility service static member at this point to be safe
-    // if someone will try to operate with it.
-
-    NS_ASSERTION(!gIsShutdown, "Accessibility was shutdown already");
-
-    gIsShutdown = PR_TRUE;
-    nsAccessNodeWrap::ShutdownAccessibility();
-  }
+  if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID))
+    Shutdown();
 
   return NS_OK;
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// nsIWebProgressListener
-
-NS_IMETHODIMP nsAccessibilityService::OnStateChange(nsIWebProgress *aWebProgress,
-  nsIRequest *aRequest, PRUint32 aStateFlags, nsresult aStatus)
-{
-  NS_ASSERTION(aStateFlags & STATE_IS_DOCUMENT, "Other notifications excluded");
-
-  if (gIsShutdown || !aWebProgress ||
-      (aStateFlags & (STATE_START | STATE_STOP)) == 0) {
-    return NS_OK;
-  }
-  
-  nsCAutoString name;
-  aRequest->GetName(name);
-  if (name.EqualsLiteral("about:blank"))
-    return NS_OK;
-
-  if (NS_FAILED(aStatus) && (aStateFlags & STATE_START))
-    return NS_OK;
-
-  if (aStateFlags & STATE_START) {
-    NS_DISPATCH_RUNNABLEMETHOD_ARG2(ProcessDocLoadEvent, this, aWebProgress,
-                                    nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_START)
-  } else if (NS_SUCCEEDED(aStatus)) {
-    NS_DISPATCH_RUNNABLEMETHOD_ARG2(ProcessDocLoadEvent, this, aWebProgress,
-                                    nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE)
-  } else { // Failed end load
-    NS_DISPATCH_RUNNABLEMETHOD_ARG2(ProcessDocLoadEvent, this, aWebProgress,
-                                    nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED)
-  }
-
-  return NS_OK;
-}
-
-// nsAccessibilityService private
-void
-nsAccessibilityService::ProcessDocLoadEvent(nsIWebProgress *aWebProgress,
-                                            PRUint32 aEventType)
-{
-  if (gIsShutdown)
-    return;
-
-  nsCOMPtr<nsIDOMWindow> domWindow;
-  aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
-  NS_ENSURE_TRUE(domWindow,);
-
-  if (aEventType == nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_START) {
-    nsCOMPtr<nsIWebNavigation> webNav(do_GetInterface(domWindow));
-    nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(webNav));
-    NS_ENSURE_TRUE(docShell,);
-    PRUint32 loadType;
-    docShell->GetLoadType(&loadType);
-    if (loadType == LOAD_RELOAD_NORMAL ||
-        loadType == LOAD_RELOAD_BYPASS_CACHE ||
-        loadType == LOAD_RELOAD_BYPASS_PROXY ||
-        loadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE) {
-      aEventType = nsIAccessibleEvent::EVENT_DOCUMENT_RELOAD;
-    }
-  }
-      
-  nsCOMPtr<nsIDOMDocument> domDoc;
-  domWindow->GetDocument(getter_AddRefs(domDoc));
-  nsCOMPtr<nsIDOMNode> docNode = do_QueryInterface(domDoc);
-  NS_ENSURE_TRUE(docNode,);
-
-  nsCOMPtr<nsIAccessible> accessible;
-  GetAccessibleFor(docNode, getter_AddRefs(accessible));
-  nsRefPtr<nsDocAccessible> docAcc = do_QueryObject(accessible);
-  NS_ENSURE_TRUE(docAcc,);
-
-  docAcc->FireDocLoadEvents(aEventType);
-}
-
 // nsIAccessibilityService
 void
 nsAccessibilityService::NotifyOfAnchorJumpTo(nsIContent *aTarget)
 {
   nsIDocument *document = aTarget->GetCurrentDoc();
-  nsCOMPtr<nsIDOMNode> documentNode(do_QueryInterface(document));
-  if (!documentNode)
+  if (!document)
     return;
 
   nsCOMPtr<nsIDOMNode> targetNode(do_QueryInterface(aTarget));
 
   nsAccessible *targetAcc = GetAccessible(targetNode);
 
   // Getting the targetAcc above will have ensured accessible doc creation.
   // XXX Bug 561683
-  nsRefPtr<nsDocAccessible> accessibleDoc =
-    nsAccessNode::GetDocAccessibleFor(documentNode);
-  if (!accessibleDoc)
+  nsDocAccessible *docAccessible = GetDocAccessible(document);
+  if (!docAccessible)
     return;
 
   // If the jump target is not accessible then fire an event for nearest
   // accessible in parent chain.
   if (!targetAcc) {
     targetAcc = GetContainerAccessible(targetNode, PR_TRUE);
     targetNode = targetAcc->GetDOMNode();
   }
 
   NS_ASSERTION(targetNode,
       "No accessible in parent chain!? Expect at least a document accessible.");
   if (!targetNode)
     return;
 
   // XXX note in rare cases the node could go away before we flush the queue,
   // for example if the node becomes inaccessible, or is removed from the DOM.
-  accessibleDoc->FireDelayedAccessibleEvent(
-                     nsIAccessibleEvent::EVENT_SCROLLING_START,
-                     targetNode);
+  docAccessible->
+    FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_SCROLLING_START,
+                               targetNode);
 }
 
 // nsIAccessibilityService
 nsresult
 nsAccessibilityService::FireAccessibleEvent(PRUint32 aEvent,
                                             nsIAccessible *aTarget)
 {
   nsEventShell::FireEvent(aEvent, aTarget);
   return NS_OK;
 }
 
-/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
-NS_IMETHODIMP nsAccessibilityService::OnProgressChange(nsIWebProgress *aWebProgress,
-  nsIRequest *aRequest, PRInt32 aCurSelfProgress, PRInt32 aMaxSelfProgress,
-  PRInt32 aCurTotalProgress, PRInt32 aMaxTotalProgress)
-{
-  NS_NOTREACHED("notification excluded in AddProgressListener(...)");
-  return NS_OK;
-}
-
-/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
-NS_IMETHODIMP nsAccessibilityService::OnLocationChange(nsIWebProgress *aWebProgress,
-  nsIRequest *aRequest, nsIURI *location)
-{
-  NS_NOTREACHED("notification excluded in AddProgressListener(...)");
-  return NS_OK;
-}
-
-/* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
-NS_IMETHODIMP nsAccessibilityService::OnStatusChange(nsIWebProgress *aWebProgress,
-  nsIRequest *aRequest, nsresult aStatus, const PRUnichar *aMessage)
-{
-  NS_NOTREACHED("notification excluded in AddProgressListener(...)");
-  return NS_OK;
-}
-
-/* void onSecurityChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long state); */
-NS_IMETHODIMP nsAccessibilityService::OnSecurityChange(nsIWebProgress *aWebProgress,
-  nsIRequest *aRequest, PRUint32 state)
-{
-  NS_NOTREACHED("notification excluded in AddProgressListener(...)");
-  return NS_OK;
-}
-
-
 // nsAccessibilityService private
 nsresult
 nsAccessibilityService::GetInfo(nsIFrame* aFrame, nsIWeakReference** aShell, nsIDOMNode** aNode)
 {
   NS_ASSERTION(aFrame,"Error -- 1st argument (aFrame) is null!!");
   if (!aFrame) {
     return NS_ERROR_FAILURE;
   }
@@ -411,74 +265,16 @@ nsAccessibilityService::CreateOuterDocAc
     new nsOuterDocAccessible(aDOMNode, outerWeakShell);
   NS_ENSURE_TRUE(outerDocAccessible, NS_ERROR_FAILURE);
 
   NS_ADDREF(*aOuterDocAccessible = outerDocAccessible);
 
   return NS_OK;
 }
 
-// nsAccessibilityService private
-already_AddRefed<nsAccessible>
-nsAccessibilityService::CreateDocOrRootAccessible(nsIPresShell *aShell,
-                                                  nsIDocument* aDocument)
-{
-  nsCOMPtr<nsIDOMNode> rootNode(do_QueryInterface(aDocument));
-  NS_ENSURE_TRUE(rootNode, nsnull);
-
-  nsIPresShell *presShell = aShell;
-  if (!presShell) {
-    presShell = aDocument->GetPrimaryShell();
-  }
-  nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(presShell));
-
-  nsCOMPtr<nsISupports> container = aDocument->GetContainer();
-  nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
-  NS_ENSURE_TRUE(docShell, nsnull);
-
-  nsCOMPtr<nsIContentViewer> contentViewer;
-  docShell->GetContentViewer(getter_AddRefs(contentViewer));
-  NS_ENSURE_TRUE(contentViewer, nsnull); // Doc was already shut down
-
-  PRUint32 busyFlags;
-  docShell->GetBusyFlags(&busyFlags);
-  if (busyFlags != nsIDocShell::BUSY_FLAGS_NONE) {
-    nsCOMPtr<nsIWebNavigation> webNav(do_GetInterface(docShell));
-    nsCOMPtr<nsIURI> uri;
-    webNav->GetCurrentURI(getter_AddRefs(uri));
-    NS_ENSURE_TRUE(uri, nsnull);
-
-    nsCAutoString url;
-    uri->GetSpec(url);
-    if (url.EqualsLiteral("about:blank")) {
-      // No load events for a busy about:blank -- they are often temporary.
-      return nsnull;
-    }
-  }
-
-  nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem =
-    do_QueryInterface(container);
-  NS_ENSURE_TRUE(docShellTreeItem, nsnull);
-  
-  nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
-  docShellTreeItem->GetParent(getter_AddRefs(parentTreeItem));
-
-  nsRefPtr<nsAccessible> accessible;
-  if (parentTreeItem) {
-    // We only create root accessibles for the true root, othewise create a
-    // doc accessible
-    accessible = new nsDocAccessibleWrap(rootNode, weakShell);
-  }
-  else {
-    accessible = new nsRootAccessibleWrap(rootNode, weakShell);
-  }
-
-  return accessible.forget();
-}
-
  /**
    * HTML widget creation
    */
 nsresult
 nsAccessibilityService::CreateHTML4ButtonAccessible(nsIFrame *aFrame, nsIAccessible **_retval)
 {
   nsCOMPtr<nsIDOMNode> node;
   nsCOMPtr<nsIWeakReference> weakShell;
@@ -977,24 +773,19 @@ nsAccessibilityService::CreateHTMLCaptio
   return NS_OK;
 }
 
 // nsAccessibilityService public
 nsAccessNode*
 nsAccessibilityService::GetCachedAccessNode(nsIDOMNode *aNode, 
                                             nsIWeakReference *aWeakShell)
 {
-  nsCOMPtr<nsIAccessibleDocument> accessibleDoc =
-    nsAccessNode::GetDocAccessibleFor(aWeakShell);
-
-  if (!accessibleDoc)
-    return nsnull;
-
-  nsRefPtr<nsDocAccessible> docAccessible = do_QueryObject(accessibleDoc);
-  return docAccessible->GetCachedAccessNode(static_cast<void*>(aNode));
+  nsDocAccessible *docAccessible = nsAccUtils::GetDocAccessibleFor(aWeakShell);
+  return docAccessible ?
+    docAccessible->GetCachedAccessNode(static_cast<void*>(aNode)) : nsnull;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsIAccessibleRetrieval
 
 NS_IMETHODIMP
 nsAccessibilityService::GetApplicationAccessible(nsIAccessible **aAccessibleApplication)
 {
@@ -1283,19 +1074,16 @@ nsAccessibilityService::GetContainerAcce
 
       accessible = cachedAcc;
     }
   }
 
   return accessible;
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// nsAccessibilityService private
-
 PRBool
 nsAccessibilityService::InitAccessible(nsAccessible *aAccessible,
                                        nsRoleMapEntry *aRoleMapEntry)
 {
   if (!aAccessible)
     return PR_FALSE;
 
   nsresult rv = aAccessible->Init(); // Add to cache, etc.
@@ -1336,17 +1124,16 @@ static PRBool HasRelatedContent(nsIConte
         // ancestor has activedescendant property, this content could be active
       return PR_TRUE;
     }
   }
 
   return PR_FALSE;
 }
 
-// nsAccessibilityService public
 already_AddRefed<nsAccessible>
 nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
                                       nsIPresShell *aPresShell,
                                       nsIWeakReference *aWeakShell,
                                       PRBool *aIsHidden)
 {
   if (!aPresShell || !aWeakShell || gIsShutdown)
     return nsnull;
@@ -1380,43 +1167,34 @@ nsAccessibilityService::GetAccessible(ns
     // accessible.
     nsRefPtr<nsAccessible> cachedAccessible = do_QueryObject(cachedAccessNode);
 
     if (cachedAccessible)
       return cachedAccessible.forget();
   }
 
   // No cache entry, so we must create the accessible.
-  nsRefPtr<nsAccessible> newAcc;
 
   nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
   if (!content) {
-    // This happens when we're on the document node, which will not QI to an
-    // nsIContent.
-    nsCOMPtr<nsIDocument> nodeIsDoc = do_QueryInterface(aNode);
-    if (!nodeIsDoc) // No content, and not doc node.
-      return nsnull;
+    // If it's document node then ask accessible document loader for
+    // document accessible, otherwise return null.
+    nsCOMPtr<nsIDocument> document(do_QueryInterface(aNode));
+    if (document) {
+      nsAccessible *accessible = GetDocAccessible(document);
+      NS_IF_ADDREF(accessible);
+      return accessible;
+    }
 
-#ifdef DEBUG
-    // XXX: remove me if you don't see an assertion.
-    nsCOMPtr<nsIAccessibleDocument> accessibleDoc =
-      nsAccessNode::GetDocAccessibleFor(nodeIsDoc);
-    NS_ASSERTION(!accessibleDoc,
-                 "Trying to create already cached accessible document!");
-#endif
-
-    newAcc = CreateDocOrRootAccessible(aPresShell, nodeIsDoc);
-    if (InitAccessible(newAcc, nsAccUtils::GetRoleMapEntry(aNode)))
-      return newAcc.forget();
     return nsnull;
   }
 
   // We have a content node.
   if (!content->IsInDoc()) {
-    NS_ERROR("Creating accessible for node with no document");
+    NS_WARNING("Creating accessible for node with no document");
     return nsnull;
   }
 
   if (content->GetOwnerDoc() != aPresShell->GetDocument()) {
     NS_ERROR("Creating accessible for wrong pres shell");
     return nsnull;
   }
 
@@ -1439,16 +1217,17 @@ nsAccessibilityService::GetAccessible(ns
     // Not the main content for this frame. This happens because <area>
     // elements return the image frame as their primary frame. The main content
     // for the image frame is the image content. If the frame is not an image
     // frame or the node is not an area element then null is returned.
     return GetAreaAccessible(weakFrame.GetFrame(), aNode, aWeakShell);
   }
 
   // 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);
       if (renderedWhitespace.IsEmpty()) {
         // Really empty -- nothing is rendered
@@ -1682,16 +1461,65 @@ nsAccessibilityService::GetAccessible(ns
     }
   }
 
   if (InitAccessible(newAcc, roleMapEntry))
     return newAcc.forget();
   return nsnull;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// nsAccessibilityService private
+
+PRBool
+nsAccessibilityService::Init()
+{
+  // Initialize accessible document manager.
+  if (!nsAccDocManager::Init())
+    return PR_FALSE;
+
+  // Add observers.
+  nsCOMPtr<nsIObserverService> observerService =
+    mozilla::services::GetObserverService();
+  if (!observerService)
+    return PR_FALSE;
+
+  observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
+
+  // Initialize accessibility.
+  nsAccessNodeWrap::InitAccessibility();
+
+  gIsShutdown = PR_FALSE;
+  return PR_TRUE;
+}
+
+void
+nsAccessibilityService::Shutdown()
+{
+  // Remove observers.
+  nsCOMPtr<nsIObserverService> observerService =
+      mozilla::services::GetObserverService();
+  if (observerService)
+    observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
+
+  // Stop accessible document loader.
+  nsAccDocManager::Shutdown();
+
+  // Application is going to be closed, shutdown accessibility and mark
+  // accessibility service as shutdown to prevent calls of its methods.
+  // Don't null accessibility service static member at this point to be safe
+  // if someone will try to operate with it.
+
+  NS_ASSERTION(!gIsShutdown, "Accessibility was shutdown already");
+
+  gIsShutdown = PR_TRUE;
+
+  nsAccessNodeWrap::ShutdownAccessibility();
+}
+
 PRBool
 nsAccessibilityService::HasUniversalAriaProperty(nsIContent *aContent)
 {
   // ARIA attributes that take token values (NMTOKEN, bool) are special cased
   // because of special value "undefined" (see HasDefinedARIAToken).
   return nsAccUtils::HasDefinedARIAToken(aContent, nsAccessibilityAtoms::aria_atomic) ||
          nsAccUtils::HasDefinedARIAToken(aContent, nsAccessibilityAtoms::aria_busy) ||
          aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_controls) ||
@@ -2121,46 +1949,52 @@ nsAccessibilityService::InvalidateSubtre
                aChangeType == nsIAccessibilityService::FRAME_HIDE ||
                aChangeType == nsIAccessibilityService::NODE_SIGNIFICANT_CHANGE ||
                aChangeType == nsIAccessibilityService::NODE_APPEND ||
                aChangeType == nsIAccessibilityService::NODE_REMOVE,
                "Incorrect aEvent passed in");
 
   NS_ENSURE_ARG_POINTER(aShell);
 
-  nsCOMPtr<nsIAccessibleDocument> accessibleDoc =
-    nsAccessNode::GetDocAccessibleFor(aShell->GetDocument());
-  nsRefPtr<nsDocAccessible> docAcc = do_QueryObject(accessibleDoc);
-  if (docAcc)
-    docAcc->InvalidateCacheSubtree(aChangeContent, aChangeType);
+  nsDocAccessible *docAccessible = GetDocAccessible(aShell->GetDocument());
+  if (docAccessible)
+    docAccessible->InvalidateCacheSubtree(aChangeContent, aChangeType);
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // NS_GetAccessibilityService
 ////////////////////////////////////////////////////////////////////////////////
 
 /**
  * Return accessibility service; creating one if necessary.
  */
 nsresult
 NS_GetAccessibilityService(nsIAccessibilityService** aResult)
 {
-   NS_ENSURE_TRUE(aResult, NS_ERROR_NULL_POINTER);
-   *aResult = nsnull;
+  NS_ENSURE_TRUE(aResult, NS_ERROR_NULL_POINTER);
+  *aResult = nsnull;
  
-  if (!nsAccessibilityService::gAccessibilityService) {
-    nsAccessibilityService::gAccessibilityService = new nsAccessibilityService();
-    NS_ENSURE_TRUE(nsAccessibilityService::gAccessibilityService, NS_ERROR_OUT_OF_MEMORY);
- 
-    nsAccessibilityService::gIsShutdown = PR_FALSE;
-   }
- 
-  NS_ADDREF(*aResult = nsAccessibilityService::gAccessibilityService);
+  if (nsAccessibilityService::gAccessibilityService) {
+    NS_ADDREF(*aResult = nsAccessibilityService::gAccessibilityService);
+    return NS_OK;
+  }
+
+  nsRefPtr<nsAccessibilityService> service = new nsAccessibilityService();
+  NS_ENSURE_TRUE(service, NS_ERROR_OUT_OF_MEMORY);
+
+  if (!service->Init()) {
+    service->Shutdown();
+    return NS_ERROR_FAILURE;
+  }
+
+  nsAccessibilityService::gAccessibilityService = service;
+  NS_ADDREF(*aResult = service);
+
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessibilityService private (DON'T put methods here)
 
 already_AddRefed<nsAccessible>
 nsAccessibilityService::CreateAccessibleForDeckChild(nsIFrame* aFrame,
--- a/accessible/src/base/nsAccessibilityService.h
+++ b/accessible/src/base/nsAccessibilityService.h
@@ -37,48 +37,42 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef __nsAccessibilityService_h__
 #define __nsAccessibilityService_h__
 
 #include "nsIAccessibilityService.h"
 
 #include "a11yGeneric.h"
-#include "nsCoreUtils.h"
+#include "nsAccDocManager.h"
 
 #include "nsCOMArray.h"
 #include "nsIObserver.h"
-#include "nsIWebProgress.h"
-#include "nsIWebProgressListener.h"
-#include "nsWeakReference.h"
 
 class nsAccessNode;
 class nsAccessible;
 class nsIFrame;
 class nsIWeakReference;
 class nsIDOMNode;
 class nsObjectFrame;
 class nsIDocShell;
 class nsIPresShell;
 class nsIContent;
 struct nsRoleMapEntry;
 
-class nsAccessibilityService : public nsIAccessibilityService,
-                               public nsIObserver,
-                               public nsIWebProgressListener,
-                               public nsSupportsWeakReference
+class nsAccessibilityService : public nsAccDocManager,
+                               public nsIAccessibilityService,
+                               public nsIObserver
 {
 public:
-  nsAccessibilityService();
   virtual ~nsAccessibilityService();
 
-  NS_DECL_ISUPPORTS
+  NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIACCESSIBLERETRIEVAL
   NS_DECL_NSIOBSERVER
-  NS_DECL_NSIWEBPROGRESSLISTENER
 
   // nsIAccessibilityService
   virtual nsAccessible* GetAccessibleInShell(nsIDOMNode *aNode,
                                              nsIPresShell *aPresShell);
 
   virtual nsresult CreateOuterDocAccessible(nsIDOMNode *aNode,
                                             nsIAccessible **aAccessible);
   virtual nsresult CreateHTML4ButtonAccessible(nsIFrame *aFrame,
@@ -150,19 +144,19 @@ public:
    * Return presentation shell for the given node.
    *
    * @param aNode - the given DOM node.
    */
   static nsresult GetShellFromNode(nsIDOMNode *aNode,
                                    nsIWeakReference **weakShell);
 
   /**
-   * Indicates whether accessibility service was shutdown.
+   * Return true if accessibility service has been shutdown.
    */
-  static PRBool gIsShutdown;
+  static PRBool IsShutdown() { return gIsShutdown; }
 
   /**
    * Return an accessible for the given DOM node.
    *
    * @param  aNode       [in] the given node
    * @param  aPresShell  [in] the pres shell of the node
    * @param  aWeakShell  [in] the weak shell for the pres shell
    * @param  aIsHidden   [out, optional] indicates whether the node's frame is
@@ -201,63 +195,74 @@ public:
    *
    * @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
    */
   nsAccessNode* GetCachedAccessNode(nsIDOMNode *aNode,
                                     nsIWeakReference *aShell);
 
-private:
-  /**
-   * Return presentation shell, DOM node for the given frame.
-   *
-   * @param aFrame - the given frame
-   * @param aShell [out] - presentation shell for DOM node associated with the
-   *                 given frame
-   * @param aContent [out] - DOM node associated with the given frame
-   */
-  nsresult GetInfo(nsIFrame *aFrame,
-                   nsIWeakReference **aShell,
-                   nsIDOMNode **aContent);
-
   /**
    * 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);
 
+private:
+  // nsAccessibilityService creation is controlled by friend
+  // NS_GetAccessibilityService, keep constructors private.
+  nsAccessibilityService();
+  nsAccessibilityService(const nsAccessibilityService&);
+  nsAccessibilityService& operator =(const nsAccessibilityService&);
+
+private:
+  /**
+   * Initialize accessibility service.
+   */
+  PRBool Init();
+
+  /**
+   * Shutdowns accessibility service.
+   */
+  void Shutdown();
+
+  /**
+   * Return presentation shell, DOM node for the given frame.
+   *
+   * @param aFrame - the given frame
+   * @param aShell [out] - presentation shell for DOM node associated with the
+   *                 given frame
+   * @param aContent [out] - DOM node associated with the given frame
+   */
+  nsresult GetInfo(nsIFrame *aFrame,
+                   nsIWeakReference **aShell,
+                   nsIDOMNode **aContent);
+
   /**
    * Return accessible for HTML area element associated with an image map.
    */
   already_AddRefed<nsAccessible>
     GetAreaAccessible(nsIFrame *aImageFrame, nsIDOMNode *aAreaNode,
                       nsIWeakReference *aWeakShell);
 
   /**
    * Create accessible for the element implementing nsIAccessibleProvider
    * interface.
    */
   already_AddRefed<nsAccessible>
     CreateAccessibleByType(nsIDOMNode *aNode, nsIWeakReference *aWeakShell);
 
   /**
-   * Create document or root accessible.
-   */
-  already_AddRefed<nsAccessible>
-    CreateDocOrRootAccessible(nsIPresShell *aShell, nsIDocument *aDocument);
-
-  /**
    * Create accessible for HTML node by tag name.
    */
   already_AddRefed<nsAccessible>
     CreateHTMLAccessibleByMarkup(nsIFrame *aFrame, nsIWeakReference *aWeakShell,
                                  nsIDOMNode *aNode);
 
   /**
    * Create accessible if parent is a deck frame.
@@ -268,46 +273,39 @@ private:
 
 #ifdef MOZ_XUL
   /**
    * Create accessible for XUL tree element.
    */
   already_AddRefed<nsAccessible>
     CreateAccessibleForXULTree(nsIDOMNode *aNode, nsIWeakReference *aWeakShell);
 #endif
-  
+
+  /**
+   * Reference for accessibility service.
+   */
   static nsAccessibilityService *gAccessibilityService;
 
   /**
+   * Indicates whether accessibility service was shutdown.
+   */
+  static PRBool gIsShutdown;
+
+  /**
    * Does this content node have a universal ARIA property set on it?
    * A universal ARIA property is one that can be defined on any element even if there is no role.
    *
    * @param aContent The content node to test
    * @return PR_TRUE if there is a universal ARIA property set on the node
    */
   PRBool HasUniversalAriaProperty(nsIContent *aContent);
 
-  /**
-   *  Process the internal doc load event.
-   *
-   *  @param  aWebProgress  [in] the nsIWebProgress object for the load event
-   *  @param  aEventType    [in] the type of load event, one of:
-   *                          nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_START,
-   *                          nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE,
-   *                          nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED
-   */
-  void ProcessDocLoadEvent(nsIWebProgress *aWebProgress, PRUint32 aEventType);
-
   friend nsAccessibilityService* GetAccService();
 
-  friend nsresult  NS_GetAccessibilityService(nsIAccessibilityService** aResult);
-
-  
-  NS_DECL_RUNNABLEMETHOD_ARG2(nsAccessibilityService, ProcessDocLoadEvent,
-                              nsCOMPtr<nsIWebProgress>, PRUint32)
+  friend nsresult NS_GetAccessibilityService(nsIAccessibilityService** aResult);
 };
 
 /**
  * Return the accessibility service instance. (Handy global function)
  */
 inline nsAccessibilityService*
 GetAccService()
 {
@@ -483,17 +481,16 @@ static const char kEventTypeNames[][40] 
   "dragdrop start",                          // EVENT_DRAGDROP_START
   "dragdrop end",                            // EVENT_DRAGDROP_END
   "dialog start",                            // EVENT_DIALOG_START
   "dialog end",                              // EVENT_DIALOG_END
   "scrolling start",                         // EVENT_SCROLLING_START
   "scrolling end",                           // EVENT_SCROLLING_END
   "minimize start",                          // EVENT_MINIMIZE_START
   "minimize end",                            // EVENT_MINIMIZE_END
-  "document load start",                     // EVENT_DOCUMENT_LOAD_START
   "document load complete",                  // EVENT_DOCUMENT_LOAD_COMPLETE
   "document reload",                         // EVENT_DOCUMENT_RELOAD
   "document load stopped",                   // EVENT_DOCUMENT_LOAD_STOPPED
   "document attributes changed",             // EVENT_DOCUMENT_ATTRIBUTES_CHANGED
   "document content changed",                // EVENT_DOCUMENT_CONTENT_CHANGED
   "property changed",                        // EVENT_PROPERTY_CHANGED
   "selection changed",                       // EVENT_SELECTION_CHANGED
   "text attribute changed",                  // EVENT_TEXT_ATTRIBUTE_CHANGED
@@ -531,18 +528,17 @@ static const char kEventTypeNames[][40] 
   "hyperlink number of anchors changed",     // EVENT_HYPERLINK_NUMBER_OF_ANCHORS_CHANGED
   "hyperlink selected link changed",         // EVENT_HYPERLINK_SELECTED_LINK_CHANGED
   "hypertext link activated",                // EVENT_HYPERTEXT_LINK_ACTIVATED
   "hypertext link selected",                 // EVENT_HYPERTEXT_LINK_SELECTED
   "hyperlink start index changed",           // EVENT_HYPERLINK_START_INDEX_CHANGED
   "hypertext changed",                       // EVENT_HYPERTEXT_CHANGED
   "hypertext links count changed",           // EVENT_HYPERTEXT_NLINKS_CHANGED
   "object attribute changed",                // EVENT_OBJECT_ATTRIBUTE_CHANGED
-  "page changed",                            // EVENT_PAGE_CHANGED
-  "internal load"                            // EVENT_INTERNAL_LOAD
+  "page changed"                             // EVENT_PAGE_CHANGED
 };
 
 /**
  * Map nsIAccessibleRelation constants to strings. Used by
  * nsIAccessibleRetrieval::getStringRelationType() method.
  */
 static const char kRelationTypeNames[][20] = {
   "unknown",             // RELATION_NUL
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -212,16 +212,26 @@ public:
 
   /**
    * Set the child count to -1 (unknown) and null out cached child pointers.
    * Should be called when accessible tree is changed because document has
    * transformed.
    */
   virtual void InvalidateChildren();
 
+  /**
+   * Append/remove a child. Alternative approach of children handling than
+   * CacheChildren/InvalidateChildren.
+   *
+   * @param  aAccessible  [in] child to append/remove
+   * @return true          if child was successfully appended/removed
+   */
+  virtual PRBool AppendChild(nsAccessible *aAccessible) { return PR_FALSE; }
+  virtual PRBool RemoveChild(nsAccessible *aAccessible) { return PR_FALSE; }
+
   //////////////////////////////////////////////////////////////////////////////
   // Accessible tree traverse methods
 
   /**
    * Return parent accessible.
    */
   virtual nsAccessible* GetParent();
 
--- a/accessible/src/base/nsApplicationAccessible.cpp
+++ b/accessible/src/base/nsApplicationAccessible.cpp
@@ -201,17 +201,17 @@ nsApplicationAccessible::GetPlatformVers
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessNode public methods
 
 PRBool
 nsApplicationAccessible::IsDefunct()
 {
-  return nsAccessibilityService::gIsShutdown;
+  return nsAccessibilityService::IsShutdown();
 }
 
 nsresult
 nsApplicationAccessible::Init()
 {
   mAppInfo = do_GetService("@mozilla.org/xre/app-info;1");
   return NS_OK;
 }
--- a/accessible/src/base/nsCaretAccessible.cpp
+++ b/accessible/src/base/nsCaretAccessible.cpp
@@ -204,26 +204,21 @@ nsCaretAccessible::RemoveDocSelectionLis
 
 NS_IMETHODIMP
 nsCaretAccessible::NotifySelectionChanged(nsIDOMDocument *aDoc,
                                           nsISelection *aSel,
                                           PRInt16 aReason)
 {
   NS_ENSURE_ARG(aDoc);
 
-  nsCOMPtr<nsIDOMNode> docNode(do_QueryInterface(aDoc));
-  nsCOMPtr<nsIAccessibleDocument> accDoc =
-    nsAccessNode::GetDocAccessibleFor(docNode);
+  nsCOMPtr<nsIDocument> document(do_QueryInterface(aDoc));
+  nsDocAccessible *docAccessible = GetAccService()->GetDocAccessible(document);
 
   // Don't fire events until document is loaded.
-  if (!accDoc)
-    return NS_OK;
-
-  nsCOMPtr<nsIAccessible> accForDoc(do_QueryInterface(accDoc));
-  if (nsAccUtils::State(accForDoc) & nsIAccessibleStates::STATE_BUSY)
+  if (!docAccessible || !docAccessible->IsContentLoaded())
     return NS_OK;
 
   nsCOMPtr<nsISelection2> sel2(do_QueryInterface(aSel));
 
   PRInt16 type = 0;
   sel2->GetType(&type);
 
   if (type == nsISelectionController::SELECTION_NORMAL)
--- a/accessible/src/base/nsCoreUtils.cpp
+++ b/accessible/src/base/nsCoreUtils.cpp
@@ -493,16 +493,76 @@ nsCoreUtils::GetDocShellTreeItemFor(nsID
   nsCOMPtr<nsISupports> container = doc->GetContainer();
   nsIDocShellTreeItem *docShellTreeItem = nsnull;
   if (container)
     CallQueryInterface(container, &docShellTreeItem);
 
   return docShellTreeItem;
 }
 
+PRBool
+nsCoreUtils::IsDocumentBusy(nsIDocument *aDocument)
+{
+  nsCOMPtr<nsISupports> container = aDocument->GetContainer();
+  nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
+  if (!docShell)
+    return PR_TRUE;
+
+  PRUint32 busyFlags = 0;
+  docShell->GetBusyFlags(&busyFlags);
+  return (busyFlags != nsIDocShell::BUSY_FLAGS_NONE);
+}
+
+PRBool
+nsCoreUtils::IsRootDocument(nsIDocument *aDocument)
+{
+  nsCOMPtr<nsISupports> container = aDocument->GetContainer();
+  nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem =
+    do_QueryInterface(container);
+  NS_ASSERTION(docShellTreeItem, "No document shell for document!");
+
+  nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
+  docShellTreeItem->GetParent(getter_AddRefs(parentTreeItem));
+
+  return !parentTreeItem;
+}
+
+PRBool
+nsCoreUtils::IsContentDocument(nsIDocument *aDocument)
+{
+  nsCOMPtr<nsISupports> container = aDocument->GetContainer();
+  nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem =
+    do_QueryInterface(container);
+  NS_ASSERTION(docShellTreeItem, "No document shell tree item for document!");
+
+  PRInt32 contentType;
+  docShellTreeItem->GetItemType(&contentType);
+  return (contentType == nsIDocShellTreeItem::typeContent);
+}
+
+PRBool
+nsCoreUtils::IsErrorPage(nsIDocument *aDocument)
+{
+  nsIURI *uri = aDocument->GetDocumentURI();
+  PRBool isAboutScheme = PR_FALSE;
+  uri->SchemeIs("about", &isAboutScheme);
+  if (!isAboutScheme)
+    return PR_FALSE;
+
+  nsCAutoString path;
+  uri->GetPath(path);
+
+  nsCAutoString::const_iterator start, end;
+  path.BeginReading(start);
+  path.EndReading(end);
+
+  NS_NAMED_LITERAL_CSTRING(neterror, "neterror");
+  return FindInReadable(neterror, start, end);
+}
+
 nsIFrame*
 nsCoreUtils::GetFrameFor(nsIDOMElement *aElm)
 {
   nsCOMPtr<nsIContent> content(do_QueryInterface(aElm));
   if (!content)
     return nsnull;
   
   return content->GetPrimaryFrame();
--- a/accessible/src/base/nsCoreUtils.h
+++ b/accessible/src/base/nsCoreUtils.h
@@ -223,16 +223,36 @@ public:
 
   /**
    * Return document shell tree item for the given DOM node.
    */
   static already_AddRefed<nsIDocShellTreeItem>
     GetDocShellTreeItemFor(nsIDOMNode *aNode);
 
   /**
+   * Return true if document is loading.
+   */
+  static PRBool IsDocumentBusy(nsIDocument *aDocument);
+
+  /**
+   * Return true if the given document is root document.
+   */
+  static PRBool IsRootDocument(nsIDocument *aDocument);
+
+  /**
+   * Return true if the given document is content document (not chrome).
+   */
+  static PRBool IsContentDocument(nsIDocument *aDocument);
+
+  /**
+   * Return true if the given document is an error page.
+   */
+  static PRBool IsErrorPage(nsIDocument *aDocument);
+
+  /**
    * Retrun frame for the given DOM element.
    */
   static nsIFrame* GetFrameFor(nsIDOMElement *aElm);
 
   /**
    * Retrun true if the type of given frame equals to the given frame type.
    *
    * @param aFrame  the frame
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -35,17 +35,16 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsAccCache.h"
 #include "nsAccessibilityAtoms.h"
 #include "nsAccessibilityService.h"
 #include "nsAccUtils.h"
-#include "nsCoreUtils.h"
 #include "nsRootAccessible.h"
 #include "nsTextEquivUtils.h"
 
 #include "nsIMutableArray.h"
 #include "nsICommandManager.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIDocument.h"
@@ -81,59 +80,46 @@
 
 PRUint32 nsDocAccessible::gLastFocusedAccessiblesState = 0;
 nsIAtom *nsDocAccessible::gLastFocusedFrameType = nsnull;
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // Constructor/desctructor
 
-nsDocAccessible::nsDocAccessible(nsIDOMNode *aDOMNode, nsIWeakReference* aShell):
+nsDocAccessible::nsDocAccessible(nsIDOMNode *aDOMNode,
+                                 nsIWeakReference *aShell) :
   nsHyperTextAccessibleWrap(aDOMNode, aShell), mWnd(nsnull),
-  mScrollPositionChangedTicks(0), mIsContentLoaded(PR_FALSE),
-  mIsLoadCompleteFired(PR_FALSE)
+  mIsLoaded(PR_FALSE), mScrollPositionChangedTicks(0)
 {
   // XXX aaronl should we use an algorithm for the initial cache size?
   mAccessNodeCache.Init(kDefaultCacheSize);
 
   // For GTK+ native window, we do nothing here.
   if (!mDOMNode)
     return;
 
-  // Because of the way document loading happens, the new nsIWidget is created before
-  // the old one is removed. Since it creates the nsDocAccessible, for a brief moment
-  // there can be 2 nsDocAccessible's for the content area, although for 2 different
-  // pres shells.
+  nsCOMPtr<nsIPresShell> shell(do_QueryReferent(mWeakShell));
+
+  // Initalize mDocument
+  mDocument = shell->GetDocument();
 
-  nsCOMPtr<nsIPresShell> shell(do_QueryReferent(mWeakShell));
-  if (shell) {
-    // Find mDocument
-    mDocument = shell->GetDocument();
-    
-    // Find mWnd
-    nsIViewManager* vm = shell->GetViewManager();
-    if (vm) {
-      nsCOMPtr<nsIWidget> widget;
-      vm->GetRootWidget(getter_AddRefs(widget));
-      if (widget) {
-        mWnd = widget->GetNativeData(NS_NATIVE_WINDOW);
-      }
+  // Initalize mWnd
+  nsIViewManager* vm = shell->GetViewManager();
+  if (vm) {
+    nsCOMPtr<nsIWidget> widget;
+    vm->GetRootWidget(getter_AddRefs(widget));
+    if (widget) {
+      mWnd = widget->GetNativeData(NS_NATIVE_WINDOW);
     }
   }
 
-  nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem =
-    nsCoreUtils::GetDocShellTreeItemFor(mDOMNode);
-  nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(docShellTreeItem);
-  if (docShell) {
-    PRUint32 busyFlags;
-    docShell->GetBusyFlags(&busyFlags);
-    if (busyFlags == nsIDocShell::BUSY_FLAGS_NONE) {
-      mIsContentLoaded = PR_TRUE;                                               
-    }
-  }
+  // nsAccDocManager creates document accessible when scrollable frame is
+  // available already, it should be safe time to add scroll listener.
+  AddScrollListener();
 }
 
 nsDocAccessible::~nsDocAccessible()
 {
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -288,17 +274,17 @@ nsDocAccessible::GetStateInternal(PRUint
     // which it should be if it is scrollable. A XUL document could be focusable.
     // See bug 376803.
     *aState |= nsIAccessibleStates::STATE_FOCUSABLE;
     if (gLastFocusedNode == mDOMNode) {
       *aState |= nsIAccessibleStates::STATE_FOCUSED;
     }
   }
 
-  if (!mIsContentLoaded) {
+  if (nsCoreUtils::IsDocumentBusy(mDocument)) {
     *aState |= nsIAccessibleStates::STATE_BUSY;
     if (aExtraState) {
       *aExtraState |= nsIAccessibleStates::EXT_STATE_STALE;
     }
   }
  
   nsIFrame* frame = GetFrame();
   while (frame != nsnull && !frame->HasView()) {
@@ -587,30 +573,23 @@ nsDocAccessible::RemoveAccessNodeFromCac
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessNode
 
 nsresult
 nsDocAccessible::Init()
 {
-  // Put the document into the global cache.
-  if (!gGlobalDocAccessibleCache.Put(static_cast<void*>(mDocument), this))
-    return NS_ERROR_OUT_OF_MEMORY;
-
   // Initialize event queue.
   mEventQueue = new nsAccEventQueue(this);
   if (!mEventQueue)
     return NS_ERROR_OUT_OF_MEMORY;
 
   AddEventListeners();
 
-  // Ensure outer doc mParent accessible.
-  GetParent();
-
   // Fire reorder event to notify new accessible document has been created and
   // attached to the tree.
   nsRefPtr<nsAccEvent> reorderEvent =
     new nsAccReorderEvent(mParent, PR_FALSE, PR_TRUE, mDOMNode);
   if (!reorderEvent)
     return NS_ERROR_OUT_OF_MEMORY;
 
   FireDelayedAccessibleEvent(reorderEvent);
@@ -619,69 +598,41 @@ nsDocAccessible::Init()
 
 nsresult
 nsDocAccessible::Shutdown()
 {
   if (!mWeakShell) {
     return NS_OK;  // Already shutdown
   }
 
+  NS_LOG_ACCDOCDESTROY_FOR("document shutdown", mDocument, this)
+
   if (mEventQueue) {
     mEventQueue->Shutdown();
     mEventQueue = nsnull;
   }
 
-  nsCOMPtr<nsIDocShellTreeItem> treeItem =
-    nsCoreUtils::GetDocShellTreeItemFor(mDOMNode);
-  ShutdownChildDocuments(treeItem);
+  RemoveEventListeners();
 
-  RemoveEventListeners();
+  if (mParent) {
+    NS_LOG_ACCDOCDESTROY_FOR("remove document from outer doc", mDocument, this);
+    mParent->RemoveChild(this);
+  }
 
   mWeakShell = nsnull;  // Avoid reentrancy
 
   ClearCache(mAccessNodeCache);
 
   nsCOMPtr<nsIDocument> kungFuDeathGripDoc = mDocument;
   mDocument = nsnull;
 
   nsHyperTextAccessibleWrap::Shutdown();
-
-  // Remove from the cache after other parts of Shutdown(), so that Shutdown() procedures
-  // can find the doc or root accessible in the cache if they need it.
-  // We don't do this during ShutdownAccessibility() because that is already clearing the cache
-  if (!nsAccessibilityService::gIsShutdown)
-    gGlobalDocAccessibleCache.Remove(static_cast<void*>(kungFuDeathGripDoc));
-
   return NS_OK;
 }
 
-// nsDocAccessible protected member
-void nsDocAccessible::ShutdownChildDocuments(nsIDocShellTreeItem *aStart)
-{
-  nsCOMPtr<nsIDocShellTreeNode> treeNode(do_QueryInterface(aStart));
-  if (treeNode) {
-    PRInt32 subDocuments;
-    treeNode->GetChildCount(&subDocuments);
-    for (PRInt32 count = 0; count < subDocuments; count ++) {
-      nsCOMPtr<nsIDocShellTreeItem> treeItemChild;
-      treeNode->GetChildAt(count, getter_AddRefs(treeItemChild));
-      NS_ASSERTION(treeItemChild, "No tree item when there should be");
-      if (!treeItemChild) {
-        continue;
-      }
-      nsCOMPtr<nsIAccessibleDocument> docAccessible =
-        GetDocAccessibleFor(treeItemChild);
-      if (docAccessible) {
-        nsRefPtr<nsAccessNode> docAccNode = do_QueryObject(docAccessible);
-        docAccNode->Shutdown();
-      }
-    }
-  }
-}
-
 nsIFrame*
 nsDocAccessible::GetFrame()
 {
   nsCOMPtr<nsIPresShell> shell(do_QueryReferent(mWeakShell));
 
   nsIFrame* root = nsnull;
   if (shell)
     root = shell->GetRootFrame();
@@ -765,19 +716,17 @@ nsresult nsDocAccessible::AddEventListen
     if (commandManager) {
       commandManager->AddCommandObserver(this, "obs_documentCreated");
     }
   }
 
   nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
   docShellTreeItem->GetRootTreeItem(getter_AddRefs(rootTreeItem));
   if (rootTreeItem) {
-    nsCOMPtr<nsIAccessibleDocument> rootAccDoc =
-      GetDocAccessibleFor(rootTreeItem, PR_TRUE); // Ensure root accessible is created;
-    nsRefPtr<nsRootAccessible> rootAccessible = GetRootAccessible(); // Then get it as ref ptr
+    nsRefPtr<nsRootAccessible> rootAccessible = GetRootAccessible();
     NS_ENSURE_TRUE(rootAccessible, NS_ERROR_FAILURE);
     nsRefPtr<nsCaretAccessible> caretAccessible = rootAccessible->GetCaretAccessible();
     if (caretAccessible) {
       caretAccessible->AddDocSelectionListener(presShell);
     }
   }
 
   // add document observer
@@ -827,89 +776,16 @@ nsresult nsDocAccessible::RemoveEventLis
       nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(mWeakShell));
       caretAccessible->RemoveDocSelectionListener(presShell);
     }
   }
 
   return NS_OK;
 }
 
-// nsDocAccessible public member
-void
-nsDocAccessible::FireDocLoadEvents(PRUint32 aEventType)
-{
-  if (IsDefunct())
-    return;
-
-  PRBool isFinished = 
-             (aEventType == nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE ||
-              aEventType == nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED);
-
-  mIsContentLoaded = isFinished;
-  if (isFinished) {
-    if (mIsLoadCompleteFired)
-      return;
-
-    mIsLoadCompleteFired = PR_TRUE;
-  }
-
-  nsCOMPtr<nsIDocShellTreeItem> treeItem =
-    nsCoreUtils::GetDocShellTreeItemFor(mDOMNode);
-  if (!treeItem)
-    return;
-
-  nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
-  treeItem->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
-
-  if (isFinished) {
-    // Need to wait until scrollable frame is available
-    AddScrollListener();
-    nsRefPtr<nsAccessible> acc(GetParent());
-    if (acc) {
-      // Make the parent forget about the old document as a child
-      acc->InvalidateChildren();
-    }
-
-    if (sameTypeRoot != treeItem) {
-      // Fire show/hide events to indicate frame/iframe content is new, rather than
-      // doc load event which causes screen readers to act is if entire page is reloaded
-      InvalidateCacheSubtree(nsnull,
-                             nsIAccessibilityService::NODE_SIGNIFICANT_CHANGE);
-    }
-    // Fire STATE_CHANGE event for doc load finish if focus is in same doc tree
-    if (gLastFocusedNode) {
-      nsCOMPtr<nsIDocShellTreeItem> focusedTreeItem =
-        nsCoreUtils::GetDocShellTreeItemFor(gLastFocusedNode);
-      if (focusedTreeItem) {
-        nsCOMPtr<nsIDocShellTreeItem> sameTypeRootOfFocus;
-        focusedTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRootOfFocus));
-        if (sameTypeRoot == sameTypeRootOfFocus) {
-          nsRefPtr<nsAccEvent> accEvent =
-            new nsAccStateChangeEvent(this, nsIAccessibleStates::STATE_BUSY, PR_FALSE, PR_FALSE);
-          nsEventShell::FireEvent(accEvent);
-        }
-      }
-    }
-  }
-
-  if (sameTypeRoot == treeItem) {
-    // Not a frame or iframe
-    if (!isFinished) {
-      // Fire state change event to set STATE_BUSY when document is loading. For
-      // example, Window-Eyes expects to get it.
-      nsRefPtr<nsAccEvent> accEvent =
-        new nsAccStateChangeEvent(this, nsIAccessibleStates::STATE_BUSY,
-                                  PR_FALSE, PR_TRUE);
-      nsEventShell::FireEvent(accEvent);
-    }
-
-    nsEventShell::FireEvent(aEventType, this);
-  }
-}
-
 void nsDocAccessible::ScrollTimerCallback(nsITimer *aTimer, void *aClosure)
 {
   nsDocAccessible *docAcc = reinterpret_cast<nsDocAccessible*>(aClosure);
 
   if (docAcc && docAcc->mScrollPositionChangedTicks &&
       ++docAcc->mScrollPositionChangedTicks > 2) {
     // Whenever scroll position changes, mScrollPositionChangeTicks gets reset to 1
     // We only want to fire accessibilty scroll event when scrolling stops or pauses
@@ -931,16 +807,17 @@ void nsDocAccessible::AddScrollListener(
 {
   nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(mWeakShell));
   if (!presShell)
     return;
 
   nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollableExternal();
   if (sf) {
     sf->AddScrollPositionListener(this);
+    NS_LOG_ACCDOCCREATE_TEXT("add scroll listener")
   }
 }
 
 // nsDocAccessible protected member
 void nsDocAccessible::RemoveScrollListener()
 {
   nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(mWeakShell));
   if (!presShell)
@@ -1052,21 +929,18 @@ nsDocAccessible::AttributeChangedImpl(ns
   // filed as bug 472143
   
   nsCOMPtr<nsISupports> container = mDocument->GetContainer();
   nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
   if (!docShell) {
     return;
   }
 
-  PRUint32 busyFlags;
-  docShell->GetBusyFlags(&busyFlags);
-  if (busyFlags) {
+  if (!IsContentLoaded())
     return; // Still loading, ignore setting of initial attributes
-  }
 
   nsCOMPtr<nsIPresShell> shell = GetPresShell();
   if (!shell) {
     return; // Document has been shut down
   }
 
   nsCOMPtr<nsIDOMNode> targetNode(do_QueryInterface(aContent));
   NS_ASSERTION(targetNode, "No node for attr modified");
@@ -1309,17 +1183,17 @@ nsDocAccessible::ARIAAttributeChanged(ns
   }
 }
 
 void nsDocAccessible::ContentAppended(nsIDocument *aDocument,
                                       nsIContent* aContainer,
                                       nsIContent* aFirstNewContent,
                                       PRInt32 /* unused */)
 {
-  if ((!mIsContentLoaded || !mDocument) && mAccessNodeCache.Count() <= 1) {
+  if (!IsContentLoaded() && mAccessNodeCache.Count() <= 1) {
     // See comments in nsDocAccessible::InvalidateCacheSubtree
     InvalidateChildren();
     return;
   }
 
   // Does this need to be a strong ref?  If so, why?
   for (nsIContent* cur = aFirstNewContent; cur; cur = cur->GetNextSibling()) {
     // InvalidateCacheSubtree will not fire the EVENT_SHOW for the new node
@@ -1393,45 +1267,32 @@ nsDocAccessible::ParentChainChanged(nsIC
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessible
 
 nsAccessible*
 nsDocAccessible::GetParent()
 {
-  if (IsDefunct())
-    return nsnull;
-
-  if (mParent)
-    return mParent;
-
-  nsIDocument* parentDoc = mDocument->GetParentDocument();
-  if (!parentDoc)
-    return nsnull;
+  return IsDefunct() ? nsnull : mParent.get();
+}
 
-  nsIContent* ownerContent = parentDoc->FindContentForSubDocument(mDocument);
-  nsCOMPtr<nsIDOMNode> ownerNode(do_QueryInterface(ownerContent));
-  if (ownerNode) {
-    nsCOMPtr<nsIAccessibilityService> accService = GetAccService();
-    if (accService) {
-      // XXX aaronl: ideally we would traverse the presshell chain. Since
-      // there's no easy way to do that, we cheat and use the document
-      // hierarchy. GetAccessibleFor() is bad because it doesn't support our
-      // concept of multiple presshells per doc.
-      // It should be changed to use GetAccessibleInWeakShell()
-      nsCOMPtr<nsIAccessible> parent;
-      accService->GetAccessibleFor(ownerNode, getter_AddRefs(parent));
-      mParent = do_QueryObject(parent);
-    }
-  }
+#ifdef DEBUG_ACCDOCMGR
+nsresult
+nsDocAccessible::HandleAccEvent(nsAccEvent *aAccEvent)
+{
+  NS_LOG_ACCDOCLOAD_HANDLEEVENT(aAccEvent)
 
-  NS_ASSERTION(mParent, "No parent for not root document accessible!");
-  return mParent;
+  return nsHyperTextAccessible::HandleAccEvent(aAccEvent);
+
 }
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Public members
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // Protected members
 
 void
 nsDocAccessible::FireValueChangeForTextFields(nsIAccessible *aPossibleTextFieldAccessible)
 {
@@ -1445,19 +1306,18 @@ nsDocAccessible::FireValueChangeForTextF
   FireDelayedAccessibleEvent(valueChangeEvent);
 }
 
 void
 nsDocAccessible::FireTextChangeEventForText(nsIContent *aContent,
                                             CharacterDataChangeInfo* aInfo,
                                             PRBool aIsInserted)
 {
-  if (!mIsContentLoaded || !mDocument) {
+  if (!IsContentLoaded())
     return;
-  }
 
   nsCOMPtr<nsIDOMNode> node(do_QueryInterface(aContent));
   if (!node)
     return;
 
   nsAccessible *accessible = GetAccService()->GetContainerAccessible(node,
                                                                      PR_TRUE);
   if (!accessible)
@@ -1597,16 +1457,17 @@ nsDocAccessible::FireDelayedAccessibleEv
   return FireDelayedAccessibleEvent(event);
 }
 
 // nsDocAccessible public member
 nsresult
 nsDocAccessible::FireDelayedAccessibleEvent(nsAccEvent *aEvent)
 {
   NS_ENSURE_ARG(aEvent);
+  NS_LOG_ACCDOCLOAD_FIREEVENT(aEvent)
 
   if (mEventQueue)
     mEventQueue->Push(aEvent);
 
   return NS_OK;
 }
 
 void
@@ -1692,24 +1553,17 @@ nsDocAccessible::ProcessPendingEvent(nsA
 
     // Fire show/create events for this node or first accessible descendants of it
     FireShowHideEvents(domNode, PR_FALSE, eventType, eNormalEvent, isAsync,
                        isFromUserInput); 
     return;
   }
 
   if (accessible) {
-    if (eventType == nsIAccessibleEvent::EVENT_INTERNAL_LOAD) {
-      nsRefPtr<nsDocAccessible> docAcc = do_QueryObject(accessible);
-      NS_ASSERTION(docAcc, "No doc accessible for doc load event");
-
-      if (docAcc)
-        docAcc->FireDocLoadEvents(nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE);
-    }
-    else if (eventType == nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED) {
+    if (eventType == nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED) {
       nsCOMPtr<nsIAccessibleText> accessibleText = do_QueryObject(accessible);
       PRInt32 caretOffset;
       if (accessibleText && NS_SUCCEEDED(accessibleText->GetCaretOffset(&caretOffset))) {
 #ifdef DEBUG_A11Y
         PRUnichar chAtOffset;
         accessibleText->GetCharacterAtOffset(caretOffset, &chAtOffset);
         printf("\nCaret moved to %d with char %c", caretOffset, chAtOffset);
 #endif
@@ -1894,17 +1748,17 @@ nsDocAccessible::InvalidateCacheSubtree(
 
   NS_ENSURE_TRUE(mDOMNode,);
 
   nsCOMPtr<nsIDOMNode> childNode = aChild ? do_QueryInterface(aChild) : mDOMNode;
 
   nsCOMPtr<nsIPresShell> presShell = GetPresShell();
   NS_ENSURE_TRUE(presShell,);
   
-  if (!mIsContentLoaded) {
+  if (!IsContentLoaded()) {
     // Still loading document
     if (mAccessNodeCache.Count() <= 1) {
       // Still loading and no accessibles has yet been created other than this
       // doc accessible. In this case we optimize
       // by not firing SHOW/HIDE/REORDER events for every document mutation
       // caused by page load, since AT is not going to want to grab the
       // document and listen to these changes until after the page is first loaded
       // Leave early, and ensure mAccChildCount stays uninitialized instead of 0,
--- a/accessible/src/base/nsDocAccessible.h
+++ b/accessible/src/base/nsDocAccessible.h
@@ -34,19 +34,20 @@
  * 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 ***** */
 
 #ifndef _nsDocAccessible_H_
 #define _nsDocAccessible_H_
 
+#include "nsIAccessibleDocument.h"
+
 #include "nsHyperTextAccessibleWrap.h"
 #include "nsEventShell.h"
-#include "nsIAccessibleDocument.h"
 
 #include "nsIDocument.h"
 #include "nsIDocumentObserver.h"
 #include "nsIEditor.h"
 #include "nsIObserver.h"
 #include "nsIScrollPositionListener.h"
 #include "nsITimer.h"
 #include "nsIWeakReference.h"
@@ -107,21 +108,43 @@ public:
   // nsAccessible
   virtual nsresult GetRoleInternal(PRUint32 *aRole);
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
   virtual nsresult GetARIAState(PRUint32 *aState, PRUint32 *aExtraState);
 
   virtual void SetRoleMapEntry(nsRoleMapEntry* aRoleMapEntry);
   virtual nsAccessible* GetParent();
 
+#ifdef DEBUG_ACCDOCMGR
+  virtual nsresult HandleAccEvent(nsAccEvent *aAccEvent);
+#endif
+
   // nsIAccessibleText
   NS_IMETHOD GetAssociatedEditor(nsIEditor **aEditor);
 
   // nsDocAccessible
 
+  nsIDocument *GetDOMDocument() const { return mDocument; }
+
+  /**
+   * Return true if associated DOM document was loaded and isn't unloading.
+   */
+  PRBool IsContentLoaded() const
+  {
+    return mDocument && mDocument->IsVisible() &&
+      (mDocument->IsShowing() || mIsLoaded);
+  }
+
+  /**
+   * Marks as loaded, used for error pages as workaround since they do not
+   * receive pageshow event and as consequence nsIDocument::IsShowing() returns
+   * false.
+   */
+  void MarkAsLoaded() { mIsLoaded = PR_TRUE; }
+
   /**
    * Non-virtual method to fire a delayed event after a 0 length timeout.
    *
    * @param aEventType   [in] the nsIAccessibleEvent event type
    * @param aDOMNode     [in] DOM node the accesible event should be fired for
    * @param aAllowDupes  [in] rule to process an event (see EEventRule constants)
    * @param aIsAsynch    [in] set to PR_TRUE if this is not being called from
    *                      code synchronous with a DOM event
@@ -175,46 +198,38 @@ public:
   PRBool CacheAccessNode(void *aUniqueID, nsAccessNode *aAccessNode);
 
   /**
    * Remove the given access node from document cache.
    */
   void RemoveAccessNodeFromCache(nsIAccessNode *aAccessNode);
 
   /**
-   * Fire document load events.
-   *
-   * @param  aEventType  [in] nsIAccessibleEvent constant
-   */
-  virtual void FireDocLoadEvents(PRUint32 aEventType);
-
-  /**
    * Process the event when the queue of pending events is untwisted. Fire
    * accessible events as result of the processing.
    */
   void ProcessPendingEvent(nsAccEvent* aEvent);
 
 protected:
-  /**
-   * Iterates through sub documents and shut them down.
-   */
-  void ShutdownChildDocuments(nsIDocShellTreeItem *aStart);
 
     virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame);
     virtual nsresult AddEventListeners();
     virtual nsresult RemoveEventListeners();
     void AddScrollListener();
     void RemoveScrollListener();
 
-    /**
-     * For any accessibles in this subtree, invalidate their knowledge of
-     * their children. Only weak references are destroyed, not accessibles.
-     * @param aStartNode  The root of the subrtee to invalidate accessible child refs in
-     */
-    void InvalidateChildrenInSubtree(nsIDOMNode *aStartNode);
+  /**
+   * Invalidate parent-child relations for any cached accessible in the DOM
+   * subtree. Accessible objects aren't destroyed.
+   *
+   * @param aStartNode  [in] the root of the subrtee to invalidate accessible
+   *                      child/parent refs in
+   */
+  void InvalidateChildrenInSubtree(nsIDOMNode *aStartNode);
+
     void RefreshNodes(nsIDOMNode *aStartNode);
     static void ScrollTimerCallback(nsITimer *aTimer, void *aClosure);
 
     /**
      * Fires accessible events when attribute is changed.
      *
      * @param aContent - node that attribute is changed for
      * @param aNameSpaceID - namespace of changed attribute
@@ -295,23 +310,26 @@ protected:
      */
     void FireValueChangeForTextFields(nsIAccessible *aPossibleTextFieldAccessible);
 
     nsAccessNodeHashtable mAccessNodeCache;
     void *mWnd;
     nsCOMPtr<nsIDocument> mDocument;
     nsCOMPtr<nsITimer> mScrollWatchTimer;
     PRUint16 mScrollPositionChangedTicks; // Used for tracking scroll events
-    PRPackedBool mIsContentLoaded;
-    PRPackedBool mIsLoadCompleteFired;
 
 protected:
 
   nsRefPtr<nsAccEventQueue> mEventQueue;
 
+  /**
+   * Specifies if the document was loaded, used for error pages only.
+   */
+  PRPackedBool mIsLoaded;
+
     static PRUint32 gLastFocusedAccessiblesState;
     static nsIAtom *gLastFocusedFrameType;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsDocAccessible,
                               NS_DOCACCESSIBLE_IMPL_CID)
 
 #endif  
--- a/accessible/src/base/nsOuterDocAccessible.cpp
+++ b/accessible/src/base/nsOuterDocAccessible.cpp
@@ -33,32 +33,38 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * 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 "nsOuterDocAccessible.h"
 
-#include "nsAccessibilityService.h"
 #include "nsAccUtils.h"
+#include "nsDocAccessible.h"
 
-#include "nsIDocument.h"
-#include "nsIServiceManager.h"
-#include "nsIContent.h"
-
-NS_IMPL_ISUPPORTS_INHERITED0(nsOuterDocAccessible, nsAccessible)
+////////////////////////////////////////////////////////////////////////////////
+// nsOuterDocAccessible
+////////////////////////////////////////////////////////////////////////////////
 
 nsOuterDocAccessible::nsOuterDocAccessible(nsIDOMNode* aNode, 
                                            nsIWeakReference* aShell):
   nsAccessibleWrap(aNode, aShell)
 {
 }
 
-/* unsigned long getRole (); */
+////////////////////////////////////////////////////////////////////////////////
+// nsISupports
+
+NS_IMPL_ISUPPORTS_INHERITED0(nsOuterDocAccessible,
+                             nsAccessible)
+
+////////////////////////////////////////////////////////////////////////////////
+// nsAccessible public (DON'T add methods here)
+
 nsresult
 nsOuterDocAccessible::GetRoleInternal(PRUint32 *aRole)
 {
   *aRole = nsIAccessibleRole::ROLE_INTERNAL_FRAME;
   return NS_OK;
 }
 
 nsresult
@@ -66,17 +72,16 @@ nsOuterDocAccessible::GetStateInternal(P
 {
   nsresult rv = nsAccessible::GetStateInternal(aState, aExtraState);
   NS_ENSURE_A11Y_SUCCESS(rv, rv);
 
   *aState &= ~nsIAccessibleStates::STATE_FOCUSABLE;
   return NS_OK;
 }
 
-// nsAccessible::GetChildAtPoint()
 nsresult
 nsOuterDocAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
                                       PRBool aDeepestChild,
                                       nsIAccessible **aChild)
 {
   PRInt32 docX = 0, docY = 0, docWidth = 0, docHeight = 0;
   nsresult rv = GetBounds(&docX, &docY, &docWidth, &docHeight);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -95,68 +100,39 @@ nsOuterDocAccessible::GetChildAtPoint(PR
 
   if (aDeepestChild)
     return childAcc->GetDeepestChildAtPoint(aX, aY, aChild);
 
   NS_ADDREF(*aChild = childAcc);
   return NS_OK;
 }
 
-void
-nsOuterDocAccessible::CacheChildren()
-{
-  // An outer doc accessible usually has 1 nsDocAccessible child, but could have
-  // none if we can't get to the inner documnet.
-
-  nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
-  NS_ASSERTION(content, "No nsIContent for <browser>/<iframe>/<editor> dom node");
-
-  nsCOMPtr<nsIDocument> outerDoc = content->GetDocument();
-  if (!outerDoc) {
-    return;
-  }
-
-  nsIDocument *innerDoc = outerDoc->GetSubDocumentFor(content);
-  nsCOMPtr<nsIDOMNode> innerNode(do_QueryInterface(innerDoc));
-  if (!innerNode) {
-    return;
-  }
-
-  nsCOMPtr<nsIAccessible> innerAccessible;
-  nsCOMPtr<nsIAccessibilityService> accService = GetAccService();
-  accService->GetAccessibleFor(innerNode, getter_AddRefs(innerAccessible));
-  nsRefPtr<nsAccessible> innerAcc(do_QueryObject(innerAccessible));
-  if (!innerAcc)
-    return;
-
-  // Success getting inner document as first child -- now we cache it.
-  mChildren.AppendElement(innerAcc);
-  innerAcc->SetParent(this);
-}
-
 nsresult
 nsOuterDocAccessible::GetAttributesInternal(nsIPersistentProperties *aAttributes)
 {
   nsAutoString tag;
   aAttributes->GetStringProperty(NS_LITERAL_CSTRING("tag"), tag);
   if (!tag.IsEmpty()) {
     // We're overriding the ARIA attributes on an sub document, but we don't want to
     // override the other attributes
     return NS_OK;
   }
   return nsAccessible::GetAttributesInternal(aAttributes);
 }
 
-// Internal frame, which is the doc's parent, should not have a click action
+////////////////////////////////////////////////////////////////////////////////
+// nsIAccessible
+
 NS_IMETHODIMP
 nsOuterDocAccessible::GetNumActions(PRUint8 *aNumActions)
 {
   NS_ENSURE_ARG_POINTER(aNumActions);
   *aNumActions = 0;
 
+  // Internal frame, which is the doc's parent, should not have a click action.
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsOuterDocAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
 {
   aName.Truncate();
 
@@ -171,8 +147,98 @@ nsOuterDocAccessible::GetActionDescripti
   return NS_ERROR_INVALID_ARG;
 }
 
 NS_IMETHODIMP
 nsOuterDocAccessible::DoAction(PRUint8 aIndex)
 {
   return NS_ERROR_INVALID_ARG;
 }
+
+////////////////////////////////////////////////////////////////////////////////
+// nsAccessNode public
+
+nsresult
+nsOuterDocAccessible::Shutdown()
+{
+  // Shutdown child document if any.
+  nsAccessible *childAcc = mChildren.SafeElementAt(0, nsnull);
+  if (childAcc) {
+    nsRefPtr<nsDocAccessible> docAcc(do_QueryObject(childAcc));
+    NS_LOG_ACCDOCDESTROY_FOR("outerdoc document shutdown",
+                             docAcc->GetDOMDocument(), docAcc.get())
+    GetAccService()->ShutdownDocAccessiblesInTree(docAcc->GetDOMDocument());
+  }
+
+  nsAccessible::InvalidateChildren();
+
+  return nsAccessibleWrap::Shutdown();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsAccessible public
+
+void
+nsOuterDocAccessible::InvalidateChildren()
+{
+  // Do not invalidate children because nsAccDocManager is responsible for
+  // document accessible lifetime when DOM document is created or destroyed. If
+  // DOM document isn't destroyed but its presshell is destroyed (for example,
+  // when DOM node of outerdoc accessible is hidden), then outerdoc accessible
+  // notifies nsAccDocManager about this. If presshell is created for existing
+  // DOM document (for example when DOM node of outerdoc accessible is shown)
+  // then allow nsAccDocManager to handle this case since the document
+  // accessible is created and appended as a child when it's requested.
+
+  mAreChildrenInitialized = PR_FALSE;
+}
+
+PRBool
+nsOuterDocAccessible::AppendChild(nsAccessible *aAccessible)
+{
+  NS_ASSERTION(!mChildren.Length(),
+               "Previous child document of outerdoc accessible wasn't removed!");
+
+  if (!mChildren.AppendElement(aAccessible))
+    return PR_FALSE;
+
+  aAccessible->SetParent(this);
+  return PR_TRUE;
+}
+
+PRBool
+nsOuterDocAccessible::RemoveChild(nsAccessible *aAccessible)
+{
+  nsAccessible *child = mChildren.SafeElementAt(0, nsnull);
+  if (child != aAccessible) {
+    NS_ERROR("Wrong child to remove!");
+    return PR_FALSE;
+  }
+
+  mChildren.RemoveElement(child);
+  NS_ASSERTION(!mChildren.Length(),
+               "This child document of outerdoc accessible wasn't removed!");
+
+  return PR_TRUE;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsAccessible protected
+
+void
+nsOuterDocAccessible::CacheChildren()
+{
+  // Request document accessible for the content document to make sure it's
+  // created because once it's created it appends itself as a child.
+  nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
+  nsIDocument *outerDoc = content->GetCurrentDoc();
+  if (!outerDoc)
+    return;
+
+  nsIDocument *innerDoc = outerDoc->GetSubDocumentFor(content);
+  nsCOMPtr<nsIDOMNode> innerNode(do_QueryInterface(innerDoc));
+  if (!innerNode)
+    return;
+
+  nsDocAccessible *docAcc = GetAccService()->GetDocAccessible(innerDoc);
+  NS_ASSERTION(docAcc && docAcc->GetParent() == this,
+               "Document accessible isn't a child of outerdoc accessible!");
+}
--- a/accessible/src/base/nsOuterDocAccessible.h
+++ b/accessible/src/base/nsOuterDocAccessible.h
@@ -35,48 +35,53 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _nsOuterDocAccessible_H_
 #define _nsOuterDocAccessible_H_
 
 #include "nsAccessibleWrap.h"
-#include "nsIAccessible.h"
 
 /**
  * Used for <browser>, <frame>, <iframe>, <page> or editor> elements.
  * 
  * In these variable names, "outer" relates to the nsOuterDocAccessible as
  * opposed to the nsDocAccessibleWrap which is "inner". The outer node is
  * a something like tags listed above, whereas the inner node corresponds to
  * the inner document root.
  */
+
 class nsOuterDocAccessible : public nsAccessibleWrap
 {
-  // XXX: why is it private?
-  // CVS comment: <aaronl@netscape.com> 2003-04-01 14:15 Fixing bustage
-  NS_DECL_ISUPPORTS_INHERITED
-
 public:
   nsOuterDocAccessible(nsIDOMNode* aNode, 
                        nsIWeakReference* aShell);
 
+  NS_DECL_ISUPPORTS_INHERITED
+
   // nsIAccessible
   NS_IMETHOD GetNumActions(PRUint8 *aNumActions);
   NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
   NS_IMETHOD GetActionDescription(PRUint8 aIndex, nsAString& aDescription);
   NS_IMETHOD DoAction(PRUint8 aIndex);
 
+  // nsAccessNode
+  virtual nsresult Shutdown();
+
   // nsAccessible
   virtual nsresult GetRoleInternal(PRUint32 *aRole);
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
   virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
   virtual nsresult GetChildAtPoint(PRInt32 aX, PRInt32 aY,
                                    PRBool aDeepestChild,
                                    nsIAccessible **aChild);
 
+  virtual void InvalidateChildren();
+  virtual PRBool AppendChild(nsAccessible *aAccessible);
+  virtual PRBool RemoveChild(nsAccessible *aAccessible);
+
 protected:
   // nsAccessible
   virtual void CacheChildren();
 };
 
 #endif  
--- a/accessible/src/base/nsRelUtils.cpp
+++ b/accessible/src/base/nsRelUtils.cpp
@@ -35,16 +35,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsRelUtils.h"
 
 #include "nsAccessibilityService.h"
 #include "nsAccessNode.h"
+#include "nsCoreUtils.h"
 
 #include "nsIDOMDocument.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMDocumentXBL.h"
 
 #include "nsAutoPtr.h"
 #include "nsArrayUtils.h"
 
--- a/accessible/src/base/nsRootAccessible.cpp
+++ b/accessible/src/base/nsRootAccessible.cpp
@@ -223,33 +223,16 @@ nsRootAccessible::GetStateInternal(PRUin
   if (GetChromeFlags() & nsIWebBrowserChrome::CHROME_MODAL) {
     *aExtraState |= nsIAccessibleStates::EXT_STATE_MODAL;
   }
 #endif
 
   return NS_OK;
 }
 
-void
-nsRootAccessible::GetChromeEventHandler(nsIDOMEventTarget **aChromeTarget)
-{
-  nsCOMPtr<nsIDOMWindow> domWin;
-  GetWindow(getter_AddRefs(domWin));
-  nsCOMPtr<nsPIDOMWindow> privateDOMWindow(do_QueryInterface(domWin));
-  nsCOMPtr<nsPIDOMEventTarget> chromeEventHandler;
-  if (privateDOMWindow) {
-    chromeEventHandler = privateDOMWindow->GetChromeEventHandler();
-  }
-
-  nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(chromeEventHandler));
-
-  *aChromeTarget = target;
-  NS_IF_ADDREF(*aChromeTarget);
-}
-
 const char* const docEvents[] = {
 #ifdef DEBUG
   // Capture mouse over events and fire fake DRAGDROPSTART event to simplify
   // debugging a11y objects with event viewers
   "mouseover",
 #endif
   // capture DOM focus and DOM blur events 
   "focus",
@@ -270,18 +253,17 @@ const char* const docEvents[] = {
   "CheckboxStateChange",
   // add ourself as a RadioStateChange Listener ( custom event fired in in nsHTMLInputElement.cpp  & radio.xml)
   "RadioStateChange",
   "popupshown",
   "popuphiding",
   "DOMMenuInactive",
   "DOMMenuItemActive",
   "DOMMenuBarActive",
-  "DOMMenuBarInactive",
-  "DOMContentLoaded"
+  "DOMMenuBarInactive"
 };
 
 nsresult nsRootAccessible::AddEventListeners()
 {
   // nsIDOMNSEventTarget interface allows to register event listeners to
   // receive untrusted events (synthetic events generated by untrusted code).
   // For example, XBL bindings implementations for elements that are hosted in
   // non chrome document fire untrusted events.
@@ -292,22 +274,16 @@ nsresult nsRootAccessible::AddEventListe
                    * const* e_end = docEvents + NS_ARRAY_LENGTH(docEvents);
          e < e_end; ++e) {
       nsresult rv = nstarget->AddEventListener(NS_ConvertASCIItoUTF16(*e),
                                                this, PR_TRUE, PR_TRUE, 1);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
-  nsCOMPtr<nsIDOMEventTarget> target;
-  GetChromeEventHandler(getter_AddRefs(target));
-  if (target) {
-    target->AddEventListener(NS_LITERAL_STRING("pagehide"), this, PR_TRUE);
-  }
-
   if (!mCaretAccessible) {
     mCaretAccessible = new nsCaretAccessible(this);
   }
 
   return nsDocAccessible::AddEventListeners();
 }
 
 nsresult nsRootAccessible::RemoveEventListeners()
@@ -317,21 +293,16 @@ nsresult nsRootAccessible::RemoveEventLi
     for (const char* const* e = docEvents,
                    * const* e_end = docEvents + NS_ARRAY_LENGTH(docEvents);
          e < e_end; ++e) {
       nsresult rv = target->RemoveEventListener(NS_ConvertASCIItoUTF16(*e), this, PR_TRUE);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
-  GetChromeEventHandler(getter_AddRefs(target));
-  if (target) {
-    target->RemoveEventListener(NS_LITERAL_STRING("pagehide"), this, PR_TRUE);
-  }
-
   // Do this before removing clearing caret accessible, so that it can use
   // shutdown the caret accessible's selection listener
   nsDocAccessible::RemoveEventListeners();
 
   if (mCaretAccessible) {
     mCaretAccessible->Shutdown();
     mCaretAccessible = nsnull;
   }
@@ -340,60 +311,16 @@ nsresult nsRootAccessible::RemoveEventLi
 }
 
 nsCaretAccessible*
 nsRootAccessible::GetCaretAccessible()
 {
   return mCaretAccessible;
 }
 
-void nsRootAccessible::TryFireEarlyLoadEvent(nsIDOMNode *aDocNode)
-{
-  // We can fire an early load event based on DOMContentLoaded unless we 
-  // have subdocuments. For that we wait until WebProgressListener
-  // STATE_STOP handling in nsAccessibilityService.
-
-  // Note, we don't fire any page load finished events for chrome or for
-  // frame/iframe page loads during the initial complete page load -- that page
-  // load event for the entire content pane needs to stand alone.
-
-  // This also works for firing events for error pages
-
-  nsCOMPtr<nsIDocShellTreeItem> treeItem =
-    nsCoreUtils::GetDocShellTreeItemFor(aDocNode);
-  NS_ASSERTION(treeItem, "No docshelltreeitem for aDocNode");
-  if (!treeItem) {
-    return;
-  }
-  PRInt32 itemType;
-  treeItem->GetItemType(&itemType);
-  if (itemType != nsIDocShellTreeItem::typeContent) {
-    return;
-  }
-
-  // The doc accessible should already be created as a result of the
-  // OnStateChange() for the initiation of page loading
-  nsCOMPtr<nsIDocShellTreeNode> treeNode(do_QueryInterface(treeItem));
-  if (treeNode) {
-    PRInt32 subDocuments;
-    treeNode->GetChildCount(&subDocuments);
-    if (subDocuments) {
-      return;
-    }
-  }
-  nsCOMPtr<nsIDocShellTreeItem> rootContentTreeItem;
-  treeItem->GetSameTypeRootTreeItem(getter_AddRefs(rootContentTreeItem));
-  NS_ASSERTION(rootContentTreeItem, "No root content tree item");
-  if (rootContentTreeItem == treeItem) {
-    // No frames or iframes, so we can fire the doc load finished event early
-    FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_INTERNAL_LOAD,
-                               aDocNode);
-  }
-}
-
 PRBool
 nsRootAccessible::FireAccessibleFocusEvent(nsIAccessible *aAccessible,
                                            nsIDOMNode *aNode,
                                            nsIDOMEvent *aFocusEvent,
                                            PRBool aForceEvent,
                                            PRBool aIsAsynch,
                                            EIsFromUserInput aIsFromUserInput)
 {
@@ -607,46 +534,21 @@ nsresult nsRootAccessible::HandleEventWi
   if (localName.LowerCaseEqualsLiteral("textbox")) {
     printf("\ndebugging %s events for %s", NS_ConvertUTF16toUTF8(eventType).get(), NS_ConvertUTF16toUTF8(localName).get());
   }
 #endif
 
   nsIAccessibilityService *accService = GetAccService();
   NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE);
 
-  if (eventType.EqualsLiteral("pagehide")) {
-    // pagehide event can be fired under several conditions, such as HTML
-    // document going away, closing a window/dialog, and wizard page changing.
-    // We only destroy the accessible object when it's a document accessible,
-    // so that we don't destroy something still in use, like wizard page. 
-    // And we only get cached document accessible to destroy, so that we don't
-    // create it just to destroy it.
-    nsCOMPtr<nsIDocument> doc(do_QueryInterface(aTargetNode));
-    nsCOMPtr<nsIAccessibleDocument> accDoc = GetDocAccessibleFor(doc);
-    if (accDoc) {
-      nsRefPtr<nsAccessNode> docAccNode = do_QueryObject(accDoc);
-      docAccNode->Shutdown();
-    }
-
-    return NS_OK;
-  }
-
   nsIPresShell *eventShell = nsCoreUtils::GetPresShellFor(aTargetNode);
   if (!eventShell) {
     return NS_OK;
   }
 
-  if (eventType.EqualsLiteral("DOMContentLoaded")) {
-    // Don't create the doc accessible until load scripts have a chance to set
-    // role attribute for <body> or <html> element, because the value of 
-    // role attribute will be cached when the doc accessible is Init()'d
-    TryFireEarlyLoadEvent(aTargetNode);
-    return NS_OK;
-  }
-
   nsAccessible *accessible =
     accService->GetAccessibleInShell(aTargetNode, eventShell);
 
   if (eventType.EqualsLiteral("popuphiding"))
     return HandlePopupHidingEvent(aTargetNode, accessible);
 
   if (!accessible)
     return NS_OK;
@@ -962,39 +864,35 @@ nsRootAccessible::GetContentDocShell(nsI
 {
   if (!aStart) {
     return nsnull;
   }
 
   PRInt32 itemType;
   aStart->GetItemType(&itemType);
   if (itemType == nsIDocShellTreeItem::typeContent) {
-    nsCOMPtr<nsIAccessibleDocument> accDoc =
-      GetDocAccessibleFor(aStart, PR_TRUE);
+    nsDocAccessible *accDoc = nsAccUtils::GetDocAccessibleFor(aStart);
 
     // Hidden documents don't have accessibles (like SeaMonkey's sidebar),
     // they are of no interest for a11y.
     if (!accDoc)
       return nsnull;
 
-    nsCOMPtr<nsIAccessible> accessible = do_QueryInterface(accDoc);
-
     // If ancestor chain of accessibles is not completely visible,
     // don't use this one. This happens for example if it's inside
     // a background tab (tabbed browsing)
-    while (accessible) {
-      if (nsAccUtils::State(accessible) & nsIAccessibleStates::STATE_INVISIBLE)
+    nsAccessible *parent = accDoc->GetParent();
+    while (parent) {
+      if (nsAccUtils::State(parent) & nsIAccessibleStates::STATE_INVISIBLE)
         return nsnull;
 
-      nsCOMPtr<nsIAccessible> ancestor;
-      accessible->GetParent(getter_AddRefs(ancestor));
-      if (ancestor == this) {
+      if (parent == this)
         break; // Don't check past original root accessible we started with
-      }
-      accessible.swap(ancestor);
+
+      parent = parent->GetParent();
     }
 
     NS_ADDREF(aStart);
     return aStart;
   }
   nsCOMPtr<nsIDocShellTreeNode> treeNode(do_QueryInterface(aStart));
   if (treeNode) {
     PRInt32 subDocuments;
@@ -1025,21 +923,18 @@ nsRootAccessible::GetRelationByType(PRUi
     return nsDocAccessibleWrap::GetRelationByType(aRelationType, aRelation);
   }
 
   nsCOMPtr<nsIDocShellTreeItem> treeItem =
     nsCoreUtils::GetDocShellTreeItemFor(mDOMNode);
   nsCOMPtr<nsIDocShellTreeItem> contentTreeItem = GetContentDocShell(treeItem);
   // there may be no content area, so we need a null check
   if (contentTreeItem) {
-    nsCOMPtr<nsIAccessibleDocument> accDoc =
-      GetDocAccessibleFor(contentTreeItem, PR_TRUE);
-
-    nsCOMPtr<nsIAccessible> acc(do_QueryInterface(accDoc));
-    return nsRelUtils::AddTarget(aRelationType, aRelation, acc);
+    nsDocAccessible *accDoc = nsAccUtils::GetDocAccessibleFor(contentTreeItem);
+    return nsRelUtils::AddTarget(aRelationType, aRelation, accDoc);
   }
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessible
 
@@ -1047,41 +942,16 @@ nsAccessible*
 nsRootAccessible::GetParent()
 {
   // Parent has been setted in nsApplicationAccesible::AddRootAccessible()
   // when root accessible was intialized.
   return mParent;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// nsDocAccessible
-
-void
-nsRootAccessible::FireDocLoadEvents(PRUint32 aEventType)
-{
-  if (IsDefunct())
-    return;
-
-  nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem =
-    nsCoreUtils::GetDocShellTreeItemFor(mDOMNode);
-  NS_ASSERTION(docShellTreeItem, "No doc shell tree item for document");
-  if (!docShellTreeItem)
-    return;
-
-  PRInt32 contentType;
-  docShellTreeItem->GetItemType(&contentType);
-  if (contentType == nsIDocShellTreeItem::typeContent)
-    nsDocAccessibleWrap::FireDocLoadEvents(aEventType); // Content might need to fire event
-
-  // Root chrome: don't fire event
-  mIsContentLoaded = (aEventType == nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE ||
-                      aEventType == nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED);
-}
-
-////////////////////////////////////////////////////////////////////////////////
 // Protected members
 
 nsresult
 nsRootAccessible::HandlePopupShownEvent(nsIAccessible *aAccessible)
 {
   PRUint32 role = nsAccUtils::Role(aAccessible);
 
   if (role == nsIAccessibleRole::ROLE_MENUPOPUP) {
--- a/accessible/src/base/nsRootAccessible.h
+++ b/accessible/src/base/nsRootAccessible.h
@@ -83,19 +83,16 @@ public:
   virtual nsresult Init();
   virtual nsresult Shutdown();
 
   // nsAccessible
   virtual nsresult GetRoleInternal(PRUint32 *aRole);
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
   virtual nsAccessible* GetParent();
 
-  // nsDocAccessible
-  virtual void FireDocLoadEvents(PRUint32 aEventType);
-
   // nsRootAccessible
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ROOTACCESSIBLE_IMPL_CID)
 
   /**
    * Fire an accessible focus event for the current focusAccssible
    * and attach a new selection listener, if necessary.
    *
    * @param  aFocusAccessible  [in] the accessible which has received focus
@@ -124,18 +121,16 @@ public:
 protected:
   NS_DECL_RUNNABLEMETHOD(nsRootAccessible, FireCurrentFocusEvent)
 
     nsresult AddEventListeners();
     nsresult RemoveEventListeners();
     nsresult HandleEventWithTarget(nsIDOMEvent* aEvent,
                                    nsIDOMNode* aTargetNode);
     static void GetTargetNode(nsIDOMEvent *aEvent, nsIDOMNode **aTargetNode);
-    void TryFireEarlyLoadEvent(nsIDOMNode *aDocNode);
-    void GetChromeEventHandler(nsIDOMEventTarget **aChromeTarget);
 
     /**
      * Used in HandleEventWithTarget().
      */
     nsresult HandlePopupShownEvent(nsIAccessible *aAccessible);
     nsresult HandlePopupHidingEvent(nsIDOMNode *aNode,
                                     nsIAccessible *aAccessible);
 
--- a/accessible/src/msaa/nsDocAccessibleWrap.cpp
+++ b/accessible/src/msaa/nsDocAccessibleWrap.cpp
@@ -48,19 +48,22 @@
 #include "nsIURI.h"
 #include "nsIViewManager.h"
 #include "nsIWebNavigation.h"
 
 /* For documentation of the accessibility architecture, 
  * see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
  */
 
-//----- nsDocAccessibleWrap -----
+////////////////////////////////////////////////////////////////////////////////
+// nsDocAccessibleWrap
+////////////////////////////////////////////////////////////////////////////////
 
-nsDocAccessibleWrap::nsDocAccessibleWrap(nsIDOMNode *aDOMNode, nsIWeakReference *aShell): 
+nsDocAccessibleWrap::nsDocAccessibleWrap(nsIDOMNode *aDOMNode,
+                                         nsIWeakReference *aShell) :
   nsDocAccessible(aDOMNode, aShell)
 {
 }
 
 nsDocAccessibleWrap::~nsDocAccessibleWrap()
 {
 }
 
@@ -263,52 +266,18 @@ STDMETHODIMP nsDocAccessibleWrap::get_ac
       role != nsIAccessibleRole::ROLE_APPLICATION &&
       role != nsIAccessibleRole::ROLE_DIALOG &&
       role != nsIAccessibleRole::ROLE_ALERT)
     return hr;
 
   return get_URL(pszValue);
 }
 
-struct nsSearchAccessibleInCacheArg
-{
-  nsRefPtr<nsAccessible> mAccessible;
-  void *mUniqueID;
-};
-
-static PLDHashOperator
-SearchAccessibleInCache(const void* aKey, nsDocAccessible* aDocAccessible,
-                        void* aUserArg)
-{
-  NS_ASSERTION(aDocAccessible,
-               "No doc accessible for the object in doc accessible cache!");
-
-  if (aDocAccessible) {
-    nsSearchAccessibleInCacheArg* arg =
-      static_cast<nsSearchAccessibleInCacheArg*>(aUserArg);
-    nsAccessNode* accessNode =
-      aDocAccessible->GetCachedAccessNode(arg->mUniqueID);
-    if (accessNode) {
-      arg->mAccessible = do_QueryObject(accessNode);
-      return PL_DHASH_STOP;
-    }
-  }
-
-  return PL_DHASH_NEXT;
-}
-
 nsAccessible*
 nsDocAccessibleWrap::GetXPAccessibleForChildID(const VARIANT& aVarChild)
 {
   NS_PRECONDITION(aVarChild.vt == VT_I4 && aVarChild.lVal < 0,
                   "Variant doesn't point to child ID!");
 
   // Convert child ID to unique ID.
   void *uniqueID = reinterpret_cast<void*>(-aVarChild.lVal);
-
-  nsSearchAccessibleInCacheArg arg;
-  arg.mUniqueID = uniqueID;
-
-  gGlobalDocAccessibleCache.EnumerateRead(SearchAccessibleInCache,
-                                          static_cast<void*>(&arg));
-
-  return arg.mAccessible;
+  return GetAccService()->FindAccessibleInCache(uniqueID);
 }
--- a/accessible/src/msaa/nsEventMap.h
+++ b/accessible/src/msaa/nsEventMap.h
@@ -82,17 +82,16 @@ static const PRUint32 gWinEventMap[] = {
   EVENT_SYSTEM_DRAGDROPSTART,                        // nsIAccessibleEvent::EVENT_DRAGDROP_START
   EVENT_SYSTEM_DRAGDROPEND,                          // nsIAccessibleEvent::EVENT_DRAGDROP_END
   kEVENT_WIN_UNKNOWN,                                // nsIAccessibleEvent::EVENT_DIALOG_START
   kEVENT_WIN_UNKNOWN,                                // nsIAccessibleEvent::EVENT_DIALOG_END
   EVENT_SYSTEM_SCROLLINGSTART,                       // nsIAccessibleEvent::EVENT_SCROLLING_START
   EVENT_SYSTEM_SCROLLINGEND,                         // nsIAccessibleEvent::EVENT_SCROLLING_END
   kEVENT_WIN_UNKNOWN,                                // nsIAccessibleEvent::EVENT_MINIMIZE_START
   kEVENT_WIN_UNKNOWN,                                // nsIAccessibleEvent::EVENT_MINIMIZE_END
-  kEVENT_WIN_UNKNOWN,                                // nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_START
   IA2_EVENT_DOCUMENT_LOAD_COMPLETE,                  // nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE
   IA2_EVENT_DOCUMENT_RELOAD,                         // nsIAccessibleEvent::EVENT_DOCUMENT_RELOAD
   IA2_EVENT_DOCUMENT_LOAD_STOPPED,                   // nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED
   IA2_EVENT_DOCUMENT_ATTRIBUTE_CHANGED,              // nsIAccessibleEvent::EVENT_DOCUMENT_ATTRIBUTES_CHANGED
   IA2_EVENT_DOCUMENT_CONTENT_CHANGED,                // nsIAccessibleEvent::EVENT_DOCUMENT_CONTENT_CHANGED
   kEVENT_WIN_UNKNOWN,                                // nsIAccessibleEvent::EVENT_PROPERTY_CHANGED
   kEVENT_WIN_UNKNOWN,                                // nsIAccessibleEvent::EVENT_SELECTION_CHANGED
   IA2_EVENT_TEXT_ATTRIBUTE_CHANGED,                  // nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED
@@ -131,12 +130,11 @@ static const PRUint32 gWinEventMap[] = {
   IA2_EVENT_HYPERLINK_SELECTED_LINK_CHANGED,         // nsIAccessibleEvent::EVENT_HYPERLINK_SELECTED_LINK_CHANGED
   IA2_EVENT_HYPERTEXT_LINK_ACTIVATED,                // nsIAccessibleEvent::EVENT_HYPERTEXT_LINK_ACTIVATED
   IA2_EVENT_HYPERTEXT_LINK_SELECTED,                 // nsIAccessibleEvent::EVENT_HYPERTEXT_LINK_SELECTED
   IA2_EVENT_HYPERLINK_START_INDEX_CHANGED,           // nsIAccessibleEvent::EVENT_HYPERLINK_START_INDEX_CHANGED
   IA2_EVENT_HYPERTEXT_CHANGED,                       // nsIAccessibleEvent::EVENT_HYPERTEXT_CHANGED
   IA2_EVENT_HYPERTEXT_NLINKS_CHANGED,                // nsIAccessibleEvent::EVENT_HYPERTEXT_NLINKS_CHANGED
   IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED,                // nsIAccessibleEvent::EVENT_OBJECT_ATTRIBUTE_CHANGED
   IA2_EVENT_PAGE_CHANGED,                            // nsIAccessibleEvent::EVENT_PAGE_CHANGED
-  kEVENT_WIN_UNKNOWN,                                // nsIAccessibleEvent::EVENT_INTERNAL_LOAD
   kEVENT_LAST_ENTRY                                  // nsIAccessibleEvent::EVENT_LAST_ENTRY
 };
 
--- a/accessible/src/xul/nsXULComboboxAccessible.cpp
+++ b/accessible/src/xul/nsXULComboboxAccessible.cpp
@@ -36,16 +36,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 "nsXULComboboxAccessible.h"
 
 #include "nsAccessibilityService.h"
+#include "nsCoreUtils.h"
 
 #include "nsIDOMXULMenuListElement.h"
 #include "nsIDOMXULSelectCntrlItemEl.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULComboboxAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
--- a/accessible/tests/mochitest/common.js
+++ b/accessible/tests/mochitest/common.js
@@ -71,16 +71,17 @@ const STATE_PRESSED = nsIAccessibleState
 const STATE_READONLY = nsIAccessibleStates.STATE_READONLY;
 const STATE_REQUIRED = nsIAccessibleStates.STATE_REQUIRED;
 const STATE_SELECTABLE = nsIAccessibleStates.STATE_SELECTABLE;
 const STATE_SELECTED = nsIAccessibleStates.STATE_SELECTED;
 const STATE_TRAVERSED = nsIAccessibleStates.STATE_TRAVERSED;
 const STATE_UNAVAILABLE = nsIAccessibleStates.STATE_UNAVAILABLE;
 
 const EXT_STATE_ACTIVE = nsIAccessibleStates.EXT_STATE_ACTIVE;
+const EXT_STATE_DEFUNCT = nsIAccessibleStates.EXT_STATE_DEFUNCT;
 const EXT_STATE_EDITABLE = nsIAccessibleStates.EXT_STATE_EDITABLE;
 const EXT_STATE_EXPANDABLE = nsIAccessibleStates.EXT_STATE_EXPANDABLE;
 const EXT_STATE_HORIZONTAL = nsIAccessibleStates.EXT_STATE_HORIZONTAL;
 const EXT_STATE_MULTI_LINE = nsIAccessibleStates.EXT_STATE_MULTI_LINE;
 const EXT_STATE_SINGLE_LINE = nsIAccessibleStates.EXT_STATE_SINGLE_LINE;
 const EXT_STATE_SUPPORTS_AUTOCOMPLETION = 
       nsIAccessibleStates.EXT_STATE_SUPPORTS_AUTOCOMPLETION;
 const EXT_STATE_VERTICAL = nsIAccessibleStates.EXT_STATE_VERTICAL;
@@ -515,21 +516,24 @@ function relationTypeToString(aRelationT
 
 /**
  * Return pretty name for identifier, it may be ID, DOM node or accessible.
  */
 function prettyName(aIdentifier)
 {
   if (aIdentifier instanceof nsIAccessible) {
     var acc = getAccessible(aIdentifier, [nsIAccessNode]);
-    var msg = "[" + getNodePrettyName(acc.DOMNode) +
-      ", role: " + roleToString(acc.role);
-
-    if (acc.name)
-      msg += ", name: '" + acc.name + "'"
+    var msg = "[" + getNodePrettyName(acc.DOMNode);
+    try {
+      msg += ", role: " + roleToString(acc.role);
+      if (acc.name)
+        msg += ", name: '" + acc.name + "'";
+    } catch (e) {
+      msg += "defunct";
+    }
     msg += "]";
 
     return msg;
   }
 
   if (aIdentifier instanceof nsIDOMNode)
     return getNodePrettyName(aIdentifier);
 
--- a/accessible/tests/mochitest/events.js
+++ b/accessible/tests/mochitest/events.js
@@ -1,12 +1,14 @@
 ////////////////////////////////////////////////////////////////////////////////
 // Constants
 
 const EVENT_DOCUMENT_LOAD_COMPLETE = nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE;
+const EVENT_DOCUMENT_RELOAD = nsIAccessibleEvent.EVENT_DOCUMENT_RELOAD;
+const EVENT_DOCUMENT_LOAD_STOPPED = nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_STOPPED;
 const EVENT_HIDE = nsIAccessibleEvent.EVENT_HIDE;
 const EVENT_FOCUS = nsIAccessibleEvent.EVENT_FOCUS;
 const EVENT_NAME_CHANGE = nsIAccessibleEvent.EVENT_NAME_CHANGE;
 const EVENT_REORDER = nsIAccessibleEvent.EVENT_REORDER;
 const EVENT_SCROLLING_START = nsIAccessibleEvent.EVENT_SCROLLING_START;
 const EVENT_SHOW = nsIAccessibleEvent.EVENT_SHOW;
 const EVENT_STATE_CHANGE = nsIAccessibleEvent.EVENT_STATE_CHANGE;
 const EVENT_TEXT_CARET_MOVED = nsIAccessibleEvent.EVENT_TEXT_CARET_MOVED;
@@ -116,16 +118,19 @@ const DO_NOT_FINISH_TEST = 1;
  *   var invoker = {
  *     // Generates accessible event or event sequence. If returns
  *     // INVOKER_ACTION_FAILED constant then stop tests.
  *     invoke: function(){},
  *
  *     // [optional] Invoker's check of handled event for correctness.
  *     check: function(aEvent){},
  *
+ *     // [optional] Invoker's check before the next invoker is proceeded.
+ *     finalCheck: function(aEvent){},
+ *
  *     // [optional] Is called when event of registered type is handled.
  *     debugCheck: function(aEvent){},
  *
  *     // [ignored if 'eventSeq' is defined] DOM node event is generated for
  *     // (used in the case when invoker expects single event).
  *     DOMNode getter: function() {},
  *
  *     // Array of checker objects defining expected events on invoker's action.
@@ -503,22 +508,48 @@ function eventQueue(aEventType)
       var info = "Event type: " + aOrigEvent.type;
       info += ". Target: " + prettyName(aOrigEvent.originalTarget);
       dumpInfoToDOM(info);
     }
 
     var currType = this.getEventType(aExpectedEventIdx);
     var currTarget = this.getEventTarget(aExpectedEventIdx);
 
-    var info = "EQ: " + (aMatch ? "matched" : "expected") + " event, type: ";
+    var containerTagName = document instanceof nsIDOMHTMLDocument ?
+      "div" : "description";
+    var inlineTagName = document instanceof nsIDOMHTMLDocument ?
+      "span" : "description";
+
+    var container = document.createElement(containerTagName);
+    container.setAttribute("style", "padding-left: 10px;");
+
+    var text1 = document.createTextNode("EQ: ");
+    container.appendChild(text1);
+
+    var styledNode = document.createElement(inlineTagName);
+    if (aMatch) {
+      styledNode.setAttribute("style", "color: blue;");
+      styledNode.textContent = "matched";
+
+      // Dump matched events into console.
+      dump("\n*****\nEQ matched: " + eventTypeToString(currType) + "\n*****\n");
+    } else {
+      styledNode.textContent = "expected";
+    }
+    container.appendChild(styledNode);
+
+    var info = " event, type: ";
     info += (typeof currType == "string") ?
       currType : eventTypeToString(currType);
     info += ". Target: " + prettyName(currTarget);
 
-    dumpInfoToDOM(info);
+    var text1 = document.createTextNode(info);
+    container.appendChild(text1);
+
+    dumpInfoToDOM(container);
   }
 
   this.mDefEventType = aEventType;
 
   this.mInvokers = new Array();
   this.mIndex = -1;
 
   this.mEventSeq = null;
@@ -782,20 +813,40 @@ function synthSelectAll(aNodeOrID, aChec
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // Event queue checkers
 
 /**
  * Common invoker checker (see eventSeq of eventQueue).
  */
-function invokerChecker(aEventType, aTarget)
+function invokerChecker(aEventType, aTargetOrFunc, aTargetFuncArg)
 {
   this.type = aEventType;
-  this.target = aTarget;
+
+  this.__defineGetter__("target", invokerChecker_targetGetter);
+  this.__defineSetter__("target", invokerChecker_targetSetter);
+
+  // implementation details
+  function invokerChecker_targetGetter()
+  {
+    if (typeof this.mTarget == "function")
+      return this.mTarget.call(null, this.mTargetFuncArg);
+
+    return this.mTarget;
+  }
+
+  function invokerChecker_targetSetter(aValue)
+  {
+    this.mTarget = aValue;
+    return this.mTarget;
+  }
+
+  this.mTarget = aTargetOrFunc;
+  this.mTargetFuncArg = aTargetFuncArg;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // Private implementation details.
 ////////////////////////////////////////////////////////////////////////////////
 
 
@@ -825,37 +876,42 @@ var gA11yEventObserver =
       // After a test is aborted (i.e. timed out by the harness), this exception is soon triggered.
       // Remove the leftover observer, otherwise it "leaks" to all the following tests.
       this.observerService.removeObserver(this, "accessible-event");
       // Forward the exception, with added explanation.
       throw "[accessible/events.js, gA11yEventObserver.observe] This is expected if a previous test has been aborted... Initial exception was: [ " + ex + " ]";
     }
     var listenersArray = gA11yEventListeners[event.eventType];
 
+    var eventFromDumpArea = false;
     if (gA11yEventDumpID) { // debug stuff
+      eventFromDumpArea = true;
+
       var target = event.DOMNode;
       var dumpElm = document.getElementById(gA11yEventDumpID);
 
       var parent = target;
       while (parent && parent != dumpElm)
         parent = parent.parentNode;
 
       if (parent != dumpElm) {
         var type = eventTypeToString(event.eventType);
         var info = "Event type: " + type;
         info += ". Target: " + prettyName(event.accessible);
 
         if (listenersArray)
           info += ". Listeners count: " + listenersArray.length;
 
+        eventFromDumpArea = false;
         dumpInfoToDOM(info);
       }
     }
 
-    if (!listenersArray)
+    // Do not notify listeners if event is result of event log changes.
+    if (!listenersArray || eventFromDumpArea)
       return;
 
     for (var index = 0; index < listenersArray.length; index++)
       listenersArray[index].handleEvent(event);
   }
 };
 
 function listenA11yEvents(aStartToListen)
@@ -900,37 +956,41 @@ function removeA11yEventListener(aEventT
   }
 
   return true;
 }
 
 /**
  * Dumps message to DOM.
  *
- * @param aInfo      [in] the message to dump
+ * @param aInfo      [in] the message or DOM node to dump
  * @param aDumpNode  [in, optional] host DOM node for dumped message, if ommited
  *                    then global variable gA11yEventDumpID is used
  */
 function dumpInfoToDOM(aInfo, aDumpNode)
 {
   var dumpID = gA11yEventDumpID ? gA11yEventDumpID : aDumpNode;
   if (!dumpID)
     return;
-
+  
   var dumpElm = document.getElementById(dumpID);
   if (!dumpElm) {
     ok(false, "No dump element '" + dumpID + "' within the document!");
     return;
   }
-
+  
   var containerTagName = document instanceof nsIDOMHTMLDocument ?
     "div" : "description";
-  var container = document.createElement(containerTagName);
 
-  container.textContent = aInfo;
+  var container = document.createElement(containerTagName);
+  if (aInfo instanceof nsIDOMNode)
+    container.appendChild(aInfo);
+  else
+    container.textContent = aInfo;
+
   dumpElm.appendChild(container);
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // Sequence
 
 /**
--- a/accessible/tests/mochitest/events/Makefile.in
+++ b/accessible/tests/mochitest/events/Makefile.in
@@ -41,23 +41,25 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = accessible/events
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES =\
+		docload_wnd.xul \
 		focus.html \
 		scroll.html \
 		test_aria_statechange.html \
 		test_attrs.html \
 		test_caretmove.html \
 	$(warning	test_coalescence.html temporarily disabled) \
-		test_doc.html \
+		test_docload.html \
+		test_docload.xul \
 		test_dragndrop.html \
 		test_flush.html \
 		test_focus.html \
 		test_focus.xul \
 		test_focus_name.html \
 		test_focusdoc.html \
 		test_mutation.html \
 		test_scroll.xul \
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/events/docload_wnd.xul
@@ -0,0 +1,258 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+
+<!-- Firefox tabbrowser -->
+<?xml-stylesheet href="chrome://browser/content/browser.css"
+                 type="text/css"?>
+<!-- Seamonkey tabbrowser -->
+<?xml-stylesheet href="chrome://navigator/content/navigator.css"
+                 type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+  <script type="application/javascript">
+  <![CDATA[
+    ////////////////////////////////////////////////////////////////////////////
+    // SimpleTest stuffs
+
+    var gOpenerWnd = window.opener.wrappedJSObject;
+
+    function ok(aCond, aMsg) {
+      gOpenerWnd.SimpleTest.ok(aCond, aMsg);
+    }
+
+    function is(aExpected, aActual, aMsg) {
+      gOpenerWnd.SimpleTest.is(aExpected, aActual, aMsg);
+    }
+
+    var invokerChecker = gOpenerWnd.invokerChecker;
+
+    const STATE_BUSY = gOpenerWnd.STATE_BUSY;
+    const EVENT_DOCUMENT_LOAD_COMPLETE =
+      gOpenerWnd.EVENT_DOCUMENT_LOAD_COMPLETE;
+    const EVENT_DOCUMENT_RELOAD = gOpenerWnd.EVENT_DOCUMENT_RELOAD;
+    const EVENT_DOCUMENT_LOAD_STOPPED =
+      gOpenerWnd.EVENT_DOCUMENT_LOAD_STOPPED;
+    const EVENT_REORDER = gOpenerWnd.EVENT_REORDER;
+    const EVENT_STATE_CHANGE = gOpenerWnd.EVENT_STATE_CHANGE;
+    const nsIAccessibleStateChangeEvent =
+      gOpenerWnd.nsIAccessibleStateChangeEvent;
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Hacks to make xul:tabbrowser work.
+
+    var handleDroppedLink = null; // needed for tabbrowser usage
+
+    Components.utils.import("resource://gre/modules/Services.jsm");
+    var XULBrowserWindow = {
+      isBusy: false,
+      setOverLink: function (link, b) {
+      }
+    };
+
+    gFindBarInitialized = false;
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Helpers.
+
+    function getContainer()
+    {
+      var idx = gTabBrowser.tabContainer.selectedIndex;
+      return gTabBrowser.getBrowserAtIndex(idx);
+    }
+
+    function getDocument()
+    {
+      return getContainer().contentDocument;
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Invoker checkers.
+    function stateBusyChecker(aIsEnabled)
+    {
+      this.type = EVENT_STATE_CHANGE;
+      this.__defineGetter__("target", getDocument);
+
+      this.check = function stateBusyChecker_check(aEvent)
+      {
+        var event = null;
+        try {
+          var event = aEvent.QueryInterface(nsIAccessibleStateChangeEvent);
+        } catch (e) {
+          ok(false, "State change event was expected");
+        }
+
+        if (!event)
+          return;
+
+        is(event.state, STATE_BUSY, "Wrong state of statechange event.");
+        is(event.isEnabled(), aIsEnabled,
+           "Wrong value of state of statechange event");
+      }
+    }
+
+    function documentReloadChecker(aIsFromUserInput)
+    {
+      this.type = EVENT_DOCUMENT_RELOAD;
+      this.__defineGetter__("target", getDocument);
+
+      this.check = function documentReloadChecker_check(aEvent)
+      {
+        is(aEvent.isFromUserInput, aIsFromUserInput,
+           "Wrong value of isFromUserInput");
+      }
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Invokers.
+
+    /**
+     * Load URI.
+     */
+    function loadURIInvoker(aURI)
+    {
+      this.invoke = function loadURIInvoker_invoke()
+      {
+        gTabBrowser.loadURI(aURI);
+      }
+
+      this.eventSeq = [
+        // We don't expect state change event for busy true since things happen
+        // quickly and it's coalesced.
+        new invokerChecker(EVENT_REORDER, getContainer),
+        new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, getDocument),
+        new stateBusyChecker(false)
+      ];
+
+      this.getID = function loadURIInvoker_getID()
+      {
+        return "load uri " + aURI;
+      }
+    }
+
+    /**
+     * Click reload page button.
+     */
+    function clickReloadBtnInvoker()
+    {
+      this.invoke = function clickReloadBtnInvoker_invoke()
+      {
+        synthesizeMouse(document.getElementById("reloadbtn"), 5, 5, {});
+      }
+
+      this.eventSeq = [
+        new documentReloadChecker(true),
+        new invokerChecker(EVENT_REORDER, getContainer),
+        new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, getDocument),
+        new stateBusyChecker(false)
+      ];
+
+      this.getID = function reloadInvoker_getID()
+      {
+        return "click reload page button";
+      }
+    }
+
+    /**
+     * Reload the page.
+     */
+    function reloadInvoker()
+    {
+      this.invoke = function reloadInvoker_invoke()
+      {
+        gTabBrowser.reload();
+      }
+
+      this.eventSeq = [
+        new documentReloadChecker(false),
+        new invokerChecker(EVENT_REORDER, getContainer),
+        new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, getDocument),
+        new stateBusyChecker(false)
+      ];
+
+      this.getID = function reloadInvoker_getID()
+      {
+        return "reload page";
+      }
+    }
+
+    /**
+     * Load wrong URI what results in error page loading.
+     */
+    function loadErrorPageInvoker()
+    {
+      this.invoke = function loadErrorPageInvoker_invoke()
+      {
+        gTabBrowser.loadURI("www.wronguri.wronguri");
+      }
+
+      this.eventSeq = [
+        // We don't expect state change for busy true, load stopped events since
+        // things happen quickly and it's coalesced.
+        new invokerChecker(EVENT_REORDER, getContainer),
+        new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, getDocument),
+        new stateBusyChecker(false)
+      ];
+
+      this.getID = function loadErrorPageInvoker_getID()
+      {
+        return "load error page";
+      }
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Tests
+
+    var gQueue = null;
+
+    const Ci = Components.interfaces;
+
+    var gTabBrowser = null;
+    function doTest()
+    {
+      gTabBrowser = document.getElementById("content");
+
+      gQueue = new gOpenerWnd.eventQueue();
+      gQueue.push(new loadURIInvoker("about:robots"));
+      gQueue.push(new clickReloadBtnInvoker());
+      gQueue.push(new loadURIInvoker("about:mozilla"));
+      gQueue.push(new reloadInvoker());
+      gQueue.push(new loadErrorPageInvoker());
+      gQueue.onFinish = function() { window.close(); }
+      gQueue.invoke();
+    }
+
+    gOpenerWnd.addA11yLoadEvent(doTest);
+  ]]>
+  </script>
+
+  <!-- Hack to make xul:tabbrowser work -->
+  <menubar>
+    <menu label="menu">
+      <menupopup>
+        <menuitem label="close window hook" id="menu_closeWindow"/>
+        <menuitem label="close hook" id="menu_close"/>
+      </menupopup>
+    </menu>
+  </menubar>
+
+  <button id="reloadbtn" label="reload page"
+          oncommand="gTabBrowser.reload();"/>
+
+  <toolbar>
+    <tabs id="tabbrowser-tabs" class="tabbrowser-tabs"
+          tabbrowser="content"
+          flex="1"
+          setfocus="false">
+      <tab class="tabbrowser-tab" selected="true"/>
+    </tabs>
+  </toolbar>
+  <tabbrowser id="content"
+              type="content-primary"
+              tabcontainer="tabbrowser-tabs"
+              flex="1"/>
+
+</window>
rename from accessible/tests/mochitest/events/test_doc.html
rename to accessible/tests/mochitest/events/test_docload.html
--- a/accessible/tests/mochitest/events/test_doc.html
+++ b/accessible/tests/mochitest/events/test_docload.html
@@ -11,16 +11,18 @@
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
 
   <script type="application/javascript"
           src="chrome://mochikit/content/a11y/accessible/common.js"></script>
   <script type="application/javascript"
           src="chrome://mochikit/content/a11y/accessible/role.js"></script>
   <script type="application/javascript"
+          src="chrome://mochikit/content/a11y/accessible/states.js"></script>
+  <script type="application/javascript"
           src="chrome://mochikit/content/a11y/accessible/events.js"></script>
 
   <script type="application/javascript">
     ////////////////////////////////////////////////////////////////////////////
     // Invokers
 
     function changeIframeSrc(aIdentifier, aURL)
     {
@@ -30,22 +32,97 @@
         new invokerChecker(EVENT_REORDER, getAccessible(this.DOMNode))
       ];
 
       this.invoke = function changeIframeSrc_invoke()
       {
         this.DOMNode.src = aURL;
       }
 
+      this.finalCheck = function changeIframeSrc_finalCheck()
+      {
+        var accTree = {
+          role: ROLE_INTERNAL_FRAME,
+          children: [
+            {
+              role: ROLE_DOCUMENT,
+              name: aURL == "about:" ? "About:" : aURL
+            }
+          ]
+        };
+
+        testAccessibleTree(this.DOMNode, accTree);
+      }
+
       this.getID = function changeIframeSrc_getID()
       {
         return "change iframe src on " + aURL;
       }
     }
 
+    const kHide = 1;
+    const kShow = 2;
+    const kRemove = 3;
+    function morphIFrame(aIdentifier, aAction)
+    {
+      this.DOMNode = getNode(aIdentifier);
+      this.IFrameContainerDOMNode = this.DOMNode.parentNode;
+
+      this.eventSeq = [];
+
+      var checker = null;
+      if (aAction == kShow)
+        checker = new invokerChecker(EVENT_SHOW, this.DOMNode);
+      else
+        checker = new invokerChecker(EVENT_HIDE, this.DOMNode);
+      this.eventSeq.push(checker);
+
+      var reorderChecker =
+        new invokerChecker(EVENT_REORDER, this.IFrameContainerDOMNode);
+      this.eventSeq.push(reorderChecker);
+
+      this.invoke = function morphIFrame_invoke()
+      {
+        if (aAction == kHide) {
+          this.DOMNode.style.display = "none";
+        } else if (aAction == kShow) {
+          this.DOMNode.style.display = "block";
+        } else {
+          this.IFrameContainerDOMNode.removeChild(this.DOMNode);
+        }
+      }
+
+      this.finalCheck = function morphIFrame_finalCheck()
+      {
+        var accTree = {
+          role: ROLE_SECTION,
+          children: (aAction == kHide || aAction == kRemove) ? [ ] :
+            [
+              {
+                role: ROLE_INTERNAL_FRAME,
+                children: [
+                  { role: ROLE_DOCUMENT }
+                ]
+              }
+            ]
+        };
+
+        testAccessibleTree(this.IFrameContainerDOMNode, accTree);
+      }
+
+      this.getID = function morphIFrame_getID()
+      {
+        if (aAction == kRemove)
+          return "remove iframe";
+
+        return "change display style of iframe to " +
+          (aAction == kHide) ? "none" : "block";
+      }
+    }
+
     function openDialogWnd(aURL)
     {
       // Get application root accessible.
       var docAcc = getAccessible(document);
       while (docAcc) {
         this.mRootAcc = docAcc;
         try {
           docAcc = docAcc.parent;
@@ -59,17 +136,17 @@
         new invokerChecker(EVENT_REORDER, this.mRootAcc)
       ];
 
       this.invoke = function openDialogWnd_invoke()
       {
         this.mDialog = window.openDialog(aURL);
       }
 
-      this.check = function openDialogWnd_check()
+      this.finalCheck = function openDialogWnd_finalCheck()
       {
         var accTree = {
           role: ROLE_APP_ROOT,
           children: [
             {
               role: ROLE_CHROME_WINDOW
             },
             {
@@ -97,42 +174,48 @@
     // var gA11yEventDumpID = "eventdump"; // debug stuff
 
     function doTests()
     {
       gQueue = new eventQueue();
 
       gQueue.push(new changeIframeSrc("iframe", "about:"));
       gQueue.push(new changeIframeSrc("iframe", "about:buildconfig"));
+      gQueue.push(new morphIFrame("iframe", kHide));
+      gQueue.push(new morphIFrame("iframe", kShow));
+      gQueue.push(new morphIFrame("iframe", kRemove));
       gQueue.push(new openDialogWnd("about:"));
 
       gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTests);
   </script>
 </head>
 
 <body>
 
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=420845"
      title="Fire event_reorder on any embedded frames/iframes whos document has just loaded">
     Mozilla Bug 420845
-  </a>
+  </a><br>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=506206"
      title="Fire event_reorder application root accessible">
     Mozilla Bug 506206
+  </a><br>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=566103"
+     title="Reorganize accessible document handling">
+    Mozilla Bug 566103
   </a>
 
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
-  <div id="testContainer">
-    <iframe id="iframe"></iframe>
-  </div>
+  <div id="testContainer"><iframe id="iframe"></iframe></div>
   <div id="eventdump"></div>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/events/test_docload.xul
@@ -0,0 +1,55 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+                 type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        title="Accessibility Loading Document Events Test.">
+
+  <script type="application/javascript" 
+          src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/a11y/accessible/common.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/a11y/accessible/role.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/a11y/accessible/events.js"></script>
+
+  <script type="application/javascript">
+  <![CDATA[
+    // var gA11yEventDumpID = "eventdump"; // debug stuff
+
+    function doTest()
+    {
+      var w = window.openDialog("chrome://mochikit/content/a11y/accessible/events/docload_wnd.xul",
+                                "docload_test",
+                                "chrome,width=600,height=600");
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addLoadEvent(doTest);
+  ]]>
+  </script>
+
+  <vbox flex="1" style="overflow: auto;">
+  <body xmlns="http://www.w3.org/1999/xhtml">
+    <a target="_blank"
+       href="https://bugzilla.mozilla.org/show_bug.cgi?id=566103"
+       title=" reorganize accessible document handling">
+      Mozilla Bug 566103
+    </a>
+    <p id="display"></p>
+    <div id="content" style="display: none">
+    </div>
+    <pre id="test">
+    </pre>
+  </body>
+
+  <vbox id="eventdump"></vbox>
+  </vbox>
+</window>