Merge review head draft
authorGregory Szorc <gps@mozilla.com>
Fri, 24 Mar 2017 14:03:09 -0700
changeset 534790 77bb2a9e378094547302c666f0d8a58c0291d5a1
parent 534789 944b9147da2eebc23dd22b41201cd112532330a2 (diff)
parent 428623 03d01ee1bfcbc0cd303a1a91a585d61ccdeae8c3 (current diff)
child 534791 1474f31ea3d57b71d173f241f2fb4118ad63d431
push id50942
push usergszorc@mozilla.com
push dateFri, 24 Mar 2017 21:06:28 +0000
milestone55.0a1
Merge review head
--- a/.clang-format
+++ b/.clang-format
@@ -1,4 +1,38 @@
 BasedOnStyle: Mozilla
 
 # Ignore all comments because they aren't reflowed properly.
 CommentPragmas: "^"
+
+# Force pointers to the type for C++.
+DerivePointerAlignment: false
+PointerAlignment: Left
+
+# Prevent the loss of indentation with these macros
+MacroBlockBegin: "^\
+NS_INTERFACE_MAP_BEGIN|\
+NS_INTERFACE_TABLE_HEAD|\
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION|\
+NS_IMPL_CYCLE_COLLECTION_.*_BEGIN|\
+NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED|\
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED|\
+NS_INTERFACE_TABLE_BEGIN|\
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED|\
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED$"
+MacroBlockEnd: "^\
+NS_INTERFACE_MAP_END|\
+NS_IMPL_CYCLE_COLLECTION_.*_END|\
+NS_INTERFACE_TABLE_END|\
+NS_INTERFACE_MAP_END_INHERITING|\
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END_INHERITED|\
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED$"
+
+SortIncludes: false
+
+
+# All of the following items are default
+# in the Mozila coding style from clang format 4.0
+AlwaysBreakAfterReturnType: TopLevel
+BinPackArguments: false
+BinPackParameters: false
+SpaceAfterTemplateKeyword: false
+ReflowComments: false
--- a/.clang-format-ignore
+++ b/.clang-format-ignore
@@ -1,3 +1,82 @@
-^mfbt/.*
-^js/.*
-^media/.*
+^build/clang-plugin/tests/.*
+^config/gcc-stl-wrapper.template.h
+^config/msvc-stl-wrapper.template.h
+^js/src/jsapi-tests/.*
+^widget/android/GeneratedJNINatives.h
+^widget/android/GeneratedJNIWrappers.cpp
+^widget/android/GeneratedJNIWrappers.h
+^widget/android/fennec/FennecJNINatives.h
+^widget/android/fennec/FennecJNIWrappers.cpp
+^widget/android/fennec/FennecJNIWrappers.h
+
+# Generated from ./tools/rewriting/ThirdPartyPaths.txt
+# awk '{print "^"$1".*"}' ./tools/rewriting/ThirdPartyPaths.txt
+^browser/components/translation/cld2/.*
+^build/stlport/.*
+^db/sqlite3/src/.*
+^dom/media/platforms/ffmpeg/libav.*
+^extensions/spellcheck/hunspell/src/.*
+^gfx/2d/convolver.*
+^gfx/2d/image_operations.*
+^gfx/angle/.*
+^gfx/cairo/.*
+^gfx/graphite2/.*
+^gfx/harfbuzz/.*
+^gfx/ots/.*
+^gfx/qcms/.*
+^gfx/skia/.*
+^gfx/webrender.*
+^gfx/webrender_traits.*
+^gfx/ycbcr/.*
+^intl/hyphenation/hyphen/.*
+^intl/icu/.*
+^ipc/chromium/.*
+^js/src/ctypes/libffi/.*
+^js/src/dtoa.c.*
+^js/src/jit/arm64/vixl/.*
+^media/gmp-clearkey/0.1/openaes/.*
+^media/kiss_fft/.*
+^media/ffvpx/.*
+^media/libav/.*
+^media/libcubeb/.*
+^media/libjpeg/.*
+^media/libmkv/.*
+^media/libnestegg/.*
+^media/libogg/.*
+^media/libopus/.*
+^media/libpng/.*
+^media/libsoundtouch/.*
+^media/libspeex_resampler/.*
+^media/libstagefright/.*
+^media/libtheora/.*
+^media/libtremor/.*
+^media/libvorbis/.*
+^media/libvpx/.*
+^media/libyuv/.*
+^media/mtransport/third_party/.*
+^media/openmax_dl/.*
+^media/pocketsphinx/.*
+^media/sphinxbase/.*
+^media/webrtc/trunk/.*
+^media/webrtc/signaling/src/sdp/sipcc/.*
+^memory/jemalloc/src/.*
+^mfbt/decimal/.*
+^mfbt/double-conversion/source/.*
+^mfbt/lz4.*
+^mobile/android/thirdparty/.*
+^modules/brotli/.*
+^modules/fdlibm/.*
+^modules/freetype2/.*
+^modules/libbz2/.*
+^modules/libmar/.*
+^modules/zlib/.*
+^netwerk/sctp/src/.*
+^netwerk/srtp/src/.*
+^nsprpub/.*
+^other-licenses/.*
+^parser/expat/.*
+^security/sandbox/chromium/.*
+^testing/gtest/gmock/.*
+^testing/gtest/gtest/.*
+^toolkit/components/protobuf/.*
+^toolkit/crashreporter/google-breakpad/.*
new file mode 100644
--- /dev/null
+++ b/.clang-tidy
@@ -0,0 +1,16 @@
+# Checks run by clang-tidy over Mozilla code.
+
+# The following checks are currently enabled:
+# * modernize-raw-string-literal -
+#     Replace string literals containing escaped characters with raw string literals
+# * modernize-use-bool-literals
+#     Replace integer literals which are cast to bool
+# * modernize-loop-convert
+#     Converts for(...; ...; ...) loops to use the new range-based loops in C++11
+# * modernize-use-default
+#     Replace default bodies of special member functions with = default;
+# * modernize-use-override
+#     Use C++11's override and remove virtual where applicable
+
+Checks:          '-*, modernize-raw-string-literal, modernize-use-bool-literals, modernize-loop-convert, modernize-use-default, modernize-use-override'
+
new file mode 100644
--- /dev/null
+++ b/.cron.yml
@@ -0,0 +1,61 @@
+# Definitions for jobs that run periodically.  For details on the format, see
+# `taskcluster/taskgraph/cron/schema.py`.  For documentation, see
+# `taskcluster/docs/cron.rst`.
+
+jobs:
+    - name: nightly-desktop
+      job:
+          type: decision-task
+          treeherder-symbol: Nd
+          triggered-by: nightly
+          target-tasks-method: nightly_linux
+      run-on-projects:
+          - mozilla-central
+          - mozilla-aurora
+          - date
+      when:
+          by-project:
+            # Match buildbot starts for now
+            date: [{hour: 16, minute: 0}]
+            mozilla-central: [{hour: 11, minute: 0}]
+            mozilla-aurora: [{hour: 8, minute: 45}]  # Buildbot uses minute 40
+            # No default
+
+    - name: nightly-android
+      job:
+          type: decision-task
+          treeherder-symbol: Na
+          triggered-by: nightly
+          target-tasks-method: nightly_fennec
+      run-on-projects:
+          - mozilla-central
+          - mozilla-aurora
+          - date
+      when:
+        by-project:
+            # Match buildbot starts for now
+            date: [{hour: 16, minute: 0}]
+            mozilla-central: [{hour: 11, minute: 0}]
+            mozilla-aurora: [{hour: 8, minute: 45}]  # Buildbot uses minute 40
+            # No default
+
+    - name: nightly-mochitest-valgrind
+      job:
+          type: decision-task
+          treeherder-symbol: Vg
+          target-tasks-method: mochitest_valgrind
+      run-on-projects:
+          - mozilla-central
+      when:
+          - {hour: 16, minute: 0}
+          - {hour: 4, minute: 0}
+
+    - name: nightly-code-coverage
+      job:
+          type: decision-task
+          treeherder-symbol: Nc
+          target-tasks-method: nightly_code_coverage
+      run-on-projects:
+          - mozilla-central
+      when:
+          - {hour: 18, minute: 0}
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,204 +1,267 @@
 # Always ignore node_modules.
 **/node_modules/**/*.*
 
 # Exclude expected objdirs.
 obj*/**
 
 # We ignore all these directories by default, until we get them enabled.
 # If you are enabling a directory, please add directory specific exclusions
-# below.
+# below.
 addon-sdk/**
 build/**
 caps/**
 chrome/**
 config/**
 db/**
 docshell/**
-dom/**
 editor/**
 embedding/**
 extensions/**
 gfx/**
 gradle/**
 hal/**
 image/**
 intl/**
 ipc/**
-js/**
 layout/**
 media/**
 memory/**
 mfbt/**
 modules/**
 mozglue/**
 netwerk/**
 nsprpub/**
 other-licenses/**
 parser/**
 probes/**
 python/**
 rdf/**
+servo/**
 startupcache/**
 testing/**
-!tools/lint/eslint/eslint-plugin-mozilla/
-tools/lint/eslint/eslint-plugin-mozilla/node_modules/**
-tools/**
+tools/update-packaging/**
 uriloader/**
 view/**
 widget/**
 xpcom/**
 xpfe/**
 xulrunner/**
 
 # b2g exclusions (pref files).
 b2g/app/b2g.js
 b2g/graphene/graphene.js
 b2g/locales/en-US/b2g-l10n.js
 
 # browser/ exclusions
 browser/app/**
-browser/base/content/browser-social.js
+browser/branding/**/firefox-branding.js
 browser/base/content/nsContextMenu.js
 browser/base/content/sanitizeDialog.js
 browser/base/content/test/general/file_csp_block_all_mixedcontent.html
 browser/base/content/test/urlbar/file_blank_but_not_blank.html
 browser/base/content/newtab/**
 browser/components/downloads/**
-browser/components/feeds/**
-browser/components/privatebrowsing/**
-browser/components/sessionstore/**
+# Test files that are really json not js, and don't need to be linted.
+browser/components/sessionstore/test/unit/data/sessionstore_valid.js
+browser/components/sessionstore/test/unit/data/sessionstore_invalid.js
 browser/components/tabview/**
-browser/components/translation/**
-# generated files in cld2
-browser/components/translation/cld2/cld-worker.js
-browser/extensions/pdfjs/**
+# generated & special files in cld2
+browser/components/translation/cld2/**
+browser/extensions/pdfjs/content/build**
+browser/extensions/pdfjs/content/web**
 # generated or library files in pocket
 browser/extensions/pocket/content/panels/js/tmpl.js
 browser/extensions/pocket/content/panels/js/vendor/**
 browser/locales/**
+# imported from chromium
+browser/extensions/mortar/**
 
 # devtools/ exclusions
 devtools/client/canvasdebugger/**
 devtools/client/commandline/**
 devtools/client/debugger/**
-devtools/client/eyedropper/**
 devtools/client/framework/**
 !devtools/client/framework/selection.js
-!devtools/client/framework/toolbox.js
-devtools/client/jsonview/lib/**
-devtools/client/memory/**
-devtools/client/netmonitor/test/**
-devtools/client/netmonitor/har/test/**
+!devtools/client/framework/target*
+!devtools/client/framework/toolbox*
+devtools/client/inspector/markup/test/doc_markup_events_*.html
+devtools/client/inspector/rules/test/doc_media_queries.html
+devtools/client/memory/test/chrome/*.html
+devtools/client/performance/components/test/test_jit_optimizations_01.html
 devtools/client/projecteditor/**
-devtools/client/promisedebugger/**
+devtools/client/responsive.html/test/browser/touch.html
 devtools/client/responsivedesign/**
+!devtools/client/responsivedesign/responsivedesign.jsm
 devtools/client/scratchpad/**
 devtools/client/shadereditor/**
 devtools/client/shared/*.jsm
+devtools/client/shared/components/reps/reps.js
+devtools/client/shared/components/reps/test/mochitest/*.html
+!devtools/client/shared/components/reps/test/mochitest/test_reps_infinity.html
+!devtools/client/shared/components/reps/test/mochitest/test_reps_nan.html
+!devtools/client/shared/components/reps/test/mochitest/test_reps_promise.html
+!devtools/client/shared/components/reps/test/mochitest/test_reps_symbol.html
+!devtools/client/shared/components/reps/test/mochitest/test_reps_text-node.html
+devtools/client/shared/components/test/mochitest/*.html
+!devtools/client/shared/components/test/mochitest/test_stack-trace.html
+devtools/client/shared/shim/test/test_*.html
+devtools/client/shared/test/browser_toolbar_webconsole_errors_count.html
 devtools/client/shared/webgl-utils.js
-devtools/client/shared/developer-toolbar.js
-devtools/client/shared/components/test/**
-devtools/client/shared/redux/middleware/test/**
-devtools/client/shared/test/**
-!devtools/client/shared/test/test-actor-registry.js
 devtools/client/shared/widgets/*.jsm
-devtools/client/sourceeditor/test/*.js
+devtools/client/storage/test/*.html
+!devtools/client/storage/test/storage-cookies.html
+!devtools/client/storage/test/storage-overflow.html
+!devtools/client/storage/test/storage-search.html
+!devtools/client/storage/test/storage-unsecured-iframe.html
+!devtools/client/storage/test/storage-unsecured-iframe-usercontextid.html
 devtools/client/webaudioeditor/**
-devtools/client/webconsole/**
-!devtools/client/webconsole/panel.js
-!devtools/client/webconsole/jsterm.js
-!devtools/client/webconsole/console-commands.js
+devtools/client/webconsole/net/**
+devtools/client/webconsole/test/**
+devtools/client/webconsole/console-output.js
+devtools/client/webconsole/hudservice.js
+devtools/client/webconsole/webconsole-connection-proxy.js
+devtools/client/webconsole/webconsole.js
 devtools/client/webide/**
 !devtools/client/webide/components/webideCli.js
-devtools/server/*.js
-devtools/server/*.jsm
-!devtools/server/child.js
-!devtools/server/css-logic.js
-!devtools/server/main.js
-!devtools/server/websocket-server.js
-devtools/server/actors/**
-!devtools/server/actors/inspector.js
-!devtools/server/actors/highlighters/css-grid.js
-!devtools/server/actors/highlighters/eye-dropper.js
-!devtools/server/actors/webbrowser.js
-!devtools/server/actors/webextension.js
-!devtools/server/actors/styles.js
-!devtools/server/actors/string.js
-!devtools/server/actors/csscoverage.js
-devtools/server/performance/**
-devtools/server/tests/**
-devtools/shared/*.js
-!devtools/shared/async-storage.js
-!devtools/shared/async-utils.js
-!devtools/shared/defer.js
-!devtools/shared/event-emitter.js
-!devtools/shared/indentation.js
-!devtools/shared/loader-plugin-raw.jsm
-!devtools/shared/task.js
-devtools/shared/*.jsm
-!devtools/shared/Loader.jsm
-devtools/shared/apps/**
-devtools/shared/client/**
-devtools/shared/discovery/**
-devtools/shared/gcli/**
-!devtools/shared/gcli/templater.js
-devtools/shared/heapsnapshot/**
-devtools/shared/layout/**
-devtools/shared/locales/**
-devtools/shared/performance/**
-!devtools/shared/platform/**
-devtools/shared/qrcode/**
-devtools/shared/security/**
-devtools/shared/shims/**
-devtools/shared/tests/**
-!devtools/shared/tests/unit/test_csslexer.js
-devtools/shared/touch/**
-devtools/shared/transport/**
-!devtools/shared/transport/transport.js
-!devtools/shared/transport/websocket-transport.js
-devtools/shared/webconsole/test/**
-devtools/shared/worker/**
-!devtools/shared/worker/worker.js
+devtools/server/actors/webconsole.js
+devtools/server/actors/object.js
+devtools/server/actors/script.js
+devtools/server/actors/styleeditor.js
+devtools/server/actors/stylesheets.js
+devtools/server/tests/browser/storage-*.html
+!devtools/server/tests/browser/storage-unsecured-iframe.html
+devtools/server/tests/browser/stylesheets-nested-iframes.html
+devtools/server/tests/unit/xpcshell_debugging_script.js
+devtools/shared/platform/content/test/test_clipboard.html
+devtools/shared/qrcode/tests/mochitest/test_decode.html
+devtools/shared/tests/mochitest/*.html
+devtools/shared/webconsole/test/test_*.html
 
 # Ignore devtools pre-processed files
 devtools/client/framework/toolbox-process-window.js
 devtools/client/performance/system.js
 devtools/client/webide/webide-prefs.js
 devtools/client/preferences/**
 
 # Ignore devtools third-party libs
 devtools/shared/jsbeautify/*
 devtools/shared/acorn/*
-devtools/client/sourceeditor/tern/*
+devtools/shared/gcli/source/*
 devtools/shared/node-properties/*
 devtools/shared/pretty-fast/*
 devtools/shared/sourcemap/*
 devtools/shared/sprintfjs/*
 devtools/shared/qrcode/decoder/*
 devtools/shared/qrcode/encoder/*
 devtools/client/shared/demangle.js
+devtools/client/shared/source-map/*
 devtools/client/shared/vendor/*
 devtools/client/sourceeditor/codemirror/*.js
 devtools/client/sourceeditor/codemirror/**/*.js
+devtools/client/sourceeditor/tern/*
+devtools/client/sourceeditor/test/cm_mode_ruby.js
 devtools/client/sourceeditor/test/codemirror/*
 devtools/client/inspector/markup/test/lib_*
 devtools/client/jsonview/lib/require.js
 devtools/server/actors/utils/automation-timeline.js
 
 # Ignore devtools files testing sourcemaps / code style
 devtools/client/debugger/test/mochitest/code_binary_search.js
 devtools/client/debugger/test/mochitest/code_math.min.js
 devtools/client/debugger/test/mochitest/code_math_bogus_map.js
 devtools/client/debugger/test/mochitest/code_ugly*
 devtools/client/debugger/test/mochitest/code_worker-source-map.js
 devtools/client/framework/test/code_ugly*
 devtools/server/tests/unit/babel_and_browserify_script_with_source_map.js
 devtools/server/tests/unit/setBreakpoint*
+devtools/server/tests/unit/sourcemapped.js
+
+# dom/ exclusions
+dom/animation/**
+dom/archivereader/**
+dom/asmjscache/**
+dom/audiochannel/**
+dom/base/**
+dom/battery/**
+dom/bindings/**
+dom/broadcastchannel/**
+dom/browser-element/**
+dom/cache/**
+dom/canvas/**
+dom/commandhandler/**
+dom/console/**
+dom/crypto/**
+dom/devicestorage/**
+dom/encoding/**
+dom/events/**
+dom/fetch/**
+dom/file/**
+dom/filehandle/**
+dom/filesystem/**
+dom/flyweb/**
+dom/gamepad/**
+dom/geolocation/**
+dom/grid/**
+dom/html/**
+dom/imptests/**
+dom/interfaces/**
+dom/ipc/**
+dom/json/**
+dom/jsurl/**
+dom/locales/**
+dom/manifest/**
+dom/mathml/**
+dom/media/**
+dom/messagechannel/**
+dom/network/**
+dom/notification/**
+dom/offline/**
+dom/performance/**
+dom/permission/**
+dom/plugins/**
+dom/power/**
+dom/presentation/**
+dom/promise/**
+dom/push/**
+dom/quota/**
+dom/res/**
+dom/secureelement/**
+dom/security/**
+dom/smil/**
+dom/storage/**
+dom/svg/**
+dom/system/**
+dom/tests/**
+dom/time/**
+dom/u2f/**
+dom/url/**
+dom/vr/**
+dom/webauthn/**
+dom/webbrowserpersist/**
+dom/webidl/**
+dom/workers/**
+dom/worklet/**
+dom/xbl/**
+dom/xhr/**
+dom/xml/**
+dom/xslt/**
+dom/xul/**
+
+# Exclude everything but self-hosted JS
+js/ductwork/**
+js/examples/**
+js/ipc/**
+js/public/**
+js/xpconnect/**
+js/src/devtools/**
+js/src/octane/**
+js/src/jit-test/**
+js/src/tests/**
 
 # mobile/android/ exclusions
 mobile/android/tests/
 
 # Uses `#filter substitution`
 mobile/android/b2gdroid/app/b2gdroid.js
 mobile/android/app/mobile.js
 mobile/android/chrome/content/healthreport-prefs.js
@@ -212,20 +275,32 @@ mobile/android/locales/
 
 # Non-standard `(catch ex if ...)`
 mobile/android/chrome/content/browser.js
 mobile/android/components/Snippets.js
 
 # Bug 1178739: Ignore this file as a quick fix for "Illegal yield expression"
 mobile/android/modules/HomeProvider.jsm
 
+# security/ exclusions (pref files).
+security/manager/ssl/security-prefs.js
+
+#NSS
+security/nss/**
+
 # services/ exclusions
 
 # Uses `#filter substitution`
 services/sync/modules/constants.js
+services/sync/services-sync.js
+
+# Third party services
+services/common/kinto-http-client.js
+services/common/kinto-offline-client.js
+services/sync/tps/extensions/mozmill
 
 # toolkit/ exclusions
 
 # Not part of the default build
 toolkit/components/help/**
 
 # Intentionally invalid JS
 toolkit/components/workerloader/tests/moduleF-syntax-error.js
@@ -233,29 +308,25 @@ toolkit/components/workerloader/tests/mo
 # Tests old non-star function generators
 toolkit/modules/tests/xpcshell/test_task.js
 
 # Not yet updated
 toolkit/components/osfile/**
 
 # External code:
 toolkit/components/microformats/test/**
+toolkit/components/microformats/microformat-shiv.js
 toolkit/components/reader/Readability.js
 toolkit/components/reader/JSDOMParser.js
 
 # Uses preprocessing
 toolkit/content/widgets/wizard.xml
 toolkit/components/jsdownloads/src/DownloadIntegration.jsm
-toolkit/components/search/nsSearchService.js
 toolkit/components/url-classifier/**
 toolkit/components/urlformatter/nsURLFormatter.js
-toolkit/identity/FirefoxAccounts.jsm
 toolkit/modules/AppConstants.jsm
 toolkit/mozapps/downloads/nsHelperAppDlg.js
 toolkit/mozapps/extensions/internal/AddonConstants.jsm
 toolkit/mozapps/update/tests/data/xpcshellConstantsPP.js
 toolkit/webapps/**
 
 # Third party
 toolkit/modules/third_party/**
-
-#NSS
-security/nss/**
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -1,14 +1,27 @@
 "use strict";
 
 module.exports = {
   // When adding items to this file please check for effects on sub-directories.
   "plugins": [
     "mozilla"
   ],
   "rules": {
-    "mozilla/import-globals": 1,
+    "mozilla/avoid-removeChild": "error",
+    "mozilla/avoid-nsISupportsString-preferences": "error",
+    "mozilla/import-globals": "warn",
+    "mozilla/no-import-into-var-and-global": "error",
+    "mozilla/no-useless-parameters": "error",
+    "mozilla/no-useless-removeEventListener": "error",
+    "mozilla/use-default-preference-values": "error",
+    "mozilla/use-ownerGlobal": "error",
+
+    // No (!foo in bar) or (!object instanceof Class)
+    "no-unsafe-negation": "error",
   },
   "env": {
     "es6": true
   },
+  "parserOptions": {
+    "ecmaVersion": 8,
+  },
 };
--- a/.flake8
+++ b/.flake8
@@ -1,5 +1,5 @@
 [flake8]
 # See http://pep8.readthedocs.io/en/latest/intro.html#configuration
-ignore = E121, E123, E126, E133, E226, E241, E242, E704, W503, E402
+ignore = E121, E123, E126, E129, E133, E226, E241, E242, E704, W503, E402
 max-line-length = 99
 filename = *.py, +.lint
--- a/.gdbinit
+++ b/.gdbinit
@@ -11,16 +11,17 @@ handle SIG32 noprint nostop pass
 handle SIG33 noprint nostop pass
 handle SIGPIPE noprint nostop pass
 
 # Don't stop for certain other signals where it's not useful,
 # such as the SIG64 signals triggered by the Linux
 # sandboxing code on older kernels.
 handle SIG38 noprint nostop pass
 handle SIG64 noprint nostop pass
+handle SIGSYS noprint nostop pass
 
 # Show the concrete types behind nsIFoo
 set print object on
 
 # run when using the auto-solib-add trick
 def prun
         tbreak main
         run
--- a/.hgignore
+++ b/.hgignore
@@ -39,16 +39,18 @@
 
 # SpiderMonkey configury
 ^js/src/configure$
 ^js/src/old-configure$
 ^js/src/autom4te.cache$
 # SpiderMonkey test result logs
 ^js/src/tests/results-.*\.(html|txt)$
 ^js/src/devtools/rootAnalysis/t/out
+# SpiderMonkey clone of the webassembly spec repository
+^js/src/wasm/spec
 
 # Java HTML5 parser classes
 ^parser/html/java/(html|java)parser/
 
 # SVN directories
 \.svn/
 
 # Ignore the files and directory that Eclipse IDE creates
@@ -110,25 +112,30 @@ GPATH
 # Ignore tox generated dir
 .tox/
 
 # Ignore node_modules
 ^tools/lint/eslint/node_modules/
 
 # Ignore talos virtualenv and tp5n files.
 # The tp5n set is supposed to be decompressed at
-# testing/talos/talos/page_load_test/tp5n in order to run tests like tps
+# testing/talos/talos/tests/tp5n in order to run tests like tps
 # locally. Similarly, running talos requires a Python package virtual
 # environment. Both the virtual environment and tp5n files end up littering
 # the status command, so we ignore them.
 ^testing/talos/.Python
 ^testing/talos/bin/
 ^testing/talos/include/
 ^testing/talos/lib/
 ^testing/talos/talos/tests/tp5n.zip
+^testing/talos/talos/tests/tp5n.tar.gz
 ^testing/talos/talos/tests/tp5n
 ^testing/talos/talos/tests/devtools/damp.manifest.develop
+^talos-venv
 
 # Ignore files created when running a reftest.
 ^lextab.py$
 
 # tup database
 ^\.tup
+
+subinclude:servo/.hgignore
+
--- a/.hgtags
+++ b/.hgtags
@@ -124,8 +124,11 @@ fcef8ded82219c89298b4e376cfbdfba79a1d35a
 67a788db9f07822cfef52351bbbe3745dff8bd7f FIREFOX_AURORA_44_BASE
 99137d6d4061f408ae0869122649d8bdf489cc30 FIREFOX_AURORA_45_BASE
 67c66c2878aed17ae3096d7db483ddbb2293c503 FIREFOX_AURORA_46_BASE
 68d3781deda0d4d58ec9877862830db89669b3a5 FIREFOX_AURORA_47_BASE
 1c6385ae1fe7e37d8f23f958ce14582f07af729e FIREFOX_AURORA_48_BASE
 d98f20c25feeac4dd7ebbd1c022957df1ef58af4 FIREFOX_AURORA_49_BASE
 465d150bc8be5bbf9f02a8607d4552b6a5e1697c FIREFOX_AURORA_50_BASE
 fc69febcbf6c0dcc4b3dfc7a346d8d348798a65f FIREFOX_AURORA_51_BASE
+1196bf3032e1bce1fb07a01fd9082a767426c5fb FIREFOX_AURORA_52_BASE
+f80dc9fc34680105b714a49b4704bb843f5f7004 FIREFOX_AURORA_53_BASE
+6583496f169cd8a13c531ed16e98e8bf313eda8e FIREFOX_AURORA_54_BASE
--- a/.taskcluster.yml
+++ b/.taskcluster.yml
@@ -8,33 +8,39 @@ metadata:
 
 scopes:
   # Note the below scopes are insecure however these get overriden on the server
   # side to whatever scopes are set by mozilla-taskcluster.
   - queue:*
   - docker-worker:*
   - scheduler:*
 
-# Available mustache parameters (see the mozilla-taskcluster source):
+# This file undergoes substitution to create tasks.  For on-push tasks, that
+# substitution is done by mozilla-taskcluster.  For cron tasks, that substitution
+# is done by `taskcluster/taskgraph/cron/decision.py`.  If you change any of the
+# template parameters, please do so in all three places!
 #
+# Available template parameters:
+#
+# - now:            current time
 # - owner:          push user (email address)
 # - source:         URL of this YAML file
 # - url:            repository URL
 # - project:        alias for the destination repository (basename of
 #                   the repo url)
 # - level:          SCM level of the destination repository
 #                   (1 = try, 3 = core)
-# - revision:       (short) hg revision of the head of the push
-# - revision_hash:  (long) hg revision of the head of the push
+# - revision:       hg revision of the head of the push
 # - comment:        comment of the push
 # - pushlog_id:     id in the pushlog table of the repository
 #
 # and functions:
 # - as_slugid:      convert a label into a slugId
 # - from_now:       generate a timestamp at a fixed offset from now
+# - shellquote:     quote the contents for injection into shell
 
 # The resulting tasks' taskGroupId will be equal to the taskId of the first
 # task listed here, which should be the decision task.  This gives other tools
 # an easy way to determine the ID of the decision task that created a
 # particular group.
 
 tasks:
   - taskId: '{{#as_slugid}}decision task{{/as_slugid}}'
@@ -50,23 +56,16 @@ tasks:
             The task that creates all of the other tasks in the task graph
 
       workerType: "gecko-decision"
       provisionerId: "aws-provisioner-v1"
 
       tags:
         createdForUser: {{owner}}
 
-      scopes:
-        # Bug 1269443: cache scopes, etc. must be listed explicitly
-        - "docker-worker:cache:level-{{level}}-*"
-        - "docker-worker:cache:tooltool-cache"
-        # mozilla-taskcluster will append the appropriate assume:repo:<repo>
-        # scope here.
-
       routes:
         - "index.gecko.v2.{{project}}.latest.firefox.decision"
         - "tc-treeherder.v2.{{project}}.{{revision}}.{{pushlog_id}}"
         - "tc-treeherder-stage.v2.{{project}}.{{revision}}.{{pushlog_id}}"
 
       payload:
         env:
           # checkout-gecko uses these to check out the source; the inputs
@@ -80,18 +79,18 @@ tasks:
         cache:
           level-{{level}}-checkouts: /home/worker/checkouts
 
         features:
           taskclusterProxy: true
           chainOfTrust: true
 
         # Note: This task is built server side without the context or tooling that
-        # exist in tree so we must hard code the version
-        image: 'taskcluster/decision:0.1.7'
+        # exist in tree so we must hard code the hash
+        image: 'taskcluster/decision:0.1.8@sha256:195d8439c8e90d59311d877bd2a8964849b2e43bfc6c234092618518d8b2891b'
 
         maxRunTime: 1800
 
         # TODO use mozilla-unified for the base repository once the tc-vcs
         # tar.gz archives are created or tc-vcs isn't being used.
         command:
           - /home/worker/bin/run-task
           - '--vcs-checkout=/home/worker/checkouts/gecko'
@@ -107,23 +106,18 @@ tasks:
               --project='{{project}}'
               --message={{#shellquote}}{{{comment}}}{{/shellquote}}
               --owner='{{owner}}'
               --level='{{level}}'
               --base-repository='https://hg.mozilla.org/mozilla-central'
               --head-repository='{{{url}}}'
               --head-ref='{{revision}}'
               --head-rev='{{revision}}'
-              --revision-hash='{{revision_hash}}'
 
         artifacts:
           'public':
             type: 'directory'
             path: '/home/worker/artifacts'
             expires: '{{#from_now}}364 days{{/from_now}}'
-          'public/docker_image_contexts':
-            type: 'directory'
-            path: '/home/worker/docker_image_contexts'
-            expires: '{{#from_now}}7 days{{/from_now}}'
 
       extra:
         treeherder:
           symbol: D
--- a/AUTHORS
+++ b/AUTHORS
@@ -874,16 +874,17 @@ Roy Yokoyama <yokoyama@netscape.com>
 RSA Security, Inc
 Russell King <rmk@arm.linux.org.uk>
 Rusty Lynch <rusty.lynch@intel.com>
 Ryan Cassin <rcassin@supernova.org>
 Ryan Flint <rflint@dslr.net>
 Ryan Jones <sciguyryan@gmail.com>
 Ryan VanderMeulen <ryanvm@gmail.com>
 Ryoichi Furukawa <oliver@1000cp.com>
+Sanyam Khurana <Sanyam.Khurana01@gmail.com>
 sagdjb@softwareag.com
 Samir Gehani <sgehani@netscape.com>
 Sammy Ford
 Samphan Raruenrom
 Samuel Sieb <samuel@sieb.net>
 Sarlos Tamas
 scole@planetweb.com
 Scooter Morris <scootermorris@comcast.net>
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1306438 and bug 1304815 - Rust update and related changes require clobber
+Bug 1343682 - backing out a previous version didn't stop the failures from it, so it appears to need a clobber both out and in
--- a/Makefile.in
+++ b/Makefile.in
@@ -91,47 +91,21 @@ config.status js/src/config.status:
 # The mach build driver will ensure the backend is up to date for partial tree
 # builds. This cleanly avoids most of the pain.
 
 ifndef TEST_MOZBUILD
 
 .PHONY: backend
 backend: $(BUILD_BACKEND_FILES)
 
-# A traditional rule would look like this:
-#    backend.%:
-#        @echo do stuff
-#
-# But with -j<n>, and multiple items in BUILD_BACKEND_FILES, the command would
-# run multiple times in parallel.
-#
-# "Fortunately", make has some weird semantics for pattern rules: if there are
-# multiple targets in a pattern rule and each of them is matched at most once,
-# the command will only run once. So:
-#     backend%RecursiveMakeBackend backend%FasterMakeBackend:
-#         @echo do stuff
-#     backend: backend.RecursiveMakeBackend backend.FasterMakeBackend
-# would only execute the command once.
-#
-# Credit where due: http://stackoverflow.com/questions/2973445/gnu-makefile-rule-generating-a-few-targets-from-a-single-source-file/3077254#3077254
-$(subst .,%,$(BUILD_BACKEND_FILES)):
-	@echo 'Build configuration changed. Regenerating backend.'
-	$(PYTHON) config.status
+include $(topsrcdir)/build/rebuild-backend.mk
 
 Makefile: $(BUILD_BACKEND_FILES)
 	@$(TOUCH) $@
 
-define build_backend_rule
-$(1)_files := $$(shell cat $(1).in)
-$(1): $$($(1)_files)
-$$($(1)_files):
-
-endef
-$(foreach file,$(BUILD_BACKEND_FILES),$(eval $(call build_backend_rule,$(file))))
-
 default:: $(BUILD_BACKEND_FILES)
 endif
 
 install_manifests := \
   $(addprefix dist/,branding idl include public private sdk xpi-stage) \
   _tests \
   $(NULL)
 # Skip the dist/bin install manifest when using the hybrid
@@ -170,52 +144,53 @@ install-manifests: faster
 faster: install-dist/idl
 	$(MAKE) -C faster FASTER_RECURSIVE_MAKE=1
 endif
 
 .PHONY: tup
 tup:
 	$(call BUILDSTATUS,TIERS make tup)
 	$(call BUILDSTATUS,TIER_START make)
-	$(MAKE) install-manifests buildid.h source-repo.h
+	$(MAKE) buildid.h source-repo.h
 	$(call BUILDSTATUS,TIER_FINISH make)
 	$(call BUILDSTATUS,TIER_START tup)
 	@$(TUP) $(if $(findstring s,$(filter-out --%,$(MAKEFLAGS))),,--verbose)
 	$(call BUILDSTATUS,TIER_FINISH tup)
 
 # process_install_manifest needs to be invoked with --no-remove when building
 # js as standalone because automated builds are building nspr separately and
 # that would remove the resulting files.
 # Eventually, a standalone js build would just be able to build nspr itself,
 # removing the need for the former.
 ifdef JS_STANDALONE
 NO_REMOVE=1
 endif
 
+# For an artifact build, _tests will already be partly populated, so run
+# this install manifest with NO_REMOVE set in this case.
+ifdef MOZ_ARTIFACT_BUILDS
+install-_tests: NO_REMOVE=1
+endif
+
 .PHONY: $(addprefix install-,$(subst /,_,$(install_manifests)))
 $(addprefix install-,$(install_manifests)): install-%: $(install_manifest_depends)
 ifneq (,$(filter FasterMake+RecursiveMake,$(BUILD_BACKENDS)))
 	@# If we're using the hybrid FasterMake/RecursiveMake backend, we want
 	@# to ensure the FasterMake end doesn't have install manifests for the
 	@# same directory, because that would blow up
 	$(if $(wildcard _build_manifests/install/$(subst /,_,$*)),$(if $(wildcard faster/install_$(subst /,_,$*)*),$(error FasterMake and RecursiveMake ends of the hybrid build system want to handle $*)))
 endif
 	$(addprefix $(call py_action,process_install_manifest,$(if $(NO_REMOVE),--no-remove )$*) ,$(wildcard _build_manifests/install/$(subst /,_,$*)))
 
 # Dummy wrapper rule to allow the faster backend to piggy back
 $(addprefix install-,$(subst /,_,$(filter dist/%,$(install_manifests)))): install-dist_%: install-dist/% ;
 
 .PHONY: install-tests
 install-tests: install-test-files
 
-# We no longer run "make install-tests" directly before running tests, but we still
-# want to depend on things like config.status, hence this target.
-.PHONY: run-tests-deps
-run-tests-deps: $(install_manifest_depends)
-
 # Force --no-remove, because $objdir/_tests is handled by multiple manifests.
 .PHONY: install-test-files
 install-test-files:
 	$(call py_action,process_install_manifest,--no-remove _tests _build_manifests/install/_test_files)
 
 include $(topsrcdir)/build/moz-automation.mk
 
 # dist and _tests should be purged during cleaning. However, we don't want them
@@ -257,16 +232,24 @@ include $(topsrcdir)/testing/testsuite-t
 endif
 endif
 
 default all::
 	$(call BUILDSTATUS,TIERS $(TIERS) $(if $(MOZ_AUTOMATION),$(MOZ_AUTOMATION_TIERS)))
 
 include $(topsrcdir)/config/rules.mk
 
+ifdef SCCACHE_VERBOSE_STATS
+# This won't contain stats for both halves of a universal build, but I can live with that.
+default::
+	@echo "===SCCACHE STATS==="
+	-$(CCACHE) --show-stats
+	@echo "==================="
+endif
+
 distclean::
 	$(RM) $(DIST_GARBAGE)
 
 ifeq ($(OS_ARCH),WINNT)
 # we want to copy PDB files on Windows
 MAKE_SYM_STORE_ARGS := -c --vcs-info
 ifdef PDBSTR_PATH
 MAKE_SYM_STORE_ARGS += -i
@@ -276,23 +259,18 @@ DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_s
 else
 DUMP_SYMS_BIN ?= $(topsrcdir)/toolkit/crashreporter/tools/win32/dump_syms_vc$(_MSC_VER).exe
 endif
 # PDB files don't get moved to dist, so we need to scan the whole objdir
 MAKE_SYM_STORE_PATH := .
 endif
 ifeq ($(OS_ARCH),Darwin)
 # need to pass arch flags for universal builds
-ifdef UNIVERSAL_BINARY
-MAKE_SYM_STORE_ARGS := -c -a 'i386 x86_64' --vcs-info
-MAKE_SYM_STORE_PATH := $(DIST)/universal
-else
 MAKE_SYM_STORE_ARGS := -c -a $(OS_TEST) --vcs-info
 MAKE_SYM_STORE_PATH := $(DIST)/bin
-endif
 DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_syms
 endif
 ifeq (,$(filter-out Linux SunOS,$(OS_ARCH)))
 MAKE_SYM_STORE_ARGS := -c --vcs-info
 DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_syms
 MAKE_SYM_STORE_PATH := $(DIST)/bin
 endif
 MAKE_SYM_STORE_ARGS += --install-manifest=$(DEPTH)/_build_manifests/install/dist_include,$(DIST)/include
@@ -349,36 +327,16 @@ ifdef SOCORRO_SYMBOL_UPLOAD_TOKEN_FILE
 	$(PYTHON) -u $(topsrcdir)/toolkit/crashreporter/tools/upload_symbols.py '$(DIST)/$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip'
 endif
 endif
 
 .PHONY: update-packaging
 update-packaging:
 	$(MAKE) -C tools/update-packaging
 
-.PHONY: pretty-package
-pretty-package:
-	unset MOZ_SIGN_CMD && $(MAKE) package MOZ_PKG_PRETTYNAMES=1
-
-.PHONY: pretty-package-tests
-pretty-package-tests:
-	unset MOZ_SIGN_CMD && $(MAKE) package-tests MOZ_PKG_PRETTYNAMES=1
-
-.PHONY: pretty-l10n-check
-pretty-l10n-check:
-	unset MOZ_SIGN_CMD && $(MAKE) l10n-check MOZ_PKG_PRETTYNAMES=1
-
-.PHONY: pretty-update-packaging
-pretty-update-packaging:
-	unset MOZ_SIGN_CMD && $(MAKE) -C tools/update-packaging MOZ_PKG_PRETTYNAMES=1
-
-.PHONY: pretty-installer
-pretty-installer:
-	unset MOZ_SIGN_CMD && $(MAKE) installer MOZ_PKG_PRETTYNAMES=1
-
 #XXX: this is a hack, since we don't want to clobber for MSVC
 # PGO support, but we can't do this test in client.mk
 ifneq ($(OS_ARCH)_$(GNU_CC), WINNT_)
 # No point in clobbering if PGO has been explicitly disabled.
 ifndef NO_PROFILE_GUIDED_OPTIMIZE
 maybe_clobber_profiledbuild: clean
 else
 maybe_clobber_profiledbuild:
--- a/README.txt
+++ b/README.txt
@@ -1,27 +1,27 @@
 An explanation of the Mozilla Source Code Directory Structure and links to
 project pages with documentation can be found at:
 
     https://developer.mozilla.org/en/Mozilla_Source_Code_Directory_Structure
 
 For information on how to build Mozilla from the source code, see:
 
-    http://developer.mozilla.org/en/docs/Build_Documentation
+    https://developer.mozilla.org/en/docs/Build_Documentation
 
 To have your bug fix / feature added to Mozilla, you should create a patch and
 submit it to Bugzilla (https://bugzilla.mozilla.org). Instructions are at:
 
-    http://developer.mozilla.org/en/docs/Creating_a_patch
-    http://developer.mozilla.org/en/docs/Getting_your_patch_in_the_tree
+    https://developer.mozilla.org/en/docs/Creating_a_patch
+    https://developer.mozilla.org/en/docs/Getting_your_patch_in_the_tree
 
 If you have a question about developing Mozilla, and can't find the solution
-on http://developer.mozilla.org, you can try asking your question in a
+on https://developer.mozilla.org, you can try asking your question in a
 mozilla.* Usenet group, or on IRC at irc.mozilla.org. [The Mozilla news groups
 are accessible on Google Groups, or news.mozilla.org with a NNTP reader.]
 
 You can download nightly development builds from the Mozilla FTP server.
 Keep in mind that nightly builds, which are used by Mozilla developers for
 testing, may be buggy. Firefox nightlies, for example, can be found at:
 
     https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central/
             - or -
-    http://nightly.mozilla.org/
+    https://nightly.mozilla.org/
--- a/accessible/aom/AccessibleNode.cpp
+++ b/accessible/aom/AccessibleNode.cpp
@@ -1,16 +1,19 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "AccessibleNode.h"
 #include "mozilla/dom/AccessibleNodeBinding.h"
 #include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/DOMStringList.h"
+#include "nsIPersistentProperties2.h"
+#include "nsISimpleEnumerator.h"
 
 #include "Accessible-inl.h"
 #include "nsAccessibilityService.h"
 #include "DocAccessible.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 using namespace mozilla::dom;
@@ -56,13 +59,119 @@ AccessibleNode::GetRole(nsAString& aRole
   if (mIntl) {
     GetOrCreateAccService()->GetStringRole(mIntl->Role(), aRole);
     return;
   }
 
   aRole.AssignLiteral("unknown");
 }
 
+void
+AccessibleNode::GetStates(nsTArray<nsString>& aStates)
+{
+  if (mIntl) {
+    if (!mStates) {
+      mStates = GetOrCreateAccService()->GetStringStates(mIntl->State());
+    }
+    aStates = mStates->StringArray();
+    return;
+  }
+
+  aStates.AppendElement(NS_LITERAL_STRING("defunct"));
+}
+
+void
+AccessibleNode::GetAttributes(nsTArray<nsString>& aAttributes)
+{
+  if (!mIntl) {
+    return;
+  }
+
+  nsCOMPtr<nsIPersistentProperties> attrs = mIntl->Attributes();
+
+  nsCOMPtr<nsISimpleEnumerator> props;
+  attrs->Enumerate(getter_AddRefs(props));
+
+  bool hasMore = false;
+  while (NS_SUCCEEDED(props->HasMoreElements(&hasMore)) && hasMore) {
+    nsCOMPtr<nsISupports> supp;
+    props->GetNext(getter_AddRefs(supp));
+
+    nsCOMPtr<nsIPropertyElement> prop(do_QueryInterface(supp));
+
+    nsAutoCString attr;
+    prop->GetKey(attr);
+    aAttributes.AppendElement(NS_ConvertUTF8toUTF16(attr));
+  }
+}
+
+bool
+AccessibleNode::Is(const Sequence<nsString>& aFlavors)
+{
+  if (!mIntl) {
+    for (const auto& flavor : aFlavors) {
+      if (!flavor.EqualsLiteral("unknown") && !flavor.EqualsLiteral("defunct")) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  nsAutoString role;
+  GetOrCreateAccService()->GetStringRole(mIntl->Role(), role);
+
+  if (!mStates) {
+    mStates = GetOrCreateAccService()->GetStringStates(mIntl->State());
+  }
+
+  for (const auto& flavor : aFlavors) {
+    if (!flavor.Equals(role) && !mStates->Contains(flavor)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool
+AccessibleNode::Has(const Sequence<nsString>& aAttributes)
+{
+  if (!mIntl) {
+    return false;
+  }
+  nsCOMPtr<nsIPersistentProperties> attrs = mIntl->Attributes();
+  for (const auto& attr : aAttributes) {
+    bool has = false;
+    attrs->Has(NS_ConvertUTF16toUTF8(attr).get(), &has);
+    if (!has) {
+      return false;
+    }
+  }
+  return true;
+}
+
+void
+AccessibleNode::Get(JSContext* aCX, const nsAString& aAttribute,
+                    JS::MutableHandle<JS::Value> aValue,
+                    ErrorResult& aRv)
+{
+  if (!mIntl) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return;
+  }
+
+  nsCOMPtr<nsIPersistentProperties> attrs = mIntl->Attributes();
+  nsAutoString value;
+  attrs->GetStringProperty(NS_ConvertUTF16toUTF8(aAttribute), value);
+
+  JS::Rooted<JS::Value> jsval(aCX);
+  if (!ToJSValue(aCX, value, &jsval)) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return;
+  }
+
+  aValue.set(jsval);
+}
+
 nsINode*
 AccessibleNode::GetDOMNode()
 {
   return mDOMNode;
 }
--- a/accessible/aom/AccessibleNode.h
+++ b/accessible/aom/AccessibleNode.h
@@ -3,51 +3,64 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef A11Y_AOM_ACCESSIBLENODE_H
 #define A11Y_AOM_ACCESSIBLENODE_H
 
 #include "nsWrapperCache.h"
-#include "mozilla/RefPtr.h"
+#include "mozilla/ErrorResult.h"
+#include "mozilla/dom/BindingDeclarations.h"
 
 class nsINode;
 
 namespace mozilla {
 
 namespace a11y {
   class Accessible;
 }
 
 namespace dom {
 
+class DOMStringList;
 struct ParentObject;
 
 class AccessibleNode : public nsISupports,
                        public nsWrapperCache
 {
 public:
   explicit AccessibleNode(nsINode* aNode);
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS;
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AccessibleNode);
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override final;
   virtual dom::ParentObject GetParentObject() const final;
 
   void GetRole(nsAString& aRole);
+  void GetStates(nsTArray<nsString>& aStates);
+  void GetAttributes(nsTArray<nsString>& aAttributes);
   nsINode* GetDOMNode();
 
+  bool Is(const Sequence<nsString>& aFlavors);
+  bool Has(const Sequence<nsString>& aAttributes);
+  void Get(JSContext* cx, const nsAString& aAttribute,
+           JS::MutableHandle<JS::Value> aValue,
+           ErrorResult& aRv);
+
+  a11y::Accessible* Internal() const { return mIntl; }
+
 protected:
   AccessibleNode(const AccessibleNode& aCopy) = delete;
   AccessibleNode& operator=(const AccessibleNode& aCopy) = delete;
   virtual ~AccessibleNode();
 
   RefPtr<a11y::Accessible> mIntl;
   RefPtr<nsINode> mDOMNode;
+  RefPtr<dom::DOMStringList> mStates;
 };
 
 } // dom
 } // mozilla
 
 
 #endif // A11Y_JSAPI_ACCESSIBLENODE
--- a/accessible/atk/AccessibleWrap.cpp
+++ b/accessible/atk/AccessibleWrap.cpp
@@ -8,32 +8,32 @@
 
 #include "Accessible-inl.h"
 #include "ApplicationAccessibleWrap.h"
 #include "InterfaceInitFuncs.h"
 #include "nsAccUtils.h"
 #include "mozilla/a11y/PDocAccessible.h"
 #include "OuterDocAccessible.h"
 #include "ProxyAccessible.h"
+#include "DocAccessibleParent.h"
 #include "RootAccessible.h"
 #include "TableAccessible.h"
 #include "TableCellAccessible.h"
 #include "nsMai.h"
 #include "nsMaiHyperlink.h"
 #include "nsString.h"
 #include "nsStateMap.h"
 #include "mozilla/a11y/Platform.h"
 #include "Relation.h"
 #include "RootAccessible.h"
 #include "States.h"
 #include "nsISimpleEnumerator.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Sprintf.h"
-#include "nsXPCOMStrings.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIPersistentProperties2.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 MaiAtkObject::EAvailableAtkSignals MaiAtkObject::gAvailableAtkSignals =
   eUnknown;
@@ -368,16 +368,19 @@ AccessibleWrap::CreateMaiInterfaces(void
   if (IsLink())
     interfacesBits |= 1 << MAI_INTERFACE_HYPERLINK_IMPL;
 
   if (!nsAccUtils::MustPrune(this)) {  // These interfaces require children
     // Table interface.
     if (AsTable())
       interfacesBits |= 1 << MAI_INTERFACE_TABLE;
  
+    if (AsTableCell())
+      interfacesBits |= 1 << MAI_INTERFACE_TABLE_CELL;
+
     // Selection interface.
     if (IsSelect()) {
       interfacesBits |= 1 << MAI_INTERFACE_SELECTION;
     }
   }
 
   return interfacesBits;
 }
@@ -605,18 +608,17 @@ getNameCB(AtkObject* aAtkObj)
 
   return aAtkObj->name;
 }
 
 static void
 MaybeFireNameChange(AtkObject* aAtkObj, const nsString& aNewName)
 {
   NS_ConvertUTF16toUTF8 newNameUTF8(aNewName);
-  if (aAtkObj->name &&
-      !strncmp(aAtkObj->name, newNameUTF8.get(), newNameUTF8.Length()))
+  if (aAtkObj->name && !strcmp(aAtkObj->name, newNameUTF8.get()))
     return;
 
   // Below we duplicate the functionality of atk_object_set_name(),
   // but without calling atk_object_get_name(). Instead of
   // atk_object_get_name() we directly access aAtkObj->name. This is because
   // atk_object_get_name() would call getNameCB() which would call
   // MaybeFireNameChange() (or atk_object_set_name() before this problem was
   // fixed) and we would get an infinite recursion.
@@ -1125,16 +1127,19 @@ GetInterfacesForProxy(ProxyAccessible* a
     interfaces |= 1 << MAI_INTERFACE_HYPERLINK_IMPL;
 
   if (aInterfaces & Interfaces::VALUE)
     interfaces |= 1 << MAI_INTERFACE_VALUE;
 
   if (aInterfaces & Interfaces::TABLE)
     interfaces |= 1 << MAI_INTERFACE_TABLE;
 
+  if (aInterfaces & Interfaces::TABLECELL)
+    interfaces |= 1 << MAI_INTERFACE_TABLE_CELL;
+
   if (aInterfaces & Interfaces::IMAGE)
     interfaces |= 1 << MAI_INTERFACE_IMAGE;
 
   if (aInterfaces & Interfaces::DOCUMENT)
     interfaces |= 1 << MAI_INTERFACE_DOCUMENT;
 
   if (aInterfaces & Interfaces::SELECTION) {
     interfaces |= 1 << MAI_INTERFACE_SELECTION;
--- a/accessible/atk/UtilInterface.cpp
+++ b/accessible/atk/UtilInterface.cpp
@@ -256,18 +256,24 @@ mai_util_add_key_event_listener(AtkKeySn
   if (MOZ_UNLIKELY(!listener)) {
     return 0;
   }
 
   static guint key = 0;
 
   if (!sKey_listener_list) {
     sKey_listener_list = g_hash_table_new(nullptr, nullptr);
+  }
+
+  // If we have no registered event listeners then we need to (re)install the
+  // key event snooper.
+  if (g_hash_table_size(sKey_listener_list) == 0) {
     sKey_snooper_id = gtk_key_snooper_install(mai_key_snooper, data);
   }
+
   AtkKeySnoopFuncPointer atkKeySnoop;
   atkKeySnoop.func_ptr = listener;
   key++;
   g_hash_table_insert(sKey_listener_list, GUINT_TO_POINTER(key),
                       atkKeySnoop.data);
   return key;
 }
 
--- a/accessible/atk/nsMaiInterfaceTable.cpp
+++ b/accessible/atk/nsMaiInterfaceTable.cpp
@@ -322,44 +322,47 @@ getSelectedRowsCB(AtkTable *aTable, gint
 }
 
 static gboolean
 isColumnSelectedCB(AtkTable *aTable, gint aColIdx)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
   if (accWrap) {
     return static_cast<gboolean>(accWrap->AsTable()->IsColSelected(aColIdx));
-  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+  }
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
     return static_cast<gboolean>(proxy->TableColumnSelected(aColIdx));
   }
 
   return FALSE;
 }
 
 static gboolean
 isRowSelectedCB(AtkTable *aTable, gint aRowIdx)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
   if (accWrap) {
     return static_cast<gboolean>(accWrap->AsTable()->IsRowSelected(aRowIdx));
-  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+  }
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
     return static_cast<gboolean>(proxy->TableRowSelected(aRowIdx));
   }
 
   return FALSE;
 }
 
 static gboolean
 isCellSelectedCB(AtkTable *aTable, gint aRowIdx, gint aColIdx)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
   if (accWrap) {
     return static_cast<gboolean>(accWrap->AsTable()->
       IsCellSelected(aRowIdx, aColIdx));
-  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+  }
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
     return static_cast<gboolean>(proxy->TableCellSelected(aRowIdx, aColIdx));
   }
 
   return FALSE;
 }
 }
 
 void
--- a/accessible/atk/nsMaiInterfaceText.cpp
+++ b/accessible/atk/nsMaiInterfaceText.cpp
@@ -495,17 +495,18 @@ getTextSelectionCB(AtkText *aText, gint 
       return nullptr;
     }
 
     text->SelectionBoundsAt(aSelectionNum, &startOffset, &endOffset);
     *aStartOffset = startOffset;
     *aEndOffset = endOffset;
 
     return getTextCB(aText, *aStartOffset, *aEndOffset);
-  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+  }
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
     nsString data;
     proxy->SelectionBoundsAt(aSelectionNum, data, &startOffset, &endOffset);
     *aStartOffset = startOffset;
     *aEndOffset = endOffset;
 
     NS_ConvertUTF16toUTF8 dataAsUTF8(data);
     return (dataAsUTF8.get()) ? g_strdup(dataAsUTF8.get()) : nullptr;
   }
@@ -521,17 +522,18 @@ addTextSelectionCB(AtkText *aText,
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
   if (accWrap) {
     HyperTextAccessible* text = accWrap->AsHyperText();
     if (!text || !text->IsTextRole()) {
       return FALSE;
     }
 
     return text->AddToSelection(aStartOffset, aEndOffset);
-  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+  }
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
     return proxy->AddToSelection(aStartOffset, aEndOffset);
   }
 
   return FALSE;
 }
 
 static gboolean
 removeTextSelectionCB(AtkText *aText,
@@ -540,17 +542,18 @@ removeTextSelectionCB(AtkText *aText,
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
   if (accWrap) {
     HyperTextAccessible* text = accWrap->AsHyperText();
     if (!text || !text->IsTextRole()) {
       return FALSE;
     }
 
     return text->RemoveFromSelection(aSelectionNum);
-  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+  }
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
     return proxy->RemoveFromSelection(aSelectionNum);
   }
 
   return FALSE;
 }
 
 static gboolean
 setTextSelectionCB(AtkText *aText, gint aSelectionNum,
@@ -559,17 +562,18 @@ setTextSelectionCB(AtkText *aText, gint 
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
   if (accWrap) {
     HyperTextAccessible* text = accWrap->AsHyperText();
     if (!text || !text->IsTextRole()) {
       return FALSE;
     }
 
     return text->SetSelectionBoundsAt(aSelectionNum, aStartOffset, aEndOffset);
-  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+  }
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
     return proxy->SetSelectionBoundsAt(aSelectionNum, aStartOffset, aEndOffset);
   }
 
   return FALSE;
 }
 
 static gboolean
 setCaretOffsetCB(AtkText *aText, gint aOffset)
--- a/accessible/base/ARIAMap.cpp
+++ b/accessible/base/ARIAMap.cpp
@@ -179,17 +179,17 @@ static const nsRoleMapEntry sWAIRoleMaps
   { // directory
     &nsGkAtoms::directory,
     roles::LIST,
     kUseMapRole,
     eNoValue,
     eNoAction,
     eNoLiveAttr,
     eList,
-    kNoReqStates
+    states::READONLY
   },
   { // document
     &nsGkAtoms::document,
     roles::DOCUMENT,
     kUseMapRole,
     eNoValue,
     eNoAction,
     eNoLiveAttr,
@@ -822,18 +822,20 @@ struct AttrCharacteristics
 
 static const AttrCharacteristics gWAIUnivAttrMap[] = {
   {&nsGkAtoms::aria_activedescendant,  ATTR_BYPASSOBJ                               },
   {&nsGkAtoms::aria_atomic,   ATTR_BYPASSOBJ_IF_FALSE | ATTR_VALTOKEN | ATTR_GLOBAL },
   {&nsGkAtoms::aria_busy,                               ATTR_VALTOKEN | ATTR_GLOBAL },
   {&nsGkAtoms::aria_checked,           ATTR_BYPASSOBJ | ATTR_VALTOKEN               }, /* exposes checkable obj attr */
   {&nsGkAtoms::aria_controls,          ATTR_BYPASSOBJ                 | ATTR_GLOBAL },
   {&nsGkAtoms::aria_describedby,       ATTR_BYPASSOBJ                 | ATTR_GLOBAL },
+  {&nsGkAtoms::aria_details,           ATTR_BYPASSOBJ                 | ATTR_GLOBAL },
   {&nsGkAtoms::aria_disabled,          ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL },
   {&nsGkAtoms::aria_dropeffect,                         ATTR_VALTOKEN | ATTR_GLOBAL },
+  {&nsGkAtoms::aria_errormessage,      ATTR_BYPASSOBJ                 | ATTR_GLOBAL },
   {&nsGkAtoms::aria_expanded,          ATTR_BYPASSOBJ | ATTR_VALTOKEN               },
   {&nsGkAtoms::aria_flowto,            ATTR_BYPASSOBJ                 | ATTR_GLOBAL },
   {&nsGkAtoms::aria_grabbed,                            ATTR_VALTOKEN | ATTR_GLOBAL },
   {&nsGkAtoms::aria_haspopup,          ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL },
   {&nsGkAtoms::aria_hidden,            ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL }, /* handled special way */
   {&nsGkAtoms::aria_invalid,           ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL },
   {&nsGkAtoms::aria_label,             ATTR_BYPASSOBJ                 | ATTR_GLOBAL },
   {&nsGkAtoms::aria_labelledby,        ATTR_BYPASSOBJ                 | ATTR_GLOBAL },
--- a/accessible/base/AccEvent.cpp
+++ b/accessible/base/AccEvent.cpp
@@ -37,17 +37,33 @@ AccEvent::AccEvent(uint32_t aEventType, 
     mIsFromUserInput = EventStateManager::IsHandlingUserInput();
   else
     mIsFromUserInput = aIsFromUserInput == eFromUserInput ? true : false;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // AccEvent cycle collection
 
-NS_IMPL_CYCLE_COLLECTION(AccEvent, mAccessible)
+NS_IMPL_CYCLE_COLLECTION_CLASS(AccEvent)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AccEvent)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mAccessible)
+  if (AccTreeMutationEvent* tmEvent = downcast_accEvent(tmp)) {
+    tmEvent->SetNextEvent(nullptr);
+    tmEvent->SetPrevEvent(nullptr);
+  }
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AccEvent)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAccessible)
+  if (AccTreeMutationEvent* tmEvent = downcast_accEvent(tmp)) {
+    CycleCollectionNoteChild(cb, tmEvent->NextEvent(), "mNext");
+    CycleCollectionNoteChild(cb, tmEvent->PrevEvent(), "mPrevEvent");
+  }
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AccEvent, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AccEvent, Release)
 
 ////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////
 // AccTextChangeEvent
 ////////////////////////////////////////////////////////////////////////////////
--- a/accessible/base/AccEvent.h
+++ b/accessible/base/AccEvent.h
@@ -46,20 +46,16 @@ public:
     //    This event will always be emitted. This flag is used for events that
     //    don't support coalescence.
     eAllowDupes,
 
      // eCoalesceReorder : For reorder events from the same subtree or the same
      //    node, only the umbrella event on the ancestor will be emitted.
     eCoalesceReorder,
 
-     // eCoalesceMutationTextChange : coalesce text change events caused by
-     // tree mutations of the same tree level.
-    eCoalesceMutationTextChange,
-
     // eCoalesceOfSameType : For events of the same type, only the newest event
     // will be processed.
     eCoalesceOfSameType,
 
     // eCoalesceSelectionChange: coalescence of selection change events.
     eCoalesceSelectionChange,
 
     // eCoalesceStateChange: coalesce state change events.
@@ -93,16 +89,17 @@ public:
 
   /**
    * Down casting.
    */
   enum EventGroup {
     eGenericEvent,
     eStateChangeEvent,
     eTextChangeEvent,
+    eTreeMutationEvent,
     eMutationEvent,
     eReorderEvent,
     eHideEvent,
     eShowEvent,
     eCaretMoveEvent,
     eTextSelChangeEvent,
     eSelectionChangeEvent,
     eTableChangeEvent,
@@ -128,16 +125,17 @@ protected:
   bool mIsFromUserInput;
   uint32_t mEventType;
   EEventRule mEventRule;
   RefPtr<Accessible> mAccessible;
 
   friend class EventQueue;
   friend class EventTree;
   friend class ::nsEventShell;
+  friend class NotificationController;
 };
 
 
 /**
  * Accessible state change event.
  */
 class AccStateChangeEvent: public AccEvent
 {
@@ -199,53 +197,88 @@ public:
   const nsString& ModifiedText() const { return mModifiedText; }
 
 private:
   int32_t mStart;
   bool mIsInserted;
   nsString mModifiedText;
 
   friend class EventTree;
+  friend class NotificationController;
 };
 
+/**
+ * A base class for events related to tree mutation, either an AccMutation
+ * event, or an AccReorderEvent.
+ */
+class AccTreeMutationEvent : public AccEvent
+{
+public:
+  AccTreeMutationEvent(uint32_t aEventType, Accessible* aTarget) :
+    AccEvent(aEventType, aTarget, eAutoDetect, eCoalesceReorder), mGeneration(0) {}
+
+  // Event
+  static const EventGroup kEventGroup = eTreeMutationEvent;
+  virtual unsigned int GetEventGroups() const override
+  {
+    return AccEvent::GetEventGroups() | (1U << eTreeMutationEvent);
+  }
+
+  void SetNextEvent(AccTreeMutationEvent* aNext) { mNextEvent = aNext; }
+  void SetPrevEvent(AccTreeMutationEvent* aPrev) { mPrevEvent = aPrev; }
+  AccTreeMutationEvent* NextEvent() const { return mNextEvent; }
+  AccTreeMutationEvent* PrevEvent() const { return mPrevEvent; }
+
+  /**
+   * A sequence number to know when this event was fired.
+   */
+  uint32_t EventGeneration() const { return mGeneration; }
+  void SetEventGeneration(uint32_t aGeneration) { mGeneration = aGeneration; }
+
+private:
+  RefPtr<AccTreeMutationEvent> mNextEvent;
+  RefPtr<AccTreeMutationEvent> mPrevEvent;
+  uint32_t mGeneration;
+};
 
 /**
  * Base class for show and hide accessible events.
  */
-class AccMutationEvent: public AccEvent
+class AccMutationEvent: public AccTreeMutationEvent
 {
 public:
   AccMutationEvent(uint32_t aEventType, Accessible* aTarget) :
-    AccEvent(aEventType, aTarget, eAutoDetect, eCoalesceMutationTextChange)
+    AccTreeMutationEvent(aEventType, aTarget)
   {
     // Don't coalesce these since they are coalesced by reorder event. Coalesce
     // contained text change events.
     mParent = mAccessible->Parent();
   }
   virtual ~AccMutationEvent() { }
 
   // Event
   static const EventGroup kEventGroup = eMutationEvent;
   virtual unsigned int GetEventGroups() const override
   {
-    return AccEvent::GetEventGroups() | (1U << eMutationEvent);
+    return AccTreeMutationEvent::GetEventGroups() | (1U << eMutationEvent);
   }
 
   // MutationEvent
   bool IsShow() const { return mEventType == nsIAccessibleEvent::EVENT_SHOW; }
   bool IsHide() const { return mEventType == nsIAccessibleEvent::EVENT_HIDE; }
 
   Accessible* Parent() const { return mParent; }
 
 protected:
   nsCOMPtr<nsINode> mNode;
   RefPtr<Accessible> mParent;
   RefPtr<AccTextChangeEvent> mTextChangeEvent;
 
   friend class EventTree;
+  friend class NotificationController;
 };
 
 
 /**
  * Accessible hide event.
  */
 class AccHideEvent: public AccMutationEvent
 {
@@ -266,16 +299,17 @@ public:
   bool NeedsShutdown() const { return mNeedsShutdown; }
 
 protected:
   bool mNeedsShutdown;
   RefPtr<Accessible> mNextSibling;
   RefPtr<Accessible> mPrevSibling;
 
   friend class EventTree;
+  friend class NotificationController;
 };
 
 
 /**
  * Accessible show event.
  */
 class AccShowEvent: public AccMutationEvent
 {
@@ -297,29 +331,28 @@ private:
 
   friend class EventTree;
 };
 
 
 /**
  * Class for reorder accessible event. Takes care about
  */
-class AccReorderEvent : public AccEvent
+class AccReorderEvent : public AccTreeMutationEvent
 {
 public:
   explicit AccReorderEvent(Accessible* aTarget) :
-    AccEvent(::nsIAccessibleEvent::EVENT_REORDER, aTarget,
-             eAutoDetect, eCoalesceReorder) { }
+    AccTreeMutationEvent(::nsIAccessibleEvent::EVENT_REORDER, aTarget) { }
   virtual ~AccReorderEvent() { }
 
   // Event
   static const EventGroup kEventGroup = eReorderEvent;
   virtual unsigned int GetEventGroups() const override
   {
-    return AccEvent::GetEventGroups() | (1U << eReorderEvent);
+    return AccTreeMutationEvent::GetEventGroups() | (1U << eReorderEvent);
   }
 };
 
 
 /**
  * Accessible caret move event.
  */
 class AccCaretMoveEvent: public AccEvent
--- a/accessible/base/DocManager.cpp
+++ b/accessible/base/DocManager.cpp
@@ -81,46 +81,65 @@ DocManager::FindAccessibleInCache(nsINod
         return accessible;
       }
     }
   }
   return nullptr;
 }
 
 void
+DocManager::RemoveFromXPCDocumentCache(DocAccessible* aDocument)
+{
+  xpcAccessibleDocument* xpcDoc = mXPCDocumentCache.GetWeak(aDocument);
+  if (xpcDoc) {
+    xpcDoc->Shutdown();
+    mXPCDocumentCache.Remove(aDocument);
+  }
+
+  if (!HasXPCDocuments()) {
+    MaybeShutdownAccService(nsAccessibilityService::eXPCOM);
+  }
+}
+
+void
 DocManager::NotifyOfDocumentShutdown(DocAccessible* aDocument,
                                      nsIDocument* aDOMDocument)
 {
   // We need to remove listeners in both cases, when document is being shutdown
   // or when accessibility service is being shut down as well.
   RemoveListeners(aDOMDocument);
 
   // Document will already be removed when accessibility service is shutting
   // down so we do not need to remove it twice.
   if (nsAccessibilityService::IsShutdown()) {
     return;
   }
 
-  xpcAccessibleDocument* xpcDoc = mXPCDocumentCache.GetWeak(aDocument);
-  if (xpcDoc) {
-    xpcDoc->Shutdown();
-    mXPCDocumentCache.Remove(aDocument);
-  }
-
+  RemoveFromXPCDocumentCache(aDocument);
   mDocAccessibleCache.Remove(aDOMDocument);
 }
 
 void
-DocManager::NotifyOfRemoteDocShutdown(DocAccessibleParent* aDoc)
+DocManager::RemoveFromRemoteXPCDocumentCache(DocAccessibleParent* aDoc)
 {
   xpcAccessibleDocument* doc = GetCachedXPCDocument(aDoc);
   if (doc) {
     doc->Shutdown();
     sRemoteXPCDocumentCache->Remove(aDoc);
   }
+
+  if (sRemoteXPCDocumentCache && sRemoteXPCDocumentCache->Count() == 0) {
+    MaybeShutdownAccService(nsAccessibilityService::eXPCOM);
+  }
+}
+
+void
+DocManager::NotifyOfRemoteDocShutdown(DocAccessibleParent* aDoc)
+{
+  RemoveFromRemoteXPCDocumentCache(aDoc);
 }
 
 xpcAccessibleDocument*
 DocManager::GetXPCDocument(DocAccessible* aDocument)
 {
   if (!aDocument)
     return nullptr;
 
@@ -497,37 +516,16 @@ DocManager::CreateDocOrRootAccessible(ns
     // the tree. The reorder event is delivered after the document tree is
     // constructed because event processing and tree construction are done by
     // the same document.
     // Note: don't use AccReorderEvent to avoid coalsecense and special reorder
     // events processing.
     docAcc->FireDelayedEvent(nsIAccessibleEvent::EVENT_REORDER,
                              ApplicationAcc());
 
-    if (IPCAccessibilityActive()) {
-      nsIDocShell* docShell = aDocument->GetDocShell();
-      if (docShell) {
-        nsCOMPtr<nsITabChild> tabChild = docShell->GetTabChild();
-
-        // XXX We may need to handle the case that we don't have a tab child
-        // differently.  It may be that this will cause us to fail to notify
-        // the parent process about important accessible documents.
-        if (tabChild) {
-          DocAccessibleChild* ipcDoc = new DocAccessibleChild(docAcc);
-          docAcc->SetIPCDoc(ipcDoc);
-          static_cast<TabChild*>(tabChild.get())->
-            SendPDocAccessibleConstructor(ipcDoc, nullptr, 0);
-
-#if defined(XP_WIN)
-          IAccessibleHolder holder(CreateHolderFromAccessible(docAcc));
-          ipcDoc->SendCOMProxy(holder);
-#endif
-        }
-      }
-    }
   } else {
     parentDocAcc->BindChildDocument(docAcc);
   }
 
 #ifdef A11Y_LOG
   if (logging::IsEnabled(logging::eDocCreate)) {
     logging::DocCreate("document creation finished", aDocument);
     logging::Stack();
--- a/accessible/base/DocManager.h
+++ b/accessible/base/DocManager.h
@@ -61,16 +61,18 @@ public:
   Accessible* FindAccessibleInCache(nsINode* aNode) const;
 
   /**
    * Called by document accessible when it gets shutdown.
    */
   void NotifyOfDocumentShutdown(DocAccessible* aDocument,
                                 nsIDocument* aDOMDocument);
 
+  void RemoveFromXPCDocumentCache(DocAccessible* aDocument);
+
   /**
    * Return XPCOM accessible document.
    */
   xpcAccessibleDocument* GetXPCDocument(DocAccessible* aDocument);
   xpcAccessibleDocument* GetCachedXPCDocument(DocAccessible* aDocument) const
     { return mXPCDocumentCache.GetWeak(aDocument); }
 
   /*
@@ -90,16 +92,18 @@ public:
   static const nsTArray<DocAccessibleParent*>* TopLevelRemoteDocs()
     { return sRemoteDocuments; }
 
   /**
    * Remove the xpc document for a remote document if there is one.
    */
   static void NotifyOfRemoteDocShutdown(DocAccessibleParent* adoc);
 
+  static void RemoveFromRemoteXPCDocumentCache(DocAccessibleParent* aDoc);
+
   /**
    * Get a XPC document for a remote document.
    */
   static xpcAccessibleDocument* GetXPCDocument(DocAccessibleParent* aDoc);
   static xpcAccessibleDocument* GetCachedXPCDocument(const DocAccessibleParent* aDoc)
   {
     return sRemoteXPCDocumentCache ? sRemoteXPCDocumentCache->GetWeak(aDoc)
       : nullptr;
@@ -118,16 +122,22 @@ protected:
    */
   bool Init();
 
   /**
    * Shutdown the manager.
    */
   void Shutdown();
 
+  bool HasXPCDocuments()
+  {
+    return mXPCDocumentCache.Count() > 0 ||
+           (sRemoteXPCDocumentCache && sRemoteXPCDocumentCache->Count() > 0);
+  }
+
 private:
   DocManager(const DocManager&);
   DocManager& operator =(const DocManager&);
 
 private:
   /**
    * Create an accessible document if it was't created and fire accessibility
    * events if needed.
--- a/accessible/base/EventQueue.cpp
+++ b/accessible/base/EventQueue.cpp
@@ -85,21 +85,25 @@ void
 EventQueue::CoalesceEvents()
 {
   NS_ASSERTION(mEvents.Length(), "There should be at least one pending event!");
   uint32_t tail = mEvents.Length() - 1;
   AccEvent* tailEvent = mEvents[tail];
 
   switch(tailEvent->mEventRule) {
     case AccEvent::eCoalesceReorder:
-      MOZ_ASSERT(tailEvent->mAccessible->IsApplication() ||
-                 tailEvent->mAccessible->IsOuterDoc() ||
-                 tailEvent->mAccessible->IsXULTree(),
+    {
+      DebugOnly<Accessible*> target = tailEvent->mAccessible.get();
+      MOZ_ASSERT(target->IsApplication() ||
+                 target->IsOuterDoc() ||
+                 target->IsXULTree(),
                  "Only app or outerdoc accessible reorder events are in the queue");
+      MOZ_ASSERT(tailEvent->GetEventType() == nsIAccessibleEvent::EVENT_REORDER, "only reorder events should be queued");
       break; // case eCoalesceReorder
+    }
 
     case AccEvent::eCoalesceOfSameType:
     {
       // Coalesce old events by newer event.
       for (uint32_t index = tail - 1; index < tail; index--) {
         AccEvent* accEvent = mEvents[index];
         if (accEvent->mEventType == tailEvent->mEventType &&
           accEvent->mEventRule == tailEvent->mEventRule) {
--- a/accessible/base/EventTree.cpp
+++ b/accessible/base/EventTree.cpp
@@ -20,24 +20,24 @@ using namespace mozilla::a11y;
 ////////////////////////////////////////////////////////////////////////////////
 // TreeMutation class
 
 EventTree* const TreeMutation::kNoEventTree = reinterpret_cast<EventTree*>(-1);
 
 TreeMutation::TreeMutation(Accessible* aParent, bool aNoEvents) :
   mParent(aParent), mStartIdx(UINT32_MAX),
   mStateFlagsCopy(mParent->mStateFlags),
-  mEventTree(aNoEvents ? kNoEventTree : nullptr)
+  mQueueEvents(!aNoEvents)
 {
 #ifdef DEBUG
   mIsDone = false;
 #endif
 
 #ifdef A11Y_LOG
-  if (mEventTree != kNoEventTree && logging::IsEnabled(logging::eEventTree)) {
+  if (mQueueEvents && logging::IsEnabled(logging::eEventTree)) {
     logging::MsgBegin("EVENTS_TREE", "reordering tree before");
     logging::AccessibleInfo("reordering for", mParent);
     Controller()->RootEventTree().Log();
     logging::MsgEnd();
 
     if (logging::IsEnabled(logging::eVerbose)) {
       logging::Tree("EVENTS_TREE", "Container tree", mParent->Document(),
                     PrefixLog, static_cast<void*>(this));
@@ -57,48 +57,42 @@ void
 TreeMutation::AfterInsertion(Accessible* aChild)
 {
   MOZ_ASSERT(aChild->Parent() == mParent);
 
   if (static_cast<uint32_t>(aChild->mIndexInParent) < mStartIdx) {
     mStartIdx = aChild->mIndexInParent + 1;
   }
 
-  if (!mEventTree) {
-    mEventTree = Controller()->QueueMutation(mParent);
-    if (!mEventTree) {
-      mEventTree = kNoEventTree;
-    }
+  if (!mQueueEvents) {
+    return;
   }
 
-  if (mEventTree != kNoEventTree) {
-    mEventTree->Shown(aChild);
-    Controller()->QueueNameChange(aChild);
-  }
+  RefPtr<AccShowEvent> ev = new AccShowEvent(aChild);
+  DebugOnly<bool> added = Controller()->QueueMutationEvent(ev);
+  MOZ_ASSERT(added);
+  aChild->SetShowEventTarget(true);
 }
 
 void
 TreeMutation::BeforeRemoval(Accessible* aChild, bool aNoShutdown)
 {
   MOZ_ASSERT(aChild->Parent() == mParent);
 
   if (static_cast<uint32_t>(aChild->mIndexInParent) < mStartIdx) {
     mStartIdx = aChild->mIndexInParent;
   }
 
-  if (!mEventTree) {
-    mEventTree = Controller()->QueueMutation(mParent);
-    if (!mEventTree) {
-      mEventTree = kNoEventTree;
-    }
+  if (!mQueueEvents) {
+    return;
   }
 
-  if (mEventTree != kNoEventTree) {
-    mEventTree->Hidden(aChild, !aNoShutdown);
-    Controller()->QueueNameChange(aChild);
+  RefPtr<AccHideEvent> ev = new AccHideEvent(aChild, !aNoShutdown);
+  if (Controller()->QueueMutationEvent(ev)) {
+    aChild->SetHideEventTarget(true);
   }
 }
 
 void
 TreeMutation::Done()
 {
   MOZ_ASSERT(mParent->mStateFlags & Accessible::eKidsMutating);
   mParent->mStateFlags &= ~Accessible::eKidsMutating;
@@ -119,17 +113,17 @@ TreeMutation::Done()
   mParent->mEmbeddedObjCollector = nullptr;
   mParent->mStateFlags |= mStateFlagsCopy & Accessible::eKidsMutating;
 
 #ifdef DEBUG
   mIsDone = true;
 #endif
 
 #ifdef A11Y_LOG
-  if (mEventTree != kNoEventTree && logging::IsEnabled(logging::eEventTree)) {
+  if (mQueueEvents && logging::IsEnabled(logging::eEventTree)) {
     logging::MsgBegin("EVENTS_TREE", "reordering tree after");
     logging::AccessibleInfo("reordering for", mParent);
     Controller()->RootEventTree().Log();
     logging::MsgEnd();
   }
 #endif
 }
 
--- a/accessible/base/EventTree.h
+++ b/accessible/base/EventTree.h
@@ -42,17 +42,21 @@ private:
 
 #ifdef A11Y_LOG
   static const char* PrefixLog(void* aData, Accessible*);
 #endif
 
   Accessible* mParent;
   uint32_t mStartIdx;
   uint32_t mStateFlagsCopy;
-  EventTree* mEventTree;
+
+  /*
+   * True if mutation events should be queued.
+   */
+  bool mQueueEvents;
 
 #ifdef DEBUG
   bool mIsDone;
 #endif
 };
 
 
 /**
@@ -62,41 +66,44 @@ class EventTree final {
 public:
   EventTree() :
     mFirst(nullptr), mNext(nullptr), mContainer(nullptr), mFireReorder(false) { }
   explicit EventTree(Accessible* aContainer, bool aFireReorder) :
     mFirst(nullptr), mNext(nullptr), mContainer(aContainer),
     mFireReorder(aFireReorder) { }
   ~EventTree() { Clear(); }
 
-  void Shown(Accessible* aChild);
-
-  void Hidden(Accessible* aChild, bool aNeedsShutdown = true);
+  void Shown(Accessible* aTarget);
+  void Hidden(Accessible*, bool);
 
   /**
    * Return an event tree node for the given accessible.
    */
   const EventTree* Find(const Accessible* aContainer) const;
 
+  /**
+   * Add a mutation event to this event tree.
+   */
+  void Mutated(AccMutationEvent* aEv);
+
 #ifdef A11Y_LOG
   void Log(uint32_t aLevel = UINT32_MAX) const;
 #endif
 
 private:
   /**
    * Processes the event queue and fires events.
    */
   void Process(const RefPtr<DocAccessible>& aDeathGrip);
 
   /**
    * Return an event subtree for the given accessible.
    */
   EventTree* FindOrInsert(Accessible* aContainer);
 
-  void Mutated(AccMutationEvent* aEv);
   void Clear();
 
   UniquePtr<EventTree> mFirst;
   UniquePtr<EventTree> mNext;
 
   Accessible* mContainer;
   nsTArray<RefPtr<AccMutationEvent>> mDependentEvents;
   bool mFireReorder;
--- a/accessible/base/NotificationController.cpp
+++ b/accessible/base/NotificationController.cpp
@@ -19,17 +19,17 @@ using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // NotificationCollector
 ////////////////////////////////////////////////////////////////////////////////
 
 NotificationController::NotificationController(DocAccessible* aDocument,
                                                nsIPresShell* aPresShell) :
   EventQueue(aDocument), mObservingState(eNotObservingRefresh),
-  mPresShell(aPresShell)
+  mPresShell(aPresShell), mEventGeneration(0)
 {
 #ifdef DEBUG
   mMoveGuardOnStack = false;
 #endif
 
   // Schedule initial accessible tree construction.
   ScheduleProcessing();
 }
@@ -75,17 +75,17 @@ NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(N
 
 ////////////////////////////////////////////////////////////////////////////////
 // NotificationCollector: public
 
 void
 NotificationController::Shutdown()
 {
   if (mObservingState != eNotObservingRefresh &&
-      mPresShell->RemoveRefreshObserver(this, Flush_Display)) {
+      mPresShell->RemoveRefreshObserver(this, FlushType::Display)) {
     mObservingState = eNotObservingRefresh;
   }
 
   // Shutdown handling child documents.
   int32_t childDocCount = mHangingChildDocuments.Length();
   for (int32_t idx = childDocCount - 1; idx >= 0; idx--) {
     if (!mHangingChildDocuments[idx]->IsDefunct())
       mHangingChildDocuments[idx]->Shutdown();
@@ -109,16 +109,306 @@ NotificationController::QueueMutation(Ac
 {
   EventTree* tree = mEventTree.FindOrInsert(aContainer);
   if (tree) {
     ScheduleProcessing();
   }
   return tree;
 }
 
+bool
+NotificationController::QueueMutationEvent(AccTreeMutationEvent* aEvent)
+{
+  // We have to allow there to be a hide and then a show event for a target
+  // because of targets getting moved.  However we need to coalesce a show and
+  // then a hide for a target which means we need to check for that here.
+  if (aEvent->GetEventType() == nsIAccessibleEvent::EVENT_HIDE  &&
+      aEvent->GetAccessible()->ShowEventTarget()) {
+    AccTreeMutationEvent* showEvent = mMutationMap.GetEvent(aEvent->GetAccessible(), EventMap::ShowEvent);
+    DropMutationEvent(showEvent);
+    return false;
+  }
+
+  AccMutationEvent* mutEvent = downcast_accEvent(aEvent);
+  mEventGeneration++;
+  mutEvent->SetEventGeneration(mEventGeneration);
+
+  if (!mFirstMutationEvent) {
+    mFirstMutationEvent = aEvent;
+    ScheduleProcessing();
+  }
+
+  if (mLastMutationEvent) {
+    NS_ASSERTION(!mLastMutationEvent->NextEvent(), "why isn't the last event the end?");
+    mLastMutationEvent->SetNextEvent(aEvent);
+  }
+
+  aEvent->SetPrevEvent(mLastMutationEvent);
+  mLastMutationEvent = aEvent;
+  mMutationMap.PutEvent(aEvent);
+
+  // Because we could be hiding the target of a show event we need to get rid
+  // of any such events.  It may be possible to do less than coallesce all
+  // events, however that is easiest.
+  if (aEvent->GetEventType() == nsIAccessibleEvent::EVENT_HIDE) {
+    CoalesceMutationEvents();
+
+    // mLastMutationEvent will point to something other than aEvent if and only
+    // if aEvent was just coalesced away.  In that case a parent accessible
+    // must already have the required reorder and text change events so we are
+    // done here.
+    if (mLastMutationEvent != aEvent) {
+      return false;
+    }
+  }
+
+  // We need to fire a reorder event after all of the events targeted at shown or
+  // hidden children of a container.  So either queue a new one, or move an
+  // existing one to the end of the queue if the container already has a
+  // reorder event.
+  Accessible* target = aEvent->GetAccessible();
+  Accessible* container = aEvent->GetAccessible()->Parent();
+  RefPtr<AccReorderEvent> reorder;
+  if (!container->ReorderEventTarget()) {
+    reorder = new AccReorderEvent(container);
+    container->SetReorderEventTarget(true);
+    mMutationMap.PutEvent(reorder);
+
+    // Since this is the first child of container that is changing, the name of
+    // container may be changing.
+    QueueNameChange(target);
+  } else {
+    AccReorderEvent* event = downcast_accEvent(mMutationMap.GetEvent(container, EventMap::ReorderEvent));
+    reorder = event;
+    if (mFirstMutationEvent == event) {
+      mFirstMutationEvent = event->NextEvent();
+    } else {
+      event->PrevEvent()->SetNextEvent(event->NextEvent());
+    }
+
+      event->NextEvent()->SetPrevEvent(event->PrevEvent());
+      event->SetNextEvent(nullptr);
+  }
+
+  reorder->SetEventGeneration(mEventGeneration);
+  reorder->SetPrevEvent(mLastMutationEvent);
+  mLastMutationEvent->SetNextEvent(reorder);
+  mLastMutationEvent = reorder;
+
+  // It is not possible to have a text change event for something other than a
+  // hyper text accessible.
+  if (!container->IsHyperText()) {
+    return true;
+  }
+
+  MOZ_ASSERT(mutEvent);
+
+  nsString text;
+  aEvent->GetAccessible()->AppendTextTo(text);
+  if (text.IsEmpty()) {
+    return true;
+  }
+
+  int32_t offset = container->AsHyperText()->GetChildOffset(target);
+  AccTreeMutationEvent* prevEvent = aEvent->PrevEvent();
+  while (prevEvent && prevEvent->GetEventType() == nsIAccessibleEvent::EVENT_REORDER) {
+    prevEvent = prevEvent->PrevEvent();
+  }
+
+  if (prevEvent && prevEvent->GetEventType() == nsIAccessibleEvent::EVENT_HIDE &&
+      mutEvent->IsHide()) {
+    AccHideEvent* prevHide = downcast_accEvent(prevEvent);
+    AccTextChangeEvent* prevTextChange = prevHide->mTextChangeEvent;
+    if (prevTextChange && prevHide->Parent() == mutEvent->Parent()) {
+      if (prevHide->mNextSibling == target) {
+        target->AppendTextTo(prevTextChange->mModifiedText);
+        prevHide->mTextChangeEvent.swap(mutEvent->mTextChangeEvent);
+      } else if (prevHide->mPrevSibling == target) {
+        nsString temp;
+        target->AppendTextTo(temp);
+
+        uint32_t extraLen = temp.Length();
+        temp += prevTextChange->mModifiedText;;
+        prevTextChange->mModifiedText = temp;
+        prevTextChange->mStart -= extraLen;
+        prevHide->mTextChangeEvent.swap(mutEvent->mTextChangeEvent);
+      }
+    }
+  } else if (prevEvent && mutEvent->IsShow() &&
+             prevEvent->GetEventType() == nsIAccessibleEvent::EVENT_SHOW) {
+    AccShowEvent* prevShow = downcast_accEvent(prevEvent);
+    AccTextChangeEvent* prevTextChange = prevShow->mTextChangeEvent;
+    if (prevTextChange && prevShow->Parent() == target->Parent()) {
+      int32_t index = target->IndexInParent();
+      int32_t prevIndex = prevShow->GetAccessible()->IndexInParent();
+      if (prevIndex + 1 == index) {
+        target->AppendTextTo(prevTextChange->mModifiedText);
+        prevShow->mTextChangeEvent.swap(mutEvent->mTextChangeEvent);
+      } else if (index + 1 == prevIndex) {
+        nsString temp;
+        target->AppendTextTo(temp);
+        prevTextChange->mStart -= temp.Length();
+        temp += prevTextChange->mModifiedText;
+        prevTextChange->mModifiedText = temp;
+        prevShow->mTextChangeEvent.swap(mutEvent->mTextChangeEvent);
+      }
+    }
+  }
+
+  if (!mutEvent->mTextChangeEvent) {
+    mutEvent->mTextChangeEvent =
+      new AccTextChangeEvent(container, offset, text, mutEvent->IsShow(),
+                             aEvent->mIsFromUserInput ? eFromUserInput : eNoUserInput);
+  }
+
+  return true;
+}
+
+void
+NotificationController::DropMutationEvent(AccTreeMutationEvent* aEvent)
+{
+  // unset the event bits since the event isn't being fired any more.
+  if (aEvent->GetEventType() == nsIAccessibleEvent::EVENT_REORDER) {
+    aEvent->GetAccessible()->SetReorderEventTarget(false);
+  } else if (aEvent->GetEventType() == nsIAccessibleEvent::EVENT_SHOW) {
+    aEvent->GetAccessible()->SetShowEventTarget(false);
+  } else {
+    AccHideEvent* hideEvent = downcast_accEvent(aEvent);
+    MOZ_ASSERT(hideEvent);
+
+    if (hideEvent->NeedsShutdown()) {
+      mDocument->ShutdownChildrenInSubtree(aEvent->GetAccessible());
+    }
+  }
+
+  // Do the work to splice the event out of the list.
+  if (mFirstMutationEvent == aEvent) {
+    mFirstMutationEvent = aEvent->NextEvent();
+  } else {
+    aEvent->PrevEvent()->SetNextEvent(aEvent->NextEvent());
+  }
+
+  if (mLastMutationEvent == aEvent) {
+    mLastMutationEvent = aEvent->PrevEvent();
+  } else {
+    aEvent->NextEvent()->SetPrevEvent(aEvent->PrevEvent());
+  }
+
+  aEvent->SetPrevEvent(nullptr);
+  aEvent->SetNextEvent(nullptr);
+  mMutationMap.RemoveEvent(aEvent);
+}
+
+void
+NotificationController::CoalesceMutationEvents()
+{
+  AccTreeMutationEvent* event = mFirstMutationEvent;
+  while (event) {
+    AccTreeMutationEvent* nextEvent = event->NextEvent();
+    uint32_t eventType = event->GetEventType();
+    if (event->GetEventType() == nsIAccessibleEvent::EVENT_REORDER) {
+      Accessible* acc = event->GetAccessible();
+      while (acc) {
+        if (acc->IsDoc()) {
+          break;
+        }
+
+        // if a parent of the reorder event's target is being hidden that
+        // hide event's target must have a parent that is also a reorder event
+        // target.  That means we don't need this reorder event.
+        if (acc->HideEventTarget()) {
+          DropMutationEvent(event);
+          break;
+        }
+
+        Accessible* parent = acc->Parent();
+        if (parent->ReorderEventTarget()) {
+          AccReorderEvent* reorder = downcast_accEvent(mMutationMap.GetEvent(parent, EventMap::ReorderEvent));
+
+          // We want to make sure that a reorder event comes after any show or
+          // hide events targeted at the children of its target.  We keep the
+          // invariant that event generation goes up as you are farther in the
+          // queue, so we want to use the spot of the event with the higher
+          // generation number, and keep that generation number.
+          if (reorder && reorder->EventGeneration() < event->EventGeneration()) {
+            reorder->SetEventGeneration(event->EventGeneration());
+
+            // It may be true that reorder was before event, and we coalesced
+            // away all the show / hide events between them.  In that case
+            // event is already immediately after reorder in the queue and we
+            // do not need to rearrange the list of events.
+            if (event != reorder->NextEvent()) {
+              // There really should be a show or hide event before the first
+              // reorder event.
+              if (reorder->PrevEvent()) {
+                reorder->PrevEvent()->SetNextEvent(reorder->NextEvent());
+              } else {
+                mFirstMutationEvent = reorder->NextEvent();
+              }
+
+              reorder->NextEvent()->SetPrevEvent(reorder->PrevEvent());
+              event->PrevEvent()->SetNextEvent(reorder);
+              reorder->SetPrevEvent(event->PrevEvent());
+              event->SetPrevEvent(reorder);
+              reorder->SetNextEvent(event);
+            }
+          }
+          DropMutationEvent(event);
+          break;
+        }
+
+        acc = parent;
+      }
+    } else if (eventType == nsIAccessibleEvent::EVENT_SHOW) {
+      Accessible* parent = event->GetAccessible()->Parent();
+      while (parent) {
+        if (parent->IsDoc()) {
+          break;
+        }
+
+        // if the parent of a show event is being either shown or hidden then
+        // we don't need to fire a show event for a subtree of that change.
+        if (parent->ShowEventTarget() || parent->HideEventTarget()) {
+          DropMutationEvent(event);
+          break;
+        }
+
+        parent = parent->Parent();
+      }
+    } else {
+      MOZ_ASSERT(eventType == nsIAccessibleEvent::EVENT_HIDE, "mutation event list has an invalid event");
+
+      AccHideEvent* hideEvent = downcast_accEvent(event);
+      Accessible* parent = hideEvent->Parent();
+      while (parent) {
+        if (parent->IsDoc()) {
+          break;
+        }
+
+        if (parent->HideEventTarget()) {
+          DropMutationEvent(event);
+          break;
+        }
+
+        if (parent->ShowEventTarget()) {
+          AccShowEvent* showEvent = downcast_accEvent(mMutationMap.GetEvent(parent, EventMap::ShowEvent));
+          if (showEvent->EventGeneration() < hideEvent->EventGeneration()) {
+            DropMutationEvent(hideEvent);
+            break;
+          }
+        }
+
+        parent = parent->Parent();
+      }
+    }
+
+    event = nextEvent;
+  }
+}
+
 void
 NotificationController::ScheduleChildDocBinding(DocAccessible* aDocument)
 {
   // Schedule child document binding to the tree.
   mHangingChildDocuments.AppendElement(aDocument);
   ScheduleProcessing();
 }
 
@@ -149,17 +439,17 @@ NotificationController::ScheduleContentI
 }
 
 void
 NotificationController::ScheduleProcessing()
 {
   // If notification flush isn't planed yet start notification flush
   // asynchronously (after style and layout).
   if (mObservingState == eNotObservingRefresh) {
-    if (mPresShell->AddRefreshObserver(this, Flush_Display))
+    if (mPresShell->AddRefreshObserver(this, FlushType::Display))
       mObservingState = eRefreshObserving;
   }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // NotificationCollector: protected
 
 bool
@@ -167,16 +457,138 @@ NotificationController::IsUpdatePending(
 {
   return mPresShell->IsLayoutFlushObserver() ||
     mObservingState == eRefreshProcessingForUpdate ||
     mContentInsertions.Count() != 0 || mNotifications.Length() != 0 ||
     mTextHash.Count() != 0 ||
     !mDocument->HasLoadState(DocAccessible::eTreeConstructed);
 }
 
+void
+NotificationController::ProcessMutationEvents()
+{
+  // there is no reason to fire a hide event for a child of a show event
+  // target.  That can happen if something is inserted into the tree and
+  // removed before the next refresh driver tick, but it should not be
+  // observable outside gecko so it should be safe to coalesce away any such
+  // events.  This means that it should be fine to fire all of the hide events
+  // first, and then deal with any shown subtrees.
+  for (AccTreeMutationEvent* event = mFirstMutationEvent;
+       event; event = event->NextEvent()) {
+    if (event->GetEventType() != nsIAccessibleEvent::EVENT_HIDE) {
+      continue;
+    }
+
+    nsEventShell::FireEvent(event);
+    if (!mDocument) {
+      return;
+    }
+
+    AccMutationEvent* mutEvent = downcast_accEvent(event);
+    if (mutEvent->mTextChangeEvent) {
+      nsEventShell::FireEvent(mutEvent->mTextChangeEvent);
+      if (!mDocument) {
+        return;
+      }
+    }
+
+    // Fire menupopup end event before a hide event if a menu goes away.
+
+    // XXX: We don't look into children of hidden subtree to find hiding
+    // menupopup (as we did prior bug 570275) because we don't do that when
+    // menu is showing (and that's impossible until bug 606924 is fixed).
+    // Nevertheless we should do this at least because layout coalesces
+    // the changes before our processing and we may miss some menupopup
+    // events. Now we just want to be consistent in content insertion/removal
+    // handling.
+    if (event->mAccessible->ARIARole() == roles::MENUPOPUP) {
+      nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END,
+                              event->mAccessible);
+      if (!mDocument) {
+        return;
+      }
+    }
+
+    AccHideEvent* hideEvent = downcast_accEvent(event);
+    if (hideEvent->NeedsShutdown()) {
+      mDocument->ShutdownChildrenInSubtree(event->mAccessible);
+    }
+  }
+
+  // Group the show events by the parent of their target.
+  nsDataHashtable<nsPtrHashKey<Accessible>, nsTArray<AccTreeMutationEvent*>> showEvents;
+  for (AccTreeMutationEvent* event = mFirstMutationEvent;
+       event; event = event->NextEvent()) {
+    if (event->GetEventType() != nsIAccessibleEvent::EVENT_SHOW) {
+      continue;
+    }
+
+    Accessible* parent = event->GetAccessible()->Parent();
+    showEvents.GetOrInsert(parent).AppendElement(event);
+  }
+
+  // We need to fire show events for the children of an accessible in the order
+  // of their indices at this point.  So sort each set of events for the same
+  // container by the index of their target.
+  for (auto iter = showEvents.Iter(); !iter.Done(); iter.Next()) {
+    struct AccIdxComparator {
+      bool LessThan(const AccTreeMutationEvent* a, const AccTreeMutationEvent* b) const
+      {
+        int32_t aIdx = a->GetAccessible()->IndexInParent();
+        int32_t bIdx = b->GetAccessible()->IndexInParent();
+        MOZ_ASSERT(aIdx >= 0 && bIdx >= 0 && aIdx != bIdx);
+        return aIdx < bIdx;
+      }
+      bool Equals(const AccTreeMutationEvent* a, const AccTreeMutationEvent* b) const
+      {
+        DebugOnly<int32_t> aIdx = a->GetAccessible()->IndexInParent();
+        DebugOnly<int32_t> bIdx = b->GetAccessible()->IndexInParent();
+        MOZ_ASSERT(aIdx >= 0 && bIdx >= 0 && aIdx != bIdx);
+        return false;
+      }
+    };
+
+    nsTArray<AccTreeMutationEvent*>& events = iter.Data();
+    events.Sort(AccIdxComparator());
+    for (AccTreeMutationEvent* event: events) {
+      nsEventShell::FireEvent(event);
+      if (!mDocument) {
+        return;
+      }
+
+      AccMutationEvent* mutEvent = downcast_accEvent(event);
+      if (mutEvent->mTextChangeEvent) {
+        nsEventShell::FireEvent(mutEvent->mTextChangeEvent);
+        if (!mDocument) {
+          return;
+        }
+      }
+    }
+  }
+
+  // Now we can fire the reorder events after all the show and hide events.
+  for (AccTreeMutationEvent* event = mFirstMutationEvent;
+       event; event = event->NextEvent()) {
+    if (event->GetEventType() != nsIAccessibleEvent::EVENT_REORDER) {
+      continue;
+    }
+
+    nsEventShell::FireEvent(event);
+    if (!mDocument) {
+      return;
+    }
+
+    Accessible* target = event->GetAccessible();
+    target->Document()->MaybeNotifyOfValueChange(target);
+    if (!mDocument) {
+      return;
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // NotificationCollector: private
 
 void
 NotificationController::WillRefresh(mozilla::TimeStamp aTime)
 {
   PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
   Telemetry::AutoTimer<Telemetry::A11Y_UPDATE_TIME> updateTimer;
@@ -338,18 +750,21 @@ NotificationController::WillRefresh(mozi
 
         outerDocAcc->RemoveChild(childDoc);
       }
 
       // Failed to bind the child document, destroy it.
       childDoc->Shutdown();
     }
   }
-
   mHangingChildDocuments.Clear();
+  MOZ_ASSERT(mDocument, "Illicit document shutdown");
+  if (!mDocument) {
+    return;
+  }
 
   // If the document is ready and all its subdocuments are completely loaded
   // then process the document load.
   if (mDocument->HasLoadState(DocAccessible::eReady) &&
       !mDocument->HasLoadState(DocAccessible::eCompletelyLoaded) &&
       hangingDocCnt == 0) {
     uint32_t childDocCnt = mDocument->ChildDocumentCount(), childDocIdx = 0;
     for (; childDocIdx < childDocCnt; childDocIdx++) {
@@ -392,57 +807,143 @@ NotificationController::WillRefresh(mozi
   }
   mRelocations.Clear();
 
   // If a generic notification occurs after this point then we may be allowed to
   // process it synchronously.  However we do not want to reenter if fireing
   // events causes script to run.
   mObservingState = eRefreshProcessing;
 
-  RefPtr<DocAccessible> deathGrip(mDocument);
-  mEventTree.Process(deathGrip);
-  deathGrip = nullptr;
+  CoalesceMutationEvents();
+  ProcessMutationEvents();
+  mEventGeneration = 0;
+
+  // Now that we are done with them get rid of the events we fired.
+  RefPtr<AccTreeMutationEvent> mutEvent = Move(mFirstMutationEvent);
+  mLastMutationEvent = nullptr;
+  mFirstMutationEvent = nullptr;
+  while (mutEvent) {
+    RefPtr<AccTreeMutationEvent> nextEvent = mutEvent->NextEvent();
+    Accessible* target = mutEvent->GetAccessible();
+
+    // We need to be careful here, while it may seem that we can simply 0 all
+    // the pending event bits that is not true.  Because accessibles may be
+    // reparented they may be the target of both a hide event and a show event
+    // at the same time.
+    if (mutEvent->GetEventType() == nsIAccessibleEvent::EVENT_SHOW) {
+      target->SetShowEventTarget(false);
+    }
+
+    if (mutEvent->GetEventType() == nsIAccessibleEvent::EVENT_HIDE) {
+      target->SetHideEventTarget(false);
+    }
+
+    // However it is not possible for a reorder event target to also be the
+    // target of a show or hide, so we can just zero that.
+    target->SetReorderEventTarget(false);
+
+    mutEvent->SetPrevEvent(nullptr);
+    mutEvent->SetNextEvent(nullptr);
+    mMutationMap.RemoveEvent(mutEvent);
+    mutEvent = nextEvent;
+  }
 
   ProcessEventQueue();
 
   if (IPCAccessibilityActive()) {
     size_t newDocCount = newChildDocs.Length();
     for (size_t i = 0; i < newDocCount; i++) {
       DocAccessible* childDoc = newChildDocs[i];
+      if (childDoc->IsDefunct()) {
+        continue;
+      }
+
       Accessible* parent = childDoc->Parent();
       DocAccessibleChild* parentIPCDoc = mDocument->IPCDoc();
+      MOZ_DIAGNOSTIC_ASSERT(parentIPCDoc);
       uint64_t id = reinterpret_cast<uintptr_t>(parent->UniqueID());
-      MOZ_ASSERT(id);
+      MOZ_DIAGNOSTIC_ASSERT(id);
       DocAccessibleChild* ipcDoc = childDoc->IPCDoc();
       if (ipcDoc) {
         parentIPCDoc->SendBindChildDoc(ipcDoc, id);
         continue;
       }
 
       ipcDoc = new DocAccessibleChild(childDoc);
       childDoc->SetIPCDoc(ipcDoc);
+
+#if defined(XP_WIN)
+      parentIPCDoc->ConstructChildDocInParentProcess(ipcDoc, id,
+                                                     AccessibleWrap::GetChildIDFor(childDoc));
+#else
       nsCOMPtr<nsITabChild> tabChild =
         do_GetInterface(mDocument->DocumentNode()->GetDocShell());
       if (tabChild) {
         static_cast<TabChild*>(tabChild.get())->
-          SendPDocAccessibleConstructor(ipcDoc, parentIPCDoc, id);
-#if defined(XP_WIN)
-        MOZ_ASSERT(parentIPCDoc);
-        ipcDoc->SendMsaaID(AccessibleWrap::GetChildIDFor(childDoc));
+          SendPDocAccessibleConstructor(ipcDoc, parentIPCDoc, id, 0, 0);
+      }
 #endif
-      }
     }
   }
 
   mObservingState = eRefreshObserving;
   if (!mDocument)
     return;
 
   // Stop further processing if there are no new notifications of any kind or
   // events and document load is processed.
   if (mContentInsertions.Count() == 0 && mNotifications.IsEmpty() &&
       mEvents.IsEmpty() && mTextHash.Count() == 0 &&
       mHangingChildDocuments.IsEmpty() &&
       mDocument->HasLoadState(DocAccessible::eCompletelyLoaded) &&
-      mPresShell->RemoveRefreshObserver(this, Flush_Display)) {
+      mPresShell->RemoveRefreshObserver(this, FlushType::Display)) {
     mObservingState = eNotObservingRefresh;
   }
 }
+
+void
+NotificationController::EventMap::PutEvent(AccTreeMutationEvent* aEvent)
+{
+  EventType type = GetEventType(aEvent);
+  uint64_t addr = reinterpret_cast<uintptr_t>(aEvent->GetAccessible());
+  MOZ_ASSERT((addr & 0x3) == 0, "accessible is not 4 byte aligned");
+  addr |= type;
+  mTable.Put(addr, aEvent);
+}
+
+AccTreeMutationEvent*
+NotificationController::EventMap::GetEvent(Accessible* aTarget, EventType aType)
+{
+  uint64_t addr = reinterpret_cast<uintptr_t>(aTarget);
+  MOZ_ASSERT((addr & 0x3) == 0, "target is not 4 byte aligned");
+
+  addr |= aType;
+  return mTable.GetWeak(addr);
+}
+
+void
+NotificationController::EventMap::RemoveEvent(AccTreeMutationEvent* aEvent)
+{
+  EventType type = GetEventType(aEvent);
+  uint64_t addr = reinterpret_cast<uintptr_t>(aEvent->GetAccessible());
+  MOZ_ASSERT((addr & 0x3) == 0, "accessible is not 4 byte aligned");
+  addr |= type;
+
+  MOZ_ASSERT(mTable.GetWeak(addr) == aEvent, "mTable has the wrong event");
+  mTable.Remove(addr);
+}
+
+  NotificationController::EventMap::EventType
+NotificationController::EventMap::GetEventType(AccTreeMutationEvent* aEvent)
+{
+  switch(aEvent->GetEventType())
+  {
+    case nsIAccessibleEvent::EVENT_SHOW:
+      return ShowEvent;
+    case nsIAccessibleEvent::EVENT_HIDE:
+      return HideEvent;
+    case nsIAccessibleEvent::EVENT_REORDER:
+      return ReorderEvent;
+    default:
+      MOZ_ASSERT_UNREACHABLE("event has invalid type");
+      return ShowEvent;
+  }
+}
--- a/accessible/base/NotificationController.h
+++ b/accessible/base/NotificationController.h
@@ -155,16 +155,27 @@ public:
     NotificationController* mController;
   };
 
 #ifdef A11Y_LOG
   const EventTree& RootEventTree() const { return mEventTree; };
 #endif
 
   /**
+   * Queue a mutation event to emit if not coalesced away.  Returns true if the
+   * event was queued and has not yet been coalesced.
+   */
+  bool QueueMutationEvent(AccTreeMutationEvent* aEvent);
+
+  /**
+   * Coalesce all queued mutation events.
+   */
+  void CoalesceMutationEvents();
+
+  /**
    * Schedule binding the child document to the tree of this document.
    */
   void ScheduleChildDocBinding(DocAccessible* aDocument);
 
   /**
    * Schedule the accessible tree update because of rendered text changes.
    */
   inline void ScheduleTextUpdate(nsIContent* aTextNode)
@@ -287,16 +298,26 @@ private:
   void StorePrecedingEvents(nsTArray<RefPtr<AccHideEvent>>&& aEvs)
   {
     MOZ_ASSERT(mMoveGuardOnStack, "No move guard on stack!");
     mPrecedingEvents.InsertElementsAt(0, aEvs);
   }
 
 private:
   /**
+   * get rid of a mutation event that is no longer necessary.
+   */
+  void DropMutationEvent(AccTreeMutationEvent* aEvent);
+
+  /**
+   * Fire all necessary mutation events.
+   */
+  void ProcessMutationEvents();
+
+  /**
    * Indicates whether we're waiting on an event queue processing from our
    * notification controller to flush events.
    */
   enum eObservingState {
     eNotObservingRefresh,
     eRefreshObserving,
     eRefreshProcessing,
     eRefreshProcessingForUpdate
@@ -371,14 +392,48 @@ private:
   nsTArray<RefPtr<AccHideEvent>> mPrecedingEvents;
 
 #ifdef DEBUG
   bool mMoveGuardOnStack;
 #endif
 
   friend class MoveGuard;
   friend class EventTree;
+
+  /**
+   * A list of all mutation events we may want to emit.  Ordered from the first
+   * event that should be emitted to the last one to emit.
+   */
+  RefPtr<AccTreeMutationEvent> mFirstMutationEvent;
+  RefPtr<AccTreeMutationEvent> mLastMutationEvent;
+
+  /**
+   * A class to map an accessible and event type to an event.
+   */
+  class EventMap
+  {
+  public:
+    enum EventType
+    {
+      ShowEvent = 0x0,
+      HideEvent = 0x1,
+      ReorderEvent = 0x2,
+    };
+
+    void PutEvent(AccTreeMutationEvent* aEvent);
+    AccTreeMutationEvent* GetEvent(Accessible* aTarget, EventType aType);
+    void RemoveEvent(AccTreeMutationEvent* aEvent);
+    void Clear() { mTable.Clear(); }
+
+  private:
+    EventType GetEventType(AccTreeMutationEvent* aEvent);
+
+    nsRefPtrHashtable<nsUint64HashKey, AccTreeMutationEvent> mTable;
+  };
+
+  EventMap mMutationMap;
+  uint32_t mEventGeneration;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif // mozilla_a11y_NotificationController_h_
--- a/accessible/base/RelationType.h
+++ b/accessible/base/RelationType.h
@@ -122,16 +122,42 @@ enum class RelationType {
    */
   CONTAINING_WINDOW = 0x13,
 
   /**
    * The target object is the containing application object.
    */
   CONTAINING_APPLICATION = 0x14,
 
-  LAST = CONTAINING_APPLICATION
+
+  /**
+   * The target object provides the detailed, extended description for this
+   * object. It provides more detailed information than would normally be
+   * provided using the DESCRIBED_BY relation. A common use for this relation is
+   * in digital publishing where an extended description needs to be conveyed in
+   * a book that requires structural markup or the embedding of other technology
+   * to provide illustrative content.
+   */
+  DETAILS = 0x15,
 
+  /**
+   * This object provides the detailed, extended description for the target
+   * object. See DETAILS relation.
+   */
+  DETAILS_FOR = 0x16,
+
+  /**
+   * The target object is the error message for this object.
+   */
+  ERRORMSG = 0x17,
+
+  /**
+   * This object is the error message for the target object.
+   */
+  ERRORMSG_FOR = 0x18,
+
+  LAST = ERRORMSG_FOR
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/base/RelationTypeMap.h
+++ b/accessible/base/RelationTypeMap.h
@@ -123,8 +123,32 @@ RELATIONTYPE(CONTAINING_TAB_PANE,
              NAVRELATION_CONTAINING_TAB_PANE,
              IA2_RELATION_CONTAINING_TAB_PANE)
 
 RELATIONTYPE(CONTAINING_APPLICATION,
              "containing application",
              ATK_RELATION_NULL,
              NAVRELATION_CONTAINING_APPLICATION,
              IA2_RELATION_CONTAINING_APPLICATION)
+
+RELATIONTYPE(DETAILS,
+             "details",
+             ATK_RELATION_NULL,
+             NAVRELATION_DETAILS,
+             IA2_RELATION_DETAILS)
+
+RELATIONTYPE(DETAILS_FOR,
+             "details for",
+             ATK_RELATION_NULL,
+             NAVRELATION_DETAILS_FOR,
+             IA2_RELATION_DETAILS_FOR)
+
+RELATIONTYPE(ERRORMSG,
+             "error",
+             ATK_RELATION_NULL,
+             NAVRELATION_ERROR,
+             IA2_RELATION_ERROR)
+
+RELATIONTYPE(ERRORMSG_FOR,
+             "error for",
+             ATK_RELATION_NULL,
+             NAVRELATION_ERROR_FOR,
+             IA2_RELATION_ERROR_FOR)
--- a/accessible/base/SelectionManager.h
+++ b/accessible/base/SelectionManager.h
@@ -116,17 +116,17 @@ protected:
 
   /**
    * Process DOM selection change. Fire selection and caret move events.
    */
   void ProcessSelectionChanged(SelData* aSelData);
 
 private:
   // Currently focused control.
-  nsWeakFrame mCurrCtrlFrame;
+  WeakFrame mCurrCtrlFrame;
   int32_t mCaretOffset;
   HyperTextAccessible* mAccWithCaret;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/base/StyleInfo.cpp
+++ b/accessible/base/StyleInfo.cpp
@@ -76,17 +76,17 @@ StyleInfo::TextIndent(nsAString& aValue)
     case eStyleUnit_Enumerated:
     case eStyleUnit_Calc:
       aValue.AppendLiteral("0px");
       break;
   }
 }
 
 void
-StyleInfo::Margin(css::Side aSide, nsAString& aValue)
+StyleInfo::Margin(Side aSide, nsAString& aValue)
 {
   MOZ_ASSERT(mElement->GetPrimaryFrame(), " mElement->GetPrimaryFrame() needs to be valid pointer");
   aValue.Truncate();
 
   nscoord coordVal = mElement->GetPrimaryFrame()->GetUsedMargin().Side(aSide);
   aValue.AppendFloat(nsPresContext::AppUnitsToFloatCSSPixels(coordVal));
   aValue.AppendLiteral("px");
 }
--- a/accessible/base/TextAttrs.cpp
+++ b/accessible/base/TextAttrs.cpp
@@ -13,20 +13,16 @@
 #include "gfxFont.h"
 #include "nsFontMetrics.h"
 #include "nsLayoutUtils.h"
 #include "nsContainerFrame.h"
 #include "HyperTextAccessible.h"
 #include "mozilla/AppUnits.h"
 #include "mozilla/gfx/2D.h"
 
-#if defined(MOZ_WIDGET_GTK)
-#include "gfxPlatformGtk.h" // xxx - for UseFcFontList
-#endif
-
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // TextAttrsMgr
 ////////////////////////////////////////////////////////////////////////////////
 
 void
@@ -369,20 +365,19 @@ TextAttrsMgr::BGColorTextAttr::
   nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::backgroundColor,
                          formattedValue);
 }
 
 bool
 TextAttrsMgr::BGColorTextAttr::
   GetColor(nsIFrame* aFrame, nscolor* aColor)
 {
-  const nsStyleBackground* styleBackground = aFrame->StyleBackground();
-
-  if (NS_GET_A(styleBackground->mBackgroundColor) > 0) {
-    *aColor = styleBackground->mBackgroundColor;
+  nscolor backgroundColor = aFrame->StyleBackground()->BackgroundColor(aFrame);
+  if (NS_GET_A(backgroundColor) > 0) {
+    *aColor = backgroundColor;
     return true;
   }
 
   nsContainerFrame *parentFrame = aFrame->GetParent();
   if (!parentFrame) {
     *aColor = aFrame->PresContext()->DefaultBackgroundColor();
     return true;
   }
@@ -648,38 +643,24 @@ TextAttrsMgr::FontWeightTextAttr::
   // When there doesn't exist a bold font in the family and so the rendering of
   // a non-bold font face is changed so that the user sees what looks like a
   // bold font, i.e. synthetic bolding is used. IsSyntheticBold method is only
   // needed on Mac, but it is "safe" to use on all platforms.  (For non-Mac
   // platforms it always return false.)
   if (font->IsSyntheticBold())
     return 700;
 
-  bool useFontEntryWeight = true;
-
-  // Under Linux, when gfxPangoFontGroup code is used,
-  // font->GetStyle()->weight will give the absolute weight requested of the
-  // font face. The gfxPangoFontGroup code uses the gfxFontEntry constructor
-  // which doesn't initialize the weight field.
-#if defined(MOZ_WIDGET_GTK)
-  useFontEntryWeight = gfxPlatformGtk::UseFcFontList();
-#endif
-
-  if (useFontEntryWeight) {
-    // On Windows, font->GetStyle()->weight will give the same weight as
-    // fontEntry->Weight(), the weight of the first font in the font group,
-    // which may not be the weight of the font face used to render the
-    // characters. On Mac, font->GetStyle()->weight will just give the same
-    // number as getComputedStyle(). fontEntry->Weight() will give the weight
-    // of the font face used.
-    gfxFontEntry *fontEntry = font->GetFontEntry();
-    return fontEntry->Weight();
-  } else {
-    return font->GetStyle()->weight;
-  }
+  // On Windows, font->GetStyle()->weight will give the same weight as
+  // fontEntry->Weight(), the weight of the first font in the font group,
+  // which may not be the weight of the font face used to render the
+  // characters. On Mac, font->GetStyle()->weight will just give the same
+  // number as getComputedStyle(). fontEntry->Weight() will give the weight
+  // of the font face used.
+  gfxFontEntry *fontEntry = font->GetFontEntry();
+  return fontEntry->Weight();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // AutoGeneratedTextAttr
 ////////////////////////////////////////////////////////////////////////////////
 TextAttrsMgr::AutoGeneratedTextAttr::
   AutoGeneratedTextAttr(HyperTextAccessible* aHyperTextAcc,
                         Accessible* aAccessible) :
--- a/accessible/base/moz.build
+++ b/accessible/base/moz.build
@@ -58,16 +58,18 @@ if CONFIG['A11Y_LOG']:
     UNIFIED_SOURCES += [
         'Logging.cpp',
     ]
 
 LOCAL_INCLUDES += [
     '/accessible/generic',
     '/accessible/html',
     '/accessible/ipc',
+    '/dom/base',
+    '/dom/xul',
 ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     LOCAL_INCLUDES += [
         '/accessible/ipc/win',
     ]
 else:
     LOCAL_INCLUDES += [
--- a/accessible/base/nsAccCache.h
+++ b/accessible/base/nsAccCache.h
@@ -20,26 +20,9 @@ UnbindCacheEntriesFromDocument(
   for (auto iter = aCache.Iter(); !iter.Done(); iter.Next()) {
     T* accessible = iter.Data();
     MOZ_ASSERT(accessible && !accessible->IsDefunct());
     accessible->Document()->UnbindFromDocument(accessible);
     iter.Remove();
   }
 }
 
-/**
- * Clear the cache and shutdown the accessibles.
- */
-template <class T>
-static void
-ClearCache(nsRefPtrHashtable<nsPtrHashKey<const void>, T>& aCache)
-{
-  for (auto iter = aCache.Iter(); !iter.Done(); iter.Next()) {
-    T* accessible = iter.Data();
-    MOZ_ASSERT(accessible);
-    if (accessible && !accessible->IsDefunct()) {
-      accessible->Shutdown();
-    }
-    iter.Remove();
-  }
-}
-
 #endif
--- a/accessible/base/nsAccessibilityService.cpp
+++ b/accessible/base/nsAccessibilityService.cpp
@@ -39,33 +39,34 @@
 #include "xpcAccessibleDocument.h"
 
 #ifdef MOZ_ACCESSIBILITY_ATK
 #include "AtkSocketAccessible.h"
 #endif
 
 #ifdef XP_WIN
 #include "mozilla/a11y/Compatibility.h"
+#include "mozilla/dom/ContentChild.h"
 #include "HTMLWin32ObjectAccessible.h"
 #include "mozilla/StaticPtr.h"
 #endif
 
 #ifdef A11Y_LOG
 #include "Logging.h"
 #endif
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 
 #include "nsImageFrame.h"
 #include "nsIObserverService.h"
 #include "nsLayoutUtils.h"
 #include "nsPluginFrame.h"
-#include "nsSVGPathGeometryFrame.h"
+#include "SVGGeometryFrame.h"
 #include "nsTreeBodyFrame.h"
 #include "nsTreeColumns.h"
 #include "nsTreeUtils.h"
 #include "nsXBLPrototypeBinding.h"
 #include "nsXBLBinding.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/dom/DOMStringList.h"
 #include "mozilla/Preferences.h"
@@ -311,26 +312,23 @@ nsAccessibilityService::ListenersChanged
           listenerName != nsGkAtoms::onmousedown &&
           listenerName != nsGkAtoms::onmouseup) {
         continue;
       }
 
       nsIDocument* ownerDoc = node->OwnerDoc();
       DocAccessible* document = GetExistingDocAccessible(ownerDoc);
 
-      // Always recreate for onclick changes.
-      if (document) {
-        if (nsCoreUtils::HasClickListener(node)) {
-          if (!document->GetAccessible(node)) {
-            document->RecreateAccessible(node);
-          }
-        } else {
-          if (document->GetAccessible(node)) {
-            document->RecreateAccessible(node);
-          }
+      // Create an accessible for a inaccessible element having click event
+      // handler.
+      if (document && !document->HasAccessible(node) &&
+          nsCoreUtils::HasClickListener(node)) {
+        nsIContent* parentEl = node->GetFlattenedTreeParent();
+        if (parentEl) {
+          document->ContentInserted(parentEl, node, node->GetNextSibling());
         }
         break;
       }
     }
   }
   return NS_OK;
 }
 
@@ -400,17 +398,17 @@ nsAccessibilityService::GetRootDocumentA
 static StaticAutoPtr<nsTArray<nsCOMPtr<nsIContent> > > sPendingPlugins;
 static StaticAutoPtr<nsTArray<nsCOMPtr<nsITimer> > > sPluginTimers;
 
 class PluginTimerCallBack final : public nsITimerCallback
 {
   ~PluginTimerCallBack() {}
 
 public:
-  PluginTimerCallBack(nsIContent* aContent) : mContent(aContent) {}
+  explicit PluginTimerCallBack(nsIContent* aContent) : mContent(aContent) {}
 
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD Notify(nsITimer* aTimer) final
   {
     if (!mContent->IsInUncomposedDoc())
       return NS_OK;
 
@@ -592,16 +590,17 @@ nsAccessibilityService::ContentRemoved(n
     if (!child) {
       Accessible* container = document->GetContainerAccessible(aChildNode);
       a11y::TreeWalker walker(container ? container : document, aChildNode,
                               a11y::TreeWalker::eWalkCache);
       child = walker.Next();
     }
 
     if (child) {
+      MOZ_DIAGNOSTIC_ASSERT(child->Parent(), "Unattached accessible from tree");
       document->ContentRemoved(child->Parent(), aChildNode);
 #ifdef A11Y_LOG
       if (logging::IsEnabled(logging::eTree))
         logging::AccessibleNNode("real container", child->Parent());
 #endif
     }
   }
 
@@ -745,175 +744,179 @@ nsAccessibilityService::GetStringRole(ui
       return;
   }
 
 #undef ROLE
 }
 
 void
 nsAccessibilityService::GetStringStates(uint32_t aState, uint32_t aExtraState,
-                                        nsISupports **aStringStates)
+                                        nsISupports** aStringStates)
 {
-  RefPtr<DOMStringList> stringStates = new DOMStringList();
-
-  uint64_t state = nsAccUtils::To64State(aState, aExtraState);
+  RefPtr<DOMStringList> stringStates = 
+    GetStringStates(nsAccUtils::To64State(aState, aExtraState));
 
-  // states
-  if (state & states::UNAVAILABLE) {
-    stringStates->Add(NS_LITERAL_STRING("unavailable"));
-  }
-  if (state & states::SELECTED) {
-    stringStates->Add(NS_LITERAL_STRING("selected"));
-  }
-  if (state & states::FOCUSED) {
-    stringStates->Add(NS_LITERAL_STRING("focused"));
-  }
-  if (state & states::PRESSED) {
-    stringStates->Add(NS_LITERAL_STRING("pressed"));
-  }
-  if (state & states::CHECKED) {
-    stringStates->Add(NS_LITERAL_STRING("checked"));
-  }
-  if (state & states::MIXED) {
-    stringStates->Add(NS_LITERAL_STRING("mixed"));
-  }
-  if (state & states::READONLY) {
-    stringStates->Add(NS_LITERAL_STRING("readonly"));
-  }
-  if (state & states::HOTTRACKED) {
-    stringStates->Add(NS_LITERAL_STRING("hottracked"));
-  }
-  if (state & states::DEFAULT) {
-    stringStates->Add(NS_LITERAL_STRING("default"));
-  }
-  if (state & states::EXPANDED) {
-    stringStates->Add(NS_LITERAL_STRING("expanded"));
-  }
-  if (state & states::COLLAPSED) {
-    stringStates->Add(NS_LITERAL_STRING("collapsed"));
-  }
-  if (state & states::BUSY) {
-    stringStates->Add(NS_LITERAL_STRING("busy"));
-  }
-  if (state & states::FLOATING) {
-    stringStates->Add(NS_LITERAL_STRING("floating"));
-  }
-  if (state & states::ANIMATED) {
-    stringStates->Add(NS_LITERAL_STRING("animated"));
-  }
-  if (state & states::INVISIBLE) {
-    stringStates->Add(NS_LITERAL_STRING("invisible"));
-  }
-  if (state & states::OFFSCREEN) {
-    stringStates->Add(NS_LITERAL_STRING("offscreen"));
-  }
-  if (state & states::SIZEABLE) {
-    stringStates->Add(NS_LITERAL_STRING("sizeable"));
-  }
-  if (state & states::MOVEABLE) {
-    stringStates->Add(NS_LITERAL_STRING("moveable"));
-  }
-  if (state & states::SELFVOICING) {
-    stringStates->Add(NS_LITERAL_STRING("selfvoicing"));
-  }
-  if (state & states::FOCUSABLE) {
-    stringStates->Add(NS_LITERAL_STRING("focusable"));
-  }
-  if (state & states::SELECTABLE) {
-    stringStates->Add(NS_LITERAL_STRING("selectable"));
-  }
-  if (state & states::LINKED) {
-    stringStates->Add(NS_LITERAL_STRING("linked"));
-  }
-  if (state & states::TRAVERSED) {
-    stringStates->Add(NS_LITERAL_STRING("traversed"));
-  }
-  if (state & states::MULTISELECTABLE) {
-    stringStates->Add(NS_LITERAL_STRING("multiselectable"));
-  }
-  if (state & states::EXTSELECTABLE) {
-    stringStates->Add(NS_LITERAL_STRING("extselectable"));
-  }
-  if (state & states::PROTECTED) {
-    stringStates->Add(NS_LITERAL_STRING("protected"));
-  }
-  if (state & states::HASPOPUP) {
-    stringStates->Add(NS_LITERAL_STRING("haspopup"));
-  }
-  if (state & states::REQUIRED) {
-    stringStates->Add(NS_LITERAL_STRING("required"));
-  }
-  if (state & states::ALERT) {
-    stringStates->Add(NS_LITERAL_STRING("alert"));
-  }
-  if (state & states::INVALID) {
-    stringStates->Add(NS_LITERAL_STRING("invalid"));
-  }
-  if (state & states::CHECKABLE) {
-    stringStates->Add(NS_LITERAL_STRING("checkable"));
-  }
-
-  // extraStates
-  if (state & states::SUPPORTS_AUTOCOMPLETION) {
-    stringStates->Add(NS_LITERAL_STRING("autocompletion"));
-  }
-  if (state & states::DEFUNCT) {
-    stringStates->Add(NS_LITERAL_STRING("defunct"));
-  }
-  if (state & states::SELECTABLE_TEXT) {
-    stringStates->Add(NS_LITERAL_STRING("selectable text"));
-  }
-  if (state & states::EDITABLE) {
-    stringStates->Add(NS_LITERAL_STRING("editable"));
-  }
-  if (state & states::ACTIVE) {
-    stringStates->Add(NS_LITERAL_STRING("active"));
-  }
-  if (state & states::MODAL) {
-    stringStates->Add(NS_LITERAL_STRING("modal"));
-  }
-  if (state & states::MULTI_LINE) {
-    stringStates->Add(NS_LITERAL_STRING("multi line"));
-  }
-  if (state & states::HORIZONTAL) {
-    stringStates->Add(NS_LITERAL_STRING("horizontal"));
-  }
-  if (state & states::OPAQUE1) {
-    stringStates->Add(NS_LITERAL_STRING("opaque"));
-  }
-  if (state & states::SINGLE_LINE) {
-    stringStates->Add(NS_LITERAL_STRING("single line"));
-  }
-  if (state & states::TRANSIENT) {
-    stringStates->Add(NS_LITERAL_STRING("transient"));
-  }
-  if (state & states::VERTICAL) {
-    stringStates->Add(NS_LITERAL_STRING("vertical"));
-  }
-  if (state & states::STALE) {
-    stringStates->Add(NS_LITERAL_STRING("stale"));
-  }
-  if (state & states::ENABLED) {
-    stringStates->Add(NS_LITERAL_STRING("enabled"));
-  }
-  if (state & states::SENSITIVE) {
-    stringStates->Add(NS_LITERAL_STRING("sensitive"));
-  }
-  if (state & states::EXPANDABLE) {
-    stringStates->Add(NS_LITERAL_STRING("expandable"));
-  }
-
-  //unknown states
+  // unknown state
   if (!stringStates->Length()) {
     stringStates->Add(NS_LITERAL_STRING("unknown"));
   }
 
   stringStates.forget(aStringStates);
 }
 
+already_AddRefed<DOMStringList>
+nsAccessibilityService::GetStringStates(uint64_t aStates) const
+{
+  RefPtr<DOMStringList> stringStates = new DOMStringList();
+
+  if (aStates & states::UNAVAILABLE) {
+    stringStates->Add(NS_LITERAL_STRING("unavailable"));
+  }
+  if (aStates & states::SELECTED) {
+    stringStates->Add(NS_LITERAL_STRING("selected"));
+  }
+  if (aStates & states::FOCUSED) {
+    stringStates->Add(NS_LITERAL_STRING("focused"));
+  }
+  if (aStates & states::PRESSED) {
+    stringStates->Add(NS_LITERAL_STRING("pressed"));
+  }
+  if (aStates & states::CHECKED) {
+    stringStates->Add(NS_LITERAL_STRING("checked"));
+  }
+  if (aStates & states::MIXED) {
+    stringStates->Add(NS_LITERAL_STRING("mixed"));
+  }
+  if (aStates & states::READONLY) {
+    stringStates->Add(NS_LITERAL_STRING("readonly"));
+  }
+  if (aStates & states::HOTTRACKED) {
+    stringStates->Add(NS_LITERAL_STRING("hottracked"));
+  }
+  if (aStates & states::DEFAULT) {
+    stringStates->Add(NS_LITERAL_STRING("default"));
+  }
+  if (aStates & states::EXPANDED) {
+    stringStates->Add(NS_LITERAL_STRING("expanded"));
+  }
+  if (aStates & states::COLLAPSED) {
+    stringStates->Add(NS_LITERAL_STRING("collapsed"));
+  }
+  if (aStates & states::BUSY) {
+    stringStates->Add(NS_LITERAL_STRING("busy"));
+  }
+  if (aStates & states::FLOATING) {
+    stringStates->Add(NS_LITERAL_STRING("floating"));
+  }
+  if (aStates & states::ANIMATED) {
+    stringStates->Add(NS_LITERAL_STRING("animated"));
+  }
+  if (aStates & states::INVISIBLE) {
+    stringStates->Add(NS_LITERAL_STRING("invisible"));
+  }
+  if (aStates & states::OFFSCREEN) {
+    stringStates->Add(NS_LITERAL_STRING("offscreen"));
+  }
+  if (aStates & states::SIZEABLE) {
+    stringStates->Add(NS_LITERAL_STRING("sizeable"));
+  }
+  if (aStates & states::MOVEABLE) {
+    stringStates->Add(NS_LITERAL_STRING("moveable"));
+  }
+  if (aStates & states::SELFVOICING) {
+    stringStates->Add(NS_LITERAL_STRING("selfvoicing"));
+  }
+  if (aStates & states::FOCUSABLE) {
+    stringStates->Add(NS_LITERAL_STRING("focusable"));
+  }
+  if (aStates & states::SELECTABLE) {
+    stringStates->Add(NS_LITERAL_STRING("selectable"));
+  }
+  if (aStates & states::LINKED) {
+    stringStates->Add(NS_LITERAL_STRING("linked"));
+  }
+  if (aStates & states::TRAVERSED) {
+    stringStates->Add(NS_LITERAL_STRING("traversed"));
+  }
+  if (aStates & states::MULTISELECTABLE) {
+    stringStates->Add(NS_LITERAL_STRING("multiselectable"));
+  }
+  if (aStates & states::EXTSELECTABLE) {
+    stringStates->Add(NS_LITERAL_STRING("extselectable"));
+  }
+  if (aStates & states::PROTECTED) {
+    stringStates->Add(NS_LITERAL_STRING("protected"));
+  }
+  if (aStates & states::HASPOPUP) {
+    stringStates->Add(NS_LITERAL_STRING("haspopup"));
+  }
+  if (aStates & states::REQUIRED) {
+    stringStates->Add(NS_LITERAL_STRING("required"));
+  }
+  if (aStates & states::ALERT) {
+    stringStates->Add(NS_LITERAL_STRING("alert"));
+  }
+  if (aStates & states::INVALID) {
+    stringStates->Add(NS_LITERAL_STRING("invalid"));
+  }
+  if (aStates & states::CHECKABLE) {
+    stringStates->Add(NS_LITERAL_STRING("checkable"));
+  }
+  if (aStates & states::SUPPORTS_AUTOCOMPLETION) {
+    stringStates->Add(NS_LITERAL_STRING("autocompletion"));
+  }
+  if (aStates & states::DEFUNCT) {
+    stringStates->Add(NS_LITERAL_STRING("defunct"));
+  }
+  if (aStates & states::SELECTABLE_TEXT) {
+    stringStates->Add(NS_LITERAL_STRING("selectable text"));
+  }
+  if (aStates & states::EDITABLE) {
+    stringStates->Add(NS_LITERAL_STRING("editable"));
+  }
+  if (aStates & states::ACTIVE) {
+    stringStates->Add(NS_LITERAL_STRING("active"));
+  }
+  if (aStates & states::MODAL) {
+    stringStates->Add(NS_LITERAL_STRING("modal"));
+  }
+  if (aStates & states::MULTI_LINE) {
+    stringStates->Add(NS_LITERAL_STRING("multi line"));
+  }
+  if (aStates & states::HORIZONTAL) {
+    stringStates->Add(NS_LITERAL_STRING("horizontal"));
+  }
+  if (aStates & states::OPAQUE1) {
+    stringStates->Add(NS_LITERAL_STRING("opaque"));
+  }
+  if (aStates & states::SINGLE_LINE) {
+    stringStates->Add(NS_LITERAL_STRING("single line"));
+  }
+  if (aStates & states::TRANSIENT) {
+    stringStates->Add(NS_LITERAL_STRING("transient"));
+  }
+  if (aStates & states::VERTICAL) {
+    stringStates->Add(NS_LITERAL_STRING("vertical"));
+  }
+  if (aStates & states::STALE) {
+    stringStates->Add(NS_LITERAL_STRING("stale"));
+  }
+  if (aStates & states::ENABLED) {
+    stringStates->Add(NS_LITERAL_STRING("enabled"));
+  }
+  if (aStates & states::SENSITIVE) {
+    stringStates->Add(NS_LITERAL_STRING("sensitive"));
+  }
+  if (aStates & states::EXPANDABLE) {
+    stringStates->Add(NS_LITERAL_STRING("expandable"));
+  }
+
+  return stringStates.forget();
+}
+
 void
 nsAccessibilityService::GetStringEventType(uint32_t aEventType,
                                            nsAString& aString)
 {
   NS_ASSERTION(nsIAccessibleEvent::EVENT_LAST_ENTRY == ArrayLength(kEventTypeNames),
                "nsIAccessibleEvent constants are out of sync to kEventTypeNames");
 
   if (aEventType >= ArrayLength(kEventTypeNames)) {
@@ -1163,18 +1166,18 @@ nsAccessibilityService::CreateAccessible
           frameType == nsGkAtoms::scrollFrame) {
         newAcc = new XULTabpanelAccessible(content, document);
       }
     }
   }
 
   if (!newAcc) {
     if (content->IsSVGElement()) {
-      nsSVGPathGeometryFrame* pathGeometryFrame = do_QueryFrame(frame);
-      if (pathGeometryFrame) {
+      SVGGeometryFrame* geometryFrame = do_QueryFrame(frame);
+      if (geometryFrame) {
         // A graphic elements: rect, circle, ellipse, line, path, polygon,
         // polyline and image. A 'use' and 'text' graphic elements require
         // special support.
         newAcc = new EnumRoleAccessible<roles::GRAPHIC>(content, document);
       } else if (content->IsSVGElement(nsGkAtoms::svg)) {
         newAcc = new EnumRoleAccessible<roles::DIAGRAM>(content, document);
       }
 
@@ -1259,20 +1262,33 @@ nsAccessibilityService::Init()
 
 #ifdef A11Y_LOG
   logging::CheckEnv();
 #endif
 
   gAccessibilityService = this;
   NS_ADDREF(gAccessibilityService); // will release in Shutdown()
 
-  if (XRE_IsParentProcess())
+  if (XRE_IsParentProcess()) {
     gApplicationAccessible = new ApplicationAccessibleWrap();
-  else
+  } else {
+#if defined(XP_WIN)
+    dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
+    MOZ_ASSERT(contentChild);
+    // If we were instantiated by the chrome process, GetMsaaID() will return
+    // a non-zero value and we may safely continue with initialization.
+    if (!contentChild->GetMsaaID()) {
+      // Since we were not instantiated by chrome, we need to synchronously
+      // obtain a MSAA content process id.
+      contentChild->SendGetA11yContentId();
+    }
+#endif // defined(XP_WIN)
+
     gApplicationAccessible = new ApplicationAccessible();
+  }
 
   NS_ADDREF(gApplicationAccessible); // will release in Shutdown()
   gApplicationAccessible->Init();
 
 #ifdef MOZ_CRASHREPORTER
   CrashReporter::
     AnnotateCrashReport(NS_LITERAL_CSTRING("Accessibility"),
                         NS_LITERAL_CSTRING("Active"));
@@ -1796,17 +1812,18 @@ MaybeShutdownAccService(uint32_t aFormer
   nsAccessibilityService* accService =
     nsAccessibilityService::gAccessibilityService;
 
   if (!accService || accService->IsShutdown()) {
     return;
   }
 
   if (nsCoreUtils::AccEventObserversExist() ||
-      xpcAccessibilityService::IsInUse()) {
+      xpcAccessibilityService::IsInUse() ||
+      accService->HasXPCDocuments()) {
     // Still used by XPCOM
     nsAccessibilityService::gConsumers =
       (nsAccessibilityService::gConsumers & ~aFormerConsumer) |
       nsAccessibilityService::eXPCOM;
     return;
   }
 
   if (nsAccessibilityService::gConsumers & ~aFormerConsumer) {
--- a/accessible/base/nsAccessibilityService.h
+++ b/accessible/base/nsAccessibilityService.h
@@ -19,16 +19,21 @@
 
 class nsImageFrame;
 class nsIArray;
 class nsIPersistentProperties;
 class nsPluginFrame;
 class nsITreeView;
 
 namespace mozilla {
+
+namespace dom {
+  class DOMStringList;
+}
+
 namespace a11y {
 
 class ApplicationAccessible;
 class xpcAccessibleApplication;
 
 /**
  * Return focus manager.
  */
@@ -103,16 +108,18 @@ public:
   /**
    * Get a string equivalent for an accessilbe role value.
    */
   void GetStringRole(uint32_t aRole, nsAString& aString);
 
   /**
    * Get a string equivalent for an accessible state/extra state.
    */
+  already_AddRefed<mozilla::dom::DOMStringList>
+    GetStringStates(uint64_t aStates) const;
   void GetStringStates(uint32_t aState, uint32_t aExtraState,
                        nsISupports **aStringStates);
 
   /**
    * Get a string equivalent for an accessible event value.
    */
   void GetStringEventType(uint32_t aEventType, nsAString& aString);
 
@@ -331,22 +338,17 @@ nsAccessibilityService* GetOrCreateAccSe
 void MaybeShutdownAccService(uint32_t aFormerConsumer);
 
 /**
  * Return true if we're in a content process and not B2G.
  */
 inline bool
 IPCAccessibilityActive()
 {
-#ifdef MOZ_B2G
-  return false;
-#else
-  return XRE_IsContentProcess() &&
-    mozilla::Preferences::GetBool("accessibility.ipc_architecture.enabled", true);
-#endif
+  return XRE_IsContentProcess();
 }
 
 /**
  * Map nsIAccessibleEvents constants to strings. Used by
  * nsAccessibilityService::GetStringEventType() method.
  */
 static const char kEventTypeNames[][40] = {
   "unknown",                                 //
--- a/accessible/base/nsCoreUtils.cpp
+++ b/accessible/base/nsCoreUtils.cpp
@@ -9,26 +9,28 @@
 
 #include "nsIBaseWindow.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDocument.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsRange.h"
 #include "nsIBoxObject.h"
-#include "nsIDOMXULElement.h"
+#include "nsXULElement.h"
+#include "mozilla/dom/BoxObject.h"
 #include "nsIDocShell.h"
 #include "nsIObserverService.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsIScrollableFrame.h"
 #include "nsISelectionPrivate.h"
 #include "nsISelectionController.h"
 #include "nsISimpleEnumerator.h"
 #include "mozilla/dom/TouchEvent.h"
+#include "mozilla/ErrorResult.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/TouchEvents.h"
 #include "nsView.h"
 #include "nsGkAtoms.h"
 
 #include "nsComponentManagerUtils.h"
@@ -92,28 +94,29 @@ nsCoreUtils::DispatchClickEvent(nsITreeB
   // Calculate x and y coordinates.
   int32_t x = 0, y = 0, width = 0, height = 0;
   nsresult rv = aTreeBoxObj->GetCoordsForCellItem(aRowIndex, aColumn,
                                                   aPseudoElt,
                                                   &x, &y, &width, &height);
   if (NS_FAILED(rv))
     return;
 
-  nsCOMPtr<nsIDOMXULElement> tcXULElm(do_QueryInterface(tcElm));
-  nsCOMPtr<nsIBoxObject> tcBoxObj;
-  tcXULElm->GetBoxObject(getter_AddRefs(tcBoxObj));
+  nsCOMPtr<nsIContent> tcXULElm(do_QueryInterface(tcElm));
+  IgnoredErrorResult ignored;
+  nsCOMPtr<nsIBoxObject> tcBoxObj =
+    nsXULElement::FromContent(tcXULElm)->GetBoxObject(ignored);
 
   int32_t tcX = 0;
   tcBoxObj->GetX(&tcX);
 
   int32_t tcY = 0;
   tcBoxObj->GetY(&tcY);
 
   // Dispatch mouse events.
-  nsWeakFrame tcFrame = tcContent->GetPrimaryFrame();
+  AutoWeakFrame tcFrame = tcContent->GetPrimaryFrame();
   nsIFrame* rootFrame = presShell->GetRootFrame();
 
   nsPoint offset;
   nsIWidget *rootWidget =
     rootFrame->GetView()->GetNearestWidget(&offset);
 
   RefPtr<nsPresContext> presContext = presShell->GetPresContext();
 
@@ -484,42 +487,41 @@ nsCoreUtils::GetLanguageFor(nsIContent *
     walkUp = walkUp->GetParent();
 }
 
 already_AddRefed<nsIBoxObject>
 nsCoreUtils::GetTreeBodyBoxObject(nsITreeBoxObject *aTreeBoxObj)
 {
   nsCOMPtr<nsIDOMElement> tcElm;
   aTreeBoxObj->GetTreeBody(getter_AddRefs(tcElm));
-  nsCOMPtr<nsIDOMXULElement> tcXULElm(do_QueryInterface(tcElm));
+  nsCOMPtr<nsIContent> tcContent(do_QueryInterface(tcElm));
+  RefPtr<nsXULElement> tcXULElm = nsXULElement::FromContentOrNull(tcContent);
   if (!tcXULElm)
     return nullptr;
 
-  nsCOMPtr<nsIBoxObject> boxObj;
-  tcXULElm->GetBoxObject(getter_AddRefs(boxObj));
-  return boxObj.forget();
+  IgnoredErrorResult ignored;
+  return tcXULElm->GetBoxObject(ignored);
 }
 
 already_AddRefed<nsITreeBoxObject>
 nsCoreUtils::GetTreeBoxObject(nsIContent *aContent)
 {
   // Find DOMNode's parents recursively until reach the <tree> tag
   nsIContent* currentContent = aContent;
   while (currentContent) {
     if (currentContent->NodeInfo()->Equals(nsGkAtoms::tree,
                                            kNameSpaceID_XUL)) {
       // We will get the nsITreeBoxObject from the tree node
-      nsCOMPtr<nsIDOMXULElement> xulElement(do_QueryInterface(currentContent));
-      if (xulElement) {
-        nsCOMPtr<nsIBoxObject> box;
-        xulElement->GetBoxObject(getter_AddRefs(box));
-        nsCOMPtr<nsITreeBoxObject> treeBox(do_QueryInterface(box));
-        if (treeBox)
-          return treeBox.forget();
-      }
+      RefPtr<nsXULElement> xulElement =
+        nsXULElement::FromContent(currentContent);
+      IgnoredErrorResult ignored;
+      nsCOMPtr<nsIBoxObject> box = xulElement->GetBoxObject(ignored);
+      nsCOMPtr<nsITreeBoxObject> treeBox(do_QueryInterface(box));
+      if (treeBox)
+        return treeBox.forget();
     }
     currentContent = currentContent->GetFlattenedTreeParent();
   }
 
   return nullptr;
 }
 
 already_AddRefed<nsITreeColumn>
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -88,33 +88,40 @@
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // Accessible: nsISupports and cycle collection
 
-NS_IMPL_CYCLE_COLLECTION(Accessible, mContent)
+NS_IMPL_CYCLE_COLLECTION_CLASS(Accessible)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Accessible)
+  tmp->Shutdown();
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Accessible)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContent, mDoc)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Accessible)
   if (aIID.Equals(NS_GET_IID(Accessible)))
     foundInterface = this;
   else
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, Accessible)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Accessible)
 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(Accessible, LastRelease())
 
 Accessible::Accessible(nsIContent* aContent, DocAccessible* aDoc) :
   mContent(aContent), mDoc(aDoc),
   mParent(nullptr), mIndexInParent(-1),
   mRoleMapEntryIndex(aria::NO_ROLE_MAP_ENTRY_INDEX),
-  mStateFlags(0), mContextFlags(0), mType(0), mGenericTypes(0)
+  mStateFlags(0), mContextFlags(0), mType(0), mGenericTypes(0),
+  mReorderEventTarget(false), mShowEventTarget(false), mHideEventTarget(false)
 {
   mBits.groupInfo = nullptr;
   mInt.mIndexOfEmbeddedChild = -1;
 }
 
 Accessible::~Accessible()
 {
   NS_ASSERTION(!mDoc, "LastRelease was never called!?!");
@@ -1742,22 +1749,34 @@ Accessible::RelationByType(RelationType 
           // If the item type is typeContent, we assume we are in browser tab
           // content. Note, this includes content such as about:addons,
           // for consistency.
           if (root->ItemType() == nsIDocShellTreeItem::typeContent) {
             return Relation(nsAccUtils::GetDocAccessibleFor(root));
           }
         }
       }
-      return  Relation();
+      return Relation();
     }
 
     case RelationType::CONTAINING_APPLICATION:
       return Relation(ApplicationAcc());
 
+    case RelationType::DETAILS:
+      return Relation(new IDRefsIterator(mDoc, mContent, nsGkAtoms::aria_details));
+
+    case RelationType::DETAILS_FOR:
+      return Relation(new RelatedAccIterator(mDoc, mContent, nsGkAtoms::aria_details));
+
+    case RelationType::ERRORMSG:
+      return Relation(new IDRefsIterator(mDoc, mContent, nsGkAtoms::aria_errormessage));
+
+    case RelationType::ERRORMSG_FOR:
+      return Relation(new RelatedAccIterator(mDoc, mContent, nsGkAtoms::aria_errormessage));
+
     default:
       return Relation();
   }
 }
 
 void
 Accessible::GetNativeInterface(void** aNativeAccessible)
 {
@@ -1806,17 +1825,17 @@ Accessible::DispatchClickEvent(nsIConten
   nsCOMPtr<nsIPresShell> presShell = mDoc->PresShell();
 
   // Scroll into view.
   presShell->ScrollContentIntoView(aContent,
                                    nsIPresShell::ScrollAxis(),
                                    nsIPresShell::ScrollAxis(),
                                    nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
 
-  nsWeakFrame frame = aContent->GetPrimaryFrame();
+  AutoWeakFrame frame = aContent->GetPrimaryFrame();
   if (!frame)
     return;
 
   // Compute x and y coordinates.
   nsPoint point;
   nsCOMPtr<nsIWidget> widget = frame->GetNearestWidget(point);
   if (!widget)
     return;
@@ -2107,52 +2126,57 @@ Accessible::InsertChildAt(uint32_t aInde
 
   aChild->BindToParent(this, aIndex);
   return true;
 }
 
 bool
 Accessible::RemoveChild(Accessible* aChild)
 {
-  if (!aChild)
-    return false;
-
-  if (aChild->mParent != this || aChild->mIndexInParent == -1)
-    return false;
-
-  MOZ_ASSERT((mStateFlags & eKidsMutating) || aChild->IsDefunct() || aChild->IsDoc(),
-             "Illicit children change");
+  MOZ_DIAGNOSTIC_ASSERT(aChild, "No child was given");
+  MOZ_DIAGNOSTIC_ASSERT(aChild->mParent, "No parent");
+  MOZ_DIAGNOSTIC_ASSERT(aChild->mParent == this, "Wrong parent");
+  MOZ_DIAGNOSTIC_ASSERT(aChild->mIndexInParent != -1, "Unbound child was given");
+  MOZ_DIAGNOSTIC_ASSERT((mStateFlags & eKidsMutating) || aChild->IsDefunct() || aChild->IsDoc(),
+                        "Illicit children change");
 
   int32_t index = static_cast<uint32_t>(aChild->mIndexInParent);
-  MOZ_ASSERT(mChildren.SafeElementAt(index) == aChild,
-             "A wrong child index");
+  if (mChildren.SafeElementAt(index) != aChild) {
+    MOZ_ASSERT_UNREACHABLE("A wrong child index");
+    index = mChildren.IndexOf(aChild);
+    if (index == -1) {
+      MOZ_ASSERT_UNREACHABLE("No child was found");
+      return false;
+    }
+  }
 
   aChild->UnbindFromParent();
   mChildren.RemoveElementAt(index);
 
   for (uint32_t idx = index; idx < mChildren.Length(); idx++) {
     mChildren[idx]->mIndexInParent = idx;
   }
 
   return true;
 }
 
 void
 Accessible::MoveChild(uint32_t aNewIndex, Accessible* aChild)
 {
-  MOZ_ASSERT(aChild, "No child was given");
-  MOZ_ASSERT(aChild->mParent == this, "A child from different subtree was given");
-  MOZ_ASSERT(aChild->mIndexInParent != -1, "Unbound child was given");
-  MOZ_ASSERT(static_cast<uint32_t>(aChild->mIndexInParent) != aNewIndex,
+  MOZ_DIAGNOSTIC_ASSERT(aChild, "No child was given");
+  MOZ_DIAGNOSTIC_ASSERT(aChild->mParent == this, "A child from different subtree was given");
+  MOZ_DIAGNOSTIC_ASSERT(aChild->mIndexInParent != -1, "Unbound child was given");
+  MOZ_DIAGNOSTIC_ASSERT(aChild->mParent->GetChildAt(aChild->mIndexInParent) == aChild, "Wrong index in parent");
+  MOZ_DIAGNOSTIC_ASSERT(static_cast<uint32_t>(aChild->mIndexInParent) != aNewIndex,
              "No move, same index");
-  MOZ_ASSERT(aNewIndex <= mChildren.Length(), "Wrong new index was given");
-
-  EventTree* eventTree = mDoc->Controller()->QueueMutation(this);
-  if (eventTree) {
-    eventTree->Hidden(aChild, false);
+  MOZ_DIAGNOSTIC_ASSERT(aNewIndex <= mChildren.Length(), "Wrong new index was given");
+
+  RefPtr<AccHideEvent> hideEvent = new AccHideEvent(aChild, false);
+  if (mDoc->Controller()->QueueMutationEvent(hideEvent)) {
+    aChild->SetHideEventTarget(true);
   }
 
   mEmbeddedObjCollector = nullptr;
   mChildren.RemoveElementAt(aChild->mIndexInParent);
 
   uint32_t startIdx = aNewIndex, endIdx = aChild->mIndexInParent;
 
   // If the child is moved after its current position.
@@ -2174,20 +2198,20 @@ Accessible::MoveChild(uint32_t aNewIndex
   }
 
   for (uint32_t idx = startIdx; idx <= endIdx; idx++) {
     mChildren[idx]->mIndexInParent = idx;
     mChildren[idx]->mStateFlags |= eGroupInfoDirty;
     mChildren[idx]->mInt.mIndexOfEmbeddedChild = -1;
   }
 
-  if (eventTree) {
-    eventTree->Shown(aChild);
-    mDoc->Controller()->QueueNameChange(aChild);
-  }
+  RefPtr<AccShowEvent> showEvent = new AccShowEvent(aChild);
+  DebugOnly<bool> added = mDoc->Controller()->QueueMutationEvent(showEvent);
+  MOZ_ASSERT(added);
+  aChild->SetShowEventTarget(true);
 }
 
 Accessible*
 Accessible::GetChildAt(uint32_t aIndex) const
 {
   Accessible* child = mChildren.SafeElementAt(aIndex, nullptr);
   if (!child)
     return nullptr;
--- a/accessible/generic/Accessible.h
+++ b/accessible/generic/Accessible.h
@@ -951,16 +951,46 @@ public:
   bool IsARIAHidden() const { return mContextFlags & eARIAHidden; }
   void SetARIAHidden(bool aIsDefined);
 
   /**
    * Return true if the element is inside an alert.
    */
   bool IsInsideAlert() const { return mContextFlags & eInsideAlert; }
 
+  /**
+   * Return true if there is a pending reorder event for this accessible.
+   */
+  bool ReorderEventTarget() const { return mReorderEventTarget; }
+
+  /**
+   * Return true if there is a pending show event for this accessible.
+   */
+  bool ShowEventTarget() const { return mShowEventTarget; }
+
+  /**
+   * Return true if there is a pending hide event for this accessible.
+   */
+  bool HideEventTarget() const { return mHideEventTarget; }
+
+  /**
+   * Set if there is a pending reorder event for this accessible.
+   */
+  void SetReorderEventTarget(bool aTarget) { mReorderEventTarget = aTarget; }
+
+  /**
+   * Set if this accessible is a show event target.
+   */
+  void SetShowEventTarget(bool aTarget) { mShowEventTarget = aTarget; }
+
+  /**
+   * Set if this accessible is a hide event target.
+   */
+  void SetHideEventTarget(bool aTarget) { mHideEventTarget = aTarget; }
+
 protected:
   virtual ~Accessible();
 
   /**
    * Return the accessible name provided by native markup. It doesn't take
    * into account ARIA markup used to specify the name.
    */
   virtual mozilla::a11y::ENameValueFlag NativeName(nsString& aName);
@@ -1103,17 +1133,17 @@ protected:
 
   /**
    * Return group info.
    */
   AccGroupInfo* GetGroupInfo();
 
   // Data Members
   nsCOMPtr<nsIContent> mContent;
-  DocAccessible* mDoc;
+  RefPtr<DocAccessible> mDoc;
 
   Accessible* mParent;
   nsTArray<Accessible*> mChildren;
   int32_t mIndexInParent;
 
   static const uint8_t kStateFlagsBits = 13;
   static const uint8_t kContextFlagsBits = 3;
   static const uint8_t kTypeBits = 6;
@@ -1127,16 +1157,19 @@ protected:
 
   /**
    * Keep in sync with StateFlags, ContextFlags, and AccTypes.
    */
   uint32_t mStateFlags : kStateFlagsBits;
   uint32_t mContextFlags : kContextFlagsBits;
   uint32_t mType : kTypeBits;
   uint32_t mGenericTypes : kGenericTypesBits;
+  uint32_t mReorderEventTarget : 1;
+  uint32_t mShowEventTarget : 1;
+  uint32_t mHideEventTarget : 1;
 
   void StaticAsserts() const;
 
 #ifdef A11Y_LOG
   friend void logging::Tree(const char* aTitle, const char* aMsgText,
                             Accessible* aRoot,
                             logging::GetTreePrefix aPrefixFunc,
                             void* aGetTreePrefixData);
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -41,16 +41,17 @@
 #include "nsIScrollableFrame.h"
 #include "nsUnicharUtils.h"
 #include "nsIURI.h"
 #include "nsIWebNavigation.h"
 #include "nsFocusManager.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/EventStates.h"
+#include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/DocumentType.h"
 #include "mozilla/dom/Element.h"
 
 #ifdef MOZ_XUL
 #include "nsIXULDocument.h"
 #endif
 
 using namespace mozilla;
@@ -58,42 +59,50 @@ using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Static member initialization
 
 static nsIAtom** kRelationAttrs[] =
 {
   &nsGkAtoms::aria_labelledby,
   &nsGkAtoms::aria_describedby,
+  &nsGkAtoms::aria_details,
   &nsGkAtoms::aria_owns,
   &nsGkAtoms::aria_controls,
   &nsGkAtoms::aria_flowto,
+  &nsGkAtoms::aria_errormessage,
   &nsGkAtoms::_for,
   &nsGkAtoms::control
 };
 
 static const uint32_t kRelationAttrsLen = ArrayLength(kRelationAttrs);
 
 ////////////////////////////////////////////////////////////////////////////////
 // Constructor/desctructor
 
 DocAccessible::
   DocAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell) :
-  HyperTextAccessibleWrap(nullptr, this),
+    // XXX don't pass a document to the Accessible constructor so that we don't
+    // set mDoc until our vtable is fully setup.  If we set mDoc before setting
+    // up the vtable we will call Accessible::AddRef() but not the overrides of
+    // it for subclasses.  It is important to call those overrides to avoid
+    // confusing leak checking machinary.
+  HyperTextAccessibleWrap(nullptr, nullptr),
   // XXX aaronl should we use an algorithm for the initial cache size?
   mAccessibleCache(kDefaultCacheLength),
   mNodeToAccessibleMap(kDefaultCacheLength),
   mDocumentNode(aDocument),
   mScrollPositionChangedTicks(0),
   mLoadState(eTreeConstructionPending), mDocFlags(0), mLoadEventType(0),
   mVirtualCursor(nullptr),
   mPresShell(aPresShell), mIPCDoc(nullptr)
 {
   mGenericTypes |= eDocument;
   mStateFlags |= eNotNodeMapEntry;
+  mDoc = this;
 
   MOZ_ASSERT(mPresShell, "should have been given a pres shell");
   mPresShell->SetDocAccessible(this);
 
   // If this is a XUL Document, it should not implement nsHyperText
   if (mDocumentNode && mDocumentNode->IsXULDocument())
     mGenericTypes &= ~eHyperText;
 }
@@ -469,17 +478,27 @@ DocAccessible::Shutdown()
     mVirtualCursor = nullptr;
   }
 
   mPresShell->SetDocAccessible(nullptr);
   mPresShell = nullptr;  // Avoid reentrancy
 
   mDependentIDsHash.Clear();
   mNodeToAccessibleMap.Clear();
-  ClearCache(mAccessibleCache);
+
+  for (auto iter = mAccessibleCache.Iter(); !iter.Done(); iter.Next()) {
+    Accessible* accessible = iter.Data();
+    MOZ_ASSERT(accessible);
+    if (accessible && !accessible->IsDefunct()) {
+      // Unlink parent to avoid its cleaning overhead in shutdown.
+      accessible->mParent = nullptr;
+      accessible->Shutdown();
+    }
+    iter.Remove();
+  }
 
   HyperTextAccessibleWrap::Shutdown();
 
   GetAccService()->NotifyOfDocumentShutdown(this, kungFuDeathGripDoc);
 }
 
 nsIFrame*
 DocAccessible::GetFrame() const
@@ -1453,18 +1472,35 @@ DocAccessible::NotifyOfLoading(bool aIsR
   RefPtr<AccEvent> stateEvent =
     new AccStateChangeEvent(this, states::BUSY, true);
   FireDelayedEvent(stateEvent);
 }
 
 void
 DocAccessible::DoInitialUpdate()
 {
-  if (nsCoreUtils::IsTabDocument(mDocumentNode))
+  if (nsCoreUtils::IsTabDocument(mDocumentNode)) {
     mDocFlags |= eTabDocument;
+    if (IPCAccessibilityActive()) {
+      nsIDocShell* docShell = mDocumentNode->GetDocShell();
+      if (RefPtr<dom::TabChild> tabChild = dom::TabChild::GetFrom(docShell)) {
+        DocAccessibleChild* ipcDoc = new DocAccessibleChild(this);
+        SetIPCDoc(ipcDoc);
+
+#if defined(XP_WIN)
+        IAccessibleHolder holder(CreateHolderFromAccessible(this));
+        int32_t childID = AccessibleWrap::GetChildIDFor(this);
+#else
+        int32_t holder = 0, childID = 0;
+#endif
+        tabChild->SendPDocAccessibleConstructor(ipcDoc, nullptr, 0, childID,
+                                                holder);
+      }
+    }
+  }
 
   mLoadState |= eTreeConstructed;
 
   // Set up a root element and ARIA role mapping.
   UpdateRootElIfNeeded();
 
   // Build initial tree.
   CacheChildrenInSubtree(this);
@@ -1853,18 +1889,18 @@ DocAccessible::ProcessContentInserted(Ac
     }
 
     if (aContainer->InsertAfter(iter.Child(), iter.ChildBefore())) {
 #ifdef A11Y_LOG
       logging::TreeInfo("accessible was inserted", 0,
                         "container", aContainer, "child", iter.Child(), nullptr);
 #endif
 
+      CreateSubtree(iter.Child());
       mt.AfterInsertion(iter.Child());
-      CreateSubtree(iter.Child());
       continue;
     }
 
     MOZ_ASSERT_UNREACHABLE("accessible was rejected");
     iter.Rejected();
   } while (iter.Next());
 
   mt.Done();
@@ -1900,20 +1936,20 @@ DocAccessible::ProcessContentInserted(Ac
       child = GetAccService()->CreateAccessible(aNode, aContainer);
     }
 
     if (child) {
       TreeMutation mt(aContainer);
       if (!aContainer->InsertAfter(child, walker.Prev())) {
         return;
       }
+      CreateSubtree(child);
       mt.AfterInsertion(child);
       mt.Done();
 
-      CreateSubtree(child);
       FireEventsOnInsertion(aContainer);
     }
   }
 
 #ifdef A11Y_LOG
   logging::TreeInfo("children after insertion", logging::eVerbose, aContainer);
 #endif
 }
@@ -2056,21 +2092,23 @@ DocAccessible::DoARIAOwnsRelocation(Acce
           TreeMutation imut(aOwner);
           aOwner->InsertChildAt(insertIdx, child);
           imut.AfterInsertion(child);
           imut.Done();
 
           child->SetRelocated(true);
           children->InsertElementAt(arrayIdx, child);
 
+          // Create subtree before adjusting the insertion index, since subtree
+          // creation may alter children in the container.
+          CreateSubtree(child);
+          FireEventsOnInsertion(aOwner);
+
           insertIdx = child->IndexInParent() + 1;
           arrayIdx++;
-
-          CreateSubtree(child);
-          FireEventsOnInsertion(aOwner);
         }
       }
       continue;
     }
 
 #ifdef A11Y_LOG
   logging::TreeInfo("aria owns traversal", logging::eVerbose,
                     "candidate", child, nullptr);
@@ -2266,18 +2304,25 @@ DocAccessible::CacheChildrenInSubtree(Ac
 
 void
 DocAccessible::UncacheChildrenInSubtree(Accessible* aRoot)
 {
   aRoot->mStateFlags |= eIsNotInDocument;
   RemoveDependentIDsFor(aRoot);
 
   uint32_t count = aRoot->ContentChildCount();
-  for (uint32_t idx = 0; idx < count; idx++)
-    UncacheChildrenInSubtree(aRoot->ContentChildAt(idx));
+  for (uint32_t idx = 0; idx < count; idx++) {
+    Accessible* child = aRoot->ContentChildAt(idx);
+
+    // Removing this accessible from the document doesn't mean anything about
+    // accessibles for subdocuments, so skip removing those from the tree.
+    if (!child->IsDoc()) {
+      UncacheChildrenInSubtree(child);
+    }
+  }
 
   if (aRoot->IsNodeMapEntry() &&
       mNodeToAccessibleMap.Get(aRoot->GetNode()) == aRoot)
     mNodeToAccessibleMap.Remove(aRoot->GetNode());
 }
 
 void
 DocAccessible::ShutdownChildrenInSubtree(Accessible* aAccessible)
--- a/accessible/generic/DocAccessible.h
+++ b/accessible/generic/DocAccessible.h
@@ -347,17 +347,17 @@ public:
   void ContentRemoved(Accessible* aContainer, nsIContent* aChildNode)
   {
     // Update the whole tree of this document accessible when the container is
     // null (document element is removed).
     UpdateTreeOnRemoval((aContainer ? aContainer : this), aChildNode);
   }
   void ContentRemoved(nsIContent* aContainerNode, nsIContent* aChildNode)
   {
-    ContentRemoved(GetAccessibleOrContainer(aContainerNode), aChildNode);
+    ContentRemoved(AccessibleOrTrueContainer(aContainerNode), aChildNode);
   }
 
   /**
    * Updates accessible tree when rendered text is changed.
    */
   void UpdateText(nsIContent* aTextNode);
 
   /**
--- a/accessible/generic/OuterDocAccessible.cpp
+++ b/accessible/generic/OuterDocAccessible.cpp
@@ -25,16 +25,22 @@ using namespace mozilla::a11y;
 ////////////////////////////////////////////////////////////////////////////////
 
 OuterDocAccessible::
   OuterDocAccessible(nsIContent* aContent, DocAccessible* aDoc) :
   AccessibleWrap(aContent, aDoc)
 {
   mType = eOuterDocType;
 
+#ifdef XP_WIN
+  if (DocAccessibleParent* remoteDoc = RemoteChildDoc()) {
+    remoteDoc->SendParentCOMProxy();
+  }
+#endif
+
   // Request document accessible for the content document to make sure it's
   // created. It will appended to outerdoc accessible children asynchronously.
   nsIDocument* outerDoc = mContent->GetUncomposedDoc();
   if (outerDoc) {
     nsIDocument* innerDoc = outerDoc->GetSubDocumentFor(mContent);
     if (innerDoc)
       GetAccService()->GetDocAccessible(innerDoc);
   }
@@ -202,17 +208,17 @@ OuterDocAccessible::GetChildAt(uint32_t 
   if (!remoteChild) {
     return nullptr;
   }
   return WrapperFor(remoteChild);
 }
 
 #endif // defined(XP_WIN)
 
-ProxyAccessible*
+DocAccessibleParent*
 OuterDocAccessible::RemoteChildDoc() const
 {
   dom::TabParent* tab = dom::TabParent::GetFrom(GetContent());
   if (!tab)
     return nullptr;
 
   return tab->GetTopLevelDocAccessible();
 }
--- a/accessible/generic/OuterDocAccessible.h
+++ b/accessible/generic/OuterDocAccessible.h
@@ -5,17 +5,17 @@
 
 #ifndef MOZILLA_A11Y_OUTERDOCACCESSIBLE_H_
 #define MOZILLA_A11Y_OUTERDOCACCESSIBLE_H_
 
 #include "AccessibleWrap.h"
 
 namespace mozilla {
 namespace a11y {
-class ProxyAccessible;
+class DocAccessibleParent;
 
 /**
  * Used for <browser>, <frame>, <iframe>, <page> or editor> elements.
  * 
  * In these variable names, "outer" relates to the OuterDocAccessible as
  * opposed to the DocAccessibleWrap which is "inner". The outer node is
  * a something like tags listed above, whereas the inner node corresponds to
  * the inner document root.
@@ -23,17 +23,17 @@ class ProxyAccessible;
 
 class OuterDocAccessible final : public AccessibleWrap
 {
 public:
   OuterDocAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   NS_DECL_ISUPPORTS_INHERITED
 
-  ProxyAccessible* RemoteChildDoc() const;
+  DocAccessibleParent* RemoteChildDoc() const;
 
   // Accessible
   virtual void Shutdown() override;
   virtual mozilla::a11y::role NativeRole() override;
   virtual Accessible* ChildAtPoint(int32_t aX, int32_t aY,
                                    EWhichChildAtPoint aWhichChild) override;
 
   virtual bool InsertChildAt(uint32_t aIdx, Accessible* aChild) override;
--- a/accessible/html/HTMLFormControlAccessible.cpp
+++ b/accessible/html/HTMLFormControlAccessible.cpp
@@ -346,18 +346,21 @@ HTMLTextFieldAccessible::Value(nsString&
 
   nsCOMPtr<nsIDOMHTMLTextAreaElement> textArea(do_QueryInterface(mContent));
   if (textArea) {
     textArea->GetValue(aValue);
     return;
   }
 
   HTMLInputElement* input = HTMLInputElement::FromContent(mContent);
-  if (input)
-    input->GetValue(aValue);
+  if (input) {
+    // Pass NonSystem as the caller type, to be safe.  We don't expect to have a
+    // file input here.
+    input->GetValue(aValue, CallerType::NonSystem);
+  }
 }
 
 void
 HTMLTextFieldAccessible::ApplyARIAState(uint64_t* aState) const
 {
   HyperTextAccessibleWrap::ApplyARIAState(aState);
   aria::MapToState(aria::eARIAAutoComplete, mContent->AsElement(), aState);
 
@@ -458,21 +461,16 @@ HTMLTextFieldAccessible::DoAction(uint8_
 
 already_AddRefed<nsIEditor>
 HTMLTextFieldAccessible::GetEditor() const
 {
   nsCOMPtr<nsIDOMNSEditableElement> editableElt(do_QueryInterface(mContent));
   if (!editableElt)
     return nullptr;
 
-  // nsGenericHTMLElement::GetEditor has a security check.
-  // Make sure we're not restricted by the permissions of
-  // whatever script is currently running.
-  mozilla::dom::AutoNoJSAPI nojsapi;
-
   nsCOMPtr<nsIEditor> editor;
   editableElt->GetEditor(getter_AddRefs(editor));
 
   return editor.forget();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // HTMLTextFieldAccessible: Widgets
@@ -552,17 +550,20 @@ HTMLSpinnerAccessible::NativeRole()
 
 void
 HTMLSpinnerAccessible::Value(nsString& aValue)
 {
   AccessibleWrap::Value(aValue);
   if (!aValue.IsEmpty())
     return;
 
-  HTMLInputElement::FromContent(mContent)->GetValue(aValue);
+  // Pass NonSystem as the caller type, to be safe.  We don't expect to have a
+  // file input here.
+  HTMLInputElement::FromContent(mContent)->GetValue(aValue,
+                                                    CallerType::NonSystem);
 }
 
 double
 HTMLSpinnerAccessible::MaxValue() const
 {
   double value = AccessibleWrap::MaxValue();
   if (!IsNaN(value))
     return value;
@@ -628,17 +629,20 @@ HTMLRangeAccessible::IsWidget() const
 
 void
 HTMLRangeAccessible::Value(nsString& aValue)
 {
   LeafAccessible::Value(aValue);
   if (!aValue.IsEmpty())
     return;
 
-  HTMLInputElement::FromContent(mContent)->GetValue(aValue);
+  // Pass NonSystem as the caller type, to be safe.  We don't expect to have a
+  // file input here.
+  HTMLInputElement::FromContent(mContent)->GetValue(aValue,
+                                                    CallerType::NonSystem);
 }
 
 double
 HTMLRangeAccessible::MaxValue() const
 {
   double value = LeafAccessible::MaxValue();
   if (!IsNaN(value))
     return value;
--- a/accessible/html/HTMLListAccessible.h
+++ b/accessible/html/HTMLListAccessible.h
@@ -58,17 +58,17 @@ public:
   // HTMLLIAccessible
   HTMLListBulletAccessible* Bullet() const { return mBullet; }
   void UpdateBullet(bool aHasBullet);
 
 protected:
   virtual ~HTMLLIAccessible() { }
 
 private:
-  RefPtr<HTMLListBulletAccessible> mBullet;
+  HTMLListBulletAccessible* mBullet;
 };
 
 
 /**
  * Used for bullet of HTML list item element (for example, HTML li).
  */
 class HTMLListBulletAccessible : public LeafAccessible
 {
--- a/accessible/html/HTMLTableAccessible.cpp
+++ b/accessible/html/HTMLTableAccessible.cpp
@@ -1070,17 +1070,17 @@ HTMLTableAccessible::IsProbablyLayoutTab
   uint32_t childCount = ChildCount();
   nscolor rowColor = 0;
   nscolor prevRowColor;
   for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) {
     Accessible* child = GetChildAt(childIdx);
     if (child->Role() == roles::ROW) {
       prevRowColor = rowColor;
       nsIFrame* rowFrame = child->GetFrame();
-      rowColor = rowFrame->StyleBackground()->mBackgroundColor;
+      rowColor = rowFrame->StyleBackground()->BackgroundColor(rowFrame);
 
       if (childIdx > 0 && prevRowColor != rowColor)
         RETURN_LAYOUT_ANSWER(false, "2 styles of row background color, non-bordered");
     }
   }
 
   // Check for many rows
   const uint32_t kMaxLayoutRows = 20;
new file mode 100644
--- /dev/null
+++ b/accessible/interfaces/gecko/IGeckoCustom.idl
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import "objidl.idl";
+import "oaidl.idl";
+
+[object, uuid(7510360f-cdae-4de9-88c8-d167eda62afc)]
+interface IGeckoCustom : IUnknown
+{
+  [propget] HRESULT ID([out, retval] unsigned __int64* aID);
+  [propget] HRESULT anchorCount([out, retval] long* aCount);
+  [propget] HRESULT DOMNodeID([out, retval] BSTR* aID);
+  [propget] HRESULT minimumIncrement([out, retval] double* aIncrement);
+  [propget] HRESULT mozState([out, retval] unsigned __int64* aState);
+}
+
+
+[
+    uuid(55769d85-f830-4d76-9e39-3670914a28f7),
+    helpstring("private custom gecko interfaces")
+]
+library IGeckoCustom
+{
+  interface IGeckoCustom;
+};
new file mode 100644
--- /dev/null
+++ b/accessible/interfaces/gecko/Makefile.in
@@ -0,0 +1,33 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+GARBAGE += $(MIDL_GENERATED_FILES) done_gen
+
+MIDL_GENERATED_FILES = \
+  dlldata.c \
+  IGeckoCustom.h \
+  IGeckoCustom_p.c \
+  IGeckoCustom_i.c \
+  IGeckoCustom.tlb \
+  $(NULL)
+
+$(MIDL_GENERATED_FILES): done_gen
+
+done_gen: IGeckoCustom.idl
+	$(MIDL) $(MIDL_FLAGS) -I $(srcdir) -Oicf $(srcdir)/IGeckoCustom.idl
+	touch $@
+
+export:: done_gen
+
+midl_exports := \
+    IGeckoCustom.h \
+    IGeckoCustom_i.c \
+    $(NULL)
+
+INSTALL_TARGETS += midl_exports
+midl_exports_FILES := $(midl_exports)
+midl_exports_DEST = $(DIST)/include
+midl_exports_TARGET := midl
+
+export:: midl
new file mode 100644
--- /dev/null
+++ b/accessible/interfaces/gecko/moz.build
@@ -0,0 +1,29 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+SOURCES += [
+    '!dlldata.c',
+    '!IGeckoCustom_i.c',
+    '!IGeckoCustom_p.c',
+]
+
+GENERATED_FILES += [
+    'dlldata.c',
+    'IGeckoCustom.h',
+    'IGeckoCustom.tlb',
+    'IGeckoCustom_i.c',
+    'IGeckoCustom_p.c',
+]
+
+FINAL_LIBRARY = 'xul'
+
+# The Windows MIDL code generator creates things like:
+#
+#   #endif !_MIDL_USE_GUIDDEF_
+#
+# which clang-cl complains about.  MSVC doesn't, so turn this warning off.
+if CONFIG['CLANG_CL']:
+    CFLAGS += ['-Wno-extra-tokens']
new file mode 100644
--- /dev/null
+++ b/accessible/interfaces/ia2/IA2Marshal.dll.manifest
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+  <assemblyIdentity type="win32" name="IA2Marshal" version="1.0.0.0" />
+  <file name="IA2Marshal.dll">
+    <comInterfaceProxyStub
+        iid="{E89F726E-C4F4-4c19-BB19-B647D7FA8478}"
+        proxyStubClsid32="{E89F726E-C4F4-4c19-BB19-B647D7FA8478}"
+        name="IAccessible2"
+        tlbid="{CE3F726E-D1D3-44FE-B995-FF1DB3B48B2B}"
+    />
+  </file>
+</assembly>
--- a/accessible/interfaces/ia2/IA2Typelib.idl
+++ b/accessible/interfaces/ia2/IA2Typelib.idl
@@ -27,11 +27,35 @@ typedef [wire_marshal(mozHACCEL)] void* 
 typedef [wire_marshal(mozHBRUSH)] void* HBRUSH;
 typedef [wire_marshal(mozHFONT)] void* HFONT;
 typedef [wire_marshal(mozHDC)] void* HDC;
 typedef [wire_marshal(mozHICON)] void* HICON;
 typedef [wire_marshal(mozHRGN)] void* HRGN;
 typedef [wire_marshal(mozHMONITOR)] void* HMONITOR;
 cpp_quote("#endif // 0")
 
+import "Accessible2.idl";
+import "Accessible2_2.idl";
+import "Accessible2_3.idl";
+import "AccessibleAction.idl";
+import "AccessibleApplication.idl";
+import "AccessibleComponent.idl";
+import "AccessibleDocument.idl";
+import "AccessibleEditableText.idl";
+import "AccessibleEventId.idl";
+import "AccessibleHyperlink.idl";
+import "AccessibleHypertext.idl";
+import "AccessibleHypertext2.idl";
+import "AccessibleImage.idl";
+import "AccessibleRelation.idl";
+import "AccessibleRole.idl";
+import "AccessibleStates.idl";
+import "AccessibleTable.idl";
+import "AccessibleTable2.idl";
+import "AccessibleTableCell.idl";
+import "AccessibleText.idl";
+import "AccessibleText2.idl";
+import "AccessibleValue.idl";
+import "IA2CommonTypes.idl";
+
 // We are explicitly using #include instead of import so that the imported
 // IDL is treated as part of this IDL file.
-#include "ia2_api_all.idl"
+#include "IA2TypeLibrary.idl"
--- a/accessible/interfaces/ia2/Makefile.in
+++ b/accessible/interfaces/ia2/Makefile.in
@@ -1,16 +1,18 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 IA2DIR        = $(topsrcdir)/other-licenses/ia2
 
 GARBAGE       += $(MIDL_GENERATED_FILES) \
                  $(MIDL_UNUSED_GENERATED_FILES) \
+                 midl_done \
+                 typelib_done \
                  $(NULL)
 
 # Please keep this list in sync with the moz.build file until the rest of this
 # Makefile is ported over.
 MIDL_INTERFACES = \
   Accessible2.idl \
   Accessible2_2.idl \
   Accessible2_3.idl \
@@ -48,43 +50,46 @@ MIDL_LIBRARIES = \
 CSRCS = \
   dlldata.c \
   $(MIDL_INTERFACES:%.idl=%_p.c) \
   $(MIDL_INTERFACES:%.idl=%_i.c) \
   $(NULL)
 
 MIDL_GENERATED_FILES = \
   dlldata.c \
+  $(MIDL_ENUMS:%.idl=%.h) \
   $(MIDL_INTERFACES:%.idl=%_p.c) \
   $(MIDL_INTERFACES:%.idl=%_i.c) \
   $(MIDL_INTERFACES:%.idl=%.h) \
-  $(MIDL_ENUMS:%.idl=%.h) \
+  $(MIDL_LIBRARIES:%.idl=%.tlb) \
   $(NULL)
 
 # We want to generate a .tlb from MIDL_LIBRARIES, but midl also generates
 # a bunch of .h and .c files that we're not interested in.
 MIDL_UNUSED_GENERATED_FILES = \
   $(MIDL_LIBRARIES:%.idl=%_p.c) \
   $(MIDL_LIBRARIES:%.idl=%_i.c) \
   $(MIDL_LIBRARIES:%.idl=%.h) \
   $(MIDL_LIBRARIES:%.idl=%.c) \
   $(NULL)
 
 EMBED_MANIFEST_AT = 2
 
 INSTALL_TARGETS += midl
 midl_FILES := $(filter %.h %_i.c,$(MIDL_GENERATED_FILES))
 midl_DEST = $(DIST)/include
-midl_TARGET := export
+midl_TARGET := midl
+
+export:: midl
 
 include $(topsrcdir)/config/rules.mk
 
 # generate list of to-be-generated files that are missing
-# but ignore special file dlldata.c
-missing:=$(strip $(foreach onefile,$(strip $(subst dlldata.c,,$(MIDL_GENERATED_FILES))),$(if $(wildcard $(onefile)),,$(onefile))))
+# but ignore special file dlldata.c and .tlb files
+missing:=$(strip $(foreach onefile,$(strip $(patsubst %.tlb,,$(subst dlldata.c,,$(MIDL_GENERATED_FILES)))),$(if $(wildcard $(onefile)),,$(onefile))))
 
 missing_base:=$(sort $(basename $(subst _p.c,,$(subst _i.c,,$(missing)))))
 
 $(MIDL_GENERATED_FILES) : midl_done typelib_done
 
 ifneq ("$(missing)","")
 midl_done : FORCE
 endif
@@ -92,17 +97,17 @@ endif
 midl_done : $(addprefix $(IA2DIR)/,$(MIDL_INTERFACES) $(MIDL_ENUMS))
 	for idl in $(sort $(subst FORCE,,$?) $(addsuffix .idl,$(addprefix $(IA2DIR)/,$(missing_base)))); do \
 	  $(MIDL) $(MIDL_FLAGS) -app_config -I $(IA2DIR) -Oicf $$idl; \
 	done
 	touch $@
 
 # The intent of this rule is to generate the .tlb file that is referenced in the
 # .rc file for IA2Marshal.dll
-typelib_done : $(MIDL_LIBRARIES)
+typelib_done : $(addprefix $(srcdir)/,$(MIDL_LIBRARIES))
 	for idl in $?; do \
-		$(MIDL) $(MIDL_FLAGS) -app_config -I $(IA2DIR) -D _MIDL_DECLARE_WIREM_HANDLE -dlldata `basename $$idl .idl`.c -Oicf $$idl; \
+	  $(MIDL) $(MIDL_FLAGS) -app_config -I $(IA2DIR) -D _MIDL_DECLARE_WIREM_HANDLE -dlldata `basename $$idl .idl`.c -Oicf $$idl; \
 	done
 	touch $@
 
 # This marshall dll is NOT registered in the installer (agreed to by IA2 participants)
 register::
 	regsvr32 -s $(DIST)/bin/$(SHARED_LIBRARY)
--- a/accessible/interfaces/ia2/moz.build
+++ b/accessible/interfaces/ia2/moz.build
@@ -14,16 +14,78 @@ OS_LIBS += [
     'uuid',
     'kernel32',
     'rpcrt4',
     'ole32',
     'oleaut32',
 ]
 
 GENERATED_FILES += [
+    'Accessible2.h',
+    'Accessible2_2.h',
+    'Accessible2_2_i.c',
+    'Accessible2_2_p.c',
+    'Accessible2_3.h',
+    'Accessible2_3_i.c',
+    'Accessible2_3_p.c',
+    'Accessible2_i.c',
+    'Accessible2_p.c',
+    'AccessibleAction.h',
+    'AccessibleAction_i.c',
+    'AccessibleAction_p.c',
+    'AccessibleApplication.h',
+    'AccessibleApplication_i.c',
+    'AccessibleApplication_p.c',
+    'AccessibleComponent.h',
+    'AccessibleComponent_i.c',
+    'AccessibleComponent_p.c',
+    'AccessibleDocument.h',
+    'AccessibleDocument_i.c',
+    'AccessibleDocument_p.c',
+    'AccessibleEditableText.h',
+    'AccessibleEditableText_i.c',
+    'AccessibleEditableText_p.c',
+    'AccessibleEventId.h',
+    'AccessibleHyperlink.h',
+    'AccessibleHyperlink_i.c',
+    'AccessibleHyperlink_p.c',
+    'AccessibleHypertext.h',
+    'AccessibleHypertext2.h',
+    'AccessibleHypertext2_i.c',
+    'AccessibleHypertext2_p.c',
+    'AccessibleHypertext_i.c',
+    'AccessibleHypertext_p.c',
+    'AccessibleImage.h',
+    'AccessibleImage_i.c',
+    'AccessibleImage_p.c',
+    'AccessibleRelation.h',
+    'AccessibleRelation_i.c',
+    'AccessibleRelation_p.c',
+    'AccessibleRole.h',
+    'AccessibleStates.h',
+    'AccessibleTable.h',
+    'AccessibleTable2.h',
+    'AccessibleTable2_i.c',
+    'AccessibleTable2_p.c',
+    'AccessibleTable_i.c',
+    'AccessibleTable_p.c',
+    'AccessibleTableCell.h',
+    'AccessibleTableCell_i.c',
+    'AccessibleTableCell_p.c',
+    'AccessibleText.h',
+    'AccessibleText2.h',
+    'AccessibleText2_i.c',
+    'AccessibleText2_p.c',
+    'AccessibleText_i.c',
+    'AccessibleText_p.c',
+    'AccessibleValue.h',
+    'AccessibleValue_i.c',
+    'AccessibleValue_p.c',
+    'dlldata.c',
+    'IA2CommonTypes.h',
     'IA2Typelib.tlb',
 ]
 
 RCINCLUDE = 'IA2Marshal.rc'
 
 # The Windows MIDL code generator creates things like:
 #
 #   #endif !_MIDL_USE_GUIDDEF_
--- a/accessible/interfaces/moz.build
+++ b/accessible/interfaces/moz.build
@@ -1,16 +1,16 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows' and CONFIG['COMPILE_ENVIRONMENT']:
-    DIRS += ['msaa', 'ia2']
+    DIRS += ['gecko', 'msaa', 'ia2']
 
 XPIDL_SOURCES += [
     'nsIAccessibilityService.idl',
     'nsIAccessible.idl',
     'nsIAccessibleApplication.idl',
     'nsIAccessibleCaretMoveEvent.idl',
     'nsIAccessibleDocument.idl',
     'nsIAccessibleEditableText.idl',
--- a/accessible/interfaces/msaa/AccessibleMarshal.rc
+++ b/accessible/interfaces/msaa/AccessibleMarshal.rc
@@ -1,5 +1,5 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-1 typelib ISimpleDOMNode.tlb
+1 typelib ISimpleDOM.tlb
new file mode 100644
--- /dev/null
+++ b/accessible/interfaces/msaa/ISimpleDOM.idl
@@ -0,0 +1,23 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// We use #include instead of import here so that MIDL treats these files as
+// part of the current file, thus forcing MIDL to generate proxy info for them.
+#include "ISimpleDOMNode.idl"
+#include "ISimpleDOMDocument.idl"
+#include "ISimpleDOMText.idl"
+
+[
+  uuid(a6245497-9c0b-4449-85a5-bd6ad07df8ea),
+  helpstring("ISimpleDOM Type Library")
+]
+library ISimpleDOM
+{
+  interface ISimpleDOMNode;
+  interface ISimpleDOMText;
+  interface ISimpleDOMDocument;
+};
+
--- a/accessible/interfaces/msaa/ISimpleDOMNode.idl
+++ b/accessible/interfaces/msaa/ISimpleDOMNode.idl
@@ -94,19 +94,16 @@ cpp_quote("//")
 cpp_quote("//")
 cpp_quote("///////////////////////////////////////////////////////////////////////////////////////////////////////")
 cpp_quote("")
 cpp_quote("")
 
 import "objidl.idl";
 import "oaidl.idl";
 
-import "ISimpleDOMText.idl";
-import "ISimpleDOMDocument.idl";
-
 [object, uuid(1814ceeb-49e2-407f-af99-fa755a7d2607)]
 interface ISimpleDOMNode : IUnknown
 {
   const unsigned short NODETYPE_ELEMENT = 1;
   const unsigned short NODETYPE_ATTRIBUTE = 2;
   const unsigned short NODETYPE_TEXT = 3;
   const unsigned short NODETYPE_CDATA_SECTION = 4;
   const unsigned short NODETYPE_ENTITY_REFERENCE = 5;
@@ -169,20 +166,8 @@ interface ISimpleDOMNode : IUnknown
 
   [propget] HRESULT innerHTML([out, retval] BSTR *innerHTML);
 
   [propget, local] HRESULT localInterface([out][retval] void **localInterface);
 
   [propget] HRESULT language([out, retval] BSTR *language);
 }
 
-
-[
-    uuid(a6245497-9c0b-4449-85a5-bd6ad07df8ea), 
-    helpstring("ISimpleDOM Type Library")
-] 
-library ISimpleDOM 
-{
-  interface ISimpleDOMNode;
-  interface ISimpleDOMText;
-  interface ISimpleDOMDocument;
-};
-
--- a/accessible/interfaces/msaa/Makefile.in
+++ b/accessible/interfaces/msaa/Makefile.in
@@ -1,50 +1,43 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-GARBAGE += $(MIDL_GENERATED_FILES) done_gen dlldata.c
+GARBAGE += $(MIDL_GENERATED_FILES) done_gen
 
 MIDL_GENERATED_FILES = \
-	ISimpleDOMNode.h \
-	ISimpleDOMNode_p.c \
-	ISimpleDOMNode_i.c \
-	ISimpleDOMDocument.h \
-	ISimpleDOMDocument_p.c \
-	ISimpleDOMDocument_i.c \
-	ISimpleDOMText.h \
-	ISimpleDOMText_p.c \
-	ISimpleDOMText_i.c \
-	$(NULL)
+  dlldata.c \
+  ISimpleDOM.h \
+  ISimpleDOM_i.c \
+  ISimpleDOM_p.c \
+  ISimpleDOM.tlb \
+  $(NULL)
 
 $(MIDL_GENERATED_FILES): done_gen
 
-done_gen: ISimpleDOMNode.idl \
+done_gen: ISimpleDOM.idl \
+          ISimpleDOMNode.idl \
           ISimpleDOMDocument.idl \
           ISimpleDOMText.idl
 
-	$(MIDL) $(MIDL_FLAGS) -I $(srcdir) -Oicf $(srcdir)/ISimpleDOMNode.idl
-	$(MIDL) $(MIDL_FLAGS) -Oicf $(srcdir)/ISimpleDOMDocument.idl
-	$(MIDL) $(MIDL_FLAGS) -Oicf $(srcdir)/ISimpleDOMText.idl
+	$(MIDL) $(MIDL_FLAGS) -I $(srcdir) -robust -Oicf $(srcdir)/ISimpleDOM.idl
 	touch $@
 
 export:: done_gen
 
 # This marshall dll is also registered in the installer
 register::
 	regsvr32 -s $(DIST)/bin/$(SHARED_LIBRARY)
 
 EMBED_MANIFEST_AT = 2
 
 midl_exports := \
-    ISimpleDOMDocument.h \
-    ISimpleDOMDocument_i.c \
-    ISimpleDOMNode.h \
-    ISimpleDOMNode_i.c \
-    ISimpleDOMText.h \
-    ISimpleDOMText_i.c \
+    ISimpleDOM.h \
+    ISimpleDOM_i.c \
     $(NULL)
 
 INSTALL_TARGETS += midl_exports
 midl_exports_FILES := $(midl_exports)
 midl_exports_DEST = $(DIST)/include
-midl_exports_TARGET := export
+midl_exports_TARGET := midl
+
+export:: midl
--- a/accessible/interfaces/msaa/moz.build
+++ b/accessible/interfaces/msaa/moz.build
@@ -3,36 +3,39 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 GeckoSharedLibrary('AccessibleMarshal', linkage=None)
 
 SOURCES += [
     '!dlldata.c',
-    '!ISimpleDOMDocument_i.c',
-    '!ISimpleDOMDocument_p.c',
-    '!ISimpleDOMNode_i.c',
-    '!ISimpleDOMNode_p.c',
-    '!ISimpleDOMText_i.c',
-    '!ISimpleDOMText_p.c',
+    '!ISimpleDOM_i.c',
+    '!ISimpleDOM_p.c',
 ]
 
 DEFINES['REGISTER_PROXY_DLL'] = True
+# The following line is required to preserve compatibility with older versions
+# of AccessibleMarshal.dll.
+DEFINES['PROXY_CLSID'] = 'IID_ISimpleDOMNode'
 
 DEFFILE = SRCDIR + '/AccessibleMarshal.def'
 
 OS_LIBS += [
     'kernel32',
     'rpcrt4',
     'oleaut32',
 ]
 
 GENERATED_FILES += [
-    'ISimpleDOMNode.tlb',
+    'dlldata.c',
+    'ISimpleDOM.h',
+    'ISimpleDOM.tlb',
+    'ISimpleDOM_i.c',
+    'ISimpleDOM_p.c',
 ]
 
 RCINCLUDE = 'AccessibleMarshal.rc'
 
 # The Windows MIDL code generator creates things like:
 #
 #   #endif !_MIDL_USE_GUIDDEF_
 #
--- a/accessible/interfaces/nsIAccessibleRelation.idl
+++ b/accessible/interfaces/nsIAccessibleRelation.idl
@@ -120,16 +120,42 @@ interface nsIAccessibleRelation : nsISup
   const unsigned long RELATION_CONTAINING_TAB_PANE = 0x12;
 
   /**
    * The target object is the containing application object.
    */
   const unsigned long RELATION_CONTAINING_APPLICATION = 0x14;
 
   /**
+   * The target object provides the detailed, extended description for this
+   * object. It provides more detailed information than would normally be
+   * provided using the DESCRIBED_BY relation. A common use for this relation is
+   * in digital publishing where an extended description needs to be conveyed in
+   * a book that requires structural markup or the embedding of other technology
+   * to provide illustrative content.
+   */
+  const unsigned long RELATION_DETAILS = 0x15;
+
+  /**
+   * This object provides the detailed, extended description for the target
+   * object. See DETAILS relation.
+   */
+  const unsigned long RELATION_DETAILS_FOR = 0x16;
+
+  /**
+   * The target object is the error message for this object.
+   */
+  const unsigned long RELATION_ERRORMSG = 0x17;
+
+  /**
+   * This object is the error message for the target object.
+   */
+  const unsigned long RELATION_ERRORMSG_FOR = 0x18;
+
+  /**
    * Returns the type of the relation.
    */
   readonly attribute unsigned long relationType;
 
   /**
    * Returns the number of targets for this relation.
    */
   readonly attribute unsigned long targetsCount;
--- a/accessible/ipc/DocAccessibleChildBase.cpp
+++ b/accessible/ipc/DocAccessibleChildBase.cpp
@@ -80,18 +80,18 @@ DocAccessibleChildBase::SerializeTree(Ac
   }
 }
 
 void
 DocAccessibleChildBase::ShowEvent(AccShowEvent* aShowEvent)
 {
   Accessible* parent = aShowEvent->Parent();
   uint64_t parentID = parent->IsDoc() ? 0 : reinterpret_cast<uint64_t>(parent->UniqueID());
-  uint32_t idxInParent = aShowEvent->InsertionIndex();
+  uint32_t idxInParent = aShowEvent->GetAccessible()->IndexInParent();
   nsTArray<AccessibleData> shownTree;
   ShowEventData data(parentID, idxInParent, shownTree);
   SerializeTree(aShowEvent->GetAccessible(), data.NewTree());
-  SendShowEvent(data, aShowEvent->IsFromUserInput());
+  MaybeSendShowEvent(data, aShowEvent->IsFromUserInput());
 }
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/ipc/DocAccessibleChildBase.h
+++ b/accessible/ipc/DocAccessibleChildBase.h
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_a11y_DocAccessibleChildBase_h
 #define mozilla_a11y_DocAccessibleChildBase_h
 
 #include "mozilla/a11y/DocAccessible.h"
 #include "mozilla/a11y/PDocAccessibleChild.h"
+#include "mozilla/Unused.h"
 #include "nsISupportsImpl.h"
 
 namespace mozilla {
 namespace a11y {
 
 class Accessible;
 class AccShowEvent;
 
@@ -33,20 +34,19 @@ public:
     MOZ_ASSERT(!mDoc);
     if (mDoc) {
       mDoc->SetIPCDoc(nullptr);
     }
 
     MOZ_COUNT_DTOR(DocAccessibleChildBase);
   }
 
-  void Shutdown()
+  virtual void Shutdown()
   {
-    mDoc->SetIPCDoc(nullptr);
-    mDoc = nullptr;
+    DetachDocument();
     SendShutdown();
   }
 
   void ShowEvent(AccShowEvent* aShowEvent);
 
   virtual void ActorDestroy(ActorDestroyReason) override
   {
     if (!mDoc) {
@@ -56,15 +56,26 @@ public:
     mDoc->SetIPCDoc(nullptr);
     mDoc = nullptr;
   }
 
 protected:
   static uint32_t InterfacesFor(Accessible* aAcc);
   static void SerializeTree(Accessible* aRoot, nsTArray<AccessibleData>& aTree);
 
+  virtual void MaybeSendShowEvent(ShowEventData& aData, bool aFromUser)
+  { Unused << SendShowEvent(aData, aFromUser); }
+
+  void DetachDocument()
+  {
+    if (mDoc) {
+      mDoc->SetIPCDoc(nullptr);
+      mDoc = nullptr;
+    }
+  }
+
   DocAccessible*  mDoc;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif // mozilla_a11y_DocAccessibleChildBase_h
--- a/accessible/ipc/DocAccessibleParent.cpp
+++ b/accessible/ipc/DocAccessibleParent.cpp
@@ -7,82 +7,98 @@
 #include "DocAccessibleParent.h"
 #include "mozilla/a11y/Platform.h"
 #include "mozilla/dom/TabParent.h"
 #include "xpcAccessibleDocument.h"
 #include "xpcAccEvents.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 
+#if defined(XP_WIN)
+#include "AccessibleWrap.h"
+#include "Compatibility.h"
+#include "nsWinUtils.h"
+#include "RootAccessible.h"
+#endif
+
 namespace mozilla {
 namespace a11y {
+uint64_t DocAccessibleParent::sMaxDocID = 0;
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleParent::RecvShowEvent(const ShowEventData& aData,
                                    const bool& aFromUser)
 {
   if (mShutdown)
-    return true;
+    return IPC_OK();
 
-  MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
+  MOZ_ASSERT(CheckDocTree());
 
   if (aData.NewTree().IsEmpty()) {
     NS_ERROR("no children being added");
-    return false;
+    return IPC_FAIL_NO_REASON(this);
   }
 
   ProxyAccessible* parent = GetAccessible(aData.ID());
 
   // XXX This should really never happen, but sometimes we fail to fire the
   // required show events.
   if (!parent) {
     NS_ERROR("adding child to unknown accessible");
-    return true;
+#ifdef DEBUG
+    return IPC_FAIL(this, "unknown parent accessible");
+#else
+    return IPC_OK();
+#endif
   }
 
   uint32_t newChildIdx = aData.Idx();
   if (newChildIdx > parent->ChildrenCount()) {
     NS_ERROR("invalid index to add child at");
-    return true;
+#ifdef DEBUG
+    return IPC_FAIL(this, "invalid index");
+#else
+    return IPC_OK();
+#endif
   }
 
   uint32_t consumed = AddSubtree(parent, aData.NewTree(), 0, newChildIdx);
   MOZ_ASSERT(consumed == aData.NewTree().Length());
 
   // XXX This shouldn't happen, but if we failed to add children then the below
   // is pointless and can crash.
   if (!consumed) {
-    return true;
+    return IPC_FAIL(this, "failed to add children");
   }
 
 #ifdef DEBUG
   for (uint32_t i = 0; i < consumed; i++) {
     uint64_t id = aData.NewTree()[i].ID();
     MOZ_ASSERT(mAccessibles.GetEntry(id));
   }
 #endif
 
-  MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
+  MOZ_ASSERT(CheckDocTree());
 
   ProxyAccessible* target = parent->ChildAt(newChildIdx);
   ProxyShowHideEvent(target, parent, true, aFromUser);
 
   if (!nsCoreUtils::AccEventObserversExist()) {
-    return true;
+    return IPC_OK();
   }
 
   uint32_t type = nsIAccessibleEvent::EVENT_SHOW;
   xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(target);
   xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
   nsIDOMNode* node = nullptr;
   RefPtr<xpcAccEvent> event = new xpcAccEvent(type, xpcAcc, doc, node,
                                               aFromUser);
   nsCoreUtils::DispatchAccEvent(Move(event));
 
-  return true;
+  return IPC_OK();
 }
 
 uint32_t
 DocAccessibleParent::AddSubtree(ProxyAccessible* aParent,
                                 const nsTArray<a11y::AccessibleData>& aNewTree,
                                 uint32_t aIdx, uint32_t aIdxInParent)
 {
   if (aNewTree.Length() <= aIdx) {
@@ -125,42 +141,42 @@ DocAccessibleParent::AddSubtree(ProxyAcc
     accessibles += consumed;
   }
 
   MOZ_ASSERT(newProxy->ChildrenCount() == kids);
 
   return accessibles;
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleParent::RecvHideEvent(const uint64_t& aRootID,
                                    const bool& aFromUser)
 {
   if (mShutdown)
-    return true;
+    return IPC_OK();
 
-  MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
+  MOZ_ASSERT(CheckDocTree());
 
   // We shouldn't actually need this because mAccessibles shouldn't have an
   // entry for the document itself, but it doesn't hurt to be explicit.
   if (!aRootID) {
     NS_ERROR("trying to hide entire document?");
-    return false;
+    return IPC_FAIL_NO_REASON(this);
   }
 
   ProxyEntry* rootEntry = mAccessibles.GetEntry(aRootID);
   if (!rootEntry) {
     NS_ERROR("invalid root being removed!");
-    return true;
+    return IPC_OK();
   }
 
   ProxyAccessible* root = rootEntry->mProxy;
   if (!root) {
     NS_ERROR("invalid root being removed!");
-    return true;
+    return IPC_OK();
   }
 
   ProxyAccessible* parent = root->Parent();
   ProxyShowHideEvent(root, parent, false, aFromUser);
 
   RefPtr<xpcAccHideEvent> event = nullptr;
   if (nsCoreUtils::AccEventObserversExist()) {
     uint32_t type = nsIAccessibleEvent::EVENT_HIDE;
@@ -174,279 +190,373 @@ DocAccessibleParent::RecvHideEvent(const
     nsIDOMNode* node = nullptr;
     event = new xpcAccHideEvent(type, xpcAcc, doc, node, aFromUser, xpcParent,
                                 xpcNext, xpcPrev);
   }
 
   parent->RemoveChild(root);
   root->Shutdown();
 
-  MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
+  MOZ_ASSERT(CheckDocTree());
 
   if (event) {
     nsCoreUtils::DispatchAccEvent(Move(event));
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleParent::RecvEvent(const uint64_t& aID, const uint32_t& aEventType)
 {
+  if (mShutdown) {
+    return IPC_OK();
+  }
+
   ProxyAccessible* proxy = GetAccessible(aID);
   if (!proxy) {
     NS_ERROR("no proxy for event!");
-    return true;
+    return IPC_OK();
   }
 
   ProxyEvent(proxy, aEventType);
 
   if (!nsCoreUtils::AccEventObserversExist()) {
-    return true;
+    return IPC_OK();
   }
 
   xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(proxy);
   xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
   nsIDOMNode* node = nullptr;
   bool fromUser = true; // XXX fix me
   RefPtr<xpcAccEvent> event = new xpcAccEvent(aEventType, xpcAcc, doc, node,
                                               fromUser);
   nsCoreUtils::DispatchAccEvent(Move(event));
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleParent::RecvStateChangeEvent(const uint64_t& aID,
                                           const uint64_t& aState,
                                           const bool& aEnabled)
 {
+  if (mShutdown) {
+    return IPC_OK();
+  }
+
   ProxyAccessible* target = GetAccessible(aID);
   if (!target) {
     NS_ERROR("we don't know about the target of a state change event!");
-    return true;
+    return IPC_OK();
   }
 
   ProxyStateChangeEvent(target, aState, aEnabled);
 
   if (!nsCoreUtils::AccEventObserversExist()) {
-    return true;
+    return IPC_OK();
   }
 
   xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(target);
   xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
   uint32_t type = nsIAccessibleEvent::EVENT_STATE_CHANGE;
   bool extra;
   uint32_t state = nsAccUtils::To32States(aState, &extra);
   bool fromUser = true; // XXX fix this
   nsIDOMNode* node = nullptr; // XXX can we do better?
   RefPtr<xpcAccStateChangeEvent> event =
     new xpcAccStateChangeEvent(type, xpcAcc, doc, node, fromUser, state, extra,
                                aEnabled);
   nsCoreUtils::DispatchAccEvent(Move(event));
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleParent::RecvCaretMoveEvent(const uint64_t& aID, const int32_t& aOffset)
 {
+  if (mShutdown) {
+    return IPC_OK();
+  }
+
   ProxyAccessible* proxy = GetAccessible(aID);
   if (!proxy) {
     NS_ERROR("unknown caret move event target!");
-    return true;
+    return IPC_OK();
   }
 
   ProxyCaretMoveEvent(proxy, aOffset);
 
   if (!nsCoreUtils::AccEventObserversExist()) {
-    return true;
+    return IPC_OK();
   }
 
   xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(proxy);
   xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
   nsIDOMNode* node = nullptr;
   bool fromUser = true; // XXX fix me
   uint32_t type = nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED;
   RefPtr<xpcAccCaretMoveEvent> event =
     new xpcAccCaretMoveEvent(type, xpcAcc, doc, node, fromUser, aOffset);
   nsCoreUtils::DispatchAccEvent(Move(event));
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleParent::RecvTextChangeEvent(const uint64_t& aID,
                                          const nsString& aStr,
                                          const int32_t& aStart,
                                          const uint32_t& aLen,
                                          const bool& aIsInsert,
                                          const bool& aFromUser)
 {
+  if (mShutdown) {
+    return IPC_OK();
+  }
+
   ProxyAccessible* target = GetAccessible(aID);
   if (!target) {
     NS_ERROR("text change event target is unknown!");
-    return true;
+    return IPC_OK();
   }
 
   ProxyTextChangeEvent(target, aStr, aStart, aLen, aIsInsert, aFromUser);
 
   if (!nsCoreUtils::AccEventObserversExist()) {
-    return true;
+    return IPC_OK();
   }
 
   xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(target);
   xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
   uint32_t type = aIsInsert ? nsIAccessibleEvent::EVENT_TEXT_INSERTED :
                               nsIAccessibleEvent::EVENT_TEXT_REMOVED;
   nsIDOMNode* node = nullptr;
   RefPtr<xpcAccTextChangeEvent> event =
     new xpcAccTextChangeEvent(type, xpcAcc, doc, node, aFromUser, aStart, aLen,
                               aIsInsert, aStr);
   nsCoreUtils::DispatchAccEvent(Move(event));
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleParent::RecvSelectionEvent(const uint64_t& aID,
                                         const uint64_t& aWidgetID,
                                         const uint32_t& aType)
 {
+  if (mShutdown) {
+    return IPC_OK();
+  }
+
   ProxyAccessible* target = GetAccessible(aID);
   ProxyAccessible* widget = GetAccessible(aWidgetID);
   if (!target || !widget) {
     NS_ERROR("invalid id in selection event");
-    return true;
+    return IPC_OK();
   }
 
   ProxySelectionEvent(target, widget, aType);
   if (!nsCoreUtils::AccEventObserversExist()) {
-    return true;
+    return IPC_OK();
   }
   xpcAccessibleGeneric* xpcTarget = GetXPCAccessible(target);
   xpcAccessibleDocument* xpcDoc = GetAccService()->GetXPCDocument(this);
   RefPtr<xpcAccEvent> event = new xpcAccEvent(aType, xpcTarget, xpcDoc,
                                               nullptr, false);
   nsCoreUtils::DispatchAccEvent(Move(event));
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleParent::RecvRoleChangedEvent(const uint32_t& aRole)
 {
+  if (mShutdown) {
+    return IPC_OK();
+  }
+
  if (aRole >= roles::LAST_ROLE) {
    NS_ERROR("child sent bad role in RoleChangedEvent");
-   return false;
+   return IPC_FAIL_NO_REASON(this);
  }
 
  mRole = static_cast<a11y::role>(aRole);
- return true;
+ return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleParent::RecvBindChildDoc(PDocAccessibleParent* aChildDoc, const uint64_t& aID)
 {
   // One document should never directly be the child of another.
   // We should always have at least an outer doc accessible in between.
   MOZ_ASSERT(aID);
   if (!aID)
-    return false;
+    return IPC_FAIL(this, "ID is 0!");
 
-  MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
+  if (mShutdown) {
+    return IPC_OK();
+  }
+
+  MOZ_ASSERT(CheckDocTree());
 
   auto childDoc = static_cast<DocAccessibleParent*>(aChildDoc);
   childDoc->Unbind();
-  bool result = AddChildDoc(childDoc, aID, false);
+  ipc::IPCResult result = AddChildDoc(childDoc, aID, false);
   MOZ_ASSERT(result);
-  MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
+  MOZ_ASSERT(CheckDocTree());
+#ifdef DEBUG
+  if (!result) {
+    return result;
+  }
+#else
+  result = IPC_OK();
+#endif
+
   return result;
 }
 
-bool
+ipc::IPCResult
 DocAccessibleParent::AddChildDoc(DocAccessibleParent* aChildDoc,
                                  uint64_t aParentID, bool aCreating)
 {
   // We do not use GetAccessible here because we want to be sure to not get the
   // document it self.
   ProxyEntry* e = mAccessibles.GetEntry(aParentID);
-  if (!e)
-    return false;
+  if (!e) {
+    return IPC_FAIL(this, "binding to nonexistant proxy!");
+  }
 
   ProxyAccessible* outerDoc = e->mProxy;
   MOZ_ASSERT(outerDoc);
 
   // OuterDocAccessibles are expected to only have a document as a child.
   // However for compatibility we tolerate replacing one document with another
   // here.
   if (outerDoc->ChildrenCount() > 1 ||
       (outerDoc->ChildrenCount() == 1 && !outerDoc->ChildAt(0)->IsDoc())) {
-    return false;
+    return IPC_FAIL(this, "binding to proxy that can't be a outerDoc!");
   }
 
-  aChildDoc->mParent = outerDoc;
+  aChildDoc->SetParent(outerDoc);
   outerDoc->SetChildDoc(aChildDoc);
-  mChildDocs.AppendElement(aChildDoc);
-  aChildDoc->mParentDoc = this;
+  mChildDocs.AppendElement(aChildDoc->mActorID);
+  aChildDoc->mParentDoc = mActorID;
 
   if (aCreating) {
     ProxyCreated(aChildDoc, Interfaces::DOCUMENT | Interfaces::HYPERTEXT);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleParent::RecvShutdown()
 {
   Destroy();
 
-  if (!static_cast<dom::TabParent*>(Manager())->IsDestroyed()) {
-  return PDocAccessibleParent::Send__delete__(this);
+  auto mgr = static_cast<dom::TabParent*>(Manager());
+  if (!mgr->IsDestroyed()) {
+    if (!PDocAccessibleParent::Send__delete__(this)) {
+      return IPC_FAIL_NO_REASON(mgr);
+    }
   }
 
-  return true;
+  return IPC_OK();
 }
 
 void
 DocAccessibleParent::Destroy()
 {
-  NS_ASSERTION(mChildDocs.IsEmpty(),
-               "why weren't the child docs destroyed already?");
-  MOZ_ASSERT(!mShutdown);
+  // If we are already shutdown that is because our containing tab parent is
+  // shutting down in which case we don't need to do anything.
+  if (mShutdown) {
+    return;
+  }
+
   mShutdown = true;
 
+  MOZ_DIAGNOSTIC_ASSERT(LiveDocs().Contains(mActorID));
   uint32_t childDocCount = mChildDocs.Length();
-  for (uint32_t i = childDocCount - 1; i < childDocCount; i--)
-    mChildDocs[i]->Destroy();
+  for (uint32_t i = 0; i < childDocCount; i++) {
+    for (uint32_t j = i + 1; j < childDocCount; j++) {
+      MOZ_DIAGNOSTIC_ASSERT(mChildDocs[i] != mChildDocs[j]);
+    }
+  }
+
+  // XXX This indirection through the hash map of live documents shouldn't be
+  // needed, but be paranoid for now.
+  int32_t actorID = mActorID;
+  for (uint32_t i = childDocCount - 1; i < childDocCount; i--) {
+    DocAccessibleParent* thisDoc = LiveDocs().Get(actorID);
+    MOZ_ASSERT(thisDoc);
+    if (!thisDoc) {
+      return;
+    }
+
+    thisDoc->ChildDocAt(i)->Destroy();
+  }
 
   for (auto iter = mAccessibles.Iter(); !iter.Done(); iter.Next()) {
     MOZ_ASSERT(iter.Get()->mProxy != this);
     ProxyDestroyed(iter.Get()->mProxy);
     iter.Remove();
   }
 
-  DocManager::NotifyOfRemoteDocShutdown(this);
-  ProxyDestroyed(this);
-  if (mParentDoc)
-    mParentDoc->RemoveChildDoc(this);
+  DocAccessibleParent* thisDoc = LiveDocs().Get(actorID);
+  MOZ_ASSERT(thisDoc);
+  if (!thisDoc) {
+    return;
+  }
+
+  // The code above should have already completely cleared these, but to be
+  // extra safe make sure they are cleared here.
+  thisDoc->mAccessibles.Clear();
+  thisDoc->mChildDocs.Clear();
+
+  DocManager::NotifyOfRemoteDocShutdown(thisDoc);
+  thisDoc = LiveDocs().Get(actorID);
+  MOZ_ASSERT(thisDoc);
+  if (!thisDoc) {
+    return;
+  }
+
+  ProxyDestroyed(thisDoc);
+  thisDoc = LiveDocs().Get(actorID);
+  MOZ_ASSERT(thisDoc);
+  if (!thisDoc) {
+    return;
+  }
+
+  if (DocAccessibleParent* parentDoc = thisDoc->ParentDoc())
+    parentDoc->RemoveChildDoc(thisDoc);
   else if (IsTopLevel())
     GetAccService()->RemoteDocShutdown(this);
 }
 
+DocAccessibleParent*
+DocAccessibleParent::ParentDoc() const
+{
+  if (mParentDoc == kNoParentDoc) {
+    return nullptr;
+  }
+
+  return LiveDocs().Get(mParentDoc);
+}
+
 bool
 DocAccessibleParent::CheckDocTree() const
 {
   size_t childDocs = mChildDocs.Length();
   for (size_t i = 0; i < childDocs; i++) {
-    if (!mChildDocs[i] || mChildDocs[i]->mParentDoc != this)
+    const DocAccessibleParent* childDoc = ChildDocAt(i);
+    if (!childDoc || childDoc->ParentDoc() != this)
       return false;
 
-    if (!mChildDocs[i]->CheckDocTree()) {
+    if (!childDoc->CheckDocTree()) {
       return false;
     }
   }
 
   return true;
 }
 
 xpcAccessibleGeneric*
@@ -454,46 +564,131 @@ DocAccessibleParent::GetXPCAccessible(Pr
 {
   xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
   MOZ_ASSERT(doc);
 
   return doc->GetXPCAccessible(aProxy);
 }
 
 #if defined(XP_WIN)
+void
+DocAccessibleParent::MaybeInitWindowEmulation()
+{
+  if (!nsWinUtils::IsWindowEmulationStarted()) {
+    return;
+  }
+
+  // XXX get the bounds from the tabParent instead of poking at accessibles
+  // which might not exist yet.
+  Accessible* outerDoc = OuterDocOfRemoteBrowser();
+  if (!outerDoc) {
+    return;
+  }
+
+  RootAccessible* rootDocument = outerDoc->RootAccessible();
+  MOZ_ASSERT(rootDocument);
+
+  bool isActive = true;
+  nsIntRect rect(CW_USEDEFAULT, CW_USEDEFAULT, 0, 0);
+  if (Compatibility::IsDolphin()) {
+    rect = Bounds();
+    nsIntRect rootRect = rootDocument->Bounds();
+    rect.x = rootRect.x - rect.x;
+    rect.y -= rootRect.y;
+
+    auto tab = static_cast<dom::TabParent*>(Manager());
+    tab->GetDocShellIsActive(&isActive);
+  }
+
+  IAccessibleHolder hWndAccHolder;
+  HWND parentWnd = reinterpret_cast<HWND>(rootDocument->GetNativeWindow());
+  HWND hWnd = nsWinUtils::CreateNativeWindow(kClassNameTabContent,
+                                             parentWnd, rect.x, rect.y,
+                                             rect.width, rect.height,
+                                             isActive);
+  if (hWnd) {
+    // Attach accessible document to the emulated native window
+    ::SetPropW(hWnd, kPropNameDocAccParent, (HANDLE)this);
+    SetEmulatedWindowHandle(hWnd);
+    IAccessible* rawHWNDAcc = nullptr;
+    if (SUCCEEDED(::AccessibleObjectFromWindow(hWnd, OBJID_WINDOW,
+                                               IID_IAccessible,
+                                               (void**)&rawHWNDAcc))) {
+      hWndAccHolder.Set(IAccessibleHolder::COMPtrType(rawHWNDAcc));
+    }
+  }
+
+  Unused << SendEmulatedWindow(reinterpret_cast<uintptr_t>(mEmulatedWindowHandle),
+                               hWndAccHolder);
+}
+
 /**
- * @param aMsaaID The MSAA ID that was generated by content that the chrome
- *        process should assign to this DocAccessibleParent.
  * @param aCOMProxy COM Proxy to the document in the content process.
- * @param aParentCOMProxy COM Proxy to the OuterDocAccessible that is
- *        the parent of the document. The content process will use this
- *        proxy when traversing up across the content/chrome boundary.
  */
-bool
-DocAccessibleParent::RecvCOMProxy(const int32_t& aMsaaID,
-                                  const IAccessibleHolder& aCOMProxy,
-                                  IAccessibleHolder* aParentCOMProxy)
+void
+DocAccessibleParent::SendParentCOMProxy()
 {
-  WrapperFor(this)->SetID(aMsaaID);
-
-  RefPtr<IAccessible> ptr(aCOMProxy.Get());
-  SetCOMInterface(ptr);
+  // Make sure that we're not racing with a tab shutdown
+  auto tab = static_cast<dom::TabParent*>(Manager());
+  MOZ_ASSERT(tab);
+  if (tab->IsDestroyed()) {
+    return;
+  }
 
   Accessible* outerDoc = OuterDocOfRemoteBrowser();
-  IAccessible* rawNative = nullptr;
-  if (outerDoc) {
-    outerDoc->GetNativeInterface((void**) &rawNative);
+  if (!outerDoc) {
+    return;
   }
 
-  aParentCOMProxy->Set(IAccessibleHolder::COMPtrType(rawNative));
-  return true;
+  IAccessible* rawNative = nullptr;
+  outerDoc->GetNativeInterface((void**) &rawNative);
+  MOZ_ASSERT(rawNative);
+
+  IAccessibleHolder::COMPtrType ptr(rawNative);
+  IAccessibleHolder holder(Move(ptr));
+  Unused << PDocAccessibleParent::SendParentCOMProxy(holder);
+}
+
+void
+DocAccessibleParent::SetEmulatedWindowHandle(HWND aWindowHandle)
+{
+  if (!aWindowHandle && mEmulatedWindowHandle && IsTopLevel()) {
+    ::DestroyWindow(mEmulatedWindowHandle);
+  }
+  mEmulatedWindowHandle = aWindowHandle;
 }
 
-bool
-DocAccessibleParent::RecvMsaaID(const int32_t& aMsaaID)
+mozilla::ipc::IPCResult
+DocAccessibleParent::RecvGetWindowedPluginIAccessible(
+      const WindowsHandle& aHwnd, IAccessibleHolder* aPluginCOMProxy)
 {
-  WrapperFor(this)->SetID(aMsaaID);
-  return true;
+#if defined(MOZ_CONTENT_SANDBOX)
+  // We don't actually want the accessible object for aHwnd, but rather the
+  // one that belongs to its child (see HTMLWin32ObjectAccessible).
+  HWND childWnd = ::GetWindow(reinterpret_cast<HWND>(aHwnd), GW_CHILD);
+  if (!childWnd) {
+    // We're seeing this in the wild - the plugin is windowed but we no longer
+    // have a window.
+    return IPC_OK();
+  }
+
+  IAccessible* rawAccPlugin = nullptr;
+  HRESULT hr = ::AccessibleObjectFromWindow(childWnd, OBJID_WINDOW,
+                                            IID_IAccessible,
+                                            (void**)&rawAccPlugin);
+  if (FAILED(hr)) {
+    // This might happen if the plugin doesn't handle WM_GETOBJECT properly.
+    // We should not consider that a failure.
+    return IPC_OK();
+  }
+
+  aPluginCOMProxy->Set(IAccessibleHolder::COMPtrType(rawAccPlugin));
+
+  return IPC_OK();
+#else
+  return IPC_FAIL(this, "Message unsupported in this build configuration");
+#endif
 }
+
 #endif // defined(XP_WIN)
 
 } // a11y
 } // mozilla
--- a/accessible/ipc/DocAccessibleParent.h
+++ b/accessible/ipc/DocAccessibleParent.h
@@ -23,103 +23,130 @@ class xpcAccessibleGeneric;
  * These objects live in the main process and comunicate with and represent
  * an accessible document in a content process.
  */
 class DocAccessibleParent : public ProxyAccessible,
     public PDocAccessibleParent
 {
 public:
   DocAccessibleParent() :
-    ProxyAccessible(this), mParentDoc(nullptr),
+    ProxyAccessible(this), mParentDoc(kNoParentDoc),
     mTopLevel(false), mShutdown(false)
-  { MOZ_COUNT_CTOR_INHERITED(DocAccessibleParent, ProxyAccessible); }
+#if defined(XP_WIN)
+                                      , mEmulatedWindowHandle(nullptr)
+#endif // defined(XP_WIN)
+  {
+    MOZ_COUNT_CTOR_INHERITED(DocAccessibleParent, ProxyAccessible);
+    sMaxDocID++;
+    mActorID = sMaxDocID;
+    MOZ_ASSERT(!LiveDocs().Get(mActorID));
+    LiveDocs().Put(mActorID, this);
+  }
   ~DocAccessibleParent()
   {
+    LiveDocs().Remove(mActorID);
     MOZ_COUNT_DTOR_INHERITED(DocAccessibleParent, ProxyAccessible);
     MOZ_ASSERT(mChildDocs.Length() == 0);
     MOZ_ASSERT(!ParentDoc());
   }
 
   void SetTopLevel() { mTopLevel = true; }
   bool IsTopLevel() const { return mTopLevel; }
 
   bool IsShutdown() const { return mShutdown; }
 
+  /**
+   * Mark this actor as shutdown without doing any cleanup.  This should only
+   * be called on actors that have just been initialized, so probably only from
+   * RecvPDocAccessibleConstructor.
+   */
+  void MarkAsShutdown()
+  {
+    MOZ_ASSERT(mChildDocs.IsEmpty());
+    MOZ_ASSERT(mAccessibles.Count() == 0);
+    mShutdown = true;
+  }
+
   /*
    * Called when a message from a document in a child process notifies the main
    * process it is firing an event.
    */
-  virtual bool RecvEvent(const uint64_t& aID, const uint32_t& aType)
+  virtual mozilla::ipc::IPCResult RecvEvent(const uint64_t& aID, const uint32_t& aType)
     override;
 
-  virtual bool RecvShowEvent(const ShowEventData& aData, const bool& aFromUser)
+  virtual mozilla::ipc::IPCResult RecvShowEvent(const ShowEventData& aData, const bool& aFromUser)
     override;
-  virtual bool RecvHideEvent(const uint64_t& aRootID, const bool& aFromUser)
+  virtual mozilla::ipc::IPCResult RecvHideEvent(const uint64_t& aRootID, const bool& aFromUser)
     override;
-  virtual bool RecvStateChangeEvent(const uint64_t& aID,
-                                    const uint64_t& aState,
-                                    const bool& aEnabled) override final;
+  virtual mozilla::ipc::IPCResult RecvStateChangeEvent(const uint64_t& aID,
+                                                       const uint64_t& aState,
+                                                       const bool& aEnabled) override final;
 
-  virtual bool RecvCaretMoveEvent(const uint64_t& aID, const int32_t& aOffset)
+  virtual mozilla::ipc::IPCResult RecvCaretMoveEvent(const uint64_t& aID, const int32_t& aOffset)
     override final;
 
-  virtual bool RecvTextChangeEvent(const uint64_t& aID, const nsString& aStr,
-                                   const int32_t& aStart, const uint32_t& aLen,
-                                   const bool& aIsInsert,
-                                   const bool& aFromUser) override;
+  virtual mozilla::ipc::IPCResult RecvTextChangeEvent(const uint64_t& aID, const nsString& aStr,
+                                                      const int32_t& aStart, const uint32_t& aLen,
+                                                      const bool& aIsInsert,
+                                                      const bool& aFromUser) override;
 
-  virtual bool RecvSelectionEvent(const uint64_t& aID,
-                                  const uint64_t& aWidgetID,
-                                  const uint32_t& aType) override;
+  virtual mozilla::ipc::IPCResult RecvSelectionEvent(const uint64_t& aID,
+                                                     const uint64_t& aWidgetID,
+                                                     const uint32_t& aType) override;
 
-  virtual bool RecvRoleChangedEvent(const uint32_t& aRole) override final;
+  virtual mozilla::ipc::IPCResult RecvRoleChangedEvent(const uint32_t& aRole) override final;
 
-  virtual bool RecvBindChildDoc(PDocAccessibleParent* aChildDoc, const uint64_t& aID) override;
+  virtual mozilla::ipc::IPCResult RecvBindChildDoc(PDocAccessibleParent* aChildDoc, const uint64_t& aID) override;
 
   void Unbind()
   {
-    mParent = nullptr;
     if (DocAccessibleParent* parent = ParentDoc()) {
-      parent->mChildDocs.RemoveElement(this);
+      parent->RemoveChildDoc(this);
     }
 
-    mParentDoc = nullptr;
+    SetParent(nullptr);
   }
 
-  virtual bool RecvShutdown() override;
+  virtual mozilla::ipc::IPCResult RecvShutdown() override;
   void Destroy();
   virtual void ActorDestroy(ActorDestroyReason aWhy) override
   {
-    MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
+    MOZ_ASSERT(CheckDocTree());
     if (!mShutdown)
       Destroy();
   }
 
   /*
    * Return the main processes representation of the parent document (if any)
    * of the document this object represents.
    */
-  DocAccessibleParent* ParentDoc() const { return mParentDoc; }
+  DocAccessibleParent* ParentDoc() const;
+  static const uint64_t kNoParentDoc = UINT64_MAX;
 
   /*
    * Called when a document in a content process notifies the main process of a
    * new child document.
    */
-  bool AddChildDoc(DocAccessibleParent* aChildDoc, uint64_t aParentID,
-                   bool aCreating = true);
+  ipc::IPCResult AddChildDoc(DocAccessibleParent* aChildDoc,
+                             uint64_t aParentID, bool aCreating = true);
 
   /*
    * Called when the document in the content process this object represents
    * notifies the main process a child document has been removed.
    */
   void RemoveChildDoc(DocAccessibleParent* aChildDoc)
   {
-    aChildDoc->Parent()->SetChildDoc(nullptr);
-    mChildDocs.RemoveElement(aChildDoc);
-    aChildDoc->mParentDoc = nullptr;
+    ProxyAccessible* parent = aChildDoc->Parent();
+    MOZ_ASSERT(parent);
+    if (parent) {
+      aChildDoc->Parent()->ClearChildDoc(aChildDoc);
+    }
+    DebugOnly<bool> result = mChildDocs.RemoveElement(aChildDoc->mActorID);
+    aChildDoc->mParentDoc = kNoParentDoc;
+    MOZ_ASSERT(result);
     MOZ_ASSERT(aChildDoc->mChildDocs.Length() == 0);
   }
 
   void RemoveAccessible(ProxyAccessible* aAccessible)
   {
     MOZ_DIAGNOSTIC_ASSERT(mAccessibles.GetEntry(aAccessible->ID()));
     mAccessibles.RemoveEntry(aAccessible->ID());
   }
@@ -136,24 +163,33 @@ public:
     return e ? e->mProxy : nullptr;
   }
 
   const ProxyAccessible* GetAccessible(uintptr_t aID) const
     { return const_cast<DocAccessibleParent*>(this)->GetAccessible(aID); }
 
   size_t ChildDocCount() const { return mChildDocs.Length(); }
   const DocAccessibleParent* ChildDocAt(size_t aIdx) const
-    { return mChildDocs[aIdx]; }
+  { return const_cast<DocAccessibleParent*>(this)->ChildDocAt(aIdx); }
+  DocAccessibleParent* ChildDocAt(size_t aIdx)
+    { return LiveDocs().Get(mChildDocs[aIdx]); }
 
 #if defined(XP_WIN)
-  virtual bool RecvCOMProxy(const int32_t& aMsaaID,
-                            const IAccessibleHolder& aCOMProxy,
-                            IAccessibleHolder* aParentCOMProxy) override;
+  void MaybeInitWindowEmulation();
+  void SendParentCOMProxy();
+
+  virtual mozilla::ipc::IPCResult RecvGetWindowedPluginIAccessible(
+      const WindowsHandle& aHwnd, IAccessibleHolder* aPluginCOMProxy) override;
 
-  virtual bool RecvMsaaID(const int32_t& aMsaaID) override;
+  /**
+   * Set emulated native window handle for a document.
+   * @param aWindowHandle emulated native window handle
+   */
+  void SetEmulatedWindowHandle(HWND aWindowHandle);
+  HWND GetEmulatedWindowHandle() const { return mEmulatedWindowHandle; }
 #endif
 
 private:
 
   class ProxyEntry : public PLDHashEntryHdr
   {
   public:
     explicit ProxyEntry(const void*) : mProxy(nullptr) {}
@@ -177,24 +213,38 @@ private:
   };
 
   uint32_t AddSubtree(ProxyAccessible* aParent,
                       const nsTArray<AccessibleData>& aNewTree, uint32_t aIdx,
                       uint32_t aIdxInParent);
   MOZ_MUST_USE bool CheckDocTree() const;
   xpcAccessibleGeneric* GetXPCAccessible(ProxyAccessible* aProxy);
 
-  nsTArray<DocAccessibleParent*> mChildDocs;
-  DocAccessibleParent* mParentDoc;
+  nsTArray<uint64_t> mChildDocs;
+  uint64_t mParentDoc;
+
+#if defined(XP_WIN)
+  // The handle associated with the emulated window that contains this document
+  HWND mEmulatedWindowHandle;
+#endif
 
   /*
    * Conceptually this is a map from IDs to proxies, but we store the ID in the
    * proxy object so we can't use a real map.
    */
   nsTHashtable<ProxyEntry> mAccessibles;
+  uint64_t mActorID;
   bool mTopLevel;
   bool mShutdown;
+
+  static uint64_t sMaxDocID;
+  static nsDataHashtable<nsUint64HashKey, DocAccessibleParent*>&
+    LiveDocs()
+    {
+      static nsDataHashtable<nsUint64HashKey, DocAccessibleParent*> sLiveDocs;
+      return sLiveDocs;
+    }
 };
 
 }
 }
 
 #endif
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/IPCTypes.h
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_IPCTypes_h
+#define mozilla_a11y_IPCTypes_h
+
+/**
+ * Since IPDL does not support preprocessing, this header file allows us to
+ * define types used by PDocAccessible differently depending on platform.
+ */
+
+#if defined(XP_WIN) && defined(ACCESSIBILITY)
+
+// So that we don't include a bunch of other Windows junk.
+#if !defined(COM_NO_WINDOWS_H)
+#define COM_NO_WINDOWS_H
+#endif // !defined(COM_NO_WINDOWS_H)
+
+// COM headers pull in MSXML which conflicts with our own XMLDocument class.
+// This define excludes those conflicting definitions.
+#if !defined(__XMLDocument_FWD_DEFINED__)
+#define __XMLDocument_FWD_DEFINED__
+#endif // !defined(__XMLDocument_FWD_DEFINED__)
+
+#include "mozilla/a11y/COMPtrTypes.h"
+
+// This define in rpcndr.h messes up our code, so we must undefine it after
+// COMPtrTypes.h has been included.
+#if defined(small)
+#undef small
+#endif // defined(small)
+
+#else
+
+namespace mozilla {
+namespace a11y {
+
+typedef uint32_t IAccessibleHolder;
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif // defined(XP_WIN) && defined(ACCESSIBILITY)
+
+#endif // mozilla_a11y_IPCTypes_h
+
--- a/accessible/ipc/ProxyAccessibleBase.cpp
+++ b/accessible/ipc/ProxyAccessibleBase.cpp
@@ -20,54 +20,68 @@
 namespace mozilla {
 namespace a11y {
 
 template <class Derived>
 void
 ProxyAccessibleBase<Derived>::Shutdown()
 {
   MOZ_DIAGNOSTIC_ASSERT(!IsDoc());
-  NS_ASSERTION(!mOuterDoc, "Why do we still have a child doc?");
   xpcAccessibleDocument* xpcDoc =
     GetAccService()->GetCachedXPCDocument(Document());
   if (xpcDoc) {
     xpcDoc->NotifyOfShutdown(static_cast<Derived*>(this));
   }
 
   // XXX Ideally  this wouldn't be necessary, but it seems OuterDoc accessibles
   // can be destroyed before the doc they own.
+  uint32_t childCount = mChildren.Length();
   if (!mOuterDoc) {
-    uint32_t childCount = mChildren.Length();
     for (uint32_t idx = 0; idx < childCount; idx++)
       mChildren[idx]->Shutdown();
   } else {
-    if (mChildren.Length() != 1)
-      MOZ_CRASH("outer doc doesn't own adoc!");
-
-    mChildren[0]->AsDoc()->Unbind();
+    if (childCount > 1) {
+      MOZ_CRASH("outer doc has too many documents!");
+    } else if (childCount == 1) {
+      mChildren[0]->AsDoc()->Unbind();
+    }
   }
 
   mChildren.Clear();
   ProxyDestroyed(static_cast<Derived*>(this));
   mDoc->RemoveAccessible(static_cast<Derived*>(this));
 }
 
 template <class Derived>
 void
-ProxyAccessibleBase<Derived>::SetChildDoc(DocAccessibleParent* aParent)
+ProxyAccessibleBase<Derived>::SetChildDoc(DocAccessibleParent* aChildDoc)
 {
-  if (aParent) {
-    MOZ_ASSERT(mChildren.IsEmpty());
-    mChildren.AppendElement(aParent);
-    mOuterDoc = true;
+  // DocAccessibleParent::AddChildDoc tolerates replacing one document with
+  // another. We must reflect that here.
+  MOZ_ASSERT(aChildDoc);
+  MOZ_ASSERT(mChildren.Length() <= 1);
+  if (mChildren.IsEmpty()) {
+    mChildren.AppendElement(aChildDoc);
   } else {
-    MOZ_ASSERT(mChildren.Length() == 1);
-    mChildren.Clear();
-    mOuterDoc = false;
+    mChildren.ReplaceElementAt(0, aChildDoc);
   }
+  mOuterDoc = true;
+}
+
+template <class Derived>
+void
+ProxyAccessibleBase<Derived>::ClearChildDoc(DocAccessibleParent* aChildDoc)
+{
+  MOZ_ASSERT(aChildDoc);
+  // This is possible if we're replacing one document with another: Doc 1
+  // has not had a chance to remove itself, but was already replaced by Doc 2
+  // in SetChildDoc(). This could result in two subsequent calls to
+  // ClearChildDoc() even though mChildren.Length() == 1.
+  MOZ_ASSERT(mChildren.Length() <= 1);
+  mChildren.RemoveElement(aChildDoc);
 }
 
 template <class Derived>
 bool
 ProxyAccessibleBase<Derived>::MustPruneChildren() const
 {
   // this is the equivalent to nsAccUtils::MustPrune for proxies and should be
   // kept in sync with that.
@@ -148,12 +162,53 @@ ProxyAccessibleBase<Derived>::OuterDocOf
   if (!frame)
     return nullptr;
 
   DocAccessible* chromeDoc = GetExistingDocAccessible(frame->OwnerDoc());
 
   return chromeDoc ? chromeDoc->GetAccessible(frame) : nullptr;
 }
 
+template<class Derived>
+void
+ProxyAccessibleBase<Derived>::SetParent(Derived* aParent)
+{
+  MOZ_ASSERT(IsDoc(), "we should only reparent documents");
+  if (!aParent) {
+    mParent = kNoParent;
+  } else {
+    MOZ_ASSERT(!aParent->IsDoc());
+    mParent = aParent->ID();
+  }
+}
+
+template<class Derived>
+Derived*
+ProxyAccessibleBase<Derived>::Parent() const
+{
+  if (mParent == kNoParent) {
+    return nullptr;
+  }
+
+  // if we are not a document then are parent is another proxy in the same
+  // document.  That means we can just ask our document for the proxy with our
+  // parent id.
+  if (!IsDoc()) {
+    return Document()->GetAccessible(mParent);
+  }
+
+  // If we are a top level document then our parent is not a proxy.
+  if (AsDoc()->IsTopLevel()) {
+    return nullptr;
+  }
+
+  // Finally if we are a non top level document then our parent id is for a
+  // proxy in our parent document so get the proxy from there.
+  DocAccessibleParent* parentDoc = AsDoc()->ParentDoc();
+  MOZ_ASSERT(parentDoc);
+  MOZ_ASSERT(mParent);
+  return parentDoc->GetAccessible(mParent);
+}
+
 template class ProxyAccessibleBase<ProxyAccessible>;
 
 } // namespace a11y
 } // namespace mozilla
--- a/accessible/ipc/ProxyAccessibleBase.h
+++ b/accessible/ipc/ProxyAccessibleBase.h
@@ -73,28 +73,29 @@ public:
     Parent()->mChildren.IndexOf(static_cast<const Derived*>(this)); }
   uint32_t EmbeddedChildCount() const;
   int32_t IndexOfEmbeddedChild(const Derived* aChild);
   Derived* EmbeddedChildAt(size_t aChildIdx);
   bool MustPruneChildren() const;
 
   void Shutdown();
 
-  void SetChildDoc(DocAccessibleParent*);
+  void SetChildDoc(DocAccessibleParent* aChildDoc);
+  void ClearChildDoc(DocAccessibleParent* aChildDoc);
 
   /**
    * Remove The given child.
    */
   void RemoveChild(Derived* aChild)
     { mChildren.RemoveElement(aChild); }
 
   /**
    * Return the proxy for the parent of the wrapped accessible.
    */
-  Derived* Parent() const { return mParent; }
+  Derived* Parent() const;
 
   Accessible* OuterDocOfRemoteBrowser() const;
 
   /**
    * Get the role of the accessible we're proxying.
    */
   role Role() const { return mRole; }
 
@@ -152,39 +153,42 @@ public:
         mRole == roles::GRID_CELL ||
         mRole == roles::MATHML_CELL);
   }
 
 protected:
   ProxyAccessibleBase(uint64_t aID, Derived* aParent,
                       DocAccessibleParent* aDoc, role aRole,
                       uint32_t aInterfaces)
-    : mParent(aParent)
+    : mParent(aParent->ID())
     , mDoc(aDoc)
     , mWrapper(0)
     , mID(aID)
     , mRole(aRole)
     , mOuterDoc(false)
     , mIsDoc(false)
     , mHasValue(aInterfaces & Interfaces::VALUE)
     , mIsHyperLink(aInterfaces & Interfaces::HYPERLINK)
     , mIsHyperText(aInterfaces & Interfaces::HYPERTEXT)
   {
   }
 
   explicit ProxyAccessibleBase(DocAccessibleParent* aThisAsDoc) :
-    mParent(nullptr), mDoc(aThisAsDoc), mWrapper(0), mID(0),
+    mParent(kNoParent), mDoc(aThisAsDoc), mWrapper(0), mID(0),
     mRole(roles::DOCUMENT), mOuterDoc(false), mIsDoc(true), mHasValue(false),
     mIsHyperLink(false), mIsHyperText(false)
   {}
 
 protected:
-  Derived* mParent;
+  void SetParent(Derived* aParent);
 
 private:
+  uintptr_t mParent;
+  static const uintptr_t kNoParent = UINTPTR_MAX;
+
   friend Derived;
 
   nsTArray<Derived*> mChildren;
   DocAccessibleParent* mDoc;
   uintptr_t mWrapper;
   uint64_t mID;
 
 protected:
--- a/accessible/ipc/moz.build
+++ b/accessible/ipc/moz.build
@@ -24,16 +24,20 @@ else:
         LOCAL_INCLUDES += [
             '/accessible/mac',
         ]
     else:
         LOCAL_INCLUDES += [
             '/accessible/other',
         ]
 
+EXPORTS.mozilla.a11y += [
+    'IPCTypes.h',
+]
+
 if CONFIG['GNU_CXX']:
     CXXFLAGS += ['-Wno-error=shadow']
 
 if CONFIG['ACCESSIBILITY']:
     EXPORTS.mozilla.a11y += [
         'DocAccessibleChildBase.h',
         'DocAccessibleParent.h',
         'ProxyAccessibleBase.h',
--- a/accessible/ipc/other/DocAccessibleChild.cpp
+++ b/accessible/ipc/other/DocAccessibleChild.cpp
@@ -80,99 +80,102 @@ DocAccessibleChild::IdToTableCellAccessi
 
 TableAccessible*
 DocAccessibleChild::IdToTableAccessible(const uint64_t& aID) const
 {
   Accessible* acc = IdToAccessible(aID);
   return (acc && acc->IsTable()) ? acc->AsTable() : nullptr;
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvState(const uint64_t& aID, uint64_t* aState)
 {
   Accessible* acc = IdToAccessible(aID);
   if (!acc) {
     *aState = states::DEFUNCT;
-    return true;
+    return IPC_OK();
   }
 
   *aState = acc->State();
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvNativeState(const uint64_t& aID, uint64_t* aState)
 {
   Accessible* acc = IdToAccessible(aID);
   if (!acc) {
     *aState = states::DEFUNCT;
-    return true;
+    return IPC_OK();
   }
 
   *aState = acc->NativeState();
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvName(const uint64_t& aID, nsString* aName)
 {
   Accessible* acc = IdToAccessible(aID);
   if (!acc)
-    return true;
+    return IPC_OK();
 
   acc->Name(*aName);
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvValue(const uint64_t& aID, nsString* aValue)
 {
   Accessible* acc = IdToAccessible(aID);
   if (!acc) {
-    return true;
+    return IPC_OK();
   }
 
   acc->Value(*aValue);
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvHelp(const uint64_t& aID, nsString* aHelp)
 {
   Accessible* acc = IdToAccessible(aID);
   if (!acc) {
-    return true;
+    return IPC_OK();
   }
 
   acc->Help(*aHelp);
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvDescription(const uint64_t& aID, nsString* aDesc)
 {
   Accessible* acc = IdToAccessible(aID);
   if (!acc)
-    return true;
+    return IPC_OK();
 
   acc->Description(*aDesc);
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvAttributes(const uint64_t& aID, nsTArray<Attribute>* aAttributes)
 {
   Accessible* acc = IdToAccessible(aID);
   if (!acc)
-    return true;
+    return IPC_OK();
 
   nsCOMPtr<nsIPersistentProperties> props = acc->Attributes();
-  return PersistentPropertiesToArray(props, aAttributes);
+  if (!PersistentPropertiesToArray(props, aAttributes)) {
+    return IPC_FAIL_NO_REASON(this);
+  }
+  return IPC_OK();
 }
 
 bool
 DocAccessibleChild::PersistentPropertiesToArray(nsIPersistentProperties* aProps,
                                                 nsTArray<Attribute>* aAttributes)
 {
   if (!aProps) {
     return true;
@@ -199,31 +202,31 @@ DocAccessibleChild::PersistentProperties
     NS_ENSURE_SUCCESS(rv, false);
 
     aAttributes->AppendElement(Attribute(name, value));
     }
 
   return true;
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvRelationByType(const uint64_t& aID,
                                        const uint32_t& aType,
                                        nsTArray<uint64_t>* aTargets)
 {
   Accessible* acc = IdToAccessible(aID);
   if (!acc)
-    return true;
+    return IPC_OK();
 
   auto type = static_cast<RelationType>(aType);
   Relation rel = acc->RelationByType(type);
   while (Accessible* target = rel.Next())
     aTargets->AppendElement(reinterpret_cast<uintptr_t>(target));
 
-  return true;
+  return IPC_OK();
 }
 
 static void
 AddRelation(Accessible* aAcc, RelationType aType,
             nsTArray<RelationTargets>* aTargets)
 {
   Relation rel = aAcc->RelationByType(aType);
   nsTArray<uint64_t> targets;
@@ -233,309 +236,315 @@ AddRelation(Accessible* aAcc, RelationTy
   if (!targets.IsEmpty()) {
     RelationTargets* newRelation =
       aTargets->AppendElement(RelationTargets(static_cast<uint32_t>(aType),
                                               nsTArray<uint64_t>()));
     newRelation->Targets().SwapElements(targets);
   }
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvRelations(const uint64_t& aID,
                                   nsTArray<RelationTargets>* aRelations)
 {
   Accessible* acc = IdToAccessible(aID);
   if (!acc)
-    return true;
+    return IPC_OK();
 
 #define RELATIONTYPE(gecko, s, a, m, i) AddRelation(acc, RelationType::gecko, aRelations);
 
 #include "RelationTypeMap.h"
 #undef RELATIONTYPE
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvIsSearchbox(const uint64_t& aID, bool* aRetVal)
 {
   Accessible* acc = IdToAccessible(aID);
   if (!acc)
-    return true;
+    return IPC_OK();
 
   *aRetVal = acc->IsSearchbox();
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvLandmarkRole(const uint64_t& aID, nsString* aLandmark)
 {
   Accessible* acc = IdToAccessible(aID);
   if (!acc) {
-    return true;
+    return IPC_OK();
   }
 
   if (nsIAtom* roleAtom = acc->LandmarkRole()) {
     roleAtom->ToString(*aLandmark);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvARIARoleAtom(const uint64_t& aID, nsString* aRole)
 {
   Accessible* acc = IdToAccessible(aID);
   if (!acc) {
-    return true;
+    return IPC_OK();
   }
 
   if (const nsRoleMapEntry* roleMap = acc->ARIARoleMap()) {
     if (nsIAtom* roleAtom = *(roleMap->roleAtom)) {
       roleAtom->ToString(*aRole);
     }
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvGetLevelInternal(const uint64_t& aID, int32_t* aLevel)
 {
   Accessible* acc = IdToAccessible(aID);
   if (acc) {
     *aLevel = acc->GetLevelInternal();
   }
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvScrollTo(const uint64_t& aID,
                                  const uint32_t& aScrollType)
 {
   Accessible* acc = IdToAccessible(aID);
   if (acc) {
     nsCoreUtils::ScrollTo(acc->Document()->PresShell(), acc->GetContent(),
                           aScrollType);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvScrollToPoint(const uint64_t& aID, const uint32_t& aScrollType, const int32_t& aX, const int32_t& aY)
 {
   Accessible* acc = IdToAccessible(aID);
   if (acc) {
     acc->ScrollToPoint(aScrollType, aX, aY);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvCaretLineNumber(const uint64_t& aID, int32_t* aLineNumber)
 {
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   *aLineNumber = acc && acc->IsTextRole() ? acc->CaretLineNumber() : 0;
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvCaretOffset(const uint64_t& aID, int32_t* aOffset)
 {
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   *aOffset = acc && acc->IsTextRole() ? acc->CaretOffset() : 0;
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvSetCaretOffset(const uint64_t& aID,
                                        const int32_t& aOffset)
 {
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   if (acc && acc->IsTextRole() && acc->IsValidOffset(aOffset)) {
     acc->SetCaretOffset(aOffset);
   }
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvCharacterCount(const uint64_t& aID, int32_t* aCount)
 {
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   *aCount = acc ? acc->CharacterCount() : 0;
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvSelectionCount(const uint64_t& aID, int32_t* aCount)
 {
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   *aCount = acc ? acc->SelectionCount() : 0;
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTextSubstring(const uint64_t& aID,
                                       const int32_t& aStartOffset,
                                       const int32_t& aEndOffset,
                                       nsString* aText, bool* aValid)
 {
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   if (!acc) {
-    return true;
+    return IPC_OK();
   }
 
   *aValid = acc->IsValidRange(aStartOffset, aEndOffset);
   acc->TextSubstring(aStartOffset, aEndOffset, *aText);
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvGetTextAfterOffset(const uint64_t& aID,
                                            const int32_t& aOffset,
                                            const int32_t& aBoundaryType,
                                            nsString* aText,
                                            int32_t* aStartOffset,
                                            int32_t* aEndOffset)
 {
   *aStartOffset = 0;
   *aEndOffset = 0;
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   if (acc) {
     acc->TextAfterOffset(aOffset, aBoundaryType,
                          aStartOffset, aEndOffset, *aText);
   }
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvGetTextAtOffset(const uint64_t& aID,
                                         const int32_t& aOffset,
                                         const int32_t& aBoundaryType,
                                         nsString* aText,
                                         int32_t* aStartOffset,
                                         int32_t* aEndOffset)
 {
   *aStartOffset = 0;
   *aEndOffset = 0;
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   if (acc) {
     acc->TextAtOffset(aOffset, aBoundaryType,
                       aStartOffset, aEndOffset, *aText);
   }
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvGetTextBeforeOffset(const uint64_t& aID,
                                             const int32_t& aOffset,
                                             const int32_t& aBoundaryType,
                                             nsString* aText,
                                             int32_t* aStartOffset,
                                             int32_t* aEndOffset)
 {
   *aStartOffset = 0;
   *aEndOffset = 0;
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   if (acc) {
     acc->TextBeforeOffset(aOffset, aBoundaryType,
                           aStartOffset, aEndOffset, *aText);
   }
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvCharAt(const uint64_t& aID,
                                const int32_t& aOffset,
                                uint16_t* aChar)
 {
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   *aChar = acc && acc->IsTextRole() ?
     static_cast<uint16_t>(acc->CharAt(aOffset)) : 0;
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTextAttributes(const uint64_t& aID,
                                        const bool& aIncludeDefAttrs,
                                        const int32_t& aOffset,
                                        nsTArray<Attribute>* aAttributes,
                                        int32_t* aStartOffset,
                                        int32_t* aEndOffset)
 {
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   if (!acc || !acc->IsTextRole()) {
-    return true;
+    return IPC_OK();
   }
 
   nsCOMPtr<nsIPersistentProperties> props =
     acc->TextAttributes(aIncludeDefAttrs, aOffset, aStartOffset, aEndOffset);
-  return PersistentPropertiesToArray(props, aAttributes);
+  if (!PersistentPropertiesToArray(props, aAttributes)) {
+    return IPC_FAIL_NO_REASON(this);
+  }
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvDefaultTextAttributes(const uint64_t& aID,
                                               nsTArray<Attribute> *aAttributes)
 {
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   if (!acc || !acc->IsTextRole()) {
-    return true;
+    return IPC_OK();
   }
 
   nsCOMPtr<nsIPersistentProperties> props = acc->DefaultTextAttributes();
-  return PersistentPropertiesToArray(props, aAttributes);
+  if (!PersistentPropertiesToArray(props, aAttributes)) {
+    return IPC_FAIL_NO_REASON(this);
+  }
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTextBounds(const uint64_t& aID,
                                    const int32_t& aStartOffset,
                                    const int32_t& aEndOffset,
                                    const uint32_t& aCoordType,
                                    nsIntRect* aRetVal)
 {
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   if (acc && acc->IsTextRole()) {
     *aRetVal = acc->TextBounds(aStartOffset, aEndOffset, aCoordType);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvCharBounds(const uint64_t& aID,
                                    const int32_t& aOffset,
                                    const uint32_t& aCoordType,
                                    nsIntRect* aRetVal)
 {
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   if (acc && acc->IsTextRole()) {
     *aRetVal = acc->CharBounds(aOffset, aCoordType);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvOffsetAtPoint(const uint64_t& aID,
                                       const int32_t& aX,
                                       const int32_t& aY,
                                       const uint32_t& aCoordType,
                                       int32_t* aRetVal)
 {
   *aRetVal = -1;
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   if (acc && acc->IsTextRole()) {
     *aRetVal = acc->OffsetAtPoint(aX, aY, aCoordType);
   }
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvSelectionBoundsAt(const uint64_t& aID,
                                           const int32_t& aSelectionNum,
                                           bool* aSucceeded,
                                           nsString* aData,
                                           int32_t* aStartOffset,
                                           int32_t* aEndOffset)
 {
   *aSucceeded = false;
@@ -545,581 +554,581 @@ DocAccessibleChild::RecvSelectionBoundsA
   if (acc && acc->IsTextRole()) {
     *aSucceeded =
       acc->SelectionBoundsAt(aSelectionNum, aStartOffset, aEndOffset);
     if (*aSucceeded) {
       acc->TextSubstring(*aStartOffset, *aEndOffset, *aData);
     }
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvSetSelectionBoundsAt(const uint64_t& aID,
                                              const int32_t& aSelectionNum,
                                              const int32_t& aStartOffset,
                                              const int32_t& aEndOffset,
                                              bool* aSucceeded)
 {
   *aSucceeded = false;
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   if (acc && acc->IsTextRole()) {
     *aSucceeded =
       acc->SetSelectionBoundsAt(aSelectionNum, aStartOffset, aEndOffset);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvAddToSelection(const uint64_t& aID,
                                        const int32_t& aStartOffset,
                                        const int32_t& aEndOffset,
                                        bool* aSucceeded)
 {
   *aSucceeded = false;
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   if (acc && acc->IsTextRole()) {
     *aSucceeded = acc->AddToSelection(aStartOffset, aEndOffset);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvRemoveFromSelection(const uint64_t& aID,
                                             const int32_t& aSelectionNum,
                                             bool* aSucceeded)
 {
   *aSucceeded = false;
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   if (acc && acc->IsTextRole()) {
     *aSucceeded = acc->RemoveFromSelection(aSelectionNum);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvScrollSubstringTo(const uint64_t& aID,
                                           const int32_t& aStartOffset,
                                           const int32_t& aEndOffset,
                                           const uint32_t& aScrollType)
 {
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   if (acc) {
     acc->ScrollSubstringTo(aStartOffset, aEndOffset, aScrollType);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvScrollSubstringToPoint(const uint64_t& aID,
                                                const int32_t& aStartOffset,
                                                const int32_t& aEndOffset,
                                                const uint32_t& aCoordinateType,
                                                const int32_t& aX,
                                                const int32_t& aY)
 {
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   if (acc) {
     acc->ScrollSubstringToPoint(aStartOffset, aEndOffset, aCoordinateType,
                                 aX, aY);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvText(const uint64_t& aID,
                              nsString* aText)
 {
   TextLeafAccessible* acc = IdToTextLeafAccessible(aID);
   if (acc) {
     *aText = acc->Text();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvReplaceText(const uint64_t& aID,
                                     const nsString& aText)
 {
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   if (acc && acc->IsTextRole()) {
     acc->ReplaceText(aText);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvInsertText(const uint64_t& aID,
                                    const nsString& aText,
                                    const int32_t& aPosition, bool* aValid)
 {
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   if (acc && acc->IsTextRole()) {
     *aValid = acc->IsValidOffset(aPosition);
     acc->InsertText(aText, aPosition);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvCopyText(const uint64_t& aID,
                                  const int32_t& aStartPos,
                                  const int32_t& aEndPos, bool* aValid)
 {
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   if (acc && acc->IsTextRole()) {
     acc->CopyText(aStartPos, aEndPos);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvCutText(const uint64_t& aID,
                                 const int32_t& aStartPos,
                                 const int32_t& aEndPos, bool* aValid)
 {
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   if (acc && acc->IsTextRole()) {
     *aValid = acc->IsValidRange(aStartPos, aEndPos);
     acc->CutText(aStartPos, aEndPos);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvDeleteText(const uint64_t& aID,
                                    const int32_t& aStartPos,
                                    const int32_t& aEndPos, bool* aValid)
 {
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   if (acc && acc->IsTextRole()) {
     *aValid = acc->IsValidRange(aStartPos, aEndPos);
     acc->DeleteText(aStartPos, aEndPos);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvPasteText(const uint64_t& aID,
                                   const int32_t& aPosition, bool* aValid)
 {
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   if (acc && acc->IsTextRole()) {
     *aValid = acc->IsValidOffset(aPosition);
     acc->PasteText(aPosition);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvImagePosition(const uint64_t& aID,
                                       const uint32_t& aCoordType,
                                       nsIntPoint* aRetVal)
 {
   ImageAccessible* acc = IdToImageAccessible(aID);
   if (acc) {
     *aRetVal = acc->Position(aCoordType);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvImageSize(const uint64_t& aID,
                                   nsIntSize* aRetVal)
 {
 
   ImageAccessible* acc = IdToImageAccessible(aID);
   if (acc) {
     *aRetVal = acc->Size();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvStartOffset(const uint64_t& aID,
                                     uint32_t* aRetVal,
                                     bool* aOk)
 {
   Accessible* acc = IdToAccessibleLink(aID);
   if (acc) {
     *aRetVal = acc->StartOffset();
     *aOk = true;
   } else {
     *aRetVal = 0;
     *aOk = false;
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvEndOffset(const uint64_t& aID,
                                   uint32_t* aRetVal,
                                   bool* aOk)
 {
   Accessible* acc = IdToAccessibleLink(aID);
   if (acc) {
     *aRetVal = acc->EndOffset();
     *aOk = true;
   } else {
     *aRetVal = 0;
     *aOk = false;
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvIsLinkValid(const uint64_t& aID,
                                     bool* aRetVal)
 {
   Accessible* acc = IdToAccessibleLink(aID);
   if (acc) {
     *aRetVal = acc->IsLinkValid();
   } else {
     *aRetVal = false;
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvAnchorCount(const uint64_t& aID,
                                     uint32_t* aRetVal,
                                     bool* aOk)
 {
   Accessible* acc = IdToAccessibleLink(aID);
   if (acc) {
     *aRetVal = acc->AnchorCount();
     *aOk = true;
   } else {
     *aRetVal = 0;
     *aOk = false;
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvAnchorURIAt(const uint64_t& aID,
                                     const uint32_t& aIndex,
                                     nsCString* aURI,
                                     bool* aOk)
 {
   Accessible* acc = IdToAccessibleLink(aID);
   *aOk = false;
   if (acc) {
     nsCOMPtr<nsIURI> uri = acc->AnchorURIAt(aIndex);
     if (uri) {
       uri->GetSpec(*aURI);
       *aOk = true;
     }
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvAnchorAt(const uint64_t& aID,
                                  const uint32_t& aIndex,
                                  uint64_t* aIDOfAnchor,
                                  bool* aOk)
 {
   *aIDOfAnchor = 0;
   *aOk = false;
   Accessible* acc = IdToAccessibleLink(aID);
   if (acc) {
     Accessible* anchor = acc->AnchorAt(aIndex);
     if (anchor) {
       *aIDOfAnchor = reinterpret_cast<uint64_t>(anchor->UniqueID());
       *aOk = true;
     }
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvLinkCount(const uint64_t& aID,
                                   uint32_t* aCount)
 {
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   *aCount = acc ? acc->LinkCount() : 0;
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvLinkAt(const uint64_t& aID,
                                const uint32_t& aIndex,
                                uint64_t* aIDOfLink,
                                bool* aOk)
 {
   *aIDOfLink = 0;
   *aOk = false;
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   if (acc) {
     Accessible* link = acc->LinkAt(aIndex);
     if (link) {
       *aIDOfLink = reinterpret_cast<uint64_t>(link->UniqueID());
       *aOk = true;
     }
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvLinkIndexOf(const uint64_t& aID,
                                     const uint64_t& aLinkID,
                                     int32_t* aIndex)
 {
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   Accessible* link = IdToAccessible(aLinkID);
   *aIndex = -1;
   if (acc && link) {
     *aIndex = acc->LinkIndexOf(link);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvLinkIndexAtOffset(const uint64_t& aID,
                                           const uint32_t& aOffset,
                                           int32_t* aIndex)
 {
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   *aIndex = acc ? acc->LinkIndexAtOffset(aOffset) : -1;
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableOfACell(const uint64_t& aID,
                                      uint64_t* aTableID,
                                      bool* aOk)
 {
   *aTableID = 0;
   *aOk = false;
   TableCellAccessible* acc = IdToTableCellAccessible(aID);
   if (acc) {
     TableAccessible* table = acc->Table();
     if (table) {
       *aTableID = reinterpret_cast<uint64_t>(table->AsAccessible()->UniqueID());
       *aOk = true;
     }
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvColIdx(const uint64_t& aID,
                                uint32_t* aIndex)
 {
   *aIndex = 0;
   TableCellAccessible* acc = IdToTableCellAccessible(aID);
   if (acc) {
     *aIndex = acc->ColIdx();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvRowIdx(const uint64_t& aID,
                                uint32_t* aIndex)
 {
   *aIndex = 0;
   TableCellAccessible* acc = IdToTableCellAccessible(aID);
   if (acc) {
     *aIndex = acc->RowIdx();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvGetPosition(const uint64_t& aID,
                                uint32_t* aColIdx, uint32_t* aRowIdx)
 {
   *aColIdx = 0;
   *aRowIdx = 0;
   TableCellAccessible* acc = IdToTableCellAccessible(aID);
   if (acc) {
     *aColIdx = acc->ColIdx();
     *aRowIdx = acc->RowIdx();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvGetColRowExtents(const uint64_t& aID,
                                          uint32_t* aColIdx, uint32_t* aRowIdx,
                                          uint32_t* aColExtent, uint32_t* aRowExtent)
 {
   *aColIdx = 0;
   *aRowIdx = 0;
   *aColExtent = 0;
   *aRowExtent = 0;
   TableCellAccessible* acc = IdToTableCellAccessible(aID);
   if (acc) {
     *aColIdx = acc->ColIdx();
     *aRowIdx = acc->RowIdx();
     *aColExtent = acc->ColExtent();
     *aRowExtent = acc->RowExtent();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvColExtent(const uint64_t& aID,
                                   uint32_t* aExtent)
 {
   *aExtent = 0;
   TableCellAccessible* acc = IdToTableCellAccessible(aID);
   if (acc) {
     *aExtent = acc->ColExtent();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvRowExtent(const uint64_t& aID,
                                   uint32_t* aExtent)
 {
   *aExtent = 0;
   TableCellAccessible* acc = IdToTableCellAccessible(aID);
   if (acc) {
     *aExtent = acc->RowExtent();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvColHeaderCells(const uint64_t& aID,
                                        nsTArray<uint64_t>* aCells)
 {
   TableCellAccessible* acc = IdToTableCellAccessible(aID);
   if (acc) {
     AutoTArray<Accessible*, 10> headerCells;
     acc->ColHeaderCells(&headerCells);
     aCells->SetCapacity(headerCells.Length());
     for (uint32_t i = 0; i < headerCells.Length(); ++i) {
       aCells->AppendElement(
         reinterpret_cast<uint64_t>(headerCells[i]->UniqueID()));
     }
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvRowHeaderCells(const uint64_t& aID,
                                        nsTArray<uint64_t>* aCells)
 {
   TableCellAccessible* acc = IdToTableCellAccessible(aID);
   if (acc) {
     AutoTArray<Accessible*, 10> headerCells;
     acc->RowHeaderCells(&headerCells);
     aCells->SetCapacity(headerCells.Length());
     for (uint32_t i = 0; i < headerCells.Length(); ++i) {
       aCells->AppendElement(
         reinterpret_cast<uint64_t>(headerCells[i]->UniqueID()));
     }
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvIsCellSelected(const uint64_t& aID,
                                        bool* aSelected)
 {
   TableCellAccessible* acc = IdToTableCellAccessible(aID);
   *aSelected = acc && acc->Selected();
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableCaption(const uint64_t& aID,
                                      uint64_t* aCaptionID,
                                      bool* aOk)
 {
   *aCaptionID = 0;
   *aOk = false;
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     Accessible* caption = acc->Caption();
     if (caption) {
       *aCaptionID = reinterpret_cast<uint64_t>(caption->UniqueID());
       *aOk = true;
     }
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableSummary(const uint64_t& aID,
                                      nsString* aSummary)
 {
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     acc->Summary(*aSummary);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableColumnCount(const uint64_t& aID,
                                          uint32_t* aColCount)
 {
   *aColCount = 0;
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     *aColCount = acc->ColCount();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableRowCount(const uint64_t& aID,
                                       uint32_t* aRowCount)
 {
   *aRowCount = 0;
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     *aRowCount = acc->RowCount();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableCellAt(const uint64_t& aID,
                                     const uint32_t& aRow,
                                     const uint32_t& aCol,
                                     uint64_t* aCellID,
                                     bool* aOk)
 {
   *aCellID = 0;
   *aOk = false;
@@ -1127,332 +1136,332 @@ DocAccessibleChild::RecvTableCellAt(cons
   if (acc) {
     Accessible* cell = acc->CellAt(aRow, aCol);
     if (cell) {
       *aCellID = reinterpret_cast<uint64_t>(cell->UniqueID());
       *aOk = true;
     }
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableCellIndexAt(const uint64_t& aID,
                                          const uint32_t& aRow,
                                          const uint32_t& aCol,
                                          int32_t* aIndex)
 {
   *aIndex = -1;
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     *aIndex = acc->CellIndexAt(aRow, aCol);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableColumnIndexAt(const uint64_t& aID,
                                            const uint32_t& aCellIndex,
                                            int32_t* aCol)
 {
   *aCol = -1;
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     *aCol = acc->ColIndexAt(aCellIndex);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableRowIndexAt(const uint64_t& aID,
                                         const uint32_t& aCellIndex,
                                         int32_t* aRow)
 {
   *aRow = -1;
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     *aRow = acc->RowIndexAt(aCellIndex);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableRowAndColumnIndicesAt(const uint64_t& aID,
                                                   const uint32_t& aCellIndex,
                                                   int32_t* aRow,
                                                   int32_t* aCol)
 {
   *aRow = -1;
   *aCol = -1;
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     acc->RowAndColIndicesAt(aCellIndex, aRow, aCol);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableColumnExtentAt(const uint64_t& aID,
                                             const uint32_t& aRow,
                                             const uint32_t& aCol,
                                             uint32_t* aExtent)
 {
   *aExtent = 0;
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     *aExtent = acc->ColExtentAt(aRow, aCol);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableRowExtentAt(const uint64_t& aID,
                                          const uint32_t& aRow,
                                          const uint32_t& aCol,
                                          uint32_t* aExtent)
 {
   *aExtent = 0;
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     *aExtent = acc->RowExtentAt(aRow, aCol);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableColumnDescription(const uint64_t& aID,
                                                const uint32_t& aCol,
                                                nsString* aDescription)
 {
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     acc->ColDescription(aCol, *aDescription);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableRowDescription(const uint64_t& aID,
                                             const uint32_t& aRow,
                                             nsString* aDescription)
 {
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     acc->RowDescription(aRow, *aDescription);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableColumnSelected(const uint64_t& aID,
                                             const uint32_t& aCol,
                                             bool* aSelected)
 {
   *aSelected = false;
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     *aSelected = acc->IsColSelected(aCol);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableRowSelected(const uint64_t& aID,
                                          const uint32_t& aRow,
                                          bool* aSelected)
 {
   *aSelected = false;
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     *aSelected = acc->IsRowSelected(aRow);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableCellSelected(const uint64_t& aID,
                                           const uint32_t& aRow,
                                           const uint32_t& aCol,
                                           bool* aSelected)
 {
   *aSelected = false;
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     *aSelected = acc->IsCellSelected(aRow, aCol);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableSelectedCellCount(const uint64_t& aID,
                                                uint32_t* aSelectedCells)
 {
   *aSelectedCells = 0;
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     *aSelectedCells = acc->SelectedCellCount();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableSelectedColumnCount(const uint64_t& aID,
                                                  uint32_t* aSelectedColumns)
 {
   *aSelectedColumns = 0;
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     *aSelectedColumns = acc->SelectedColCount();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableSelectedRowCount(const uint64_t& aID,
                                               uint32_t* aSelectedRows)
 {
   *aSelectedRows = 0;
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     *aSelectedRows = acc->SelectedRowCount();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableSelectedCells(const uint64_t& aID,
                                            nsTArray<uint64_t>* aCellIDs)
 {
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     AutoTArray<Accessible*, 30> cells;
     acc->SelectedCells(&cells);
     aCellIDs->SetCapacity(cells.Length());
     for (uint32_t i = 0; i < cells.Length(); ++i) {
       aCellIDs->AppendElement(
         reinterpret_cast<uint64_t>(cells[i]->UniqueID()));
     }
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableSelectedCellIndices(const uint64_t& aID,
                                                  nsTArray<uint32_t>* aCellIndices)
 {
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     acc->SelectedCellIndices(aCellIndices);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableSelectedColumnIndices(const uint64_t& aID,
                                                    nsTArray<uint32_t>* aColumnIndices)
 {
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     acc->SelectedColIndices(aColumnIndices);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableSelectedRowIndices(const uint64_t& aID,
                                                 nsTArray<uint32_t>* aRowIndices)
 {
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     acc->SelectedRowIndices(aRowIndices);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableSelectColumn(const uint64_t& aID,
                                           const uint32_t& aCol)
 {
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     acc->SelectCol(aCol);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableSelectRow(const uint64_t& aID,
                                        const uint32_t& aRow)
 {
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     acc->SelectRow(aRow);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableUnselectColumn(const uint64_t& aID,
                                             const uint32_t& aCol)
 {
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     acc->UnselectCol(aCol);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableUnselectRow(const uint64_t& aID,
                                          const uint32_t& aRow)
 {
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     acc->UnselectRow(aRow);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTableIsProbablyForLayout(const uint64_t& aID,
                                                  bool* aForLayout)
 {
   *aForLayout = false;
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
     *aForLayout = acc->IsProbablyLayoutTable();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvAtkTableColumnHeader(const uint64_t& aID,
                                              const int32_t& aCol,
                                              uint64_t* aHeader,
                                              bool* aOk)
 {
   *aHeader = 0;
   *aOk = false;
 
@@ -1462,20 +1471,20 @@ DocAccessibleChild::RecvAtkTableColumnHe
     Accessible* header = AccessibleWrap::GetColumnHeader(acc, aCol);
     if (header) {
       *aHeader = reinterpret_cast<uint64_t>(header->UniqueID());
       *aOk = true;
     }
   }
 #endif
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvAtkTableRowHeader(const uint64_t& aID,
                                           const int32_t& aRow,
                                           uint64_t* aHeader,
                                           bool* aOk)
 {
   *aHeader = 0;
   *aOk = false;
 
@@ -1485,434 +1494,434 @@ DocAccessibleChild::RecvAtkTableRowHeade
     Accessible* header = AccessibleWrap::GetRowHeader(acc, aRow);
     if (header) {
       *aHeader = reinterpret_cast<uint64_t>(header->UniqueID());
       *aOk = true;
     }
   }
 #endif
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvSelectedItems(const uint64_t& aID,
                                       nsTArray<uint64_t>* aSelectedItemIDs)
 {
   Accessible* acc = IdToAccessibleSelect(aID);
   if (acc) {
     AutoTArray<Accessible*, 10> selectedItems;
     acc->SelectedItems(&selectedItems);
     aSelectedItemIDs->SetCapacity(selectedItems.Length());
     for (size_t i = 0; i < selectedItems.Length(); ++i) {
       aSelectedItemIDs->AppendElement(
         reinterpret_cast<uint64_t>(selectedItems[i]->UniqueID()));
     }
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvSelectedItemCount(const uint64_t& aID,
                                           uint32_t* aCount)
 {
   *aCount = 0;
   Accessible* acc = IdToAccessibleSelect(aID);
   if (acc) {
     *aCount = acc->SelectedItemCount();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvGetSelectedItem(const uint64_t& aID,
                                         const uint32_t& aIndex,
                                         uint64_t* aSelected,
                                         bool* aOk)
 {
   *aSelected = 0;
   *aOk = false;
   Accessible* acc = IdToAccessibleSelect(aID);
   if (acc) {
     Accessible* item = acc->GetSelectedItem(aIndex);
     if (item) {
       *aSelected = reinterpret_cast<uint64_t>(item->UniqueID());
       *aOk = true;
     }
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvIsItemSelected(const uint64_t& aID,
                                        const uint32_t& aIndex,
                                        bool* aSelected)
 {
   *aSelected = false;
   Accessible* acc = IdToAccessibleSelect(aID);
   if (acc) {
     *aSelected = acc->IsItemSelected(aIndex);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvAddItemToSelection(const uint64_t& aID,
                                            const uint32_t& aIndex,
                                            bool* aSuccess)
 {
   *aSuccess = false;
   Accessible* acc = IdToAccessibleSelect(aID);
   if (acc) {
     *aSuccess = acc->AddItemToSelection(aIndex);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvRemoveItemFromSelection(const uint64_t& aID,
                                                 const uint32_t& aIndex,
                                                 bool* aSuccess)
 {
   *aSuccess = false;
   Accessible* acc = IdToAccessibleSelect(aID);
   if (acc) {
     *aSuccess = acc->RemoveItemFromSelection(aIndex);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvSelectAll(const uint64_t& aID,
                                   bool* aSuccess)
 {
   *aSuccess = false;
   Accessible* acc = IdToAccessibleSelect(aID);
   if (acc) {
     *aSuccess = acc->SelectAll();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvUnselectAll(const uint64_t& aID,
                                     bool* aSuccess)
 {
   *aSuccess = false;
   Accessible* acc = IdToAccessibleSelect(aID);
   if (acc) {
     *aSuccess = acc->UnselectAll();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTakeSelection(const uint64_t& aID)
 {
   Accessible* acc = IdToAccessible(aID);
   if (acc) {
     acc->TakeSelection();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvSetSelected(const uint64_t& aID, const bool& aSelect)
 {
   Accessible* acc = IdToAccessible(aID);
   if (acc) {
     acc->SetSelected(aSelect);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvDoAction(const uint64_t& aID,
                                  const uint8_t& aIndex,
                                  bool* aSuccess)
 {
   *aSuccess = false;
   Accessible* acc = IdToAccessible(aID);
   if (acc) {
     *aSuccess = acc->DoAction(aIndex);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvActionCount(const uint64_t& aID,
                                     uint8_t* aCount)
 {
   *aCount = 0;
   Accessible* acc = IdToAccessible(aID);
   if (acc) {
     *aCount = acc->ActionCount();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvActionDescriptionAt(const uint64_t& aID,
                                             const uint8_t& aIndex,
                                             nsString* aDescription)
 {
   Accessible* acc = IdToAccessible(aID);
   if (acc) {
     acc->ActionDescriptionAt(aIndex, *aDescription);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvActionNameAt(const uint64_t& aID,
                                      const uint8_t& aIndex,
                                      nsString* aName)
 {
   Accessible* acc = IdToAccessible(aID);
   if (acc) {
     acc->ActionNameAt(aIndex, *aName);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvAccessKey(const uint64_t& aID,
                                   uint32_t* aKey,
                                   uint32_t* aModifierMask)
 {
   *aKey = 0;
   *aModifierMask = 0;
   Accessible* acc = IdToAccessible(aID);
   if (acc) {
     KeyBinding kb = acc->AccessKey();
     *aKey = kb.Key();
     *aModifierMask = kb.ModifierMask();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvKeyboardShortcut(const uint64_t& aID,
                                          uint32_t* aKey,
                                          uint32_t* aModifierMask)
 {
   *aKey = 0;
   *aModifierMask = 0;
   Accessible* acc = IdToAccessible(aID);
   if (acc) {
     KeyBinding kb = acc->KeyboardShortcut();
     *aKey = kb.Key();
     *aModifierMask = kb.ModifierMask();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvAtkKeyBinding(const uint64_t& aID,
                                       nsString* aResult)
 {
 #ifdef MOZ_ACCESSIBILITY_ATK
   Accessible* acc = IdToAccessible(aID);
   if (acc) {
     AccessibleWrap::GetKeyBinding(acc, *aResult);
   }
 #endif
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvCurValue(const uint64_t& aID,
                                  double* aValue)
 {
   *aValue = UnspecifiedNaN<double>();
   Accessible* acc = IdToAccessible(aID);
   if (acc) {
     *aValue = acc->CurValue();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvSetCurValue(const uint64_t& aID,
                                     const double& aValue,
                                     bool* aRetVal)
 {
   *aRetVal = false;
   Accessible* acc = IdToAccessible(aID);
   if (acc) {
     *aRetVal = acc->SetCurValue(aValue);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvMinValue(const uint64_t& aID,
                                  double* aValue)
 {
   *aValue = UnspecifiedNaN<double>();
   Accessible* acc = IdToAccessible(aID);
   if (acc) {
     *aValue = acc->MinValue();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvMaxValue(const uint64_t& aID,
                                  double* aValue)
 {
   *aValue = UnspecifiedNaN<double>();
   Accessible* acc = IdToAccessible(aID);
   if (acc) {
     *aValue = acc->MaxValue();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvStep(const uint64_t& aID,
                              double* aStep)
 {
   *aStep = UnspecifiedNaN<double>();
   Accessible* acc = IdToAccessible(aID);
   if (acc) {
     *aStep = acc->Step();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTakeFocus(const uint64_t& aID)
 {
   Accessible* acc = IdToAccessible(aID);
   if (acc) {
     acc->TakeFocus();
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvFocusedChild(const uint64_t& aID,
                                        uint64_t* aChild,
                                        bool* aOk)
 {
   *aChild = 0;
   *aOk = false;
   Accessible* acc = IdToAccessible(aID);
   if (acc) {
     Accessible* child = acc->FocusedChild();
     if (child) {
       *aChild = reinterpret_cast<uint64_t>(child->UniqueID());
       *aOk = true;
     }
   }
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvLanguage(const uint64_t& aID,
                                  nsString* aLocale)
 {
   Accessible* acc = IdToAccessible(aID);
   if (acc) {
     acc->Language(*aLocale);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvDocType(const uint64_t& aID,
                                 nsString* aType)
 {
   Accessible* acc = IdToAccessible(aID);
   if (acc && acc->IsDoc()) {
     acc->AsDoc()->DocType(*aType);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvTitle(const uint64_t& aID,
                             nsString* aTitle)
 {
   Accessible* acc = IdToAccessible(aID);
   if (acc) {
     mozilla::ErrorResult rv;
     acc->GetContent()->GetTextContent(*aTitle, rv);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvURL(const uint64_t& aID,
                             nsString* aURL)
 {
   Accessible* acc = IdToAccessible(aID);
   if (acc && acc->IsDoc()) {
     acc->AsDoc()->URL(*aURL);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvMimeType(const uint64_t& aID,
                                  nsString* aMime)
 {
   Accessible* acc = IdToAccessible(aID);
   if (acc && acc->IsDoc()) {
     acc->AsDoc()->MimeType(*aMime);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvURLDocTypeMimeType(const uint64_t& aID,
                                            nsString* aURL,
                                            nsString* aDocType,
                                            nsString* aMimeType)
 {
   Accessible* acc = IdToAccessible(aID);
   if (acc && acc->IsDoc()) {
     DocAccessible* doc = acc->AsDoc();
     doc->URL(*aURL);
     doc->DocType(*aDocType);
     doc->MimeType(*aMimeType);
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvAccessibleAtPoint(const uint64_t& aID,
                                           const int32_t& aX,
                                           const int32_t& aY,
                                           const bool& aNeedsScreenCoords,
                                           const uint32_t& aWhich,
                                           uint64_t* aResult,
                                           bool* aOk)
 {
@@ -1933,20 +1942,20 @@ DocAccessibleChild::RecvAccessibleAtPoin
       acc->ChildAtPoint(x, y,
                         static_cast<Accessible::EWhichChildAtPoint>(aWhich));
     if (result) {
       *aResult = reinterpret_cast<uint64_t>(result->UniqueID());
       *aOk = true;
     }
   }
 
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvExtents(const uint64_t& aID,
                                 const bool& aNeedsScreenCoords,
                                 int32_t* aX,
                                 int32_t* aY,
                                 int32_t* aWidth,
                                 int32_t* aHeight)
 {
   *aX = 0;
@@ -1965,34 +1974,34 @@ DocAccessibleChild::RecvExtents(const ui
       }
 
       *aX = screenRect.x;
       *aY = screenRect.y;
       *aWidth = screenRect.width;
       *aHeight = screenRect.height;
     }
   }
-  return true;
+  return IPC_OK();
 }
 
-bool
+mozilla::ipc::IPCResult
 DocAccessibleChild::RecvDOMNodeID(const uint64_t& aID, nsString* aDOMNodeID)
 {
   Accessible* acc = IdToAccessible(aID);
   if (!acc) {
-    return true;
+    return IPC_OK();
   }
 
   nsIContent* content = acc->GetContent();
   if (!content) {
-    return true;
+    return IPC_OK();
   }
 
   nsIAtom* id = content->GetID();
   if (id) {
     id->ToString(*aDOMNodeID);
   }
 
-  return true;
+  return IPC_OK();
 }
 
 }
 }
--- a/accessible/ipc/other/DocAccessibleChild.h
+++ b/accessible/ipc/other/DocAccessibleChild.h
@@ -35,444 +35,444 @@ public:
   ~DocAccessibleChild()
   {
     MOZ_COUNT_DTOR_INHERITED(DocAccessibleChild, DocAccessibleChildBase);
   }
 
   /*
    * Return the state for the accessible with given ID.
    */
-  virtual bool RecvState(const uint64_t& aID, uint64_t* aState) override;
+  virtual mozilla::ipc::IPCResult RecvState(const uint64_t& aID, uint64_t* aState) override;
 
   /*
    * Return the native state for the accessible with given ID.
    */
-  virtual bool RecvNativeState(const uint64_t& aID, uint64_t* aState) override;
+  virtual mozilla::ipc::IPCResult RecvNativeState(const uint64_t& aID, uint64_t* aState) override;
 
   /*
    * Get the name for the accessible with given id.
    */
-  virtual bool RecvName(const uint64_t& aID, nsString* aName) override;
+  virtual mozilla::ipc::IPCResult RecvName(const uint64_t& aID, nsString* aName) override;
 
-  virtual bool RecvValue(const uint64_t& aID, nsString* aValue) override;
+  virtual mozilla::ipc::IPCResult RecvValue(const uint64_t& aID, nsString* aValue) override;
 
-  virtual bool RecvHelp(const uint64_t& aID, nsString* aHelp) override;
+  virtual mozilla::ipc::IPCResult RecvHelp(const uint64_t& aID, nsString* aHelp) override;
 
   /*
    * Get the description for the accessible with given id.
    */
-  virtual bool RecvDescription(const uint64_t& aID, nsString* aDesc) override;
-  virtual bool RecvRelationByType(const uint64_t& aID, const uint32_t& aType,
-                                  nsTArray<uint64_t>* aTargets) override;
-  virtual bool RecvRelations(const uint64_t& aID,
-                             nsTArray<RelationTargets>* aRelations)
+  virtual mozilla::ipc::IPCResult RecvDescription(const uint64_t& aID, nsString* aDesc) override;
+  virtual mozilla::ipc::IPCResult RecvRelationByType(const uint64_t& aID, const uint32_t& aType,
+                                                     nsTArray<uint64_t>* aTargets) override;
+  virtual mozilla::ipc::IPCResult RecvRelations(const uint64_t& aID,
+                                                nsTArray<RelationTargets>* aRelations)
     override;
 
-  virtual bool RecvIsSearchbox(const uint64_t& aID, bool* aRetVal) override;
+  virtual mozilla::ipc::IPCResult RecvIsSearchbox(const uint64_t& aID, bool* aRetVal) override;
 
-  virtual bool RecvLandmarkRole(const uint64_t& aID, nsString* aLandmark) override;
+  virtual mozilla::ipc::IPCResult RecvLandmarkRole(const uint64_t& aID, nsString* aLandmark) override;
 
-  virtual bool RecvARIARoleAtom(const uint64_t& aID, nsString* aRole) override;
+  virtual mozilla::ipc::IPCResult RecvARIARoleAtom(const uint64_t& aID, nsString* aRole) override;
 
-  virtual bool RecvGetLevelInternal(const uint64_t& aID, int32_t* aLevel) override;
+  virtual mozilla::ipc::IPCResult RecvGetLevelInternal(const uint64_t& aID, int32_t* aLevel) override;
 
-  virtual bool RecvAttributes(const uint64_t& aID,
-                              nsTArray<Attribute> *aAttributes) override;
-  virtual bool RecvScrollTo(const uint64_t& aID, const uint32_t& aScrollType)
+  virtual mozilla::ipc::IPCResult RecvAttributes(const uint64_t& aID,
+                                                 nsTArray<Attribute> *aAttributes) override;
+  virtual mozilla::ipc::IPCResult RecvScrollTo(const uint64_t& aID, const uint32_t& aScrollType)
     override;
-  virtual bool RecvScrollToPoint(const uint64_t& aID,
-                                 const uint32_t& aScrollType,
-                                 const int32_t& aX, const int32_t& aY) override;
+  virtual mozilla::ipc::IPCResult RecvScrollToPoint(const uint64_t& aID,
+                                                    const uint32_t& aScrollType,
+                                                    const int32_t& aX, const int32_t& aY) override;
 
-  virtual bool RecvCaretLineNumber(const uint64_t& aID, int32_t* aLineNumber)
+  virtual mozilla::ipc::IPCResult RecvCaretLineNumber(const uint64_t& aID, int32_t* aLineNumber)
     override;
-  virtual bool RecvCaretOffset(const uint64_t& aID, int32_t* aOffset)
+  virtual mozilla::ipc::IPCResult RecvCaretOffset(const uint64_t& aID, int32_t* aOffset)
     override;
-  virtual bool RecvSetCaretOffset(const uint64_t& aID, const int32_t& aOffset)
+  virtual mozilla::ipc::IPCResult RecvSetCaretOffset(const uint64_t& aID, const int32_t& aOffset)
     override;
 
-  virtual bool RecvCharacterCount(const uint64_t& aID, int32_t* aCount)
+  virtual mozilla::ipc::IPCResult RecvCharacterCount(const uint64_t& aID, int32_t* aCount)
      override;
-  virtual bool RecvSelectionCount(const uint64_t& aID, int32_t* aCount)
+  virtual mozilla::ipc::IPCResult RecvSelectionCount(const uint64_t& aID, int32_t* aCount)
      override;
 
-  virtual bool RecvTextSubstring(const uint64_t& aID,
-                                 const int32_t& aStartOffset,
-                                 const int32_t& aEndOffset, nsString* aText,
-                                 bool* aValid) override;
+  virtual mozilla::ipc::IPCResult RecvTextSubstring(const uint64_t& aID,
+                                                    const int32_t& aStartOffset,
+                                                    const int32_t& aEndOffset, nsString* aText,
+                                                    bool* aValid) override;
 
-  virtual bool RecvGetTextAfterOffset(const uint64_t& aID,
-                                      const int32_t& aOffset,
-                                      const int32_t& aBoundaryType,
-                                      nsString* aText, int32_t* aStartOffset,
-                                      int32_t* aEndOffset) override;
-  virtual bool RecvGetTextAtOffset(const uint64_t& aID,
-                                   const int32_t& aOffset,
-                                   const int32_t& aBoundaryType,
-                                   nsString* aText, int32_t* aStartOffset,
-                                   int32_t* aEndOffset) override;
-  virtual bool RecvGetTextBeforeOffset(const uint64_t& aID,
-                                       const int32_t& aOffset,
-                                       const int32_t& aBoundaryType,
-                                       nsString* aText, int32_t* aStartOffset,
-                                       int32_t* aEndOffset) override;
+  virtual mozilla::ipc::IPCResult RecvGetTextAfterOffset(const uint64_t& aID,
+                                                         const int32_t& aOffset,
+                                                         const int32_t& aBoundaryType,
+                                                         nsString* aText, int32_t* aStartOffset,
+                                                         int32_t* aEndOffset) override;
+  virtual mozilla::ipc::IPCResult RecvGetTextAtOffset(const uint64_t& aID,
+                                                      const int32_t& aOffset,
+                                                      const int32_t& aBoundaryType,
+                                                      nsString* aText, int32_t* aStartOffset,
+                                                      int32_t* aEndOffset) override;
+  virtual mozilla::ipc::IPCResult RecvGetTextBeforeOffset(const uint64_t& aID,
+                                                          const int32_t& aOffset,
+                                                          const int32_t& aBoundaryType,
+                                                          nsString* aText, int32_t* aStartOffset,
+                                                          int32_t* aEndOffset) override;
 
-  virtual bool RecvCharAt(const uint64_t& aID,
-                          const int32_t& aOffset,
-                          uint16_t* aChar) override;
+  virtual mozilla::ipc::IPCResult RecvCharAt(const uint64_t& aID,
+                                             const int32_t& aOffset,
+                                             uint16_t* aChar) override;
 
-  virtual bool RecvTextAttributes(const uint64_t& aID,
-                                  const bool& aIncludeDefAttrs,
-                                  const int32_t& aOffset,
-                                  nsTArray<Attribute>* aAttributes,
-                                  int32_t* aStartOffset,
-                                  int32_t* aEndOffset)
+  virtual mozilla::ipc::IPCResult RecvTextAttributes(const uint64_t& aID,
+                                                     const bool& aIncludeDefAttrs,
+                                                     const int32_t& aOffset,
+                                                     nsTArray<Attribute>* aAttributes,
+                                                     int32_t* aStartOffset,
+                                                     int32_t* aEndOffset)
     override;
 
-  virtual bool RecvDefaultTextAttributes(const uint64_t& aID,
-                                         nsTArray<Attribute>* aAttributes)
+  virtual mozilla::ipc::IPCResult RecvDefaultTextAttributes(const uint64_t& aID,
+                                                            nsTArray<Attribute>* aAttributes)
     override;
 
-  virtual bool RecvTextBounds(const uint64_t& aID,
-                              const int32_t& aStartOffset,
-                              const int32_t& aEndOffset,
-                              const uint32_t& aCoordType,
-                              nsIntRect* aRetVal) override;
+  virtual mozilla::ipc::IPCResult RecvTextBounds(const uint64_t& aID,
+                                                 const int32_t& aStartOffset,
+                                                 const int32_t& aEndOffset,
+                                                 const uint32_t& aCoordType,
+                                                 nsIntRect* aRetVal) override;
 
-  virtual bool RecvCharBounds(const uint64_t& aID,
-                              const int32_t& aOffset,
-                              const uint32_t& aCoordType,
-                              nsIntRect* aRetVal) override;
+  virtual mozilla::ipc::IPCResult RecvCharBounds(const uint64_t& aID,
+                                                 const int32_t& aOffset,
+                                                 const uint32_t& aCoordType,
+                                                 nsIntRect* aRetVal) override;
 
-  virtual bool RecvOffsetAtPoint(const uint64_t& aID,
-                                 const int32_t& aX,
-                                 const int32_t& aY,
-                                 const uint32_t& aCoordType,
-                                 int32_t* aRetVal) override;
+  virtual mozilla::ipc::IPCResult RecvOffsetAtPoint(const uint64_t& aID,
+                                                    const int32_t& aX,
+                                                    const int32_t& aY,
+                                                    const uint32_t& aCoordType,
+                                                    int32_t* aRetVal) override;
 
-  virtual bool RecvSelectionBoundsAt(const uint64_t& aID,
-                                     const int32_t& aSelectionNum,
-                                     bool* aSucceeded,
-                                     nsString* aData,
-                                     int32_t* aStartOffset,
-                                     int32_t* aEndOffset) override;
+  virtual mozilla::ipc::IPCResult RecvSelectionBoundsAt(const uint64_t& aID,
+                                                        const int32_t& aSelectionNum,
+                                                        bool* aSucceeded,
+                                                        nsString* aData,
+                                                        int32_t* aStartOffset,
+                                                        int32_t* aEndOffset) override;
 
-  virtual bool RecvSetSelectionBoundsAt(const uint64_t& aID,
-                                        const int32_t& aSelectionNum,
-                                        const int32_t& aStartOffset,
-                                        const int32_t& aEndOffset,
-                                        bool* aSucceeded) override;
+  virtual mozilla::ipc::IPCResult RecvSetSelectionBoundsAt(const uint64_t& aID,
+                                                           const int32_t& aSelectionNum,
+                                                           const int32_t& aStartOffset,
+                                                           const int32_t& aEndOffset,
+                                                           bool* aSucceeded) override;
 
-  virtual bool RecvAddToSelection(const uint64_t& aID,
-                                  const int32_t& aStartOffset,
-                                  const int32_t& aEndOffset,
-                                  bool* aSucceeded) override;
+  virtual mozilla::ipc::IPCResult RecvAddToSelection(const uint64_t& aID,
+                                                     const int32_t& aStartOffset,
+                                                     const int32_t& aEndOffset,
+                                                     bool* aSucceeded) override;
 
-  virtual bool RecvRemoveFromSelection(const uint64_t& aID,
-                                       const int32_t& aSelectionNum,
-                                       bool* aSucceeded) override;
+  virtual mozilla::ipc::IPCResult RecvRemoveFromSelection(const uint64_t& aID,
+                                                          const int32_t& aSelectionNum,
+                                                          bool* aSucceeded) override;
 
-  virtual bool RecvScrollSubstringTo(const uint64_t& aID,
-                                     const int32_t& aStartOffset,
-                                     const int32_t& aEndOffset,
-                                     const uint32_t& aScrollType) override;
+  virtual mozilla::ipc::IPCResult RecvScrollSubstringTo(const uint64_t& aID,
+                                                        const int32_t& aStartOffset,
+                                                        const int32_t& aEndOffset,
+                                                        const uint32_t& aScrollType) override;
 
-  virtual bool RecvScrollSubstringToPoint(const uint64_t& aID,
-                                          const int32_t& aStartOffset,
-                                          const int32_t& aEndOffset,
-                                          const uint32_t& aCoordinateType,
-                                          const int32_t& aX,
-                                          const int32_t& aY) override;
+  virtual mozilla::ipc::IPCResult RecvScrollSubstringToPoint(const uint64_t& aID,
+                                                             const int32_t& aStartOffset,
+                                                             const int32_t& aEndOffset,
+                                                             const uint32_t& aCoordinateType,
+                                                             const int32_t& aX,
+                                                             const int32_t& aY) override;
 
-  virtual bool RecvText(const uint64_t& aID,
-                        nsString* aText) override;
+  virtual mozilla::ipc::IPCResult RecvText(const uint64_t& aID,
+                                           nsString* aText) override;
 
-  virtual bool RecvReplaceText(const uint64_t& aID,
-                               const nsString& aText) override;
+  virtual mozilla::ipc::IPCResult RecvReplaceText(const uint64_t& aID,
+                                                  const nsString& aText) override;
 
-  virtual bool RecvInsertText(const uint64_t& aID,
-                              const nsString& aText,
-                              const int32_t& aPosition, bool* aValid) override;
+  virtual mozilla::ipc::IPCResult RecvInsertText(const uint64_t& aID,
+                                                 const nsString& aText,
+                                                 const int32_t& aPosition, bool* aValid) override;
 
-  virtual bool RecvCopyText(const uint64_t& aID,
-                            const int32_t& aStartPos,
-                            const int32_t& aEndPos, bool* aValid) override;
+  virtual mozilla::ipc::IPCResult RecvCopyText(const uint64_t& aID,
+                                               const int32_t& aStartPos,
+                                               const int32_t& aEndPos, bool* aValid) override;
 
-  virtual bool RecvCutText(const uint64_t& aID,
-                           const int32_t& aStartPos,
-                           const int32_t& aEndPos, bool* aValid) override;
+  virtual mozilla::ipc::IPCResult RecvCutText(const uint64_t& aID,
+                                              const int32_t& aStartPos,
+                                              const int32_t& aEndPos, bool* aValid) override;
 
-  virtual bool RecvDeleteText(const uint64_t& aID,
-                              const int32_t& aStartPos,
-                              const int32_t& aEndPos, bool* aValid) override;
+  virtual mozilla::ipc::IPCResult RecvDeleteText(const uint64_t& aID,
+                                                 const int32_t& aStartPos,
+                                                 const int32_t& aEndPos, bool* aValid) override;
 
-  virtual bool RecvPasteText(const uint64_t& aID,
-                             const int32_t& aPosition, bool* aValid) override;
+  virtual mozilla::ipc::IPCResult RecvPasteText(const uint64_t& aID,
+                                                const int32_t& aPosition, bool* aValid) override;
 
-  virtual bool RecvImagePosition(const uint64_t& aID,
-                                 const uint32_t& aCoordType,
-                                 nsIntPoint* aRetVal) override;
+  virtual mozilla::ipc::IPCResult RecvImagePosition(const uint64_t& aID,
+                                                    const uint32_t& aCoordType,
+                                                    nsIntPoint* aRetVal) override;
 
-  virtual bool RecvImageSize(const uint64_t& aID,
-                             nsIntSize* aRetVal) override;
+  virtual mozilla::ipc::IPCResult RecvImageSize(const uint64_t& aID,
+                                                nsIntSize* aRetVal) override;
 
-  virtual bool RecvStartOffset(const uint64_t& aID,
-                               uint32_t* aRetVal,
-                               bool* aOk) override;
-  virtual bool RecvEndOffset(const uint64_t& aID,
-                             uint32_t* aRetVal,
-                             bool* aOk) override;
-  virtual bool RecvIsLinkValid(const uint64_t& aID,
-                               bool* aRetVal) override;
-  virtual bool RecvAnchorCount(const uint64_t& aID,
-                               uint32_t* aRetVal, bool* aOk) override;
-  virtual bool RecvAnchorURIAt(const uint64_t& aID,
-                               const uint32_t& aIndex,
-                               nsCString* aURI,
-                               bool* aOk) override;
-  virtual bool RecvAnchorAt(const uint64_t& aID,
-                            const uint32_t& aIndex,
-                            uint64_t* aIDOfAnchor,
-                            bool* aOk) override;
+  virtual mozilla::ipc::IPCResult RecvStartOffset(const uint64_t& aID,
+                                                  uint32_t* aRetVal,
+                                                  bool* aOk) override;
+  virtual mozilla::ipc::IPCResult RecvEndOffset(const uint64_t& aID,
+                                                uint32_t* aRetVal,
+                                                bool* aOk) override;
+  virtual mozilla::ipc::IPCResult RecvIsLinkValid(const uint64_t& aID,
+                                                  bool* aRetVal) override;
+  virtual mozilla::ipc::IPCResult RecvAnchorCount(const uint64_t& aID,
+                                                  uint32_t* aRetVal, bool* aOk) override;
+  virtual mozilla::ipc::IPCResult RecvAnchorURIAt(const uint64_t& aID,
+                                                  const uint32_t& aIndex,
+                                                  nsCString* aURI,
+                                                  bool* aOk) override;
+  virtual mozilla::ipc::IPCResult RecvAnchorAt(const uint64_t& aID,
+                                               const uint32_t& aIndex,
+                                               uint64_t* aIDOfAnchor,
+                                               bool* aOk) override;
 
-  virtual bool RecvLinkCount(const uint64_t& aID,
-                             uint32_t* aCount) override;
+  virtual mozilla::ipc::IPCResult RecvLinkCount(const uint64_t& aID,
+                                                uint32_t* aCount) override;
 
-  virtual bool RecvLinkAt(const uint64_t& aID,
-                          const uint32_t& aIndex,
-                          uint64_t* aIDOfLink,
-                          bool* aOk) override;
+  virtual mozilla::ipc::IPCResult RecvLinkAt(const uint64_t& aID,
+                                             const uint32_t& aIndex,
+                                             uint64_t* aIDOfLink,
+                                             bool* aOk) override;
 
-  virtual bool RecvLinkIndexOf(const uint64_t& aID,
-                               const uint64_t& aLinkID,
-                               int32_t* aIndex) override;
+  virtual mozilla::ipc::IPCResult RecvLinkIndexOf(const uint64_t& aID,
+                                                  const uint64_t& aLinkID,
+                                                  int32_t* aIndex) override;
 
-  virtual bool RecvLinkIndexAtOffset(const uint64_t& aID,
-                                     const uint32_t& aOffset,
-                                     int32_t* aIndex) override;
+  virtual mozilla::ipc::IPCResult RecvLinkIndexAtOffset(const uint64_t& aID,
+                                                        const uint32_t& aOffset,
+                                                        int32_t* aIndex) override;
 
-  virtual bool RecvTableOfACell(const uint64_t& aID,
-                                uint64_t* aTableID,
-                                bool* aOk) override;
+  virtual mozilla::ipc::IPCResult RecvTableOfACell(const uint64_t& aID,
+                                                   uint64_t* aTableID,
+                                                   bool* aOk) override;
 
-  virtual bool RecvColIdx(const uint64_t& aID, uint32_t* aIndex) override;
+  virtual mozilla::ipc::IPCResult RecvColIdx(const uint64_t& aID, uint32_t* aIndex) override;
 
-  virtual bool RecvRowIdx(const uint64_t& aID, uint32_t* aIndex) override;
+  virtual mozilla::ipc::IPCResult RecvRowIdx(const uint64_t& aID, uint32_t* aIndex) override;
 
-  virtual bool RecvColExtent(const uint64_t& aID, uint32_t* aExtent) override;
+  virtual mozilla::ipc::IPCResult RecvColExtent(const uint64_t& aID, uint32_t* aExtent) override;
 
-  virtual bool RecvGetPosition(const uint64_t& aID,
-                               uint32_t* aColIdx, uint32_t* aRowIdx) override;
+  virtual mozilla::ipc::IPCResult RecvGetPosition(const uint64_t& aID,
+                                                  uint32_t* aColIdx, uint32_t* aRowIdx) override;
 
-  virtual bool RecvGetColRowExtents(const uint64_t& aID,
-                                  uint32_t* aColIdx, uint32_t* aRowIdx,
-                                  uint32_t* aColExtent, uint32_t* aRowExtent) override;
+  virtual mozilla::ipc::IPCResult RecvGetColRowExtents(const uint64_t& aID,
+                                                       uint32_t* aColIdx, uint32_t* aRowIdx,
+                                                       uint32_t* aColExtent, uint32_t* aRowExtent) override;
 
-  virtual bool RecvRowExtent(const uint64_t& aID, uint32_t* aExtent) override;
+  virtual mozilla::ipc::IPCResult RecvRowExtent(const uint64_t& aID, uint32_t* aExtent) override;
 
-  virtual bool RecvColHeaderCells(const uint64_t& aID,
-                                  nsTArray<uint64_t>* aCells) override;
+  virtual mozilla::ipc::IPCResult RecvColHeaderCells(const uint64_t& aID,
+                                                     nsTArray<uint64_t>* aCells) override;
 
-  virtual bool RecvRowHeaderCells(const uint64_t& aID,
-                                  nsTArray<uint64_t>* aCells) override;
+  virtual mozilla::ipc::IPCResult RecvRowHeaderCells(const uint64_t& aID,
+                                                     nsTArray<uint64_t>* aCells) override;
 
-  virtual bool RecvIsCellSelected(const uint64_t& aID,
-                                  bool* aSelected) override;
+  virtual mozilla::ipc::IPCResult RecvIsCellSelected(const uint64_t& aID,
+                                                     bool* aSelected) override;
 
-  virtual bool RecvTableCaption(const uint64_t& aID,
-                                uint64_t* aCaptionID,
-                                bool* aOk) override;
-  virtual bool RecvTableSummary(const uint64_t& aID,
-                                nsString* aSummary) override;
-  virtual bool RecvTableColumnCount(const uint64_t& aID,
-                                    uint32_t* aColCount) override;
-  virtual bool RecvTableRowCount(const uint64_t& aID,
-                                 uint32_t* aRowCount) override;
-  virtual bool RecvTableCellAt(const uint64_t& aID,
-                               const uint32_t& aRow,
-                               const uint32_t& aCol,
-                               uint64_t* aCellID,
-                               bool* aOk) override;
-  virtual bool RecvTableCellIndexAt(const uint64_t& aID,
-                                    const uint32_t& aRow,
-                                    const uint32_t& aCol,
-                                    int32_t* aIndex) override;
-  virtual bool RecvTableColumnIndexAt(const uint64_t& aID,
-                                      const uint32_t& aCellIndex,
-                                      int32_t* aCol) override;
-  virtual bool RecvTableRowIndexAt(const uint64_t& aID,
-                                   const uint32_t& aCellIndex,
-                                   int32_t* aRow) override;
-  virtual bool RecvTableRowAndColumnIndicesAt(const uint64_t& aID,
-                                             const uint32_t& aCellIndex,
-                                             int32_t* aRow,
-                                             int32_t* aCol) override;
-  virtual bool RecvTableColumnExtentAt(const uint64_t& aID,
-                                       const uint32_t& aRow,
-                                       const uint32_t& aCol,
-                                       uint32_t* aExtent) override;
-  virtual bool RecvTableRowExtentAt(const uint64_t& aID,
-                                    const uint32_t& aRow,
-                                    const uint32_t& aCol,
-                                    uint32_t* aExtent) override;
-  virtual bool RecvTableColumnDescription(const uint64_t& aID,
-                                          const uint32_t& aCol,
-                                          nsString* aDescription) override;
-  virtual bool RecvTableRowDescription(const uint64_t& aID,
-                                       const uint32_t& aRow,
-                                       nsString* aDescription) override;
-  virtual bool RecvTableColumnSelected(const uint64_t& aID,
-                                       const uint32_t& aCol,
-                                       bool* aSelected) override;
-  virtual bool RecvTableRowSelected(const uint64_t& aID,
-                                    const uint32_t& aRow,
-                                    bool* aSelected) override;
-  virtual bool RecvTableCellSelected(const uint64_t& aID,
-                                     const uint32_t& aRow,
-                                     const uint32_t& aCol,
-                                     bool* aSelected) override;
-  virtual bool RecvTableSelectedCellCount(const uint64_t& aID,
-                                          uint32_t* aSelectedCells) override;
-  virtual bool RecvTableSelectedColumnCount(const uint64_t& aID,
-                                            uint32_t* aSelectedColumns) override;
-  virtual bool RecvTableSelectedRowCount(const uint64_t& aID,
-                                         uint32_t* aSelectedRows) override;
-  virtual bool RecvTableSelectedCells(const uint64_t& aID,
-                                      nsTArray<uint64_t>* aCellIDs) override;
-  virtual bool RecvTableSelectedCellIndices(const uint64_t& aID,
-                                            nsTArray<uint32_t>* aCellIndices) override;
-  virtual bool RecvTableSelectedColumnIndices(const uint64_t& aID,
-                                              nsTArray<uint32_t>* aColumnIndices) override;
-  virtual bool RecvTableSelectedRowIndices(const uint64_t& aID,
-                                           nsTArray<uint32_t>* aRowIndices) override;
-  virtual bool RecvTableSelectColumn(const uint64_t& aID,
-                                     const uint32_t& aCol) override;
-  virtual bool RecvTableSelectRow(const uint64_t& aID,
-                                  const uint32_t& aRow) override;
-  virtual bool RecvTableUnselectColumn(const uint64_t& aID,
-                                       const uint32_t& aCol) override;
-  virtual bool RecvTableUnselectRow(const uint64_t& aID,
-                                    const uint32_t& aRow) override;
-  virtual bool RecvTableIsProbablyForLayout(const uint64_t& aID,
-                                            bool* aForLayout) override;
-  virtual bool RecvAtkTableColumnHeader(const uint64_t& aID,
-                                        const int32_t& aCol,
-                                        uint64_t* aHeader,
-                                        bool* aOk) override;
-  virtual bool RecvAtkTableRowHeader(const uint64_t& aID,
-                                     const int32_t& aRow,
-                                     uint64_t* aHeader,
-                                     bool* aOk) override;
+  virtual mozilla::ipc::IPCResult RecvTableCaption(const uint64_t& aID,
+                                                   uint64_t* aCaptionID,
+                                                   bool* aOk) override;
+  virtual mozilla::ipc::IPCResult RecvTableSummary(const uint64_t& aID,
+                                                   nsString* aSummary) override;
+  virtual mozilla::ipc::IPCResult RecvTableColumnCount(const uint64_t& aID,
+                                                       uint32_t* aColCount) override;
+  virtual mozilla::ipc::IPCResult RecvTableRowCount(const uint64_t& aID,
+                                                    uint32_t* aRowCount) override;
+  virtual mozilla::ipc::IPCResult RecvTableCellAt(const uint64_t& aID,
+                                                  const uint32_t& aRow,
+                                                  const uint32_t& aCol,
+                                                  uint64_t* aCellID,
+                                                  bool* aOk) override;
+  virtual mozilla::ipc::IPCResult RecvTableCellIndexAt(const uint64_t& aID,
+                                                       const uint32_t& aRow,
+                                                       const uint32_t& aCol,
+                                                       int32_t* aIndex) override;
+  virtual mozilla::ipc::IPCResult RecvTableColumnIndexAt(const uint64_t& aID,
+                                                         const uint32_t& aCellIndex,
+                                                         int32_t* aCol) override;
+  virtual mozilla::ipc::IPCResult RecvTableRowIndexAt(const uint64_t& aID,
+                                                      const uint32_t& aCellIndex,
+                                                      int32_t* aRow) override;
+  virtual mozilla::ipc::IPCResult RecvTableRowAndColumnIndicesAt(const uint64_t& aID,
+                                                                 const uint32_t& aCellIndex,
+                                                                 int32_t* aRow,
+                                                                 int32_t* aCol) override;
+  virtual mozilla::ipc::IPCResult RecvTableColumnExtentAt(const uint64_t& aID,
+                                                          const uint32_t& aRow,
+                                                          const uint32_t& aCol,
+                                                          uint32_t* aExtent) override;
+  virtual mozilla::ipc::IPCResult RecvTableRowExtentAt(const uint64_t& aID,
+                                                       const uint32_t& aRow,
+                                                       const uint32_t& aCol,
+                                                       uint32_t* aExtent) override;
+  virtual mozilla::ipc::IPCResult RecvTableColumnDescription(const uint64_t& aID,
+                                                             const uint32_t& aCol,
+                                                             nsString* aDescription) override;
+  virtual mozilla::ipc::IPCResult RecvTableRowDescription(const uint64_t& aID,
+                                                          const uint32_t& aRow,
+                                                          nsString* aDescription) override;
+  virtual mozilla::ipc::IPCResult RecvTableColumnSelected(const uint64_t& aID,
+                                                          const uint32_t& aCol,
+                                                          bool* aSelected) override;
+  virtual mozilla::ipc::IPCResult RecvTableRowSelected(const uint64_t& aID,
+                                                       const uint32_t& aRow,
+                                                       bool* aSelected) override;
+  virtual mozilla::ipc::IPCResult RecvTableCellSelected(const uint64_t& aID,
+                                                        const uint32_t& aRow,
+                                                        const uint32_t& aCol,
+                                                        bool* aSelected) override;
+  virtual mozilla::ipc::IPCResult RecvTableSelectedCellCount(const uint64_t& aID,
+                                                             uint32_t* aSelectedCells) override;
+  virtual mozilla::ipc::IPCResult RecvTableSelectedColumnCount(const uint64_t& aID,
+                                                               uint32_t* aSelectedColumns) override;
+  virtual mozilla::ipc::IPCResult RecvTableSelectedRowCount(const uint64_t& aID,
+                                                            uint32_t* aSelectedRows) override;
+  virtual mozilla::ipc::IPCResult RecvTableSelectedCells(const uint64_t& aID,
+                                                         nsTArray<uint64_t>* aCellIDs) override;
+  virtual mozilla::ipc::IPCResult RecvTableSelectedCellIndices(const uint64_t& aID,
+                                                               nsTArray<uint32_t>* aCellIndices) override;
+  virtual mozilla::ipc::IPCResult RecvTableSelectedColumnIndices(const uint64_t& aID,
+                                                                 nsTArray<uint32_t>* aColumnIndices) override;
+  virtual mozilla::ipc::IPCResult RecvTableSelectedRowIndices(const uint64_t& aID,
+                                                              nsTArray<uint32_t>* aRowIndices) override;
+  virtual mozilla::ipc::IPCResult RecvTableSelectColumn(const uint64_t& aID,
+                                                        const uint32_t& aCol) override;
+  virtual mozilla::ipc::IPCResult RecvTableSelectRow(const uint64_t& aID,
+                                                     const uint32_t& aRow) override;
+  virtual mozilla::ipc::IPCResult RecvTableUnselectColumn(const uint64_t& aID,
+                                                          const uint32_t& aCol) override;
+  virtual mozilla::ipc::IPCResult RecvTableUnselectRow(const uint64_t& aID,
+                                                       const uint32_t& aRow) override;
+  virtual mozilla::ipc::IPCResult RecvTableIsProbablyForLayout(const uint64_t& aID,
+                                                               bool* aForLayout) override;
+  virtual mozilla::ipc::IPCResult RecvAtkTableColumnHeader(const uint64_t& aID,
+                                                           const int32_t& aCol,
+                                                           uint64_t* aHeader,
+                                                           bool* aOk) override;
+  virtual mozilla::ipc::IPCResult RecvAtkTableRowHeader(const uint64_t& aID,
+                                                        const int32_t& aRow,
+                                                        uint64_t* aHeader,
+                                                        bool* aOk) override;
 
-  virtual bool RecvSelectedItems(const uint64_t& aID,
-                                 nsTArray<uint64_t>* aSelectedItemIDs) override;
+  virtual mozilla::ipc::IPCResult RecvSelectedItems(const uint64_t& aID,
+                                                    nsTArray<uint64_t>* aSelectedItemIDs) override;
 
-  virtual bool RecvSelectedItemCount(const uint64_t& aID,
-                                     uint32_t* aCount) override;
+  virtual mozilla::ipc::IPCResult RecvSelectedItemCount(const uint64_t& aID,
+                                                        uint32_t* aCount) override;
 
-  virtual bool RecvGetSelectedItem(const uint64_t& aID,
-                                   const uint32_t& aIndex,
-                                   uint64_t* aSelected,
-                                   bool* aOk) override;
+  virtual mozilla::ipc::IPCResult RecvGetSelectedItem(const uint64_t& aID,
+                                                      const uint32_t& aIndex,
+                                                      uint64_t* aSelected,
+                                                      bool* aOk) override;
 
-  virtual bool RecvIsItemSelected(const uint64_t& aID,
-                                  const uint32_t& aIndex,
-                                  bool* aSelected) override;
+  virtual mozilla::ipc::IPCResult RecvIsItemSelected(const uint64_t& aID,
+                                                     const uint32_t& aIndex,
+                                                     bool* aSelected) override;
 
-  virtual bool RecvAddItemToSelection(const uint64_t& aID,
-                                      const uint32_t& aIndex,
-                                      bool* aSuccess) override;
+  virtual mozilla::ipc::IPCResult RecvAddItemToSelection(const uint64_t& aID,
+                                                         const uint32_t& aIndex,
+                                                         bool* aSuccess) override;
 
-  virtual bool RecvRemoveItemFromSelection(const uint64_t& aID,
-                                           const uint32_t& aIndex,
-                                           bool* aSuccess) override;
+  virtual mozilla::ipc::IPCResult RecvRemoveItemFromSelection(const uint64_t& aID,
+                                                              const uint32_t& aIndex,
+                                                              bool* aSuccess) override;
 
-  virtual bool RecvSelectAll(const uint64_t& aID,
-                             bool* aSuccess) override;
+  virtual mozilla::ipc::IPCResult RecvSelectAll(const uint64_t& aID,
+                                                bool* aSuccess) override;
 
-  virtual bool RecvUnselectAll(const uint64_t& aID,
-                               bool* aSuccess) override;
+  virtual mozilla::ipc::IPCResult RecvUnselectAll(const uint64_t& aID,
+                                                  bool* aSuccess) override;
 
-  virtual bool RecvTakeSelection(const uint64_t& aID) override;
-  virtual bool RecvSetSelected(const uint64_t& aID,
-                               const bool& aSelect) override;
+  virtual mozilla::ipc::IPCResult RecvTakeSelection(const uint64_t& aID) override;
+  virtual mozilla::ipc::IPCResult RecvSetSelected(const uint64_t& aID,
+                                                  const bool& aSelect) override;
 
-  virtual bool RecvDoAction(const uint64_t& aID,
-                            const uint8_t& aIndex,
-                            bool* aSuccess) override;
+  virtual mozilla::ipc::IPCResult RecvDoAction(const uint64_t& aID,
+                                               const uint8_t& aIndex,
+                                               bool* aSuccess) override;
 
-  virtual bool RecvActionCount(const uint64_t& aID,
-                               uint8_t* aCount) override;
+  virtual mozilla::ipc::IPCResult RecvActionCount(const uint64_t& aID,
+                                                  uint8_t* aCount) override;
 
-  virtual bool RecvActionDescriptionAt(const uint64_t& aID,
-                                       const uint8_t& aIndex,
-                                       nsString* aDescription) override;
+  virtual mozilla::ipc::IPCResult RecvActionDescriptionAt(const uint64_t& aID,
+                                                          const uint8_t& aIndex,
+                                                          nsString* aDescription) override;
 
-  virtual bool RecvActionNameAt(const uint64_t& aID,
-                                const uint8_t& aIndex,
-                                nsString* aName) override;
+  virtual mozilla::ipc::IPCResult RecvActionNameAt(const uint64_t& aID,
+                                                   const uint8_t& aIndex,
+                                                   nsString* aName) override;
 
-  virtual bool RecvAccessKey(const uint64_t& aID,
-                             uint32_t* aKey,
-                             uint32_t* aModifierMask) override;
+  virtual mozilla::ipc::IPCResult RecvAccessKey(const uint64_t& aID,
+                                                uint32_t* aKey,
+                                                uint32_t* aModifierMask) override;
 
-  virtual bool RecvKeyboardShortcut(const uint64_t& aID,
-                                    uint32_t* aKey,
-                                    uint32_t* aModifierMask) override;
+  virtual mozilla::ipc::IPCResult RecvKeyboardShortcut(const uint64_t& aID,
+                                                       uint32_t* aKey,
+                                                       uint32_t* aModifierMask) override;
 
-  virtual bool RecvAtkKeyBinding(const uint64_t& aID,
-                                 nsString* aResult) override;
+  virtual mozilla::ipc::IPCResult RecvAtkKeyBinding(const uint64_t& aID,
+                                                    nsString* aResult) override;
 
-  virtual bool RecvCurValue(const uint64_t& aID,
-                            double* aValue) override;
+  virtual mozilla::ipc::IPCResult RecvCurValue(const uint64_t& aID,
+                                               double* aValue) override;
 
-  virtual bool RecvSetCurValue(const uint64_t& aID,
-                               const double& aValue,
-                               bool* aRetVal) override;
+  virtual mozilla::ipc::IPCResult RecvSetCurValue(const uint64_t& aID,
+                                                  const double& aValue,
+                                                  bool* aRetVal) override;
 
-  virtual bool RecvMinValue(const uint64_t& aID,
-                            double* aValue) override;
+  virtual mozilla::ipc::IPCResult RecvMinValue(const uint64_t& aID,
+                                               double* aValue) override;
 
-  virtual bool RecvMaxValue(const uint64_t& aID,
-                            double* aValue) override;
+  virtual mozilla::ipc::IPCResult RecvMaxValue(const uint64_t& aID,
+                                               double* aValue) override;
 
-  virtual bool RecvStep(const uint64_t& aID,
-                        double* aStep) override;
+  virtual mozilla::ipc::IPCResult RecvStep(const uint64_t& aID,
+                                           double* aStep) override;
 
-  virtual bool RecvTakeFocus(const uint64_t& aID) override;
+  virtual mozilla::ipc::IPCResult RecvTakeFocus(const uint64_t& aID) override;
 
-  virtual bool RecvFocusedChild(const uint64_t& aID,
-                                uint64_t* aChild,
-                                bool* aOk) override;
+  virtual mozilla::ipc::IPCResult RecvFocusedChild(const uint64_t& aID,
+                                                   uint64_t* aChild,
+                                                   bool* aOk) override;
 
-  virtual bool RecvLanguage(const uint64_t& aID, nsString* aLocale) override;
-  virtual bool RecvDocType(const uint64_t& aID, nsString* aType) override;
-  virtual bool RecvTitle(const uint64_t& aID, nsString* aTitle) override;
-  virtual bool RecvURL(const uint64_t& aID, nsString* aURL) override;
-  virtual bool RecvMimeType(const uint64_t& aID, nsString* aMime) override;
-  virtual bool RecvURLDocTypeMimeType(const uint64_t& aID,
-                                      nsString* aURL,
-                                      nsString* aDocType,
-                                      nsString* aMimeType) override;
+  virtual mozilla::ipc::IPCResult RecvLanguage(const uint64_t& aID, nsString* aLocale) override;
+  virtual mozilla::ipc::IPCResult RecvDocType(const uint64_t& aID, nsString* aType) override;
+  virtual mozilla::ipc::IPCResult RecvTitle(const uint64_t& aID, nsString* aTitle) override;
+  virtual mozilla::ipc::IPCResult RecvURL(const uint64_t& aID, nsString* aURL) override;
+  virtual mozilla::ipc::IPCResult RecvMimeType(const uint64_t& aID, nsString* aMime) override;
+  virtual mozilla::ipc::IPCResult RecvURLDocTypeMimeType(const uint64_t& aID,
+                                                         nsString* aURL,
+                                                         nsString* aDocType,
+                                                         nsString* aMimeType) override;
 
-  virtual bool RecvAccessibleAtPoint(const uint64_t& aID,
-                                     const int32_t& aX,
-                                     const int32_t& aY,
-                                     const bool& aNeedsScreenCoords,
-                                     const uint32_t& aWhich,
-                                     uint64_t* aResult,
-                                     bool* aOk) override;
+  virtual mozilla::ipc::IPCResult RecvAccessibleAtPoint(const uint64_t& aID,
+                                                        const int32_t& aX,
+                                                        const int32_t& aY,
+                                                        const bool& aNeedsScreenCoords,
+                                                        const uint32_t& aWhich,
+                                                        uint64_t* aResult,
+                                                        bool* aOk) override;
 
-  virtual bool RecvExtents(const uint64_t& aID,
-                           const bool& aNeedsScreenCoords,
-                           int32_t* aX,
-                           int32_t* aY,
-                           int32_t* aWidth,
-                           int32_t* aHeight) override;
-  virtual bool RecvDOMNodeID(const uint64_t& aID, nsString* aDOMNodeID) override;
+  virtual mozilla::ipc::IPCResult RecvExtents(const uint64_t& aID,
+                                              const bool& aNeedsScreenCoords,
+                                              int32_t* aX,
+                                              int32_t* aY,
+                                              int32_t* aWidth,
+                                              int32_t* aHeight) override;
+  virtual mozilla::ipc::IPCResult RecvDOMNodeID(const uint64_t& aID, nsString* aDOMNodeID) override;
 private:
 
   Accessible* IdToAccessible(const uint64_t& aID) const;
   Accessible* IdToAccessibleLink(const uint64_t& aID) const;
   Accessible* IdToAccessibleSelect(const uint64_t& aID) const;
   HyperTextAccessible* IdToHyperTextAccessible(const uint64_t& aID) const;
   TextLeafAccessible* IdToTextLeafAccessible(const uint64_t& aID) const;
   ImageAccessible* IdToImageAccessible(const uint64_t& aID) const;
--- a/accessible/ipc/win/DocAccessibleChild.cpp
+++ b/accessible/ipc/win/DocAccessibleChild.cpp
@@ -4,41 +4,249 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DocAccessibleChild.h"
 
 #include "Accessible-inl.h"
 #include "mozilla/a11y/PlatformChild.h"
 #include "mozilla/ClearOnShutdown.h"
+#include "RootAccessible.h"
 
 namespace mozilla {
 namespace a11y {
 
 static StaticAutoPtr<PlatformChild> sPlatformChild;
 
 DocAccessibleChild::DocAccessibleChild(DocAccessible* aDoc)
   : DocAccessibleChildBase(aDoc)
+  , mEmulatedWindowHandle(nullptr)
+  , mIsRemoteConstructed(false)
 {
   MOZ_COUNT_CTOR_INHERITED(DocAccessibleChild, DocAccessibleChildBase);
   if (!sPlatformChild) {
     sPlatformChild = new PlatformChild();
     ClearOnShutdown(&sPlatformChild, ShutdownPhase::Shutdown);
   }
 }
 
 DocAccessibleChild::~DocAccessibleChild()
 {
   MOZ_COUNT_DTOR_INHERITED(DocAccessibleChild, DocAccessibleChildBase);
 }
 
 void
-DocAccessibleChild::SendCOMProxy(const IAccessibleHolder& aProxy)
+DocAccessibleChild::Shutdown()
+{
+  if (IsConstructedInParentProcess()) {
+    DocAccessibleChildBase::Shutdown();
+    return;
+  }
+
+  PushDeferredEvent(MakeUnique<SerializedShutdown>(this));
+  DetachDocument();
+}
+
+ipc::IPCResult
+DocAccessibleChild::RecvParentCOMProxy(const IAccessibleHolder& aParentCOMProxy)
+{
+  MOZ_ASSERT(!mParentProxy && !aParentCOMProxy.IsNull());
+  mParentProxy.reset(const_cast<IAccessibleHolder&>(aParentCOMProxy).Release());
+  SetConstructedInParentProcess();
+
+  for (uint32_t i = 0, l = mDeferredEvents.Length(); i < l; ++i) {
+    mDeferredEvents[i]->Dispatch();
+  }
+
+  mDeferredEvents.Clear();
+
+  return IPC_OK();
+}
+
+ipc::IPCResult
+DocAccessibleChild::RecvEmulatedWindow(const WindowsHandle& aEmulatedWindowHandle,
+                                       const IAccessibleHolder& aEmulatedWindowCOMProxy)
+{
+  mEmulatedWindowHandle = reinterpret_cast<HWND>(aEmulatedWindowHandle);
+  if (!aEmulatedWindowCOMProxy.IsNull()) {
+    MOZ_ASSERT(!mEmulatedWindowProxy);
+    mEmulatedWindowProxy.reset(
+      const_cast<IAccessibleHolder&>(aEmulatedWindowCOMProxy).Release());
+  }
+
+  return IPC_OK();
+}
+
+void
+DocAccessibleChild::PushDeferredEvent(UniquePtr<DeferredEvent> aEvent)
+{
+  DocAccessibleChild* topLevelIPCDoc = nullptr;
+
+  if (mDoc && mDoc->IsRoot()) {
+    topLevelIPCDoc = this;
+  } else {
+    auto tabChild = static_cast<dom::TabChild*>(Manager());
+    if (!tabChild) {
+      return;
+    }
+
+    nsTArray<PDocAccessibleChild*> ipcDocAccs;
+    tabChild->ManagedPDocAccessibleChild(ipcDocAccs);
+
+    // Look for the top-level DocAccessibleChild - there will only be one
+    // per TabChild.
+    for (uint32_t i = 0, l = ipcDocAccs.Length(); i < l; ++i) {
+      auto ipcDocAcc = static_cast<DocAccessibleChild*>(ipcDocAccs[i]);
+      if (ipcDocAcc->mDoc && ipcDocAcc->mDoc->IsRoot()) {
+        topLevelIPCDoc = ipcDocAcc;
+        break;
+      }
+    }
+  }
+
+  if (topLevelIPCDoc) {
+    topLevelIPCDoc->mDeferredEvents.AppendElement(Move(aEvent));
+  }
+}
+
+bool
+DocAccessibleChild::SendEvent(const uint64_t& aID, const uint32_t& aType)
+{
+  if (IsConstructedInParentProcess()) {
+    return PDocAccessibleChild::SendEvent(aID, aType);
+  }
+
+  PushDeferredEvent(MakeUnique<SerializedEvent>(this, aID, aType));
+  return false;
+}
+
+void
+DocAccessibleChild::MaybeSendShowEvent(ShowEventData& aData, bool aFromUser)
+{
+  if (IsConstructedInParentProcess()) {
+    Unused << SendShowEvent(aData, aFromUser);
+    return;
+  }
+
+  PushDeferredEvent(MakeUnique<SerializedShow>(this, aData, aFromUser));
+}
+
+bool
+DocAccessibleChild::SendHideEvent(const uint64_t& aRootID,
+                                  const bool& aFromUser)
 {
-  int32_t msaaID = AccessibleWrap::GetChildIDFor(mDoc);
-  IAccessibleHolder parentProxy;
-  PDocAccessibleChild::SendCOMProxy(msaaID, aProxy, &parentProxy);
-  mParentProxy.reset(parentProxy.Release());
+  if (IsConstructedInParentProcess()) {
+    return PDocAccessibleChild::SendHideEvent(aRootID, aFromUser);
+  }
+
+  PushDeferredEvent(MakeUnique<SerializedHide>(this, aRootID, aFromUser));
+  return true;
+}
+
+bool
+DocAccessibleChild::SendStateChangeEvent(const uint64_t& aID,
+                                         const uint64_t& aState,
+                                         const bool& aEnabled)
+{
+  if (IsConstructedInParentProcess()) {
+    return PDocAccessibleChild::SendStateChangeEvent(aID, aState, aEnabled);
+  }
+
+  PushDeferredEvent(MakeUnique<SerializedStateChange>(this, aID, aState,
+                                                      aEnabled));
+  return true;
+}
+
+bool
+DocAccessibleChild::SendCaretMoveEvent(const uint64_t& aID,
+                                       const int32_t& aOffset)
+{
+  if (IsConstructedInParentProcess()) {
+    return PDocAccessibleChild::SendCaretMoveEvent(aID, aOffset);
+  }
+
+  PushDeferredEvent(MakeUnique<SerializedCaretMove>(this, aID, aOffset));
+  return true;
+}
+
+bool
+DocAccessibleChild::SendTextChangeEvent(const uint64_t& aID,
+                                        const nsString& aStr,
+                                        const int32_t& aStart,
+                                        const uint32_t& aLen,
+                                        const bool& aIsInsert,
+                                        const bool& aFromUser)
+{
+  if (IsConstructedInParentProcess()) {
+    return PDocAccessibleChild::SendTextChangeEvent(aID, aStr, aStart,
+                                                    aLen, aIsInsert, aFromUser);
+  }
+
+  PushDeferredEvent(MakeUnique<SerializedTextChange>(this, aID, aStr, aStart,
+                                                     aLen, aIsInsert, aFromUser));
+  return true;
+}
+
+bool
+DocAccessibleChild::SendSelectionEvent(const uint64_t& aID,
+                                       const uint64_t& aWidgetID,
+                                       const uint32_t& aType)
+{
+  if (IsConstructedInParentProcess()) {
+    return PDocAccessibleChild::SendSelectionEvent(aID, aWidgetID, aType);
+  }
+
+  PushDeferredEvent(MakeUnique<SerializedSelection>(this, aID,
+                                                                aWidgetID,
+                                                                aType));
+  return true;
+}
+
+bool
+DocAccessibleChild::SendRoleChangedEvent(const uint32_t& aRole)
+{
+  if (IsConstructedInParentProcess()) {
+    return PDocAccessibleChild::SendRoleChangedEvent(aRole);
+  }
+
+  PushDeferredEvent(MakeUnique<SerializedRoleChanged>(this, aRole));
+  return true;
+}
+
+bool
+DocAccessibleChild::ConstructChildDocInParentProcess(
+                                        DocAccessibleChild* aNewChildDoc,
+                                        uint64_t aUniqueID, uint32_t aMsaaID)
+{
+  if (IsConstructedInParentProcess()) {
+    // We may send the constructor immediately
+    auto tabChild = static_cast<dom::TabChild*>(Manager());
+    MOZ_ASSERT(tabChild);
+    bool result = tabChild->SendPDocAccessibleConstructor(aNewChildDoc, this,
+                                                          aUniqueID, aMsaaID,
+                                                          IAccessibleHolder());
+    if (result) {
+      aNewChildDoc->SetConstructedInParentProcess();
+    }
+    return result;
+  }
+
+  PushDeferredEvent(MakeUnique<SerializedChildDocConstructor>(aNewChildDoc, this,
+                                                              aUniqueID, aMsaaID));
+  return true;
+}
+
+bool
+DocAccessibleChild::SendBindChildDoc(DocAccessibleChild* aChildDoc,
+                                     const uint64_t& aNewParentID)
+{
+  if (IsConstructedInParentProcess()) {
+    return DocAccessibleChildBase::SendBindChildDoc(aChildDoc, aNewParentID);
+  }
+
+  PushDeferredEvent(MakeUnique<SerializedBindChildDoc>(this, aChildDoc,
+                                                       aNewParentID));
+  return true;
 }
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/ipc/win/DocAccessibleChild.h
+++ b/accessible/ipc/win/DocAccessibleChild.h
@@ -4,34 +4,323 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_a11y_DocAccessibleChild_h
 #define mozilla_a11y_DocAccessibleChild_h
 
 #include "mozilla/a11y/COMPtrTypes.h"
 #include "mozilla/a11y/DocAccessibleChildBase.h"
+#include "mozilla/dom/TabChild.h"
 #include "mozilla/mscom/Ptr.h"
 
 namespace mozilla {
 namespace a11y {
 
 /*
  * These objects handle content side communication for an accessible document,
  * and their lifetime is the same as the document they represent.
  */
 class DocAccessibleChild : public DocAccessibleChildBase
 {
 public:
   explicit DocAccessibleChild(DocAccessible* aDoc);
   ~DocAccessibleChild();
 
-  void SendCOMProxy(const IAccessibleHolder& aProxy);
+  virtual void Shutdown() override;
+
+  virtual ipc::IPCResult
+  RecvParentCOMProxy(const IAccessibleHolder& aParentCOMProxy) override;
+  virtual ipc::IPCResult
+    RecvEmulatedWindow(const WindowsHandle& aEmulatedWindowHandle,
+                       const IAccessibleHolder& aEmulatedWindowCOMProxy) override;
+
+  HWND GetEmulatedWindowHandle() const { return mEmulatedWindowHandle; }
+  IAccessible* GetEmulatedWindowIAccessible() const { return mEmulatedWindowProxy.get(); }
+
   IAccessible* GetParentIAccessible() const { return mParentProxy.get(); }
 
+  bool SendEvent(const uint64_t& aID, const uint32_t& type);
+  bool SendHideEvent(const uint64_t& aRootID, const bool& aFromUser);
+  bool SendStateChangeEvent(const uint64_t& aID, const uint64_t& aState,
+                            const bool& aEnabled);
+  bool SendCaretMoveEvent(const uint64_t& aID, const int32_t& aOffset);
+  bool SendTextChangeEvent(const uint64_t& aID, const nsString& aStr,
+                           const int32_t& aStart, const uint32_t& aLen,
+                           const bool& aIsInsert, const bool& aFromUser);
+  bool SendSelectionEvent(const uint64_t& aID, const uint64_t& aWidgetID,
+                          const uint32_t& aType);
+  bool SendRoleChangedEvent(const uint32_t& aRole);
+
+  bool ConstructChildDocInParentProcess(DocAccessibleChild* aNewChildDoc,
+                                        uint64_t aUniqueID, uint32_t aMsaaID);
+
+  bool SendBindChildDoc(DocAccessibleChild* aChildDoc,
+                        const uint64_t& aNewParentID);
+
+protected:
+  virtual void MaybeSendShowEvent(ShowEventData& aData, bool aFromUser) override;
+
 private:
+  void RemoveDeferredConstructor();
+
+  bool IsConstructedInParentProcess() const { return mIsRemoteConstructed; }
+  void SetConstructedInParentProcess() { mIsRemoteConstructed = true; }
+
+  /**
+   * DocAccessibleChild should not fire events until it has asynchronously
+   * received the COM proxy for its parent. OTOH, content a11y may still be
+   * attempting to fire events during this window of time. If this object does
+   * not yet have its parent proxy, instead of immediately sending the events to
+   * our parent, we enqueue them to mDeferredEvents. As soon as
+   * RecvParentCOMProxy is called, we play back mDeferredEvents.
+   */
+  struct DeferredEvent
+  {
+    void Dispatch()
+    {
+      Dispatch(mTarget);
+    }
+
+    virtual ~DeferredEvent() {}
+
+  protected:
+    explicit DeferredEvent(DocAccessibleChild* aTarget)
+      : mTarget(aTarget)
+    {}
+
+    virtual void Dispatch(DocAccessibleChild* aIPCDoc) = 0;
+
+  private:
+    DocAccessibleChild* mTarget;
+  };
+
+  void PushDeferredEvent(UniquePtr<DeferredEvent> aEvent);
+
+  struct SerializedShow final : public DeferredEvent
+  {
+    SerializedShow(DocAccessibleChild* aTarget,
+                   ShowEventData& aEventData, bool aFromUser)
+      : DeferredEvent(aTarget)
+      , mEventData(aEventData.ID(), aEventData.Idx(), nsTArray<AccessibleData>())
+      , mFromUser(aFromUser)
+    {
+      // Since IPDL doesn't generate a move constructor for ShowEventData,
+      // we move NewTree manually (ugh). We still construct with an empty
+      // NewTree above so that the compiler catches any changes made to the
+      // ShowEventData structure in IPDL.
+      mEventData.NewTree() = Move(aEventData.NewTree());
+    }
+
+    void Dispatch(DocAccessibleChild* aIPCDoc) override
+    {
+      Unused << aIPCDoc->SendShowEvent(mEventData, mFromUser);
+    }
+
+    ShowEventData mEventData;
+    bool          mFromUser;
+  };
+
+  struct SerializedHide final : public DeferredEvent
+  {
+    SerializedHide(DocAccessibleChild* aTarget, uint64_t aRootID, bool aFromUser)
+      : DeferredEvent(aTarget)
+      , mRootID(aRootID)
+      , mFromUser(aFromUser)
+    {}
+
+    void Dispatch(DocAccessibleChild* aIPCDoc) override
+    {
+      Unused << aIPCDoc->SendHideEvent(mRootID, mFromUser);
+    }
+
+    uint64_t  mRootID;
+    bool      mFromUser;
+  };
+
+  struct SerializedStateChange final : public DeferredEvent
+  {
+    SerializedStateChange(DocAccessibleChild* aTarget, uint64_t aID,
+                          uint64_t aState, bool aEnabled)
+      : DeferredEvent(aTarget)
+      , mID(aID)
+      , mState(aState)
+      , mEnabled(aEnabled)
+    {}
+
+    void Dispatch(DocAccessibleChild* aIPCDoc) override
+    {
+      Unused << aIPCDoc->SendStateChangeEvent(mID, mState, mEnabled);
+    }
+
+    uint64_t  mID;
+    uint64_t  mState;
+    bool      mEnabled;
+  };
+
+  struct SerializedCaretMove final : public DeferredEvent
+  {
+    SerializedCaretMove(DocAccessibleChild* aTarget, uint64_t aID,
+                        int32_t aOffset)
+      : DeferredEvent(aTarget)
+      , mID(aID)
+      , mOffset(aOffset)
+    {}
+
+    void Dispatch(DocAccessibleChild* aIPCDoc) override
+    {
+      Unused << aIPCDoc->SendCaretMoveEvent(mID, mOffset);
+    }
+
+    uint64_t  mID;
+    int32_t   mOffset;
+  };
+
+  struct SerializedTextChange final : public DeferredEvent
+  {
+    SerializedTextChange(DocAccessibleChild* aTarget, uint64_t aID,
+                         const nsString& aStr, int32_t aStart, uint32_t aLen,
+                         bool aIsInsert, bool aFromUser)
+      : DeferredEvent(aTarget)
+      , mID(aID)
+      , mStr(aStr)
+      , mStart(aStart)
+      , mLen(aLen)
+      , mIsInsert(aIsInsert)
+      , mFromUser(aFromUser)
+    {}
+
+    void Dispatch(DocAccessibleChild* aIPCDoc) override
+    {
+      Unused << aIPCDoc->SendTextChangeEvent(mID, mStr, mStart, mLen, mIsInsert,
+                                             mFromUser);
+    }
+
+    uint64_t  mID;
+    nsString  mStr;
+    int32_t   mStart;
+    uint32_t  mLen;
+    bool      mIsInsert;
+    bool      mFromUser;
+  };
+
+  struct SerializedSelection final : public DeferredEvent
+  {
+    SerializedSelection(DocAccessibleChild* aTarget, uint64_t aID,
+                        uint64_t aWidgetID, uint32_t aType)
+      : DeferredEvent(aTarget)
+      , mID(aID)
+      , mWidgetID(aWidgetID)
+      , mType(aType)
+    {}
+
+    void Dispatch(DocAccessibleChild* aIPCDoc) override
+    {
+      Unused << aIPCDoc->SendSelectionEvent(mID, mWidgetID, mType);
+    }
+
+    uint64_t  mID;
+    uint64_t  mWidgetID;
+    uint32_t  mType;
+  };
+
+  struct SerializedRoleChanged final : public DeferredEvent
+  {
+    explicit SerializedRoleChanged(DocAccessibleChild* aTarget, uint32_t aRole)
+      : DeferredEvent(aTarget)
+      , mRole(aRole)
+    {}
+
+    void Dispatch(DocAccessibleChild* aIPCDoc) override
+    {
+      Unused << aIPCDoc->SendRoleChangedEvent(mRole);
+    }
+
+    uint32_t mRole;
+  };
+
+  struct SerializedEvent final : public DeferredEvent
+  {
+    SerializedEvent(DocAccessibleChild* aTarget, uint64_t aID, uint32_t aType)
+      : DeferredEvent(aTarget)
+      , mID(aID)
+      , mType(aType)
+    {}
+
+    void Dispatch(DocAccessibleChild* aIPCDoc) override
+    {
+      Unused << aIPCDoc->SendEvent(mID, mType);
+    }
+
+    uint64_t  mID;
+    uint32_t  mType;
+  };
+
+  struct SerializedChildDocConstructor final : public DeferredEvent
+  {
+    SerializedChildDocConstructor(DocAccessibleChild* aIPCDoc,
+                                  DocAccessibleChild* aParentIPCDoc,
+                                  uint64_t aUniqueID, uint32_t aMsaaID)
+      : DeferredEvent(aParentIPCDoc)
+      , mIPCDoc(aIPCDoc)
+      , mUniqueID(aUniqueID)
+      , mMsaaID(aMsaaID)
+    {}
+
+    void Dispatch(DocAccessibleChild* aParentIPCDoc) override
+    {
+      auto tabChild = static_cast<dom::TabChild*>(aParentIPCDoc->Manager());
+      MOZ_ASSERT(tabChild);
+      Unused << tabChild->SendPDocAccessibleConstructor(mIPCDoc, aParentIPCDoc,
+                                                        mUniqueID, mMsaaID,
+                                                        IAccessibleHolder());
+      mIPCDoc->SetConstructedInParentProcess();
+    }
+
+    DocAccessibleChild* mIPCDoc;
+    uint64_t            mUniqueID;
+    uint32_t            mMsaaID;
+  };
+
+  friend struct SerializedChildDocConstructor;
+
+  struct SerializedBindChildDoc final : public DeferredEvent
+  {
+    SerializedBindChildDoc(DocAccessibleChild* aParentDoc,
+                           DocAccessibleChild* aChildDoc, uint64_t aNewParentID)
+      : DeferredEvent(aParentDoc)
+      , mChildDoc(aChildDoc)
+      , mNewParentID(aNewParentID)
+    {}
+
+    void Dispatch(DocAccessibleChild* aParentIPCDoc) override
+    {
+      Unused << aParentIPCDoc->SendBindChildDoc(mChildDoc, mNewParentID);
+    }
+
+    DocAccessibleChild* mChildDoc;
+    uint64_t            mNewParentID;
+  };
+
+  struct SerializedShutdown final : public DeferredEvent
+  {
+    explicit SerializedShutdown(DocAccessibleChild* aTarget)
+      : DeferredEvent(aTarget)
+    {
+    }
+
+    void Dispatch(DocAccessibleChild* aIPCDoc) override
+    {
+      aIPCDoc->Shutdown();
+    }
+  };
+
+  bool mIsRemoteConstructed;
   mscom::ProxyUniquePtr<IAccessible> mParentProxy;
+  mscom::ProxyUniquePtr<IAccessible> mEmulatedWindowProxy;
+  nsTArray<UniquePtr<DeferredEvent>> mDeferredEvents;
+  HWND mEmulatedWindowHandle;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif // mozilla_a11y_DocAccessibleChild_h
--- a/accessible/ipc/win/PDocAccessible.ipdl
+++ b/accessible/ipc/win/PDocAccessible.ipdl
@@ -2,17 +2,18 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PFileDescriptorSet;
 include protocol PBrowser;
 
-using mozilla::a11y::IAccessibleHolder from "mozilla/a11y/COMPtrTypes.h";
+using mozilla::a11y::IAccessibleHolder from "mozilla/a11y/IPCTypes.h";
+using mozilla::WindowsHandle from "ipc/IPCMessageUtils.h";
 
 namespace mozilla {
 namespace a11y {
 
 struct AccessibleData
 {
   uint64_t ID;
   int32_t MsaaID;
@@ -56,21 +57,21 @@ parent:
   async RoleChangedEvent(uint32_t aRole);
 
   /*
    * Tell the parent document to bind the existing document as a new child
    * document.
    */
   async BindChildDoc(PDocAccessible aChildDoc, uint64_t aID);
 
-  // For now we'll add the command to send the proxy here. This might move to
-  // PDocAccessible constructor in PBrowser.
-  sync COMProxy(int32_t aMsaaID, IAccessibleHolder aDocCOMProxy)
-    returns(IAccessibleHolder aParentCOMProxy);
-
-  async MsaaID(int32_t aMsaaID);
+  sync GetWindowedPluginIAccessible(WindowsHandle aHwnd)
+    returns (IAccessibleHolder aPluginCOMProxy);
 
 child:
+  async ParentCOMProxy(IAccessibleHolder aParentCOMProxy);
+  async EmulatedWindow(WindowsHandle aEmulatedWindowHandle,
+                       IAccessibleHolder aEmulatedWindowCOMProxy);
+
   async __delete__();
 };
 
 }
 }
--- a/accessible/ipc/win/PlatformChild.cpp
+++ b/accessible/ipc/win/PlatformChild.cpp
@@ -23,34 +23,46 @@ namespace a11y {
  * outparams. Instead we manually define the relevant metadata here, and
  * register it in a call to mozilla::mscom::RegisterArrayData.
  * @see mozilla::mscom::ArrayData
  */
 static const mozilla::mscom::ArrayData sPlatformChildArrayData[] = {
   {IID_IEnumVARIANT, 3, 1, VT_DISPATCH, IID_IDispatch, 2},
   {IID_IAccessible2, 30, 1, VT_UNKNOWN | VT_BYREF, IID_IAccessibleRelation, 2},
   {IID_IAccessibleRelation, 7, 1, VT_UNKNOWN | VT_BYREF, IID_IUnknown, 2},
-  {IID_IAccessible2_2, 48, 2, VT_UNKNOWN | VT_BYREF, IID_IUnknown, 3},
-  {IID_IAccessibleTableCell, 4, 0, VT_UNKNOWN | VT_BYREF, IID_IUnknown, 1},
-  {IID_IAccessibleTableCell, 7, 0, VT_UNKNOWN | VT_BYREF, IID_IUnknown, 1},
-  {IID_IAccessibleHypertext2, 25, 0, VT_UNKNOWN | VT_BYREF, IID_IUnknown, 1}
+  {IID_IAccessible2_2, 48, 2, VT_UNKNOWN | VT_BYREF, IID_IUnknown, 3,
+   mozilla::mscom::ArrayData::Flag::eAllocatedByServer},
+  {IID_IAccessibleTableCell, 4, 0, VT_UNKNOWN | VT_BYREF, IID_IUnknown, 1,
+   mozilla::mscom::ArrayData::Flag::eAllocatedByServer},
+  {IID_IAccessibleTableCell, 7, 0, VT_UNKNOWN | VT_BYREF, IID_IUnknown, 1,
+   mozilla::mscom::ArrayData::Flag::eAllocatedByServer},
+  {IID_IAccessibleHypertext2, 25, 0, VT_UNKNOWN | VT_BYREF, IID_IUnknown, 1,
+   mozilla::mscom::ArrayData::Flag::eAllocatedByServer}
 };
 
 // Type libraries are thread-neutral, so we can register those from any
 // apartment. OTOH, proxies must be registered from within the apartment where
 // we intend to instantiate them. Therefore RegisterProxy() must be called
 // via EnsureMTA.
 PlatformChild::PlatformChild()
   : mAccTypelib(mozilla::mscom::RegisterTypelib(L"oleacc.dll",
         mozilla::mscom::RegistrationFlags::eUseSystemDirectory))
   , mMiscTypelib(mozilla::mscom::RegisterTypelib(L"Accessible.tlb"))
+  , mSdnTypelib(mozilla::mscom::RegisterTypelib(L"AccessibleMarshal.dll"))
 {
   mozilla::mscom::InterceptorLog::Init();
   mozilla::mscom::RegisterArrayData(sPlatformChildArrayData);
 
+
+  UniquePtr<mozilla::mscom::RegisteredProxy> customProxy;
+  mozilla::mscom::EnsureMTA([&customProxy]() -> void {
+    customProxy = Move(mozilla::mscom::RegisterProxy());
+  });
+  mCustomProxy = Move(customProxy);
+
   UniquePtr<mozilla::mscom::RegisteredProxy> ia2Proxy;
   mozilla::mscom::EnsureMTA([&ia2Proxy]() -> void {
     ia2Proxy = Move(mozilla::mscom::RegisterProxy(L"ia2marshal.dll"));
   });
   mIA2Proxy = Move(ia2Proxy);
 }
 
 } // namespace a11y
--- a/accessible/ipc/win/PlatformChild.h
+++ b/accessible/ipc/win/PlatformChild.h
@@ -18,18 +18,20 @@ public:
   PlatformChild();
 
   PlatformChild(PlatformChild&) = delete;
   PlatformChild(PlatformChild&&) = delete;
   PlatformChild& operator=(PlatformChild&) = delete;
   PlatformChild& operator=(PlatformChild&&) = delete;
 
 private:
+  UniquePtr<mozilla::mscom::RegisteredProxy> mCustomProxy;
   UniquePtr<mozilla::mscom::RegisteredProxy> mIA2Proxy;
   UniquePtr<mozilla::mscom::RegisteredProxy> mAccTypelib;
   UniquePtr<mozilla::mscom::RegisteredProxy> mMiscTypelib;
+  UniquePtr<mozilla::mscom::RegisteredProxy> mSdnTypelib;
 };
 
 } // namespace mozilla
 } // namespace a11y
 
 #endif // mozilla_a11y_PlatformChild_h
 
--- a/accessible/ipc/win/ProxyAccessible.cpp
+++ b/accessible/ipc/win/ProxyAccessible.cpp
@@ -1,16 +1,19 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Accessible2.h"
 #include "ProxyAccessible.h"
+#include "ia2AccessibleRelation.h"
+#include "ia2AccessibleValue.h"
+#include "IGeckoCustom.h"
 #include "mozilla/a11y/DocAccessibleParent.h"
 #include "DocAccessible.h"
 #include "mozilla/a11y/DocManager.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/Unused.h"
 #include "mozilla/a11y/Platform.h"
 #include "RelationType.h"
@@ -44,16 +47,90 @@ ProxyAccessible::GetCOMInterface(void** 
     thisPtr->mCOMProxy = wrap->GetIAccessibleFor(realId, &isDefunct);
   }
 
   RefPtr<IAccessible> addRefed = mCOMProxy;
   addRefed.forget(aOutAccessible);
   return !!mCOMProxy;
 }
 
+/**
+ * Specializations of this template map an IAccessible type to its IID
+ */
+template<typename Interface> struct InterfaceIID {};
+
+template<>
+struct InterfaceIID<IAccessibleValue>
+{
+  static REFIID Value() { return IID_IAccessibleValue; }
+};
+
+template<>
+struct InterfaceIID<IAccessibleText>
+{
+  static REFIID Value() { return IID_IAccessibleText; }
+};
+
+template<>
+struct InterfaceIID<IAccessibleHyperlink>
+{
+  static REFIID Value() { return IID_IAccessibleHyperlink; }
+};
+
+template<>
+struct InterfaceIID<IGeckoCustom>
+{
+  static REFIID Value() { return IID_IGeckoCustom; }
+};
+
+template<>
+struct InterfaceIID<IAccessible2_2>
+{
+  static REFIID Value() { return IID_IAccessible2_2; }
+};
+
+/**
+ * Get the COM proxy for this proxy accessible and QueryInterface it with the
+ * correct IID
+ */
+template<typename Interface>
+static already_AddRefed<Interface>
+QueryInterface(const ProxyAccessible* aProxy)
+{
+  RefPtr<IAccessible> acc;
+  if (!aProxy->GetCOMInterface((void**)getter_AddRefs(acc))) {
+    return nullptr;
+  }
+
+  RefPtr<Interface> acc2;
+  if (FAILED(acc->QueryInterface(InterfaceIID<Interface>::Value(),
+                                 (void**)getter_AddRefs(acc2)))) {
+    return nullptr;
+  }
+
+  return acc2.forget();
+}
+
+static ProxyAccessible*
+GetProxyFor(DocAccessibleParent* aDoc, IUnknown* aCOMProxy)
+{
+  RefPtr<IGeckoCustom> custom;
+  if (FAILED(aCOMProxy->QueryInterface(IID_IGeckoCustom,
+                                       (void**) getter_AddRefs(custom)))) {
+    return nullptr;
+  }
+
+  uint64_t id;
+  if (FAILED(custom->get_ID(&id))) {
+    return nullptr;
+  }
+
+  return aDoc->GetAccessible(id);
+}
+
 void
 ProxyAccessible::Name(nsString& aName) const
 {
   aName.Truncate();
   RefPtr<IAccessible> acc;
   if (!GetCOMInterface((void**)getter_AddRefs(acc))) {
     return;
   }
@@ -80,16 +157,33 @@ ProxyAccessible::Value(nsString& aValue)
   HRESULT hr = acc->get_accValue(kChildIdSelf, &result);
   _bstr_t resultWrap(result, false);
   if (FAILED(hr)) {
     return;
   }
   aValue = (wchar_t*)resultWrap;
 }
 
+double
+ProxyAccessible::Step()
+{
+  RefPtr<IGeckoCustom> custom = QueryInterface<IGeckoCustom>(this);
+  if (!custom) {
+    return 0;
+  }
+
+  double increment;
+  HRESULT hr = custom->get_minimumIncrement(&increment);
+  if (FAILED(hr)) {
+    return 0;
+  }
+
+  return increment;
+}
+
 void
 ProxyAccessible::Description(nsString& aDesc) const
 {
   aDesc.Truncate();
   RefPtr<IAccessible> acc;
   if (!GetCOMInterface((void**)getter_AddRefs(acc))) {
     return;
   }
@@ -101,28 +195,27 @@ ProxyAccessible::Description(nsString& a
     return;
   }
   aDesc = (wchar_t*)resultWrap;
 }
 
 uint64_t
 ProxyAccessible::State() const
 {
-  uint64_t state = 0;
-  RefPtr<IAccessible> acc;
-  if (!GetCOMInterface((void**)getter_AddRefs(acc))) {
-    return state;
+  RefPtr<IGeckoCustom> custom = QueryInterface<IGeckoCustom>(this);
+  if (!custom) {
+    return 0;
   }
 
-  VARIANT varState;
-  HRESULT hr = acc->get_accState(kChildIdSelf, &varState);
+  uint64_t state;
+  HRESULT hr = custom->get_mozState(&state);
   if (FAILED(hr)) {
-    return state;
+    return 0;
   }
-  return uint64_t(varState.lVal);
+  return state;
 }
 
 nsIntRect
 ProxyAccessible::Bounds()
 {
   nsIntRect rect;
 
   RefPtr<IAccessible> acc;
@@ -241,16 +334,17 @@ ConvertBSTRAttributesToArray(const nsASt
         tokens[eName].Truncate();
         tokens[eValue].Truncate();
         ++itr;
         continue;
       default:
         break;
     }
     tokens[state] += *itr;
+    ++itr;
   }
   return true;
 }
 
 void
 ProxyAccessible::Attributes(nsTArray<Attribute>* aAttrs) const
 {
   aAttrs->Clear();
@@ -272,10 +366,425 @@ ProxyAccessible::Attributes(nsTArray<Att
     return;
   }
 
   ConvertBSTRAttributesToArray(nsDependentString((wchar_t*)attrs,
                                                  attrsWrap.length()),
                                aAttrs);
 }
 
+nsTArray<ProxyAccessible*>
+ProxyAccessible::RelationByType(RelationType aType) const
+{
+  RefPtr<IAccessible2_2> acc = QueryInterface<IAccessible2_2>(this);
+  if (!acc) {
+    nsTArray<ProxyAccessible*>();
+  }
+
+  _bstr_t relationType;
+  for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) {
+    if (aType == sRelationTypePairs[idx].first) {
+      relationType = sRelationTypePairs[idx].second;
+      break;
+    }
+  }
+
+  if (!relationType) {
+    nsTArray<ProxyAccessible*>();
+  }
+
+  IUnknown** targets;
+  long nTargets = 0;
+  HRESULT hr = acc->get_relationTargetsOfType(relationType, 0, &targets, &nTargets);
+  if (FAILED(hr)) {
+    nsTArray<ProxyAccessible*>();
+  }
+
+  nsTArray<ProxyAccessible*> proxies;
+  for (long idx = 0; idx < nTargets; idx++) {
+    IUnknown* target = targets[idx];
+    proxies.AppendElement(GetProxyFor(Document(), target));
+    target->Release();
+  }
+  CoTaskMemFree(targets);
+
+  return Move(proxies);
+}
+
+double
+ProxyAccessible::CurValue()
+{
+  RefPtr<IAccessibleValue> acc = QueryInterface<IAccessibleValue>(this);
+  if (!acc) {
+    return UnspecifiedNaN<double>();
+  }
+
+  VARIANT currentValue;
+  HRESULT hr = acc->get_currentValue(&currentValue);
+  if (FAILED(hr) || currentValue.vt != VT_R8) {
+    return UnspecifiedNaN<double>();
+  }
+
+  return currentValue.dblVal;
+}
+
+bool
+ProxyAccessible::SetCurValue(double aValue)
+{
+  RefPtr<IAccessibleValue> acc = QueryInterface<IAccessibleValue>(this);
+  if (!acc) {
+    return false;
+  }
+
+  VARIANT currentValue;
+  VariantInit(&currentValue);
+  currentValue.vt = VT_R8;
+  currentValue.dblVal = aValue;
+  HRESULT hr = acc->setCurrentValue(currentValue);
+  return SUCCEEDED(hr);
+}
+
+double
+ProxyAccessible::MinValue()
+{
+  RefPtr<IAccessibleValue> acc = QueryInterface<IAccessibleValue>(this);
+  if (!acc) {
+    return UnspecifiedNaN<double>();
+  }
+
+  VARIANT minimumValue;
+  HRESULT hr = acc->get_minimumValue(&minimumValue);
+  if (FAILED(hr) || minimumValue.vt != VT_R8) {
+    return UnspecifiedNaN<double>();
+  }
+
+  return minimumValue.dblVal;
+}
+
+double
+ProxyAccessible::MaxValue()
+{
+  RefPtr<IAccessibleValue> acc = QueryInterface<IAccessibleValue>(this);
+  if (!acc) {
+    return UnspecifiedNaN<double>();
+  }
+
+  VARIANT maximumValue;
+  HRESULT hr = acc->get_maximumValue(&maximumValue);
+  if (FAILED(hr) || maximumValue.vt != VT_R8) {
+    return UnspecifiedNaN<double>();
+  }
+
+  return maximumValue.dblVal;
+}
+
+static IA2TextBoundaryType
+GetIA2TextBoundary(AccessibleTextBoundary aGeckoBoundaryType)
+{
+  switch (aGeckoBoundaryType) {
+    case nsIAccessibleText::BOUNDARY_CHAR:
+      return IA2_TEXT_BOUNDARY_CHAR;
+    case nsIAccessibleText::BOUNDARY_WORD_START:
+      return IA2_TEXT_BOUNDARY_WORD;
+    case nsIAccessibleText::BOUNDARY_LINE_START:
+      return IA2_TEXT_BOUNDARY_LINE;
+    default:
+      MOZ_RELEASE_ASSERT(false);
+  }
+}
+
+bool
+ProxyAccessible::TextSubstring(int32_t aStartOffset, int32_t aEndOffset,
+                               nsString& aText) const
+{
+  RefPtr<IAccessibleText> acc = QueryInterface<IAccessibleText>(this);
+  if (!acc) {
+    return false;
+  }
+
+  BSTR result;
+  HRESULT hr = acc->get_text(static_cast<long>(aStartOffset),
+                             static_cast<long>(aEndOffset), &result);
+  if (FAILED(hr)) {
+    return false;
+  }
+
+  _bstr_t resultWrap(result, false);
+  aText = (wchar_t*)result;
+
+  return true;
+}
+
+void
+ProxyAccessible::GetTextBeforeOffset(int32_t aOffset,
+                                    AccessibleTextBoundary aBoundaryType,
+                                    nsString& aText, int32_t* aStartOffset,
+                                    int32_t* aEndOffset)
+{
+  RefPtr<IAccessibleText> acc = QueryInterface<IAccessibleText>(this);
+  if (!acc) {
+    return;
+  }
+
+  BSTR result;
+  long start, end;
+  HRESULT hr = acc->get_textBeforeOffset(aOffset,
+                                         GetIA2TextBoundary(aBoundaryType),
+                                         &start, &end, &result);
+  if (FAILED(hr)) {
+    return;
+  }
+
+  _bstr_t resultWrap(result, false);
+  *aStartOffset = start;
+  *aEndOffset = end;
+  aText = (wchar_t*)result;
+}
+
+void
+ProxyAccessible::GetTextAfterOffset(int32_t aOffset,
+                                    AccessibleTextBoundary aBoundaryType,
+                                    nsString& aText, int32_t* aStartOffset,
+                                    int32_t* aEndOffset)
+{
+  RefPtr<IAccessibleText> acc = QueryInterface<IAccessibleText>(this);
+  if (!acc) {
+    return;
+  }
+
+  BSTR result;
+  long start, end;
+  HRESULT hr = acc->get_textAfterOffset(aOffset,
+                                        GetIA2TextBoundary(aBoundaryType),
+                                        &start, &end, &result);
+  if (FAILED(hr)) {
+    return;
+  }
+
+  _bstr_t resultWrap(result, false);
+  aText = (wchar_t*)result;
+  *aStartOffset = start;
+  *aEndOffset = end;
+}
+
+void
+ProxyAccessible::GetTextAtOffset(int32_t aOffset,
+                                    AccessibleTextBoundary aBoundaryType,
+                                    nsString& aText, int32_t* aStartOffset,
+                                    int32_t* aEndOffset)
+{
+  RefPtr<IAccessibleText> acc = QueryInterface<IAccessibleText>(this);
+  if (!acc) {
+    return;
+  }
+
+  BSTR result;
+  long start, end;
+  HRESULT hr = acc->get_textAtOffset(aOffset, GetIA2TextBoundary(aBoundaryType),
+                                     &start, &end, &result);
+  if (FAILED(hr)) {
+    return;
+  }
+
+  _bstr_t resultWrap(result, false);
+  aText = (wchar_t*)result;
+  *aStartOffset = start;
+  *aEndOffset = end;
+}
+
+bool
+ProxyAccessible::AddToSelection(int32_t aStartOffset, int32_t aEndOffset)
+{
+  RefPtr<IAccessibleText> acc = QueryInterface<IAccessibleText>(this);
+  if (!acc) {
+    return false;
+  }
+
+  return SUCCEEDED(acc->addSelection(static_cast<long>(aStartOffset),
+                                     static_cast<long>(aEndOffset)));
+}
+
+bool
+ProxyAccessible::RemoveFromSelection(int32_t aSelectionNum)
+{
+  RefPtr<IAccessibleText> acc = QueryInterface<IAccessibleText>(this);
+  if (!acc) {
+    return false;
+  }
+
+  return SUCCEEDED(acc->removeSelection(static_cast<long>(aSelectionNum)));
+}
+
+int32_t
+ProxyAccessible::CaretOffset()
+{
+  RefPtr<IAccessibleText> acc = QueryInterface<IAccessibleText>(this);
+  if (!acc) {
+    return -1;
+  }
+
+  long offset;
+  HRESULT hr = acc->get_caretOffset(&offset);
+  if (FAILED(hr)) {
+    return -1;
+  }
+
+  return static_cast<int32_t>(offset);
+}
+
+void
+ProxyAccessible::SetCaretOffset(int32_t aOffset)
+{
+  RefPtr<IAccessibleText> acc = QueryInterface<IAccessibleText>(this);
+  if (!acc) {
+    return;
+  }
+
+  acc->setCaretOffset(static_cast<long>(aOffset));
+}
+
+/**
+ * aScrollType should be one of the nsIAccessiblescrollType constants.
+ */
+void
+ProxyAccessible::ScrollSubstringTo(int32_t aStartOffset, int32_t aEndOffset,
+                                   uint32_t aScrollType)
+{
+  RefPtr<IAccessibleText> acc = QueryInterface<IAccessibleText>(this);
+  if (!acc) {
+    return;
+  }
+
+  acc->scrollSubstringTo(static_cast<long>(aStartOffset),
+                         static_cast<long>(aEndOffset),
+                         static_cast<IA2ScrollType>(aScrollType));
+}
+
+/**
+ * aCoordinateType is one of the nsIAccessibleCoordinateType constants.
+ */
+void
+ProxyAccessible::ScrollSubstringToPoint(int32_t aStartOffset, int32_t aEndOffset,
+                                        uint32_t aCoordinateType, int32_t aX,
+                                        int32_t aY)
+{
+  RefPtr<IAccessibleText> acc = QueryInterface<IAccessibleText>(this);
+  if (!acc) {
+    return;
+  }
+
+  IA2CoordinateType coordType;
+  if (aCoordinateType == nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE) {
+    coordType = IA2_COORDTYPE_SCREEN_RELATIVE;
+  } else if (aCoordinateType == nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE) {
+    coordType = IA2_COORDTYPE_PARENT_RELATIVE;
+  } else {
+    MOZ_RELEASE_ASSERT(false, "unsupported coord type");
+  }
+
+  acc->scrollSubstringToPoint(static_cast<long>(aStartOffset),
+                              static_cast<long>(aEndOffset),
+                              coordType,
+                              static_cast<long>(aX),
+                              static_cast<long>(aY));
+}
+
+uint32_t
+ProxyAccessible::StartOffset(bool* aOk)
+{
+  RefPtr<IAccessibleHyperlink> acc = QueryInterface<IAccessibleHyperlink>(this);
+  if (!acc) {
+    *aOk = false;
+    return 0;
+  }
+
+  long startOffset;
+  *aOk = SUCCEEDED(acc->get_startIndex(&startOffset));
+  return static_cast<uint32_t>(startOffset);
+}
+
+uint32_t
+ProxyAccessible::EndOffset(bool* aOk)
+{
+  RefPtr<IAccessibleHyperlink> acc = QueryInterface<IAccessibleHyperlink>(this);
+  if (!acc) {
+    *aOk = false;
+    return 0;
+  }
+
+  long endOffset;
+  *aOk = SUCCEEDED(acc->get_endIndex(&endOffset));
+  return static_cast<uint32_t>(endOffset);
+}
+
+bool
+ProxyAccessible::IsLinkValid()
+{
+  RefPtr<IAccessibleHyperlink> acc = QueryInterface<IAccessibleHyperlink>(this);
+  if (!acc) {
+    return false;
+  }
+
+  boolean valid;
+  if (FAILED(acc->get_valid(&valid))) {
+    return false;
+  }
+
+  return valid;
+}
+
+uint32_t
+ProxyAccessible::AnchorCount(bool* aOk)
+{
+  *aOk = false;
+  RefPtr<IGeckoCustom> custom = QueryInterface<IGeckoCustom>(this);
+  if (!custom) {
+    return 0;
+  }
+
+  long count;
+  if (FAILED(custom->get_anchorCount(&count))) {
+    return 0;
+  }
+
+  *aOk = true;
+  return count;
+}
+
+ProxyAccessible*
+ProxyAccessible::AnchorAt(uint32_t aIdx)
+{
+  RefPtr<IAccessibleHyperlink> link = QueryInterface<IAccessibleHyperlink>(this);
+  if (!link) {
+    return nullptr;
+  }
+
+  VARIANT anchor;
+  if (FAILED(link->get_anchor(aIdx, &anchor))) {
+    return nullptr;
+  }
+
+  MOZ_ASSERT(anchor.vt == VT_UNKNOWN);
+  ProxyAccessible* proxyAnchor = GetProxyFor(Document(), anchor.punkVal);
+  anchor.punkVal->Release();
+  return proxyAnchor;
+}
+
+void
+ProxyAccessible::DOMNodeID(nsString& aID)
+{
+  aID.Truncate();
+  RefPtr<IGeckoCustom> custom = QueryInterface<IGeckoCustom>(this);
+  if (!custom) {
+    return;
+  }
+
+  BSTR result;
+  HRESULT hr = custom->get_DOMNodeID(&result);
+  _bstr_t resultWrap(result, false);
+  if (FAILED(hr)) {
+    return;
+  }
+  aID = (wchar_t*)resultWrap;
+}
+
 } // namespace a11y
 } // namespace mozilla
--- a/accessible/ipc/win/ProxyAccessible.h
+++ b/accessible/ipc/win/ProxyAccessible.h
@@ -34,25 +34,24 @@ public:
   ~ProxyAccessible()
   {
     MOZ_COUNT_DTOR(ProxyAccessible);
   }
 
 #include "mozilla/a11y/ProxyAccessibleShared.h"
 
   bool GetCOMInterface(void** aOutAccessible) const;
+  void SetCOMInterface(const RefPtr<IAccessible>& aIAccessible)
+  { mCOMProxy = aIAccessible; }
 
 protected:
   explicit ProxyAccessible(DocAccessibleParent* aThisAsDoc)
     : ProxyAccessibleBase(aThisAsDoc)
   { MOZ_COUNT_CTOR(ProxyAccessible); }
 
-  void SetCOMInterface(const RefPtr<IAccessible>& aIAccessible)
-  { mCOMProxy = aIAccessible; }
-
 private:
   RefPtr<IAccessible> mCOMProxy;
 };
 
 }
 }
 
 #endif
--- a/accessible/ipc/win/moz.build
+++ b/accessible/ipc/win/moz.build
@@ -1,15 +1,16 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-DIRS += ['typelib']
+if CONFIG['COMPILE_ENVIRONMENT']:
+    DIRS += ['typelib']
 
 # With --disable-accessibility, we need to compile PDocAccessible.ipdl (which
 # also depends on COMPtrTypes.h), but not the C++.
 IPDL_SOURCES += ['PDocAccessible.ipdl']
 EXPORTS.mozilla.a11y += ['COMPtrTypes.h']
 
 if CONFIG['ACCESSIBILITY']:
     EXPORTS.mozilla.a11y += [
--- a/accessible/jsat/AccessFu.jsm
+++ b/accessible/jsat/AccessFu.jsm
@@ -10,16 +10,20 @@
 
 const {utils: Cu, interfaces: Ci} = Components;
 
 this.EXPORTED_SYMBOLS = ['AccessFu']; // jshint ignore:line
 
 Cu.import('resource://gre/modules/Services.jsm');
 Cu.import('resource://gre/modules/accessibility/Utils.jsm');
 
+if (Utils.MozBuildApp === 'mobile/android') {
+  Cu.import('resource://gre/modules/Messaging.jsm');
+}
+
 const ACCESSFU_DISABLE = 0; // jshint ignore:line
 const ACCESSFU_ENABLE = 1;
 const ACCESSFU_AUTO = 2;
 
 const SCREENREADER_SETTING = 'accessibility.screenreader';
 const QUICKNAV_MODES_PREF = 'accessibility.accessfu.quicknav_modes';
 const QUICKNAV_INDEX_PREF = 'accessibility.accessfu.quicknav_index';
 
@@ -27,32 +31,19 @@ this.AccessFu = { // jshint ignore:line
   /**
    * Initialize chrome-layer accessibility functionality.
    * If accessibility is enabled on the platform, then a special accessibility
    * mode is started.
    */
   attach: function attach(aWindow) {
     Utils.init(aWindow);
 
-    try {
-      Services.androidBridge.handleGeckoMessage(
-          { type: 'Accessibility:Ready' });
-      Services.obs.addObserver(this, 'Accessibility:Settings', false);
-    } catch (x) {
-      // Not on Android
-      if (aWindow.navigator.mozSettings) {
-        let lock = aWindow.navigator.mozSettings.createLock();
-        let req = lock.get(SCREENREADER_SETTING);
-        req.addEventListener('success', () => {
-          this._systemPref = req.result[SCREENREADER_SETTING];
-          this._enableOrDisable();
-        });
-        aWindow.navigator.mozSettings.addObserver(
-          SCREENREADER_SETTING, this.handleEvent);
-      }
+    if (Utils.MozBuildApp === 'mobile/android') {
+      EventDispatcher.instance.dispatch('Accessibility:Ready');
+      EventDispatcher.instance.registerListener(this, 'Accessibility:Settings');
     }
 
     this._activatePref = new PrefCache(
       'accessibility.accessfu.activate', this._enableOrDisable.bind(this));
 
     this._enableOrDisable();
   },
 
@@ -60,20 +51,17 @@ this.AccessFu = { // jshint ignore:line
    * Shut down chrome-layer accessibility functionality from the outside.
    */
   detach: function detach() {
     // Avoid disabling twice.
     if (this._enabled) {
       this._disable();
     }
     if (Utils.MozBuildApp === 'mobile/android') {
-      Services.obs.removeObserver(this, 'Accessibility:Settings');
-    } else if (Utils.win.navigator.mozSettings) {
-      Utils.win.navigator.mozSettings.removeObserver(
-        SCREENREADER_SETTING, this.handleEvent);
+      EventDispatcher.instance.unregisterListener(this, 'Accessibility:Settings');
     }
     delete this._activatePref;
     Utils.uninit();
   },
 
   /**
    * A lazy getter for event handler that binds the scope to AccessFu object.
    */
@@ -129,26 +117,31 @@ this.AccessFu = { // jshint ignore:line
     this._notifyOutputPref =
       new PrefCache('accessibility.accessfu.notify_output');