Merge review head draft
authorGregory Szorc <gps@mozilla.com>
Fri, 24 Mar 2017 12:41:40 -0700
changeset 524948 2e2f86150df41fa4204161678b603003b4f3c00a
parent 524947 c473c99e26781e11e7139149437af0c72bbd5099 (diff)
parent 385536 2a9127efdd6ac8c2b1164fc9119f95f2b2c7d691 (current diff)
child 524949 5b74b4a0b3176e1ded97f9acaf0a345557cfbf3b
push id50924
push usergszorc@mozilla.com
push dateFri, 24 Mar 2017 19:46:38 +0000
milestone55.0a1
Merge review head
new file mode 100644
--- /dev/null
+++ b/.cargo/.gitignore
@@ -0,0 +1,1 @@
+config
new file mode 100644
--- /dev/null
+++ b/.cargo/config.in
@@ -0,0 +1,6 @@
+[source.crates-io]
+registry = 'https://github.com/rust-lang/crates.io-index'
+replace-with = 'vendored-sources'
+
+[source.vendored-sources]
+directory = '@top_srcdir@/third_party/rust'
--- 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,216 +1,306 @@
 # 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/**
+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/preferences/**
-browser/components/privatebrowsing/**
-browser/components/sessionstore/**
-browser/components/shell/**
+# 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/**
-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/**
-
-# Ignore all of loop since it is imported from github and checked at source.
-browser/extensions/loop/**
+# 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/jsonview/lib/**
-devtools/client/memory/**
-devtools/client/netmonitor/test/**
-devtools/client/netmonitor/har/test/**
-devtools/client/performance/**
+!devtools/client/framework/selection.js
+!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/widgets/*.jsm
-devtools/client/sourceeditor/**
+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/**
-!devtools/server/child.js
-!devtools/server/css-logic.js
-!devtools/server/main.js
-!devtools/server/actors/webbrowser.js
-!devtools/server/actors/styles.js
-!devtools/server/actors/string.js
-!devtools/server/actors/csscoverage.js
-devtools/shared/*.js
-!devtools/shared/css-lexer.js
-!devtools/shared/defer.js
-!devtools/shared/event-emitter.js
-!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/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/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/chrome/content
 mobile/android/tests/
 
 # Uses `#filter substitution`
 mobile/android/b2gdroid/app/b2gdroid.js
 mobile/android/app/mobile.js
 mobile/android/chrome/content/healthreport-prefs.js
 
 # Uses `#expand`
 mobile/android/chrome/content/about.js
 
 # Not much JS to lint and non-standard at that
 mobile/android/installer/
 mobile/android/locales/
 
-# Pretty sure we're disabling this one anyway
-mobile/android/modules/ContactService.jsm
-
 # 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
@@ -218,27 +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/videocontrols.xml
 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/**
rename from .eslintrc
rename to .eslintrc.js
--- a/.eslintrc
+++ b/.eslintrc.js
@@ -1,12 +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,3 +1,5 @@
 [flake8]
+# See http://pep8.readthedocs.io/en/latest/intro.html#configuration
+ignore = E121, E123, E126, E129, E133, E226, E241, E242, E704, W503, E402
 max-line-length = 99
 filename = *.py, +.lint
--- a/.gdbinit
+++ b/.gdbinit
@@ -6,16 +6,23 @@
 #
 #  add-auto-load-safe-path ~/moz
 
 # Don't stop for the SIG32/33/etc signals that Flash produces
 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
 	set auto-solib-add 0
--- a/.gitignore
+++ b/.gitignore
@@ -6,19 +6,16 @@
 *.pyo
 TAGS
 tags
 ID
 .DS_Store*
 *.pdb
 *.egg-info
 
-# Allow the id locale directory for loop ('ID' matches this normally)
-!browser/extensions/loop/chrome/locale/id
-
 # Vim swap files.
 .*.sw[a-z]
 
 # Emacs directory variable files.
 **/.dir-locals.el
 
 # User files that may appear at the root
 /.mozconfig*
@@ -72,16 +69,19 @@ parser/html/java/javaparser/
 python/psutil/**/*.so
 python/psutil/**/*.pyd
 python/psutil/build/
 
 # Ignore chrome.manifest files from the devtools loader
 devtools/client/chrome.manifest
 devtools/shared/chrome.manifest
 
+# Ignore node_modules directories in devtools
+devtools/**/node_modules
+
 # Tag files generated by GNU Global
 GTAGS
 GRTAGS
 GSYMS
 GPATH
 
 # Git clone directory for updating web-platform-tests
 testing/web-platform/sync/
@@ -114,8 +114,11 @@ testing/talos/bin/
 testing/talos/include/
 testing/talos/lib/
 testing/talos/talos/tests/tp5n.zip
 testing/talos/talos/tests/tp5n
 testing/talos/talos/tests/devtools/damp.manifest.develop
 
 # Ignore files created when running a reftest.
 lextab.py
+
+# tup database
+/.tup
--- 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
@@ -73,35 +75,28 @@
 
 # Git repositories
 .git/
 
 # Ignore chrome.manifest files from the devtools loader
 ^devtools/client/chrome.manifest$
 ^devtools/shared/chrome.manifest$
 
+# Ignore node_modules directories in devtools
+^devtools/.*/node_modules/
+
 # git checkout of libstagefright
 ^media/libstagefright/android$
 
 # Tag files generated by GNU Global
 GTAGS
 GRTAGS
 GSYMS
 GPATH
 
-# Various items for Loop
-^browser/components/loop/standalone/content/config\.js$
-^browser/extensions/loop/.*/node_modules/
-^browser/extensions/loop/.*\.module-cache
-^browser/extensions/loop/test/coverage/desktop
-^browser/extensions/loop/test/coverage/shared_standalone
-^browser/extensions/loop/test/visual-regression/diff
-^browser/extensions/loop/test/visual-regression/new
-^browser/extensions/loop/test/visual-regression/refs
-
 # Git clone directory for updating web-platform-tests
 ^testing/web-platform/sync/
 
 # Android Gradle artifacts.
 ^mobile/android/gradle/.gradle
 
 # XCode project cruft
 ^embedding/ios/GeckoEmbed/GeckoEmbed.xcodeproj/project.xcworkspace/xcuserdata
@@ -117,22 +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
@@ -122,8 +122,13 @@ 312c68b16549de9cea1557f461d5d234bd5e0a7d
 7a19194812eb767bee7cdf8fc36ba9a383c1bead FIREFOX_AURORA_42_BASE
 fcef8ded82219c89298b4e376cfbdfba79a1d35a FIREFOX_AURORA_43_BASE
 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,109 +8,116 @@ 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}}'
     task:
       created: '{{now}}'
       deadline: '{{#from_now}}1 day{{/from_now}}'
-      expires: '{{#from_now}}14 day{{/from_now}}'
+      expires: '{{#from_now}}365 day{{/from_now}}'
       metadata:
         owner: mozilla-taskcluster-maintenance@mozilla.com
         source: {{{source}}}
         name: "Gecko Decision Task"
         description: |
             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"
-        - "secrets:get:project/taskcluster/gecko/hgfingerprint"
-        # 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
           # to `mach taskgraph decision` are all on the command line.
-          GECKO_BASE_REPOSITORY: 'https://hg.mozilla.org/mozilla-central'
+          GECKO_BASE_REPOSITORY: 'https://hg.mozilla.org/mozilla-unified'
           GECKO_HEAD_REPOSITORY: '{{{url}}}'
           GECKO_HEAD_REF: '{{revision}}'
           GECKO_HEAD_REV: '{{revision}}'
+          HG_STORE_PATH: /home/worker/checkouts/hg-store
 
         cache:
-          level-{{level}}-{{project}}-tc-vcs-public-sources: /home/worker/.tc-vcs/
-          level-{{level}}-{{project}}-gecko-decision: /home/worker/workspace
+          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.0'
+        # 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:
-          - /bin/bash
+          - /home/worker/bin/run-task
+          - '--vcs-checkout=/home/worker/checkouts/gecko'
+          - '--'
+          - bash
           - -cx
           - >
-            mkdir -p /home/worker/artifacts &&
-            checkout-gecko workspace &&
-            cd workspace/gecko &&
-            ln -s /home/worker/artifacts artifacts &&
-            ./mach taskgraph decision
-            --pushlog-id='{{pushlog_id}}'
-            --project='{{project}}'
-            --message='{{comment}}'
-            --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}}'
+              cd /home/worker/checkouts/gecko &&
+              ln -s /home/worker/artifacts artifacts &&
+              ./mach --log-no-times taskgraph decision
+              --pushlog-id='{{pushlog_id}}'
+              --pushdate='{{pushdate}}'
+              --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}}'
 
         artifacts:
           'public':
             type: 'directory'
             path: '/home/worker/artifacts'
-            expires: '{{#from_now}}7 days{{/from_now}}'
+            expires: '{{#from_now}}364 days{{/from_now}}'
 
       extra:
         treeherder:
           symbol: D
--- a/.ycm_extra_conf.py
+++ b/.ycm_extra_conf.py
@@ -1,17 +1,20 @@
 # 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 imp
 import os
-from StringIO import StringIO
 import shlex
 import sys
+try:
+    from StringIO import StringIO
+except ImportError:
+    from io import StringIO
 
 old_bytecode = sys.dont_write_bytecode
 sys.dont_write_bytecode = True
 
 path = os.path.join(os.path.dirname(__file__), 'mach')
 
 if not os.path.exists(path):
     path = os.path.join(os.path.dirname(__file__), 'config.status')
@@ -19,16 +22,20 @@ if not os.path.exists(path):
     path = os.path.join(config.topsrcdir, 'mach')
 mach_module = imp.load_module('_mach', open(path), path, ('', 'r', imp.PY_SOURCE))
 
 sys.dont_write_bytecode = old_bytecode
 
 def FlagsForFile(filename):
     mach = mach_module.get_mach()
     out = StringIO()
+
+    # Mach calls sys.stdout.fileno(), so we need to fake it when capturing it.
+    # Returning an invalid file descriptor does the trick.
+    out.fileno = lambda: -1
     out.encoding = None
     mach.run(['compileflags', filename], stdout=out, stderr=out)
 
     flag_list = shlex.split(out.getvalue())
 
     # This flag is added by Fennec for android build and causes ycmd to fail to parse the file.
     # Removing this flag is a workaround until ycmd starts to handle this flag properly.
     # https://github.com/Valloric/YouCompleteMe/issues/1490
--- 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 1267887 - Build skew after updating rust mp4parse
+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
@@ -166,46 +140,57 @@ install-manifests: $(addprefix install-,
 # config/faster/rules.mk)
 ifneq (,$(filter FasterMake+RecursiveMake,$(BUILD_BACKENDS)))
 install-manifests: faster
 .PHONY: 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) 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
@@ -247,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
@@ -266,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
@@ -291,73 +279,64 @@ SYM_STORE_SOURCE_DIRS := $(topsrcdir)
 
 ifdef MOZ_CRASHREPORTER
 include $(topsrcdir)/toolkit/mozapps/installer/package-name.mk
 
 SYMBOL_INDEX_NAME = \
   $(MOZ_APP_NAME)-$(MOZ_APP_VERSION)-$(OS_TARGET)-$(BUILDID)-$(CPU_ARCH)-symbols.txt
 endif
 
-buildsymbols:
-ifdef MOZ_CRASHREPORTER
+.PHONY: generatesymbols
+generatesymbols:
 	echo building symbol store
 	$(RM) -r $(DIST)/crashreporter-symbols
 	$(RM) '$(DIST)/$(SYMBOL_ARCHIVE_BASENAME).zip'
 	$(RM) '$(DIST)/$(SYMBOL_FULL_ARCHIVE_BASENAME).zip'
 	$(NSINSTALL) -D $(DIST)/crashreporter-symbols
 	OBJCOPY='$(OBJCOPY)' \
 	$(PYTHON) $(topsrcdir)/toolkit/crashreporter/tools/symbolstore.py \
 	  $(MAKE_SYM_STORE_ARGS)                                          \
 	  $(foreach dir,$(SYM_STORE_SOURCE_DIRS),-s $(dir))               \
 	  $(DUMP_SYMS_BIN)                                                \
 	  $(DIST)/crashreporter-symbols                                   \
 	  $(MAKE_SYM_STORE_PATH) | grep -iv test >                        \
 	  $(DIST)/crashreporter-symbols/$(SYMBOL_INDEX_NAME)
 	echo packing symbols
 	$(NSINSTALL) -D $(DIST)/$(PKG_PATH)
+
+.PHONY: symbolsfullarchive
+symbolsfullarchive: generatesymbols
 	cd $(DIST)/crashreporter-symbols && \
           zip -r5D '../$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip' . -x '*test*' -x '*Test*'
+
+.PHONY: symbolsarchive
+symbolsarchive: generatesymbols
 	cd $(DIST)/crashreporter-symbols && \
 	grep 'sym' $(SYMBOL_INDEX_NAME) > $(SYMBOL_INDEX_NAME).tmp && \
 	  mv $(SYMBOL_INDEX_NAME).tmp $(SYMBOL_INDEX_NAME)
 	cd $(DIST)/crashreporter-symbols && \
-          zip -r5D '../$(PKG_PATH)$(SYMBOL_ARCHIVE_BASENAME).zip' . -i '*.sym' -i '*.txt'  -x '*test*' -x '*Test*'
-endif # MOZ_CRASHREPORTER
+          zip -r5D '../$(PKG_PATH)$(SYMBOL_ARCHIVE_BASENAME).zip' . -i '*.sym' -i '*.txt'
+
+ifdef MOZ_CRASHREPORTER
+buildsymbols: symbolsfullarchive symbolsarchive
+else
+buildsymbols:
+endif
 
 uploadsymbols:
 ifdef MOZ_CRASHREPORTER
 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/
rename from accessible/.eslintrc
rename to accessible/.eslintrc.js
--- a/accessible/.eslintrc
+++ b/accessible/.eslintrc.js
@@ -1,15 +1,17 @@
-{
+"use strict";
+
+module.exports = {
   "extends": [
-    "../.eslintrc"
+    "../.eslintrc.js"
   ],
   "globals": {
     "Cc": true,
     "Ci": true,
     "Components": true,
     "console": true,
     "Cu": true,
     "dump": true,
     "Services": true,
     "XPCOMUtils": true
   }
-}
+};
new file mode 100644
--- /dev/null
+++ b/accessible/aom/AccessibleNode.cpp
@@ -0,0 +1,177 @@
+/* -*- 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;
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(AccessibleNode)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AccessibleNode)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(AccessibleNode)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(AccessibleNode)
+
+AccessibleNode::AccessibleNode(nsINode* aNode) : mDOMNode(aNode)
+{
+  DocAccessible* doc =
+    GetOrCreateAccService()->GetDocAccessible(mDOMNode->OwnerDoc());
+  if (doc) {
+    mIntl = doc->GetAccessible(mDOMNode);
+  }
+}
+
+AccessibleNode::~AccessibleNode()
+{
+}
+
+/* virtual */ JSObject*
+AccessibleNode::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  return AccessibleNodeBinding::Wrap(aCx, this, aGivenProto);
+}
+
+/* virtual */ ParentObject
+AccessibleNode::GetParentObject() const
+{
+  return mDOMNode->GetParentObject();
+}
+
+void
+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;
+}
new file mode 100644
--- /dev/null
+++ b/accessible/aom/AccessibleNode.h
@@ -0,0 +1,66 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* 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/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
new file mode 100644
--- /dev/null
+++ b/accessible/aom/moz.build
@@ -0,0 +1,40 @@
+# -*- 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/.
+
+EXPORTS.mozilla.dom += [
+    'AccessibleNode.h',
+]
+
+UNIFIED_SOURCES += [
+    'AccessibleNode.cpp',
+]
+
+LOCAL_INCLUDES += [
+    '/accessible/base',
+    '/accessible/generic',
+]
+
+if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
+    LOCAL_INCLUDES += [
+        '/accessible/atk',
+    ]
+elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
+    LOCAL_INCLUDES += [
+        '/accessible/windows/ia2',
+        '/accessible/windows/msaa',
+    ]
+elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
+    LOCAL_INCLUDES += [
+        '/accessible/mac',
+    ]
+else:
+    LOCAL_INCLUDES += [
+        '/accessible/other',
+    ]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'xul'
--- 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 "prprf.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 "nsXPCOMStrings.h"
+#include "mozilla/Sprintf.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIPersistentProperties2.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 MaiAtkObject::EAvailableAtkSignals MaiAtkObject::gAvailableAtkSignals =
   eUnknown;
@@ -61,17 +61,18 @@ enum MaiInterfaceType {
     MAI_INTERFACE_VALUE,
     MAI_INTERFACE_EDITABLE_TEXT,
     MAI_INTERFACE_HYPERTEXT,
     MAI_INTERFACE_HYPERLINK_IMPL,
     MAI_INTERFACE_SELECTION,
     MAI_INTERFACE_TABLE,
     MAI_INTERFACE_TEXT,
     MAI_INTERFACE_DOCUMENT, 
-    MAI_INTERFACE_IMAGE /* 10 */
+    MAI_INTERFACE_IMAGE, /* 10 */
+    MAI_INTERFACE_TABLE_CELL
 };
 
 static GType GetAtkTypeForMai(MaiInterfaceType type)
 {
   switch (type) {
     case MAI_INTERFACE_COMPONENT:
       return ATK_TYPE_COMPONENT;
     case MAI_INTERFACE_ACTION:
@@ -89,22 +90,27 @@ static GType GetAtkTypeForMai(MaiInterfa
     case MAI_INTERFACE_TABLE:
       return ATK_TYPE_TABLE;
     case MAI_INTERFACE_TEXT:
       return ATK_TYPE_TEXT;
     case MAI_INTERFACE_DOCUMENT:
       return ATK_TYPE_DOCUMENT;
     case MAI_INTERFACE_IMAGE:
       return ATK_TYPE_IMAGE;
+    case MAI_INTERFACE_TABLE_CELL:
+      MOZ_ASSERT(false);
   }
   return G_TYPE_INVALID;
 }
 
 #define NON_USER_EVENT ":system"
     
+// The atk interfaces we can expose without checking what version of ATK we are
+// dealing with.  At the moment AtkTableCell is the only interface we can't
+// always expose.
 static const GInterfaceInfo atk_if_infos[] = {
     {(GInterfaceInitFunc)componentInterfaceInitCB,
      (GInterfaceFinalizeFunc) nullptr, nullptr}, 
     {(GInterfaceInitFunc)actionInterfaceInitCB,
      (GInterfaceFinalizeFunc) nullptr, nullptr},
     {(GInterfaceInitFunc)valueInterfaceInitCB,
      (GInterfaceFinalizeFunc) nullptr, nullptr},
     {(GInterfaceInitFunc)editableTextInterfaceInitCB,
@@ -362,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;
 }
@@ -420,29 +429,37 @@ GetMaiAtkType(uint16_t interfacesBits)
     for (uint32_t index = 0; index < ArrayLength(atk_if_infos); index++) {
       if (interfacesBits & (1 << index)) {
         g_type_add_interface_static(type,
                                     GetAtkTypeForMai((MaiInterfaceType)index),
                                     &atk_if_infos[index]);
       }
     }
 
+    // Special case AtkTableCell so we can check what version of Atk we are
+    // dealing with.
+    if (IsAtkVersionAtLeast(2, 12) && (interfacesBits & (1 << MAI_INTERFACE_TABLE_CELL))) {
+      const GInterfaceInfo cellInfo = {
+        (GInterfaceInitFunc)tableCellInterfaceInitCB,
+        (GInterfaceFinalizeFunc)nullptr, nullptr};
+      g_type_add_interface_static(type, gAtkTableCellGetTypeFunc(), &cellInfo);
+    }
+
     return type;
 }
 
 static const char*
 GetUniqueMaiAtkTypeName(uint16_t interfacesBits)
 {
 #define MAI_ATK_TYPE_NAME_LEN (30)     /* 10+sizeof(uint16_t)*8/4+1 < 30 */
 
     static gchar namePrefix[] = "MaiAtkType";   /* size = 10 */
     static gchar name[MAI_ATK_TYPE_NAME_LEN + 1];
 
-    PR_snprintf(name, MAI_ATK_TYPE_NAME_LEN, "%s%x", namePrefix,
-                interfacesBits);
+    SprintfLiteral(name, "%s%x", namePrefix, interfacesBits);
     name[MAI_ATK_TYPE_NAME_LEN] = '\0';
 
     return name;
 }
 
 bool
 AccessibleWrap::IsValidObject()
 {
@@ -591,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.
@@ -1111,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/InterfaceInitFuncs.h
+++ b/accessible/atk/InterfaceInitFuncs.h
@@ -22,16 +22,17 @@ void actionInterfaceInitCB(AtkActionIfac
 void componentInterfaceInitCB(AtkComponentIface* aIface);
 void documentInterfaceInitCB(AtkDocumentIface *aIface);
 void editableTextInterfaceInitCB(AtkEditableTextIface* aIface);
 void hyperlinkImplInterfaceInitCB(AtkHyperlinkImplIface *aIface);
 void hypertextInterfaceInitCB(AtkHypertextIface* aIface);
 void imageInterfaceInitCB(AtkImageIface* aIface);
 void selectionInterfaceInitCB(AtkSelectionIface* aIface);
 void tableInterfaceInitCB(AtkTableIface *aIface);
+void tableCellInterfaceInitCB(AtkTableCellIface *aIface);
 void textInterfaceInitCB(AtkTextIface* aIface);
 void valueInterfaceInitCB(AtkValueIface *aIface);
 }
 
 /**
  * XXX these should live in a file of utils for atk.
  */
 AtkObject* refAccessibleAtPointHelper(AtkObject* aAtkObj,
--- a/accessible/atk/Platform.cpp
+++ b/accessible/atk/Platform.cpp
@@ -23,16 +23,18 @@
 extern "C" __attribute__((weak,visibility("default"))) int atk_bridge_adaptor_init(int*, char **[]);
 #endif
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 int atkMajorVersion = 1, atkMinorVersion = 12;
 
+GType (*gAtkTableCellGetTypeFunc)();
+
 extern "C" {
 typedef GType (* AtkGetTypeType) (void);
 typedef void (*GnomeAccessibilityInit) (void);
 typedef void (*GnomeAccessibilityShutdown) (void);
 }
 
 static PRLibrary* sATKLib = nullptr;
 static const char sATKLibName[] = "libatk-1.0.so.0";
@@ -151,16 +153,19 @@ a11y::PlatformInit()
     AtkSocketAccessible::g_atk_socket_type = pfn_atk_socket_get_type();
     AtkSocketAccessible::g_atk_socket_embed = (AtkSocketEmbedType)
       PR_FindFunctionSymbol(sATKLib, AtkSocketAccessible ::sATKSocketEmbedSymbol);
     AtkSocketAccessible::gCanEmbed =
       AtkSocketAccessible::g_atk_socket_type != G_TYPE_INVALID &&
       AtkSocketAccessible::g_atk_socket_embed;
   }
 
+  gAtkTableCellGetTypeFunc = (GType (*)())
+    PR_FindFunctionSymbol(sATKLib, "atk_table_cell_get_type");
+
   const char* (*atkGetVersion)() =
     (const char* (*)()) PR_FindFunctionSymbol(sATKLib, "atk_get_version");
   if (atkGetVersion) {
     const char* version = atkGetVersion();
     if (version) {
       char* endPtr = nullptr;
       atkMajorVersion = strtol(version, &endPtr, 10);
       if (*endPtr == '.')
--- a/accessible/atk/UtilInterface.cpp
+++ b/accessible/atk/UtilInterface.cpp
@@ -246,33 +246,40 @@ mai_key_snooper(GtkWidget *the_widget, G
     }
     g_free(info);
     return (consumed ? 1 : 0);
 }
 
 static guint sKey_snooper_id = 0;
 
 static guint
-mai_util_add_key_event_listener (AtkKeySnoopFunc listener,
-                                 gpointer data)
+mai_util_add_key_event_listener(AtkKeySnoopFunc listener, gpointer data)
 {
-  if (MOZ_UNLIKELY(!listener))
+  if (MOZ_UNLIKELY(!listener)) {
     return 0;
+  }
 
-    static guint key=0;
+  static guint key = 0;
+
+  if (!sKey_listener_list) {
+    sKey_listener_list = g_hash_table_new(nullptr, nullptr);
+  }
 
-    if (!sKey_listener_list) {
-        sKey_listener_list = g_hash_table_new(nullptr, nullptr);
-        sKey_snooper_id = gtk_key_snooper_install(mai_key_snooper, data);
-    }
-    AtkKeySnoopFuncPointer atkKeySnoop;
-    atkKeySnoop.func_ptr = listener;
-    g_hash_table_insert(sKey_listener_list, GUINT_TO_POINTER (key++),
-                        atkKeySnoop.data);
-    return key;
+  // 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;
 }
 
 static void
 mai_util_remove_key_event_listener (guint remove_listener)
 {
     if (!sKey_listener_list) {
         // atk-bridge is initialized with gail (e.g. yelp)
         // try gail_remove_key_event_listener
--- a/accessible/atk/moz.build
+++ b/accessible/atk/moz.build
@@ -1,9 +1,9 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# -*- 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/.
 
 EXPORTS.mozilla.a11y += [
     'AccessibleWrap.h',
     'HyperTextAccessibleWrap.h',
@@ -19,28 +19,30 @@ SOURCES += [
     'nsMaiInterfaceComponent.cpp',
     'nsMaiInterfaceDocument.cpp',
     'nsMaiInterfaceEditableText.cpp',
     'nsMaiInterfaceHyperlinkImpl.cpp',
     'nsMaiInterfaceHypertext.cpp',
     'nsMaiInterfaceImage.cpp',
     'nsMaiInterfaceSelection.cpp',
     'nsMaiInterfaceTable.cpp',
+    'nsMaiInterfaceTableCell.cpp',
     'nsMaiInterfaceText.cpp',
     'nsMaiInterfaceValue.cpp',
     'Platform.cpp',
     'RootAccessibleWrap.cpp',
     'UtilInterface.cpp',
 ]
 
 LOCAL_INCLUDES += [
     '/accessible/base',
     '/accessible/generic',
     '/accessible/html',
     '/accessible/ipc',
+    '/accessible/ipc/other',
     '/accessible/xpcom',
     '/accessible/xul',
     '/other-licenses/atk-1.0',
 ]
 
 FINAL_LIBRARY = 'xul'
 
 if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
--- a/accessible/atk/nsMai.h
+++ b/accessible/atk/nsMai.h
@@ -60,16 +60,20 @@ typedef struct _MaiAtkSocket
   mozilla::a11y::AccessibleWrap* accWrap;
 } MaiAtkSocket;
 
 typedef struct _MaiAtkSocketClass
 {
   AtkSocketClass parent_class;
 } MaiAtkSocketClass;
 
+// This is a pointer to the atk_table_cell_get_type function if we are using
+// a version of atk that defines that.
+extern "C" GType (*gAtkTableCellGetTypeFunc)();
+
 mozilla::a11y::AccessibleWrap* GetAccessibleWrap(AtkObject* aAtkObj);
 mozilla::a11y::ProxyAccessible* GetProxy(AtkObject* aAtkObj);
 mozilla::a11y::AccessibleOrProxy GetInternalObj(AtkObject* aObj);
 AtkObject* GetWrapperFor(mozilla::a11y::ProxyAccessible* aProxy);
 AtkObject* GetWrapperFor(mozilla::a11y::AccessibleOrProxy aObj);
 
 extern int atkMajorVersion, atkMinorVersion;
 
--- a/accessible/atk/nsMaiHyperlink.cpp
+++ b/accessible/atk/nsMaiHyperlink.cpp
@@ -183,28 +183,29 @@ getUriCB(AtkHyperlink *aLink, gint aLink
 
   return g_strdup(cautoStr.get());
 }
 
 AtkObject *
 getObjectCB(AtkHyperlink *aLink, gint aLinkIndex)
 {
   MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
-  if (!maiLink)
+  if (!maiLink) {
     return nullptr;
+  }
 
-    if (Accessible* hyperlink = maiLink->GetAccHyperlink()) {
-      Accessible* anchor = hyperlink->AnchorAt(aLinkIndex);
-      NS_ENSURE_TRUE(anchor, nullptr);
+  if (Accessible* hyperlink = maiLink->GetAccHyperlink()) {
+    Accessible* anchor = hyperlink->AnchorAt(aLinkIndex);
+    NS_ENSURE_TRUE(anchor, nullptr);
 
-      return AccessibleWrap::GetAtkObject(anchor);
-    }
+    return AccessibleWrap::GetAtkObject(anchor);
+  }
 
-    ProxyAccessible* anchor = maiLink->Proxy()->AnchorAt(aLinkIndex);
-    return anchor ? GetWrapperFor(anchor) : nullptr;
+  ProxyAccessible* anchor = maiLink->Proxy()->AnchorAt(aLinkIndex);
+  return anchor ? GetWrapperFor(anchor) : nullptr;
 }
 
 gint
 getEndIndexCB(AtkHyperlink *aLink)
 {
   MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
   if (!maiLink)
     return false;
--- a/accessible/atk/nsMaiInterfaceDocument.cpp
+++ b/accessible/atk/nsMaiInterfaceDocument.cpp
@@ -56,24 +56,25 @@ getDocumentLocaleCB(AtkDocument *aDocume
   }
 
   return locale.IsEmpty() ? nullptr : AccessibleWrap::ReturnString(locale);
 }
 
 static inline GSList *
 prependToList(GSList *aList, const char *const aName, const nsAutoString &aValue)
 {
-  if (aValue.IsEmpty())
+  if (aValue.IsEmpty()) {
     return aList;
+  }
 
-    // libspi will free these
-    AtkAttribute *atkAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute));
-    atkAttr->name = g_strdup(aName);
-    atkAttr->value = g_strdup(NS_ConvertUTF16toUTF8(aValue).get());
-    return g_slist_prepend(aList, atkAttr);
+  // libspi will free these
+  AtkAttribute *atkAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute));
+  atkAttr->name = g_strdup(aName);
+  atkAttr->value = g_strdup(NS_ConvertUTF16toUTF8(aValue).get());
+  return g_slist_prepend(aList, atkAttr);
 }
 
 AtkAttributeSet *
 getDocumentAttributesCB(AtkDocument *aDocument)
 {
   nsAutoString url;
   nsAutoString w3cDocType;
   nsAutoString mimeType;
--- 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
new file mode 100644
--- /dev/null
+++ b/accessible/atk/nsMaiInterfaceTableCell.cpp
@@ -0,0 +1,216 @@
+/* -*- 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 "InterfaceInitFuncs.h"
+
+#include "Accessible-inl.h"
+#include "AccessibleWrap.h"
+#include "nsAccUtils.h"
+#include "TableAccessible.h"
+#include "TableCellAccessible.h"
+#include "nsMai.h"
+#include "ProxyAccessible.h"
+#include "nsArrayUtils.h"
+
+#include "mozilla/Likely.h"
+
+using namespace mozilla::a11y;
+
+extern "C" {
+static gint
+GetColumnSpanCB(AtkTableCell* aCell)
+{
+  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell));
+  if (accWrap) {
+    return accWrap->AsTableCell()->ColExtent();
+  }
+
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) {
+    return proxy->ColExtent();
+  }
+
+  return 0;
+}
+
+static gboolean
+GetRowSpanCB(AtkTableCell* aCell)
+{
+  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell));
+  if (accWrap) {
+    return accWrap->AsTableCell()->RowExtent();
+  }
+
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) {
+    return proxy->RowExtent();
+  }
+
+  return 0;
+}
+
+static gboolean
+GetPositionCB(AtkTableCell* aCell, gint* aRow, gint* aCol)
+{
+  if (AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell))) {
+    TableCellAccessible* cell = accWrap->AsTableCell();
+    *aRow = cell->RowIdx();
+    *aCol = cell->ColIdx();
+    return true;
+  }
+
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) {
+    uint32_t rowIdx = 0, colIdx = 0;
+    proxy->GetPosition(&rowIdx, &colIdx);
+    *aCol = colIdx;
+    *aRow = rowIdx;
+    return true;
+  }
+
+  return false;
+}
+
+static gboolean
+GetColumnRowSpanCB(AtkTableCell* aCell, gint* aCol, gint* aRow,
+                   gint* aColExtent, gint* aRowExtent) {
+  if (AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell))) {
+    TableCellAccessible* cellAcc = accWrap->AsTableCell();
+    *aCol = cellAcc->ColIdx();
+    *aRow = cellAcc->RowIdx();
+    *aColExtent = cellAcc->ColExtent();
+    *aRowExtent = cellAcc->ColExtent();
+    return true;
+  }
+
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) {
+    uint32_t colIdx = 0, rowIdx = 0, colExtent = 0, rowExtent = 0;
+    proxy->GetColRowExtents(&colIdx, &rowIdx, &colExtent, &rowExtent);
+    *aCol = colIdx;
+    *aRow = rowIdx;
+    *aColExtent = colExtent;
+    *aRowExtent = rowExtent;
+  return true;
+  }
+
+  return false;
+}
+
+static AtkObject*
+GetTableCB(AtkTableCell* aTableCell)
+{
+  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTableCell));
+  if (accWrap) {
+    TableAccessible* table = accWrap->AsTableCell()->Table();
+    if (!table) {
+      return nullptr;
+    }
+
+    Accessible* tableAcc = table->AsAccessible();
+    return tableAcc ? AccessibleWrap::GetAtkObject(tableAcc) : nullptr;
+  }
+
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTableCell))) {
+    ProxyAccessible* table = proxy->TableOfACell();
+    return table ? GetWrapperFor(table) : nullptr;
+  }
+
+  return nullptr;
+}
+
+static GPtrArray*
+GetColumnHeaderCellsCB(AtkTableCell* aCell)
+{
+  if (AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell))) {
+    AutoTArray<Accessible*, 10> headers;
+    accWrap->AsTableCell()->ColHeaderCells(&headers);
+    if (headers.IsEmpty()) {
+      return nullptr;
+    }
+
+    GPtrArray* atkHeaders = g_ptr_array_sized_new(headers.Length());
+    for (Accessible* header: headers) {
+      AtkObject* atkHeader = AccessibleWrap::GetAtkObject(header);
+      g_object_ref(atkHeader);
+      g_ptr_array_add(atkHeaders, atkHeader);
+    }
+
+    return atkHeaders;
+  }
+
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) {
+    AutoTArray<ProxyAccessible*, 10> headers;
+    proxy->ColHeaderCells(&headers);
+    if (headers.IsEmpty()) {
+      return nullptr;
+    }
+
+    GPtrArray* atkHeaders = g_ptr_array_sized_new(headers.Length());
+    for (ProxyAccessible* header: headers) {
+      AtkObject* atkHeader = GetWrapperFor(header);
+      g_object_ref(atkHeader);
+      g_ptr_array_add(atkHeaders, atkHeader);
+    }
+
+    return atkHeaders;
+  }
+
+  return nullptr;
+}
+
+static GPtrArray*
+GetRowHeaderCellsCB(AtkTableCell* aCell)
+{
+  if (AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell))) {
+    AutoTArray<Accessible*, 10> headers;
+    accWrap->AsTableCell()->RowHeaderCells(&headers);
+    if (headers.IsEmpty()) {
+      return nullptr;
+    }
+
+    GPtrArray* atkHeaders = g_ptr_array_sized_new(headers.Length());
+    for (Accessible* header: headers) {
+      AtkObject* atkHeader = AccessibleWrap::GetAtkObject(header);
+      g_object_ref(atkHeader);
+      g_ptr_array_add(atkHeaders, atkHeader);
+    }
+
+    return atkHeaders;
+  }
+
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) {
+    AutoTArray<ProxyAccessible*, 10> headers;
+    proxy->RowHeaderCells(&headers);
+    if (headers.IsEmpty()) {
+      return nullptr;
+    }
+
+    GPtrArray* atkHeaders = g_ptr_array_sized_new(headers.Length());
+    for (ProxyAccessible* header: headers) {
+      AtkObject* atkHeader = GetWrapperFor(header);
+      g_object_ref(atkHeader);
+      g_ptr_array_add(atkHeaders, atkHeader);
+    }
+
+    return atkHeaders;
+  }
+
+  return nullptr;
+}
+}
+
+void
+tableCellInterfaceInitCB(AtkTableCellIface* aIface)
+{
+  NS_ASSERTION(aIface, "no interface!");
+  if (MOZ_UNLIKELY(!aIface))
+    return;
+
+  aIface->get_column_span = GetColumnSpanCB;
+  aIface->get_column_header_cells = GetColumnHeaderCellsCB;
+  aIface->get_position = GetPositionCB;
+  aIface->get_row_span = GetRowSpanCB;
+  aIface->get_row_header_cells = GetRowHeaderCellsCB;
+  aIface->get_row_column_span = GetColumnRowSpanCB;
+  aIface->get_table = GetTableCB;
+}
--- 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/atk/nsStateMap.h
+++ b/accessible/atk/nsStateMap.h
@@ -73,17 +73,17 @@ static const AtkStateMap gAtkStateMap[] 
   { ATK_STATE_INDETERMINATE,                  kMapDirectly },   // states::MIXED                   = 1 << 5
   { kNone,                                    kMapDirectly },   // states::READONLY                = 1 << 6
   { kNone,                                    kMapDirectly },   // states::HOTTRACKED              = 1 << 7
   { ATK_STATE_DEFAULT,                        kMapDirectly },   // states::DEFAULT                 = 1 << 8
   { ATK_STATE_EXPANDED,                       kMapDirectly },   // states::EXPANDED                = 1 << 9
   { kNone,                                    kNoStateChange }, // states::COLLAPSED               = 1 << 10
   { ATK_STATE_BUSY,                           kMapDirectly },   // states::BUSY                    = 1 << 11
   { kNone,                                    kMapDirectly },   // states::FLOATING                = 1 << 12
-  { kNone,                                    kMapDirectly },   // states::CHECKABLE               = 1 << 13
+  { ATK_STATE_CHECKABLE,                      kMapDirectly },   // states::CHECKABLE               = 1 << 13
   { ATK_STATE_ANIMATED,                       kMapDirectly },   // states::ANIMATED                = 1 << 14
   { ATK_STATE_VISIBLE,                        kMapOpposite },   // states::INVISIBLE               = 1 << 15
   { ATK_STATE_SHOWING,                        kMapOpposite },   // states::OFFSCREEN               = 1 << 16
   { ATK_STATE_RESIZABLE,                      kMapDirectly },   // states::SIZEABLE                = 1 << 17
   { kNone,                                    kMapDirectly },   // states::MOVEABLE                = 1 << 18
   { kNone,                                    kMapDirectly },   // states::SELFVOICING             = 1 << 19
   { ATK_STATE_FOCUSABLE,                      kMapDirectly },   // states::FOCUSABLE               = 1 << 20
   { ATK_STATE_SELECTABLE,                     kMapDirectly },   // states::SELECTABLE              = 1 << 21
--- a/accessible/base/ARIAMap.cpp
+++ b/accessible/base/ARIAMap.cpp
@@ -179,29 +179,39 @@ 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,
     kGenericAccType,
     kNoReqStates,
     eReadonlyUntilEditable
   },
+  { // feed
+    &nsGkAtoms::feed,
+    roles::GROUPING,
+    kUseMapRole,
+    eNoValue,
+    eNoAction,
+    eNoLiveAttr,
+    kGenericAccType,
+    kNoReqStates
+  },
   { // form
     &nsGkAtoms::form,
     roles::FORM,
     kUseMapRole,
     eNoValue,
     eNoAction,
     eNoLiveAttr,
     eLandmark,
@@ -812,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 },
@@ -859,37 +871,73 @@ struct RoleComparator
   }
 };
 
 }
 
 const nsRoleMapEntry*
 aria::GetRoleMap(dom::Element* aEl)
 {
+  return GetRoleMapFromIndex(GetRoleMapIndex(aEl));
+}
+
+uint8_t
+aria::GetRoleMapIndex(dom::Element* aEl)
+{
   nsAutoString roles;
   if (!aEl || !aEl->GetAttr(kNameSpaceID_None, nsGkAtoms::role, roles) ||
       roles.IsEmpty()) {
     // We treat role="" as if the role attribute is absent (per aria spec:8.1.1)
-    return nullptr;
+    return NO_ROLE_MAP_ENTRY_INDEX;
   }
 
   nsWhitespaceTokenizer tokenizer(roles);
   while (tokenizer.hasMoreTokens()) {
     // Do a binary search through table for the next role in role list
     const nsDependentSubstring role = tokenizer.nextToken();
     size_t idx;
     if (BinarySearchIf(sWAIRoleMaps, 0, ArrayLength(sWAIRoleMaps),
                        RoleComparator(role), &idx)) {
-      return sWAIRoleMaps + idx;
+      return idx;
     }
   }
 
-  // Always use some entry if there is a non-empty role string
+  // Always use some entry index if there is a non-empty role string
   // To ensure an accessible object is created
-  return &sLandmarkRoleMap;
+  return LANDMARK_ROLE_MAP_ENTRY_INDEX;
+}
+
+
+const nsRoleMapEntry*
+aria::GetRoleMapFromIndex(uint8_t aRoleMapIndex)
+{
+  switch (aRoleMapIndex) {
+    case NO_ROLE_MAP_ENTRY_INDEX:
+      return nullptr;
+    case EMPTY_ROLE_MAP_ENTRY_INDEX:
+      return &gEmptyRoleMap;
+    case LANDMARK_ROLE_MAP_ENTRY_INDEX:
+      return &sLandmarkRoleMap;
+    default:
+      return sWAIRoleMaps + aRoleMapIndex;
+  }
+}
+
+uint8_t
+aria::GetIndexFromRoleMap(const nsRoleMapEntry* aRoleMapEntry)
+{
+  if (aRoleMapEntry == nullptr) {
+    return NO_ROLE_MAP_ENTRY_INDEX;
+  } else if (aRoleMapEntry == &gEmptyRoleMap) {
+    return EMPTY_ROLE_MAP_ENTRY_INDEX;
+  } else if (aRoleMapEntry == &sLandmarkRoleMap) {
+      return LANDMARK_ROLE_MAP_ENTRY_INDEX;
+  } else {
+    return aRoleMapEntry - sWAIRoleMaps;
+  }
 }
 
 uint64_t
 aria::UniversalStatesFor(mozilla::dom::Element* aElement)
 {
   uint64_t state = 0;
   uint32_t index = 0;
   while (MapToState(sWAIUnivStateMap[index], aElement, &state))
--- a/accessible/base/ARIAMap.h
+++ b/accessible/base/ARIAMap.h
@@ -198,26 +198,67 @@ namespace aria {
 /**
  * Empty role map entry. Used by accessibility service to create an accessible
  * if the accessible can't use role of used accessible class. For example,
  * it is used for table cells that aren't contained by table.
  */
 extern nsRoleMapEntry gEmptyRoleMap;
 
 /**
+ * Constants for the role map entry index to indicate that the role map entry
+ * isn't in sWAIRoleMaps, but rather is a special entry: nullptr,
+ * gEmptyRoleMap, and sLandmarkRoleMap
+ */
+const uint8_t NO_ROLE_MAP_ENTRY_INDEX = UINT8_MAX - 2;
+const uint8_t EMPTY_ROLE_MAP_ENTRY_INDEX = UINT8_MAX - 1;
+const uint8_t LANDMARK_ROLE_MAP_ENTRY_INDEX = UINT8_MAX;
+
+/**
  * Get the role map entry for a given DOM node. This will use the first
  * ARIA role if the role attribute provides a space delimited list of roles.
  *
- * @param aNode  [in] the DOM node to get the role map entry for
+ * @param aEl     [in] the DOM node to get the role map entry for
  * @return        a pointer to the role map entry for the ARIA role, or nullptr
  *                if none
  */
 const nsRoleMapEntry* GetRoleMap(dom::Element* aEl);
 
 /**
+ * Get the role map entry pointer's index for a given DOM node. This will use
+ * the first ARIA role if the role attribute provides a space delimited list of
+ * roles.
+ *
+ * @param aEl     [in] the DOM node to get the role map entry for
+ * @return        the index of the pointer to the role map entry for the ARIA
+ *                role, or NO_ROLE_MAP_ENTRY_INDEX if none
+ */
+uint8_t GetRoleMapIndex(dom::Element* aEl);
+
+/**
+ * Get the role map entry pointer for a given role map entry index.
+ *
+ * @param aRoleMapIndex  [in] the role map index to get the role map entry
+ *                       pointer for
+ * @return               a pointer to the role map entry for the ARIA role,
+ *                       or nullptr, if none
+ */
+const nsRoleMapEntry* GetRoleMapFromIndex(uint8_t aRoleMapIndex);
+
+/**
+ * Get the role map entry index for a given role map entry pointer. If the role
+ * map entry is within sWAIRoleMaps, return the index within that array,
+ * otherwise return one of the special index constants listed above.
+ *
+ * @param aRoleMap  [in] the role map entry pointer to get the index for
+ * @return          the index of the pointer to the role map entry, or
+ *                  NO_ROLE_MAP_ENTRY_INDEX if none
+ */
+uint8_t GetIndexFromRoleMap(const nsRoleMapEntry* aRoleMap);
+
+/**
  * Return accessible state from ARIA universal states applied to the given
  * element.
  */
 uint64_t UniversalStatesFor(mozilla::dom::Element* aElement);
 
 /**
  * Get the ARIA attribute characteristics for a given ARIA attribute.
  *
--- 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
@@ -5,16 +5,17 @@
 
 #ifndef _AccEvent_H_
 #define _AccEvent_H_
 
 #include "nsIAccessibleEvent.h"
 
 #include "mozilla/a11y/Accessible.h"
 
+class nsEventShell;
 namespace mozilla {
 
 namespace dom {
 class Selection;
 }
 
 namespace a11y {
 
@@ -45,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.
@@ -92,16 +89,17 @@ public:
 
   /**
    * Down casting.
    */
   enum EventGroup {
     eGenericEvent,
     eStateChangeEvent,
     eTextChangeEvent,
+    eTreeMutationEvent,
     eMutationEvent,
     eReorderEvent,
     eHideEvent,
     eShowEvent,
     eCaretMoveEvent,
     eTextSelChangeEvent,
     eSelectionChangeEvent,
     eTableChangeEvent,
@@ -126,16 +124,18 @@ 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
 {
@@ -197,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
 {
@@ -264,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
 {
@@ -285,36 +321,38 @@ public:
   virtual unsigned int GetEventGroups() const override
   {
     return AccMutationEvent::GetEventGroups() | (1U << eShowEvent);
   }
 
   uint32_t InsertionIndex() const { return mInsertionIndex; }
 
 private:
+  nsTArray<RefPtr<AccHideEvent>> mPrecedingEvents;
   uint32_t mInsertionIndex;
+
+  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,37 +81,65 @@ DocManager::FindAccessibleInCache(nsINod
         return accessible;
       }
     }
   }
   return nullptr;
 }
 
 void
-DocManager::NotifyOfDocumentShutdown(DocAccessible* aDocument,
-                                     nsIDocument* aDOMDocument)
+DocManager::RemoveFromXPCDocumentCache(DocAccessible* aDocument)
 {
   xpcAccessibleDocument* xpcDoc = mXPCDocumentCache.GetWeak(aDocument);
   if (xpcDoc) {
     xpcDoc->Shutdown();
     mXPCDocumentCache.Remove(aDocument);
   }
 
-  mDocAccessibleCache.Remove(aDOMDocument);
-  RemoveListeners(aDOMDocument);
+  if (!HasXPCDocuments()) {
+    MaybeShutdownAccService(nsAccessibilityService::eXPCOM);
+  }
 }
 
 void
-DocManager::NotifyOfRemoteDocShutdown(DocAccessibleParent* aDoc)
+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;
+  }
+
+  RemoveFromXPCDocumentCache(aDocument);
+  mDocAccessibleCache.Remove(aDOMDocument);
+}
+
+void
+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;
 
@@ -488,32 +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);
-        }
-      }
-    }
   } else {
     parentDocAcc->BindChildDocument(docAcc);
   }
 
 #ifdef A11Y_LOG
   if (logging::IsEnabled(logging::eDocCreate)) {
     logging::DocCreate("document creation finished", aDocument);
     logging::Stack();
@@ -525,29 +537,42 @@ DocManager::CreateDocOrRootAccessible(ns
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // DocManager static
 
 void
 DocManager::ClearDocCache()
 {
-  // This unusual do-one-element-per-iterator approach is required because each
-  // DocAccessible is removed elsewhere upon its Shutdown() method being
-  // called, which invalidates the existing iterator.
   while (mDocAccessibleCache.Count() > 0) {
     auto iter = mDocAccessibleCache.Iter();
     MOZ_ASSERT(!iter.Done());
     DocAccessible* docAcc = iter.UserData();
     NS_ASSERTION(docAcc,
                  "No doc accessible for the object in doc accessible cache!");
     if (docAcc) {
       docAcc->Shutdown();
     }
+
+    iter.Remove();
   }
+
+  // Ensure that all xpcom accessible documents are shut down as well.
+  while (mXPCDocumentCache.Count() > 0) {
+    auto iter = mXPCDocumentCache.Iter();
+    MOZ_ASSERT(!iter.Done());
+    xpcAccessibleDocument* xpcDoc = iter.UserData();
+    NS_ASSERTION(xpcDoc, "No xpc doc for the object in xpc doc cache!");
+
+    if (xpcDoc) {
+      xpcDoc->Shutdown();
+    }
+
+    iter.Remove();
+   }
 }
 
 void
 DocManager::RemoteDocAdded(DocAccessibleParent* aDoc)
 {
   if (!sRemoteDocuments) {
     sRemoteDocuments = new nsTArray<DocAccessibleParent*>;
     ClearOnShutdown(&sRemoteDocuments);
--- 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
@@ -7,35 +7,37 @@
 
 #include "Accessible-inl.h"
 #include "nsEventShell.h"
 #include "DocAccessible.h"
 #ifdef A11Y_LOG
 #include "Logging.h"
 #endif
 
+#include "mozilla/UniquePtr.h"
+
 using namespace mozilla;
 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));
@@ -55,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;
@@ -117,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
 }
 
@@ -147,43 +143,70 @@ TreeMutation::PrefixLog(void* aData, Acc
 }
 #endif
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // EventTree
 
 void
+EventTree::Shown(Accessible* aChild)
+{
+  RefPtr<AccShowEvent> ev = new AccShowEvent(aChild);
+  Controller(aChild)->WithdrawPrecedingEvents(&ev->mPrecedingEvents);
+  Mutated(ev);
+}
+
+void
+EventTree::Hidden(Accessible* aChild, bool aNeedsShutdown)
+{
+  RefPtr<AccHideEvent> ev = new AccHideEvent(aChild, aNeedsShutdown);
+  if (!aNeedsShutdown) {
+    Controller(aChild)->StorePrecedingEvent(ev);
+  }
+  Mutated(ev);
+}
+
+void
 EventTree::Process(const RefPtr<DocAccessible>& aDeathGrip)
 {
   while (mFirst) {
     // Skip a node and its subtree if its container is not in the document.
     if (mFirst->mContainer->IsInDocument()) {
       mFirst->Process(aDeathGrip);
       if (aDeathGrip->IsDefunct()) {
         return;
       }
     }
-    mFirst = mFirst->mNext.forget();
+    mFirst = Move(mFirst->mNext);
   }
 
   MOZ_ASSERT(mContainer || mDependentEvents.IsEmpty(),
              "No container, no events");
   MOZ_ASSERT(!mContainer || !mContainer->IsDefunct(),
              "Processing events for defunct container");
   MOZ_ASSERT(!mFireReorder || mContainer, "No target for reorder event");
 
   // Fire mutation events.
   uint32_t eventsCount = mDependentEvents.Length();
   for (uint32_t jdx = 0; jdx < eventsCount; jdx++) {
     AccMutationEvent* mtEvent = mDependentEvents[jdx];
-    MOZ_ASSERT(mtEvent->mEventRule != AccEvent::eDoNotEmit,
-               "The event shouldn't be presented in the tree");
     MOZ_ASSERT(mtEvent->Document(), "No document for event target");
 
+    // Fire all hide events that has to be fired before this show event.
+    if (mtEvent->IsShow()) {
+      AccShowEvent* showEv = downcast_accEvent(mtEvent);
+      for (uint32_t i = 0; i < showEv->mPrecedingEvents.Length(); i++) {
+        nsEventShell::FireEvent(showEv->mPrecedingEvents[i]);
+        if (aDeathGrip->IsDefunct()) {
+          return;
+        }
+      }
+    }
+
     nsEventShell::FireEvent(mtEvent);
     if (aDeathGrip->IsDefunct()) {
       return;
     }
 
     if (mtEvent->mTextChangeEvent) {
       nsEventShell::FireEvent(mtEvent->mTextChangeEvent);
       if (aDeathGrip->IsDefunct()) {
@@ -224,21 +247,22 @@ EventTree::Process(const RefPtr<DocAcces
 
   mDependentEvents.Clear();
 }
 
 EventTree*
 EventTree::FindOrInsert(Accessible* aContainer)
 {
   if (!mFirst) {
-    return mFirst = new EventTree(aContainer, true);
+    mFirst.reset(new EventTree(aContainer, mDependentEvents.IsEmpty()));
+    return mFirst.get();
   }
 
   EventTree* prevNode = nullptr;
-  EventTree* node = mFirst;
+  EventTree* node = mFirst.get();
   do {
     MOZ_ASSERT(!node->mContainer->IsApplication(),
                "No event for application accessible is expected here");
     MOZ_ASSERT(!node->mContainer->IsDefunct(), "An event target has to be alive");
 
     // Case of same target.
     if (node->mContainer == aContainer) {
       return node;
@@ -250,16 +274,40 @@ EventTree::FindOrInsert(Accessible* aCon
     while (parent) {
       // Reached a top, no match for a current event.
       if (parent == top) {
         break;
       }
 
       // We got a match.
       if (parent->Parent() == node->mContainer) {
+        // Reject the node if it's contained by a show/hide event target
+        uint32_t evCount = node->mDependentEvents.Length();
+        for (uint32_t idx = 0; idx < evCount; idx++) {
+          AccMutationEvent* ev = node->mDependentEvents[idx];
+          if (ev->GetAccessible() == parent) {
+#ifdef A11Y_LOG
+            if (logging::IsEnabled(logging::eEventTree)) {
+              logging::MsgBegin("EVENTS_TREE",
+                "Rejecting node contained by show/hide");
+              logging::AccessibleInfo("Node", aContainer);
+              logging::MsgEnd();
+            }
+#endif
+            // If the node is rejected, then check if it has related hide event
+            // on stack, and if so, then connect it to the parent show event.
+            if (ev->IsShow()) {
+              AccShowEvent* showEv = downcast_accEvent(ev);
+              Controller(aContainer)->
+                WithdrawPrecedingEvents(&showEv->mPrecedingEvents);
+            }
+            return nullptr;
+          }
+        }
+
         return node->FindOrInsert(aContainer);
       }
 
       parent = parent->Parent();
       MOZ_ASSERT(parent, "Wrong tree");
     }
 
     // If the given container contains a current node
@@ -272,78 +320,80 @@ EventTree::FindOrInsert(Accessible* aCon
       if (curParent->Parent() != aContainer) {
         curParent = curParent->Parent();
         continue;
       }
 
       // Insert the tail node into the hierarchy between the current node and
       // its parent.
       node->mFireReorder = false;
-      nsAutoPtr<EventTree>& nodeOwnerRef = prevNode ? prevNode->mNext : mFirst;
-      nsAutoPtr<EventTree> newNode(new EventTree(aContainer, mDependentEvents.IsEmpty()));
+      UniquePtr<EventTree>& nodeOwnerRef = prevNode ? prevNode->mNext : mFirst;
+      UniquePtr<EventTree> newNode(new EventTree(aContainer, mDependentEvents.IsEmpty()));
       newNode->mFirst = Move(nodeOwnerRef);
       nodeOwnerRef = Move(newNode);
       nodeOwnerRef->mNext = Move(node->mNext);
 
       // Check if a next node is contained by the given node too, and move them
       // under the given node if so.
-      prevNode = nodeOwnerRef;
-      node = nodeOwnerRef->mNext;
-      nsAutoPtr<EventTree>* nodeRef = &nodeOwnerRef->mNext;
-      EventTree* insNode = nodeOwnerRef->mFirst;
+      prevNode = nodeOwnerRef.get();
+      node = nodeOwnerRef->mNext.get();
+      UniquePtr<EventTree>* nodeRef = &nodeOwnerRef->mNext;
+      EventTree* insNode = nodeOwnerRef->mFirst.get();
       while (node) {
         Accessible* curParent = node->mContainer;
         while (curParent && !curParent->IsDoc()) {
           if (curParent->Parent() != aContainer) {
             curParent = curParent->Parent();
             continue;
           }
 
           MOZ_ASSERT(!insNode->mNext);
 
           node->mFireReorder = false;
           insNode->mNext = Move(*nodeRef);
-          insNode = insNode->mNext;
+          insNode = insNode->mNext.get();
 
           prevNode->mNext = Move(node->mNext);
           node = prevNode;
           break;
         }
 
         prevNode = node;
         nodeRef = &node->mNext;
-        node = node->mNext;
+        node = node->mNext.get();
       }
 
-      return nodeOwnerRef;
+      return nodeOwnerRef.get();
     }
 
     prevNode = node;
-  } while ((node = node->mNext));
+  } while ((node = node->mNext.get()));
 
   MOZ_ASSERT(prevNode, "Nowhere to insert");
   MOZ_ASSERT(!prevNode->mNext, "Taken by another node");
 
   // If 'this' node contains the given container accessible, then
   //   do not emit a reorder event for the container
   //   if a dependent show event target contains the given container then do not
   //   emit show / hide events (see Process() method)
 
-  return prevNode->mNext = new EventTree(aContainer, mDependentEvents.IsEmpty());
+  prevNode->mNext.reset(new EventTree(aContainer, mDependentEvents.IsEmpty()));
+  return prevNode->mNext.get();
 }
 
 void
 EventTree::Clear()
 {
   mFirst = nullptr;
   mNext = nullptr;
   mContainer = nullptr;
 
   uint32_t eventsCount = mDependentEvents.Length();
   for (uint32_t jdx = 0; jdx < eventsCount; jdx++) {
+    mDependentEvents[jdx]->mEventType = AccEvent::eDoNotEmit;
     AccHideEvent* ev = downcast_accEvent(mDependentEvents[jdx]);
     if (ev && ev->NeedsShutdown()) {
       ev->Document()->ShutdownChildrenInSubtree(ev->mAccessible);
     }
   }
   mDependentEvents.Clear();
 }
 
@@ -352,24 +402,24 @@ EventTree::Find(const Accessible* aConta
 {
   const EventTree* et = this;
   while (et) {
     if (et->mContainer == aContainer) {
       return et;
     }
 
     if (et->mFirst) {
-      et = et->mFirst;
+      et = et->mFirst.get();
       const EventTree* cet = et->Find(aContainer);
       if (cet) {
         return cet;
       }
     }
 
-    et = et->mNext;
+    et = et->mNext.get();
     const EventTree* cet = et->Find(aContainer);
     if (cet) {
       return cet;
     }
   }
 
   return nullptr;
 }
@@ -388,23 +438,32 @@ EventTree::Log(uint32_t aLevel) const
   for (uint32_t i = 0; i < aLevel; i++) {
     printf("  ");
   }
   logging::AccessibleInfo("container", mContainer);
 
   for (uint32_t i = 0; i < mDependentEvents.Length(); i++) {
     AccMutationEvent* ev = mDependentEvents[i];
     if (ev->IsShow()) {
-      for (uint32_t i = 0; i < aLevel; i++) {
+      for (uint32_t i = 0; i < aLevel + 1; i++) {
         printf("  ");
       }
       logging::AccessibleInfo("shown", ev->mAccessible);
+
+      AccShowEvent* showEv = downcast_accEvent(ev);
+      for (uint32_t i = 0; i < showEv->mPrecedingEvents.Length(); i++) {
+        for (uint32_t j = 0; j < aLevel + 1; j++) {
+          printf("  ");
+        }
+        logging::AccessibleInfo("preceding",
+                                showEv->mPrecedingEvents[i]->mAccessible);
+      }
     }
     else {
-      for (uint32_t i = 0; i < aLevel; i++) {
+      for (uint32_t i = 0; i < aLevel + 1; i++) {
         printf("  ");
       }
       logging::AccessibleInfo("hidden", ev->mAccessible);
     }
   }
 
   if (mFirst) {
     mFirst->Log(aLevel + 1);
@@ -416,21 +475,81 @@ EventTree::Log(uint32_t aLevel) const
 }
 #endif
 
 void
 EventTree::Mutated(AccMutationEvent* aEv)
 {
   // If shown or hidden node is a root of previously mutated subtree, then
   // discard those subtree mutations as we are no longer interested in them.
-  nsAutoPtr<EventTree>* node = &mFirst;
+  UniquePtr<EventTree>* node = &mFirst;
   while (*node) {
-    if ((*node)->mContainer == aEv->mAccessible) {
-      *node = Move((*node)->mNext);
-      break;
+    Accessible* cntr = (*node)->mContainer;
+    while (cntr != mContainer) {
+      if (cntr == aEv->mAccessible) {
+#ifdef A11Y_LOG
+        if (logging::IsEnabled(logging::eEventTree)) {
+          logging::MsgBegin("EVENTS_TREE", "Trim subtree");
+          logging::AccessibleInfo("Show/hide container", aEv->mAccessible);
+          logging::AccessibleInfo("Trimmed subtree root", (*node)->mContainer);
+          logging::MsgEnd();
+        }
+#endif
+
+        // If the new hide is part of a move and it contains existing child
+        // shows, then move preceding events from the child shows to the buffer,
+        // so the ongoing show event will pick them up.
+        if (aEv->IsHide()) {
+          AccHideEvent* hideEv = downcast_accEvent(aEv);
+          if (!hideEv->mNeedsShutdown) {
+            for (uint32_t i = 0; i < (*node)->mDependentEvents.Length(); i++) {
+              AccMutationEvent* childEv = (*node)->mDependentEvents[i];
+              if (childEv->IsShow()) {
+                AccShowEvent* childShowEv = downcast_accEvent(childEv);
+                if (childShowEv->mPrecedingEvents.Length() > 0) {
+                  Controller(mContainer)->StorePrecedingEvents(
+                    mozilla::Move(childShowEv->mPrecedingEvents));
+                }
+              }
+            }
+          }
+        }
+        // If the new show contains existing child shows, then move preceding
+        // events from the child shows to the new show.
+        else if (aEv->IsShow()) {
+          AccShowEvent* showEv = downcast_accEvent(aEv);
+          for (uint32_t i = 0; (*node)->mDependentEvents.Length(); i++) {
+            AccMutationEvent* childEv = (*node)->mDependentEvents[i];
+            if (childEv->IsShow()) {
+              AccShowEvent* showChildEv = downcast_accEvent(childEv);
+              if (showChildEv->mPrecedingEvents.Length() > 0) {
+#ifdef A11Y_LOG
+                if (logging::IsEnabled(logging::eEventTree)) {
+                  logging::MsgBegin("EVENTS_TREE", "Adopt preceding events");
+                  logging::AccessibleInfo("Parent", aEv->mAccessible);
+                  for (uint32_t j = 0; j < showChildEv->mPrecedingEvents.Length(); j++) {
+                    logging::AccessibleInfo("Adoptee",
+                      showChildEv->mPrecedingEvents[i]->mAccessible);
+                  }
+                  logging::MsgEnd();
+                }
+#endif
+                showEv->mPrecedingEvents.AppendElements(showChildEv->mPrecedingEvents);
+              }
+            }
+          }
+        }
+
+        *node = Move((*node)->mNext);
+        break;
+      }
+      cntr = cntr->Parent();
+    }
+    if (cntr == aEv->mAccessible) {
+      continue;
     }
     node = &(*node)->mNext;
   }
 
   AccMutationEvent* prevEvent = mDependentEvents.SafeLastElement(nullptr);
   mDependentEvents.AppendElement(aEv);
 
   // Coalesce text change events from this hide/show event and the previous one.
--- a/accessible/base/EventTree.h
+++ b/accessible/base/EventTree.h
@@ -5,16 +5,17 @@
 
 #ifndef mozilla_a11y_EventTree_h_
 #define mozilla_a11y_EventTree_h_
 
 #include "AccEvent.h"
 #include "Accessible.h"
 
 #include "mozilla/RefPtr.h"
+#include "mozilla/UniquePtr.h"
 
 namespace mozilla {
 namespace a11y {
 
 /**
  * This class makes sure required tasks are done before and after tree
  * mutations. Currently this only includes group info invalidation. You must
  * have an object of this class on the stack when calling methods that mutate
@@ -41,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
 };
 
 
 /**
@@ -61,58 +66,56 @@ 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)
-  {
-    RefPtr<AccShowEvent> ev = new AccShowEvent(aChild);
-    Mutated(ev);
-  }
-
-  void Hidden(Accessible* aChild, bool aNeedsShutdown = true)
-  {
-    RefPtr<AccHideEvent> ev = new AccHideEvent(aChild, aNeedsShutdown);
-    Mutated(ev);
-  }
+  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();
 
-  nsAutoPtr<EventTree> mFirst;
-  nsAutoPtr<EventTree> mNext;
+  UniquePtr<EventTree> mFirst;
+  UniquePtr<EventTree> mNext;
 
   Accessible* mContainer;
   nsTArray<RefPtr<AccMutationEvent>> mDependentEvents;
   bool mFireReorder;
 
+  static NotificationController* Controller(Accessible* aAcc)
+    { return aAcc->Document()->Controller(); }
+
   friend class NotificationController;
 };
 
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif // mozilla_a11y_EventQueue_h_
--- a/accessible/base/Logging.cpp
+++ b/accessible/base/Logging.cpp
@@ -85,41 +85,40 @@ EnableLogging(const char* aModulesStr)
     if (*token == ',')
       token++; // skip ',' char
   }
 }
 
 static void
 LogDocURI(nsIDocument* aDocumentNode)
 {
-  nsIURI* uri = aDocumentNode->GetDocumentURI();
-  nsAutoCString spec;
-  uri->GetSpec(spec);
-  printf("uri: %s", spec.get());
+  printf("uri: %s", aDocumentNode->GetDocumentURI()->GetSpecOrDefault().get());
 }
 
 static void
 LogDocShellState(nsIDocument* aDocumentNode)
 {
   printf("docshell busy: ");
 
   nsAutoCString docShellBusy;
   nsCOMPtr<nsIDocShell> docShell = aDocumentNode->GetDocShell();
   uint32_t busyFlags = nsIDocShell::BUSY_FLAGS_NONE;
   docShell->GetBusyFlags(&busyFlags);
-  if (busyFlags == nsIDocShell::BUSY_FLAGS_NONE)
+  if (busyFlags == nsIDocShell::BUSY_FLAGS_NONE) {
     printf("'none'");
-  if (busyFlags & nsIDocShell::BUSY_FLAGS_BUSY)
+  }
+  if (busyFlags & nsIDocShell::BUSY_FLAGS_BUSY) {
     printf("'busy'");
-  if (busyFlags & nsIDocShell::BUSY_FLAGS_BEFORE_PAGE_LOAD)
+  }
+  if (busyFlags & nsIDocShell::BUSY_FLAGS_BEFORE_PAGE_LOAD) {
     printf(", 'before page load'");
-  if (busyFlags & nsIDocShell::BUSY_FLAGS_PAGE_LOADING)
+  }
+  if (busyFlags & nsIDocShell::BUSY_FLAGS_PAGE_LOADING) {
     printf(", 'page loading'");
-
-    printf("[failed]");
+  }
 }
 
 static void
 LogDocType(nsIDocument* aDocumentNode)
 {
   if (aDocumentNode->IsActive()) {
     bool isContent = nsCoreUtils::IsContentDocument(aDocumentNode);
     printf("%s document", (isContent ? "content" : "chrome"));
@@ -643,17 +642,17 @@ logging::TreeInfo(const char* aMsg, uint
 void
 logging::TreeInfo(const char* aMsg, uint32_t aExtraFlags,
                   const char* aMsg1, Accessible* aAcc,
                   const char* aMsg2, nsINode* aNode)
 {
   if (IsEnabledAll(logging::eTree | aExtraFlags)) {
     MsgBegin("TREE", "%s; doc: %p", aMsg, aAcc ? aAcc->Document() : nullptr);
     AccessibleInfo(aMsg1, aAcc);
-    Accessible* acc = aAcc->Document()->GetAccessible(aNode);
+    Accessible* acc = aAcc ? aAcc->Document()->GetAccessible(aNode) : nullptr;
     if (acc) {
       AccessibleInfo(aMsg2, acc);
     }
     else {
       Node(aMsg2, aNode);
     }
     MsgEnd();
   }
@@ -670,51 +669,51 @@ logging::TreeInfo(const char* aMsg, uint
       AccessibleInfo("child", aParent->GetChildAt(idx));
     }
     MsgEnd();
   }
 }
 
 void
 logging::Tree(const char* aTitle, const char* aMsgText,
-              DocAccessible* aDocument, GetTreePrefix aPrefixFunc,
+              Accessible* aRoot, GetTreePrefix aPrefixFunc,
               void* aGetTreePrefixData)
 {
   logging::MsgBegin(aTitle, aMsgText);
 
   nsAutoString level;
-  Accessible* root = aDocument;
+  Accessible* root = aRoot;
   do {
     const char* prefix = aPrefixFunc ? aPrefixFunc(aGetTreePrefixData, root) : "";
     printf("%s", NS_ConvertUTF16toUTF8(level).get());
     logging::AccessibleInfo(prefix, root);
     if (root->FirstChild() && !root->FirstChild()->IsDoc()) {
       level.Append(NS_LITERAL_STRING("  "));
       root = root->FirstChild();
       continue;
     }
-    int32_t idxInParent = !root->IsDoc() && root->mParent ?
+    int32_t idxInParent = root != aRoot && root->mParent ?
       root->mParent->mChildren.IndexOf(root) : -1;
     if (idxInParent != -1 &&
         idxInParent < static_cast<int32_t>(root->mParent->mChildren.Length() - 1)) {
       root = root->mParent->mChildren.ElementAt(idxInParent + 1);
       continue;
     }
-    while (!root->IsDoc() && (root = root->Parent())) {
+    while (root != aRoot && (root = root->Parent())) {
       level.Cut(0, 2);
       int32_t idxInParent = !root->IsDoc() && root->mParent ?
         root->mParent->mChildren.IndexOf(root) : -1;
       if (idxInParent != -1 &&
           idxInParent < static_cast<int32_t>(root->mParent->mChildren.Length() - 1)) {
         root = root->mParent->mChildren.ElementAt(idxInParent + 1);
         break;
       }
     }
   }
-  while (root && !root->IsDoc());
+  while (root && root != aRoot);
 
   logging::MsgEnd();
 }
 
 void
 logging::DOMTree(const char* aTitle, const char* aMsgText,
                  DocAccessible* aDocument)
 {
--- a/accessible/base/Logging.h
+++ b/accessible/base/Logging.h
@@ -138,17 +138,17 @@ void TreeInfo(const char* aMsg, uint32_t
               const char* aMsg1, Accessible* aAcc,
               const char* aMsg2, nsINode* aNode);
 void TreeInfo(const char* aMsg, uint32_t aExtraFlags, Accessible* aParent);
 
 /**
  * Log the accessible/DOM tree.
  */
 typedef const char* (*GetTreePrefix)(void* aData, Accessible*);
-void Tree(const char* aTitle, const char* aMsgText, DocAccessible* aDoc,
+void Tree(const char* aTitle, const char* aMsgText, Accessible* aRoot,
           GetTreePrefix aPrefixFunc = nullptr, void* aGetTreePrefixData = nullptr);
 void DOMTree(const char* aTitle, const char* aMsgText, DocAccessible* aDoc);
 
 /**
  * Log the message ('title: text' format) on new line. Print the start and end
  * boundaries of the message body designated by '{' and '}' (2 spaces indent for
  * body).
  */
--- a/accessible/base/NotificationController.cpp
+++ b/accessible/base/NotificationController.cpp
@@ -19,18 +19,22 @@ 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();
 }
 
 NotificationController::~NotificationController()
 {
   NS_ASSERTION(!mDocument, "Controller wasn't shutdown properly!");
   if (mDocument)
@@ -71,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();
@@ -105,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();
 }
 
@@ -145,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
@@ -163,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;
@@ -214,34 +630,16 @@ NotificationController::WillRefresh(mozi
     NS_ASSERTION(mContentInsertions.Count() == 0,
                  "Pending content insertions while initial accessible tree isn't created!");
   }
 
   // Initialize scroll support if needed.
   if (!(mDocument->mDocFlags & DocAccessible::eScrollInitialized))
     mDocument->AddScrollListener();
 
-  // Process content inserted notifications to update the tree. Process other
-  // notifications like DOM events and then flush event queue. If any new
-  // notifications are queued during this processing then they will be processed
-  // on next refresh. If notification processing queues up new events then they
-  // are processed in this refresh. If events processing queues up new events
-  // then new events are processed on next refresh.
-  // Note: notification processing or event handling may shut down the owning
-  // document accessible.
-
-  // Process only currently queued content inserted notifications.
-  for (auto iter = mContentInsertions.ConstIter(); !iter.Done(); iter.Next()) {
-    mDocument->ProcessContentInserted(iter.Key(), iter.UserData());
-    if (!mDocument) {
-      return;
-    }
-  }
-  mContentInsertions.Clear();
-
   // Process rendered text change notifications.
   for (auto iter = mTextHash.Iter(); !iter.Done(); iter.Next()) {
     nsCOMPtrHashKey<nsIContent>* entry = iter.Get();
     nsIContent* textNode = entry->GetKey();
     Accessible* textAcc = mDocument->GetAccessible(textNode);
 
     // If the text node is not in tree or doesn't have frame then this case should
     // have been handled already by content removal notifications.
@@ -306,27 +704,37 @@ NotificationController::WillRefresh(mozi
       if (logging::IsEnabled(logging::eTree | logging::eText)) {
         logging::MsgBegin("TREE", "text node gains new content; doc: %p", mDocument);
         logging::Node("container", containerElm);
         logging::Node("content", textNode);
         logging::MsgEnd();
       }
   #endif
 
-      // Make sure the text node is in accessible document still.
       Accessible* container = mDocument->AccessibleOrTrueContainer(containerNode);
       MOZ_ASSERT(container,
                  "Text node having rendered text hasn't accessible document!");
       if (container) {
-        mDocument->ProcessContentInserted(container, textNode);
+        nsTArray<nsCOMPtr<nsIContent>>* list =
+          mContentInsertions.LookupOrAdd(container);
+        list->AppendElement(textNode);
       }
     }
   }
   mTextHash.Clear();
 
+  // Process content inserted notifications to update the tree.
+  for (auto iter = mContentInsertions.ConstIter(); !iter.Done(); iter.Next()) {
+    mDocument->ProcessContentInserted(iter.Key(), iter.UserData());
+    if (!mDocument) {
+      return;
+    }
+  }
+  mContentInsertions.Clear();
+
   // Bind hanging child documents.
   uint32_t hangingDocCnt = mHangingChildDocuments.Length();
   nsTArray<RefPtr<DocAccessible>> newChildDocs;
   for (uint32_t idx = 0; idx < hangingDocCnt; idx++) {
     DocAccessible* childDoc = mHangingChildDocuments[idx];
     if (childDoc->IsDefunct())
       continue;
 
@@ -342,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++) {
@@ -396,53 +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);
+          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
@@ -127,21 +127,55 @@ public:
   }
 
   /**
    * Returns existing event tree for the given the accessible or creates one if
    * it doesn't exists yet.
    */
   EventTree* QueueMutation(Accessible* aContainer);
 
+  class MoveGuard final {
+  public:
+    explicit MoveGuard(NotificationController* aController) :
+      mController(aController)
+    {
+#ifdef DEBUG
+      MOZ_ASSERT(!mController->mMoveGuardOnStack,
+                 "Move guard is on stack already!");
+      mController->mMoveGuardOnStack = true;
+#endif
+    }
+    ~MoveGuard() {
+#ifdef DEBUG
+      MOZ_ASSERT(mController->mMoveGuardOnStack, "No move guard on stack!");
+      mController->mMoveGuardOnStack = false;
+#endif
+      mController->mPrecedingEvents.Clear();
+    }
+
+  private:
+    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)
@@ -242,18 +276,48 @@ protected:
 
 private:
   NotificationController(const NotificationController&);
   NotificationController& operator = (const NotificationController&);
 
   // nsARefreshObserver
   virtual void WillRefresh(mozilla::TimeStamp aTime) override;
 
+  /**
+   * Set and returns a hide event, paired with a show event, for the move.
+   */
+  void WithdrawPrecedingEvents(nsTArray<RefPtr<AccHideEvent>>* aEvs)
+  {
+    if (mPrecedingEvents.Length() > 0) {
+      aEvs->AppendElements(mozilla::Move(mPrecedingEvents));
+    }
+  }
+  void StorePrecedingEvent(AccHideEvent* aEv)
+  {
+    MOZ_ASSERT(mMoveGuardOnStack, "No move guard on stack!");
+    mPrecedingEvents.AppendElement(aEv);
+  }
+  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
@@ -315,14 +379,61 @@ private:
    * Holds all scheduled relocations.
    */
   nsTArray<RefPtr<Accessible> > mRelocations;
 
   /**
    * Holds all mutation events.
    */
   EventTree mEventTree;
+
+  /**
+   * A temporary collection of hide events that should be fired before related
+   * show event. Used by EventTree.
+   */
+  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/Platform.h
+++ b/accessible/base/Platform.h
@@ -1,14 +1,17 @@
 /* -*- 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/. */
 
+#ifndef mozilla_a11y_Platform_h
+#define mozilla_a11y_Platform_h
+
 #include <stdint.h>
 
 class nsString;
 
 namespace mozilla {
 namespace a11y {
 
 class ProxyAccessible;
@@ -77,8 +80,9 @@ void ProxyTextChangeEvent(ProxyAccessibl
                           bool aFromUser);
 void ProxyShowHideEvent(ProxyAccessible* aTarget, ProxyAccessible* aParent,
                         bool aInsert, bool aFromUser);
 void ProxySelectionEvent(ProxyAccessible* aTarget, ProxyAccessible* aWidget,
                          uint32_t aType);
 } // namespace a11y
 } // namespace mozilla
 
+#endif // mozilla_a11y_Platform_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
@@ -48,51 +48,45 @@ StyleInfo::TextIndent(nsAString& aValue)
 
   const nsStyleCoord& styleCoord =
     mStyleContext->StyleText()->mTextIndent;
 
   nscoord coordVal = 0;
   switch (styleCoord.GetUnit()) {
     case eStyleUnit_Coord:
       coordVal = styleCoord.GetCoordValue();
+      aValue.AppendFloat(nsPresContext::AppUnitsToFloatCSSPixels(coordVal));
+      aValue.AppendLiteral("px");
       break;
 
     case eStyleUnit_Percent:
-    {
-      nsIFrame* frame = mElement->GetPrimaryFrame();
-      MOZ_ASSERT(frame, "frame must be a valid pointer.");
-      nsIFrame* containerFrame = frame->GetContainingBlock();
-      nscoord percentageBase = containerFrame->GetContentRect().width;
-      coordVal = NSCoordSaturatingMultiply(percentageBase,
-                                           styleCoord.GetPercentValue());
+      aValue.AppendFloat(styleCoord.GetPercentValue() * 100);
+      aValue.AppendLiteral("%");
       break;
-    }
 
     case eStyleUnit_Null:
     case eStyleUnit_Normal:
     case eStyleUnit_Auto:
     case eStyleUnit_None:
     case eStyleUnit_Factor:
     case eStyleUnit_Degree:
     case eStyleUnit_Grad:
     case eStyleUnit_Radian:
     case eStyleUnit_Turn:
     case eStyleUnit_FlexFraction:
     case eStyleUnit_Integer:
     case eStyleUnit_Enumerated:
     case eStyleUnit_Calc:
+      aValue.AppendLiteral("0px");
       break;
   }
-
-  aValue.AppendFloat(nsPresContext::AppUnitsToFloatCSSPixels(coordVal));
-  aValue.AppendLiteral("px");
 }
 
 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,40 +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_QT)
-  useFontEntryWeight = false;
-#elif 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) :
@@ -713,23 +692,19 @@ TextAttrsMgr::AutoGeneratedTextAttr::
 ////////////////////////////////////////////////////////////////////////////////
 // TextDecorTextAttr
 ////////////////////////////////////////////////////////////////////////////////
 
 TextAttrsMgr::TextDecorValue::
   TextDecorValue(nsIFrame* aFrame)
 {
   const nsStyleTextReset* textReset = aFrame->StyleTextReset();
-  mStyle = textReset->GetDecorationStyle();
-
-  bool isForegroundColor = false;
-  textReset->GetDecorationColor(mColor, isForegroundColor);
-  if (isForegroundColor)
-    mColor = aFrame->StyleColor()->mColor;
-
+  mStyle = textReset->mTextDecorationStyle;
+  mColor = aFrame->StyleColor()->
+    CalcComplexColor(textReset->mTextDecorationColor);
   mLine = textReset->mTextDecorationLine &
     (NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE |
      NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH);
 }
 
 TextAttrsMgr::TextDecorTextAttr::
   TextDecorTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
   TTextAttr<TextDecorValue>(!aFrame)
--- a/accessible/base/TextAttrs.h
+++ b/accessible/base/TextAttrs.h
@@ -175,23 +175,23 @@ protected:
     virtual bool GetValueFor(Accessible* aAccessible, T* aValue) = 0;
 
     // Indicates if root value should be exposed.
     bool mGetRootValue;
 
     // Native value and flag indicating if the value is defined (initialized in
     // derived classes). Note, undefined native value means it is inherited
     // from root.
-    T mNativeValue;
-    bool mIsDefined;
+    MOZ_INIT_OUTSIDE_CTOR T mNativeValue;
+    MOZ_INIT_OUTSIDE_CTOR bool mIsDefined;
 
     // Native root value and flag indicating if the value is defined  (initialized
     // in derived classes).
-    T mRootNativeValue;
-    bool mIsRootDefined;
+    MOZ_INIT_OUTSIDE_CTOR T mRootNativeValue;
+    MOZ_INIT_OUTSIDE_CTOR bool mIsRootDefined;
   };
 
 
   /**
    * Class is used for the work with 'language' text attribute.
    */
   class LangTextAttr : public TTextAttr<nsString>
   {
--- a/accessible/base/TreeWalker.cpp
+++ b/accessible/base/TreeWalker.cpp
@@ -52,24 +52,43 @@ TreeWalker::
   MOZ_COUNT_CTOR(TreeWalker);
 }
 
 TreeWalker::~TreeWalker()
 {
   MOZ_COUNT_DTOR(TreeWalker);
 }
 
+Accessible*
+TreeWalker::Scope(nsIContent* aAnchorNode)
+{
+  Reset();
+
+  mAnchorNode = aAnchorNode;
+
+  bool skipSubtree = false;
+  Accessible* acc = AccessibleFor(aAnchorNode, 0, &skipSubtree);
+  if (acc) {
+    mPhase = eAtEnd;
+    return acc;
+  }
+
+  return skipSubtree ? nullptr : Next();
+}
+
 bool
 TreeWalker::Seek(nsIContent* aChildNode)
 {
   MOZ_ASSERT(aChildNode, "Child cannot be null");
 
-  mPhase = eAtStart;
-  mStateStack.Clear();
-  mARIAOwnsIdx = 0;
+  Reset();
+
+  if (mAnchorNode == aChildNode) {
+    return true;
+  }
 
   nsIContent* childNode = nullptr;
   nsINode* parentNode = aChildNode;
   do {
     childNode = parentNode->AsContent();
     parentNode = childNode->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) &&
       (mChildFilter & nsIContent::eAllButXBL) ?
       childNode->GetParentNode() : childNode->GetFlattenedTreeParent();
@@ -105,17 +124,17 @@ TreeWalker::Seek(nsIContent* aChildNode)
       return true;
     }
   } while (true);
 
   return false;
 }
 
 Accessible*
-TreeWalker::Next(nsIContent* aStopNode)
+TreeWalker::Next()
 {
   if (mStateStack.IsEmpty()) {
     if (mPhase == eAtEnd) {
       return nullptr;
     }
 
     if (mPhase == eAtDOM || mPhase == eAtARIAOwns) {
       mPhase = eAtARIAOwns;
@@ -134,72 +153,64 @@ TreeWalker::Next(nsIContent* aStopNode)
     }
 
     mPhase = eAtDOM;
     PushState(mAnchorNode, true);
   }
 
   dom::AllChildrenIterator* top = &mStateStack[mStateStack.Length() - 1];
   while (top) {
-    if (aStopNode && top->Get() == aStopNode) {
-      return nullptr;
-    }
-
     while (nsIContent* childNode = top->GetNextChild()) {
       bool skipSubtree = false;
       Accessible* child = AccessibleFor(childNode, mFlags, &skipSubtree);
       if (child) {
         return child;
       }
 
-      // Walk down the subtree if allowed, otherwise check if we have reached
-      // a stop node.
+      // Walk down the subtree if allowed.
       if (!skipSubtree && childNode->IsElement()) {
         top = PushState(childNode, true);
       }
-      else if (childNode == aStopNode) {
-        return nullptr;
-      }
     }
     top = PopState();
   }
 
   // If we traversed the whole subtree of the anchor node. Move to next node
   // relative anchor node within the context subtree if asked.
   if (mFlags != eWalkContextTree) {
     // eWalkCache flag presence indicates that the search is scoped to the
     // anchor (no ARIA owns stuff).
     if (mFlags & eWalkCache) {
       mPhase = eAtEnd;
       return nullptr;
     }
-    return Next(aStopNode);
+    return Next();
   }
 
   nsINode* contextNode = mContext->GetNode();
   while (mAnchorNode != contextNode) {
     nsINode* parentNode = mAnchorNode->GetFlattenedTreeParent();
     if (!parentNode || !parentNode->IsElement())
       return nullptr;
 
     nsIContent* parent = parentNode->AsElement();
     top = PushState(parent, true);
     if (top->Seek(mAnchorNode)) {
       mAnchorNode = parent;
-      return Next(aStopNode);
+      return Next();
     }
 
     // XXX We really should never get here, it means we're trying to find an
     // accessible for a dom node where iterating over its parent's children
     // doesn't return it. However this sometimes happens when we're asked for
     // the nearest accessible to place holder content which we ignore.
     mAnchorNode = parent;
   }
 
-  return Next(aStopNode);
+  return Next();
 }
 
 Accessible*
 TreeWalker::Prev()
 {
   if (mStateStack.IsEmpty()) {
     if (mPhase == eAtStart || mPhase == eAtDOM) {
       mPhase = eAtStart;
@@ -283,17 +294,24 @@ TreeWalker::AccessibleFor(nsIContent* aN
       *aSkipSubtree = true;
       return nullptr;
     }
     return child;
   }
 
   // Create an accessible if allowed.
   if (!(aFlags & eWalkCache) && mContext->IsAcceptableChild(aNode)) {
-    if (mDoc->RelocateARIAOwnedIfNeeded(aNode)) {
+    // We may have ARIA owned element in the dependent attributes map, but the
+    // element may be not allowed for this ARIA owns relation, if the relation
+    // crosses out XBL anonymous content boundaries. In this case we won't
+    // create an accessible object for it, when aria-owns is processed, which
+    // may make the element subtree inaccessible. To avoid that let's create
+    // an accessible object now, and later, if allowed, move it in the tree,
+    // when aria-owns relation is processed.
+    if (mDoc->RelocateARIAOwnedIfNeeded(aNode) && !aNode->IsXULElement()) {
       *aSkipSubtree = true;
       return nullptr;
     }
     return GetAccService()->CreateAccessible(aNode, mContext, aSkipSubtree);
   }
 
   return nullptr;
 }
--- a/accessible/base/TreeWalker.h
+++ b/accessible/base/TreeWalker.h
@@ -45,29 +45,44 @@ public:
    * @param aAnchorNode [in] the node the search will be prepared relative to
    * @param aFlags   [in] flags (see enum above)
    */
   TreeWalker(Accessible* aContext, nsIContent* aAnchorNode, uint32_t aFlags = eWalkCache);
 
   ~TreeWalker();
 
   /**
-   * Clears the tree walker state and resets it to the given child within
-   * the anchor.
+   * Resets the walker state, and sets the given node as an anchor. Returns a
+   * first accessible element within the node including the node itself.
+   */
+  Accessible* Scope(nsIContent* aAnchorNode);
+
+  /**
+   * Resets the walker state.
+   */
+  void Reset()
+  {
+    mPhase = eAtStart;
+    mStateStack.Clear();
+    mARIAOwnsIdx = 0;
+  }
+
+  /**
+   * Sets the walker state to the given child node if it's within the anchor.
    */
   bool Seek(nsIContent* aChildNode);
 
   /**
    * Return the next/prev accessible.
    *
    * @note Returned accessible is bound to the document, if the accessible is
    *       rejected during tree creation then the caller should be unbind it
    *       from the document.
    */
-  Accessible* Next(nsIContent* aStopNode = nullptr);
+  Accessible* Next();
   Accessible* Prev();
 
   Accessible* Context() const { return mContext; }
   DocAccessible* Document() const { return mDoc; }
 
 private:
   TreeWalker();
   TreeWalker(const TreeWalker&);
--- a/accessible/base/moz.build
+++ b/accessible/base/moz.build
@@ -1,9 +1,9 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# -*- 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/.
 
 EXPORTS += [
     'AccEvent.h',
     'nsAccessibilityService.h'
@@ -58,16 +58,30 @@ 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 += [
+        '/accessible/ipc/other',
+    ]
+
+LOCAL_INCLUDES += [
     '/accessible/xpcom',
     '/accessible/xul',
     '/dom/base',
     '/dom/xbl',
     '/ipc/chromium/src',
     '/layout/generic',
     '/layout/style',
     '/layout/svg',
--- 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
@@ -15,17 +15,16 @@
 #include "HTMLElementAccessibles.h"
 #include "HTMLImageMapAccessible.h"
 #include "HTMLLinkAccessible.h"
 #include "HTMLListAccessible.h"
 #include "HTMLSelectAccessible.h"
 #include "HTMLTableAccessibleWrap.h"
 #include "HyperTextAccessibleWrap.h"
 #include "RootAccessible.h"
-#include "nsAccessiblePivot.h"
 #include "nsAccUtils.h"
 #include "nsArrayUtils.h"
 #include "nsAttrName.h"
 #include "nsEventShell.h"
 #include "nsIURI.h"
 #include "OuterDocAccessible.h"
 #include "Platform.h"
 #include "Role.h"
@@ -40,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"
@@ -259,26 +259,26 @@ static const MarkupMapInfo sMarkupMapLis
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessibilityService
 ////////////////////////////////////////////////////////////////////////////////
 
 nsAccessibilityService *nsAccessibilityService::gAccessibilityService = nullptr;
 ApplicationAccessible* nsAccessibilityService::gApplicationAccessible = nullptr;
 xpcAccessibleApplication* nsAccessibilityService::gXPCApplicationAccessible = nullptr;
-bool nsAccessibilityService::gIsShutdown = true;
+uint32_t nsAccessibilityService::gConsumers = 0;
 
 nsAccessibilityService::nsAccessibilityService() :
   DocManager(), FocusManager(), mMarkupMaps(ArrayLength(sMarkupMapList))
 {
 }
 
 nsAccessibilityService::~nsAccessibilityService()
 {
-  NS_ASSERTION(gIsShutdown, "Accessibility wasn't shutdown!");
+  NS_ASSERTION(IsShutdown(), "Accessibility wasn't shutdown!");
   gAccessibilityService = nullptr;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsIListenerChangeListener
 
 NS_IMETHODIMP
 nsAccessibilityService::ListenersChanged(nsIArray* aEventChanges)
@@ -312,41 +312,36 @@ 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;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsISupports
 
 NS_IMPL_ISUPPORTS_INHERITED(nsAccessibilityService,
                             DocManager,
-                            nsIAccessibilityService,
-                            nsIAccessibleRetrieval,
                             nsIObserver,
                             nsIListenerChangeListener,
                             nsISelectionListener) // from SelectionManager
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsIObserver
 
 NS_IMETHODIMP
@@ -354,39 +349,34 @@ nsAccessibilityService::Observe(nsISuppo
                          const char16_t *aData)
 {
   if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID))
     Shutdown();
 
   return NS_OK;
 }
 
-// nsIAccessibilityService
 void
 nsAccessibilityService::NotifyOfAnchorJumpTo(nsIContent* aTargetNode)
 {
   nsIDocument* documentNode = aTargetNode->GetUncomposedDoc();
   if (documentNode) {
     DocAccessible* document = GetDocAccessible(documentNode);
     if (document)
       document->SetAnchorJump(aTargetNode);
   }
 }
 
-// nsIAccessibilityService
 void
 nsAccessibilityService::FireAccessibleEvent(uint32_t aEvent,
                                             Accessible* aTarget)
 {
   nsEventShell::FireEvent(aEvent, aTarget);
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// nsIAccessibilityService
-
 Accessible*
 nsAccessibilityService::GetRootDocumentAccessible(nsIPresShell* aPresShell,
                                                   bool aCanCreate)
 {
   nsIPresShell* ps = aPresShell;
   nsIDocument* documentNode = aPresShell->GetDocument();
   if (documentNode) {
     nsCOMPtr<nsIDocShellTreeItem> treeItem(documentNode->GetDocShell());
@@ -408,21 +398,21 @@ 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_IMETHODIMP Notify(nsITimer* aTimer) final
+  NS_IMETHOD Notify(nsITimer* aTimer) final
   {
     if (!mContent->IsInUncomposedDoc())
       return NS_OK;
 
     nsIPresShell* ps = mContent->OwnerDoc()->GetShell();
     if (ps) {
       DocAccessible* doc = ps->GetDocAccessible();
       if (doc) {
@@ -600,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
     }
   }
 
@@ -732,301 +723,248 @@ void
 nsAccessibilityService::RecreateAccessible(nsIPresShell* aPresShell,
                                            nsIContent* aContent)
 {
   DocAccessible* document = GetDocAccessible(aPresShell);
   if (document)
     document->RecreateAccessible(aContent);
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// nsIAccessibleRetrieval
-
-NS_IMETHODIMP
-nsAccessibilityService::GetApplicationAccessible(nsIAccessible** aAccessibleApplication)
-{
-  NS_ENSURE_ARG_POINTER(aAccessibleApplication);
-
-  NS_IF_ADDREF(*aAccessibleApplication = XPCApplicationAcc());
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsAccessibilityService::GetAccessibleFor(nsIDOMNode *aNode,
-                                         nsIAccessible **aAccessible)
-{
-  NS_ENSURE_ARG_POINTER(aAccessible);
-  *aAccessible = nullptr;
-  if (!aNode)
-    return NS_OK;
-
-  nsCOMPtr<nsINode> node(do_QueryInterface(aNode));
-  if (!node)
-    return NS_ERROR_INVALID_ARG;
-
-  DocAccessible* document = GetDocAccessible(node->OwnerDoc());
-  if (document)
-    NS_IF_ADDREF(*aAccessible = ToXPC(document->GetAccessible(node)));
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
+void
 nsAccessibilityService::GetStringRole(uint32_t aRole, nsAString& aString)
 {
 #define ROLE(geckoRole, stringRole, atkRole, \
              macRole, msaaRole, ia2Role, nameRule) \
   case roles::geckoRole: \
     CopyUTF8toUTF16(stringRole, aString); \
-    return NS_OK;
+    return;
 
   switch (aRole) {
 #include "RoleMap.h"
     default:
       aString.AssignLiteral("unknown");
-      return NS_OK;
+      return;
   }
 
 #undef ROLE
 }
 
-NS_IMETHODIMP
+void
 nsAccessibilityService::GetStringStates(uint32_t aState, uint32_t aExtraState,
-                                        nsISupports **aStringStates)
+                                        nsISupports** aStringStates)
+{
+  RefPtr<DOMStringList> stringStates = 
+    GetStringStates(nsAccUtils::To64State(aState, aExtraState));
+
+  // 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();
 
-  uint64_t state = nsAccUtils::To64State(aState, aExtraState);
-
-  // states
-  if (state & states::UNAVAILABLE)
+  if (aStates & states::UNAVAILABLE) {
     stringStates->Add(NS_LITERAL_STRING("unavailable"));
-  if (state & states::SELECTED)
+  }
+  if (aStates & states::SELECTED) {
     stringStates->Add(NS_LITERAL_STRING("selected"));
-  if (state & states::FOCUSED)
+  }
+  if (aStates & states::FOCUSED) {
     stringStates->Add(NS_LITERAL_STRING("focused"));
-  if (state & states::PRESSED)
+  }
+  if (aStates & states::PRESSED) {
     stringStates->Add(NS_LITERAL_STRING("pressed"));
-  if (state & states::CHECKED)
+  }
+  if (aStates & states::CHECKED) {
     stringStates->Add(NS_LITERAL_STRING("checked"));
-  if (state & states::MIXED)
+  }
+  if (aStates & states::MIXED) {
     stringStates->Add(NS_LITERAL_STRING("mixed"));
-  if (state & states::READONLY)
+  }
+  if (aStates & states::READONLY) {
     stringStates->Add(NS_LITERAL_STRING("readonly"));
-  if (state & states::HOTTRACKED)
+  }
+  if (aStates & states::HOTTRACKED) {
     stringStates->Add(NS_LITERAL_STRING("hottracked"));
-  if (state & states::DEFAULT)
+  }
+  if (aStates & states::DEFAULT) {
     stringStates->Add(NS_LITERAL_STRING("default"));
-  if (state & states::EXPANDED)
+  }
+  if (aStates & states::EXPANDED) {
     stringStates->Add(NS_LITERAL_STRING("expanded"));
-  if (state & states::COLLAPSED)
+  }
+  if (aStates & states::COLLAPSED) {
     stringStates->Add(NS_LITERAL_STRING("collapsed"));
-  if (state & states::BUSY)
+  }
+  if (aStates & states::BUSY) {
     stringStates->Add(NS_LITERAL_STRING("busy"));
-  if (state & states::FLOATING)
+  }
+  if (aStates & states::FLOATING) {
     stringStates->Add(NS_LITERAL_STRING("floating"));
-  if (state & states::ANIMATED)
+  }
+  if (aStates & states::ANIMATED) {
     stringStates->Add(NS_LITERAL_STRING("animated"));
-  if (state & states::INVISIBLE)
+  }
+  if (aStates & states::INVISIBLE) {
     stringStates->Add(NS_LITERAL_STRING("invisible"));
-  if (state & states::OFFSCREEN)
+  }
+  if (aStates & states::OFFSCREEN) {
     stringStates->Add(NS_LITERAL_STRING("offscreen"));
-  if (state & states::SIZEABLE)
+  }
+  if (aStates & states::SIZEABLE) {
     stringStates->Add(NS_LITERAL_STRING("sizeable"));
-  if (state & states::MOVEABLE)
+  }
+  if (aStates & states::MOVEABLE) {
     stringStates->Add(NS_LITERAL_STRING("moveable"));
-  if (state & states::SELFVOICING)
+  }
+  if (aStates & states::SELFVOICING) {
     stringStates->Add(NS_LITERAL_STRING("selfvoicing"));
-  if (state & states::FOCUSABLE)
+  }
+  if (aStates & states::FOCUSABLE) {
     stringStates->Add(NS_LITERAL_STRING("focusable"));
-  if (state & states::SELECTABLE)
+  }
+  if (aStates & states::SELECTABLE) {
     stringStates->Add(NS_LITERAL_STRING("selectable"));
-  if (state & states::LINKED)
+  }
+  if (aStates & states::LINKED) {
     stringStates->Add(NS_LITERAL_STRING("linked"));
-  if (state & states::TRAVERSED)
+  }
+  if (aStates & states::TRAVERSED) {
     stringStates->Add(NS_LITERAL_STRING("traversed"));
-  if (state & states::MULTISELECTABLE)
+  }
+  if (aStates & states::MULTISELECTABLE) {
     stringStates->Add(NS_LITERAL_STRING("multiselectable"));
-  if (state & states::EXTSELECTABLE)
+  }
+  if (aStates & states::EXTSELECTABLE) {
     stringStates->Add(NS_LITERAL_STRING("extselectable"));
-  if (state & states::PROTECTED)
+  }
+  if (aStates & states::PROTECTED) {
     stringStates->Add(NS_LITERAL_STRING("protected"));
-  if (state & states::HASPOPUP)
+  }
+  if (aStates & states::HASPOPUP) {
     stringStates->Add(NS_LITERAL_STRING("haspopup"));
-  if (state & states::REQUIRED)
+  }
+  if (aStates & states::REQUIRED) {
     stringStates->Add(NS_LITERAL_STRING("required"));
-  if (state & states::ALERT)
+  }
+  if (aStates & states::ALERT) {
     stringStates->Add(NS_LITERAL_STRING("alert"));
-  if (state & states::INVALID)
+  }
+  if (aStates & states::INVALID) {
     stringStates->Add(NS_LITERAL_STRING("invalid"));
-  if (state & states::CHECKABLE)
+  }
+  if (aStates & states::CHECKABLE) {
     stringStates->Add(NS_LITERAL_STRING("checkable"));
-
-  // extraStates
-  if (state & states::SUPPORTS_AUTOCOMPLETION)
+  }
+  if (aStates & states::SUPPORTS_AUTOCOMPLETION) {
     stringStates->Add(NS_LITERAL_STRING("autocompletion"));
-  if (state & states::DEFUNCT)
+  }
+  if (aStates & states::DEFUNCT) {
     stringStates->Add(NS_LITERAL_STRING("defunct"));
-  if (state & states::SELECTABLE_TEXT)
+  }
+  if (aStates & states::SELECTABLE_TEXT) {
     stringStates->Add(NS_LITERAL_STRING("selectable text"));
-  if (state & states::EDITABLE)
+  }
+  if (aStates & states::EDITABLE) {
     stringStates->Add(NS_LITERAL_STRING("editable"));
-  if (state & states::ACTIVE)
+  }
+  if (aStates & states::ACTIVE) {
     stringStates->Add(NS_LITERAL_STRING("active"));
-  if (state & states::MODAL)
+  }
+  if (aStates & states::MODAL) {
     stringStates->Add(NS_LITERAL_STRING("modal"));
-  if (state & states::MULTI_LINE)
+  }
+  if (aStates & states::MULTI_LINE) {
     stringStates->Add(NS_LITERAL_STRING("multi line"));
-  if (state & states::HORIZONTAL)
+  }
+  if (aStates & states::HORIZONTAL) {
     stringStates->Add(NS_LITERAL_STRING("horizontal"));
-  if (state & states::OPAQUE1)
+  }
+  if (aStates & states::OPAQUE1) {
     stringStates->Add(NS_LITERAL_STRING("opaque"));
-  if (state & states::SINGLE_LINE)
+  }
+  if (aStates & states::SINGLE_LINE) {
     stringStates->Add(NS_LITERAL_STRING("single line"));
-  if (state & states::TRANSIENT)
+  }
+  if (aStates & states::TRANSIENT) {
     stringStates->Add(NS_LITERAL_STRING("transient"));
-  if (state & states::VERTICAL)
+  }
+  if (aStates & states::VERTICAL) {
     stringStates->Add(NS_LITERAL_STRING("vertical"));
-  if (state & states::STALE)
+  }
+  if (aStates & states::STALE) {
     stringStates->Add(NS_LITERAL_STRING("stale"));
-  if (state & states::ENABLED)
+  }
+  if (aStates & states::ENABLED) {
     stringStates->Add(NS_LITERAL_STRING("enabled"));
-  if (state & states::SENSITIVE)
+  }
+  if (aStates & states::SENSITIVE) {
     stringStates->Add(NS_LITERAL_STRING("sensitive"));
-  if (state & states::EXPANDABLE)
+  }
+  if (aStates & states::EXPANDABLE) {
     stringStates->Add(NS_LITERAL_STRING("expandable"));
+  }
 
-  //unknown states
-  if (!stringStates->Length())
-    stringStates->Add(NS_LITERAL_STRING("unknown"));
-
-  stringStates.forget(aStringStates);
-  return NS_OK;
+  return stringStates.forget();
 }
 
-// nsIAccessibleRetrieval::getStringEventType()
-NS_IMETHODIMP
+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)) {
     aString.AssignLiteral("unknown");
-    return NS_OK;
+    return;
   }
 
   CopyUTF8toUTF16(kEventTypeNames[aEventType], aString);
-  return NS_OK;
 }
 
-// nsIAccessibleRetrieval::getStringRelationType()
-NS_IMETHODIMP
+void
 nsAccessibilityService::GetStringRelationType(uint32_t aRelationType,
                                               nsAString& aString)
 {
-  NS_ENSURE_ARG(aRelationType <= static_cast<uint32_t>(RelationType::LAST));
+  NS_ENSURE_TRUE_VOID(aRelationType <= static_cast<uint32_t>(RelationType::LAST));
 
 #define RELATIONTYPE(geckoType, geckoTypeName, atkType, msaaType, ia2Type) \
   case RelationType::geckoType: \
     aString.AssignLiteral(geckoTypeName); \
-    return NS_OK;
+    return;
 
   RelationType relationType = static_cast<RelationType>(aRelationType);
   switch (relationType) {
 #include "RelationTypeMap.h"
     default:
       aString.AssignLiteral("unknown");
-      return NS_OK;
+      return;
   }
 
 #undef RELATIONTYPE
 }
 
-NS_IMETHODIMP
-nsAccessibilityService::GetAccessibleFromCache(nsIDOMNode* aNode,
-                                               nsIAccessible** aAccessible)
-{
-  NS_ENSURE_ARG_POINTER(aAccessible);
-  *aAccessible = nullptr;
-  if (!aNode)
-    return NS_OK;
-
-  nsCOMPtr<nsINode> node(do_QueryInterface(aNode));
-  if (!node)
-    return NS_ERROR_INVALID_ARG;
-
-  // Search for an accessible in each of our per document accessible object
-  // caches. If we don't find it, and the given node is itself a document, check
-  // our cache of document accessibles (document cache). Note usually shutdown
-  // document accessibles are not stored in the document cache, however an
-  // "unofficially" shutdown document (i.e. not from DocManager) can still
-  // exist in the document cache.
-  Accessible* accessible = FindAccessibleInCache(node);
-  if (!accessible) {
-    nsCOMPtr<nsIDocument> document(do_QueryInterface(node));
-    if (document)
-      accessible = GetExistingDocAccessible(document);
-  }
-
-  NS_IF_ADDREF(*aAccessible = ToXPC(accessible));
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsAccessibilityService::CreateAccessiblePivot(nsIAccessible* aRoot,
-                                              nsIAccessiblePivot** aPivot)
-{
-  NS_ENSURE_ARG_POINTER(aPivot);
-  NS_ENSURE_ARG(aRoot);
-  *aPivot = nullptr;
-
-  Accessible* accessibleRoot = aRoot->ToInternalAccessible();
-  NS_ENSURE_TRUE(accessibleRoot, NS_ERROR_INVALID_ARG);
-
-  nsAccessiblePivot* pivot = new nsAccessiblePivot(accessibleRoot);
-  NS_ADDREF(*aPivot = pivot);
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsAccessibilityService::SetLogging(const nsACString& aModules)
-{
-#ifdef A11Y_LOG
-  logging::Enable(PromiseFlatCString(aModules));
-#endif
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsAccessibilityService::IsLogged(const nsAString& aModule, bool* aIsLogged)
-{
-  NS_ENSURE_ARG_POINTER(aIsLogged);
-  *aIsLogged = false;
-
-#ifdef A11Y_LOG
-  *aIsLogged = logging::IsEnabled(aModule);
-#endif
-
-  return NS_OK;
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessibilityService public
 
 Accessible*
 nsAccessibilityService::CreateAccessible(nsINode* aNode,
                                          Accessible* aContext,
                                          bool* aIsSubtreeHidden)
 {
   MOZ_ASSERT(aContext, "No context provided");
   MOZ_ASSERT(aNode, "No node to create an accessible for");
-  MOZ_ASSERT(!gIsShutdown, "No creation after shutdown");
+  MOZ_ASSERT(gConsumers, "No creation after shutdown");
 
   if (aIsSubtreeHidden)
     *aIsSubtreeHidden = false;
 
   DocAccessible* document = aContext->Document();
   MOZ_ASSERT(!document->GetAccessible(aNode),
              "We already have an accessible for this node.");
 
@@ -1228,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);
       }
 
@@ -1322,48 +1260,71 @@ nsAccessibilityService::Init()
   for (uint32_t i = 0; i < ArrayLength(sMarkupMapList); i++)
     mMarkupMaps.Put(*sMarkupMapList[i].tag, &sMarkupMapList[i]);
 
 #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"));
 #endif
 
 #ifdef XP_WIN
   sPendingPlugins = new nsTArray<nsCOMPtr<nsIContent> >;
   sPluginTimers = new nsTArray<nsCOMPtr<nsITimer> >;
 #endif
 
-  gIsShutdown = false;
-
   // Now its safe to start platform accessibility.
   if (XRE_IsParentProcess())
     PlatformInit();
 
+  statistics::A11yInitialized();
+
   return true;
 }
 
 void
 nsAccessibilityService::Shutdown()
 {
+  // Application is going to be closed, shutdown accessibility and mark
+  // accessibility service as shutdown to prevent calls of its methods.
+  // Don't null accessibility service static member at this point to be safe
+  // if someone will try to operate with it.
+
+  MOZ_ASSERT(gConsumers, "Accessibility was shutdown already");
+
+  gConsumers = 0;
+
   // Remove observers.
   nsCOMPtr<nsIObserverService> observerService =
       mozilla::services::GetObserverService();
   if (observerService) {
     observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
 
     static const char16_t kShutdownIndicator[] = { '0', 0 };
     observerService->NotifyObservers(nullptr, "a11y-init-or-shutdown", kShutdownIndicator);
@@ -1379,34 +1340,28 @@ nsAccessibilityService::Shutdown()
 
   uint32_t timerCount = sPluginTimers->Length();
   for (uint32_t i = 0; i < timerCount; i++)
     sPluginTimers->ElementAt(i)->Cancel();
 
   sPluginTimers = nullptr;
 #endif
 
-  // Application is going to be closed, shutdown accessibility and mark
-  // accessibility service as shutdown to prevent calls of its methods.
-  // Don't null accessibility service static member at this point to be safe
-  // if someone will try to operate with it.
-
-  NS_ASSERTION(!gIsShutdown, "Accessibility was shutdown already");
-
-  gIsShutdown = true;
-
   if (XRE_IsParentProcess())
     PlatformShutdown();
 
   gApplicationAccessible->Shutdown();
   NS_RELEASE(gApplicationAccessible);
   gApplicationAccessible = nullptr;
 
   NS_IF_RELEASE(gXPCApplicationAccessible);
   gXPCApplicationAccessible = nullptr;
+
+  NS_RELEASE(gAccessibilityService);
+  gAccessibilityService = nullptr;
 }
 
 already_AddRefed<Accessible>
 nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
                                                DocAccessible* aDoc)
 {
   nsAutoString role;
   nsCoreUtils::XBLBindingRole(aContent, role);
@@ -1751,19 +1706,16 @@ nsAccessibilityService::MarkupAttributes
 
       continue;
     }
 
     nsAccUtils::SetAccAttr(aAttributes, *info->name, *info->value);
   }
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// nsIAccessibilityService (DON'T put methods here)
-
 Accessible*
 nsAccessibilityService::AddNativeRootAccessible(void* aAtkAccessible)
 {
 #ifdef MOZ_ACCESSIBILITY_ATK
   ApplicationAccessible* applicationAcc = ApplicationAcc();
   if (!applicationAcc)
     return nullptr;
 
@@ -1798,48 +1750,16 @@ nsAccessibilityService::HasAccessible(ns
   DocAccessible* document = GetDocAccessible(node->OwnerDoc());
   if (!document)
     return false;
 
   return document->HasAccessible(node);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// NS_GetAccessibilityService
-////////////////////////////////////////////////////////////////////////////////
-
-/**
- * Return accessibility service; creating one if necessary.
- */
-nsresult
-NS_GetAccessibilityService(nsIAccessibilityService** aResult)
-{
-  NS_ENSURE_TRUE(aResult, NS_ERROR_NULL_POINTER);
-  *aResult = nullptr;
-
-  if (nsAccessibilityService::gAccessibilityService) {
-    NS_ADDREF(*aResult = nsAccessibilityService::gAccessibilityService);
-    return NS_OK;
-  }
-
-  RefPtr<nsAccessibilityService> service = new nsAccessibilityService();
-  NS_ENSURE_TRUE(service, NS_ERROR_OUT_OF_MEMORY);
-
-  if (!service->Init()) {
-    service->Shutdown();
-    return NS_ERROR_FAILURE;
-  }
-
-  statistics::A11yInitialized();
-
-  NS_ADDREF(*aResult = service);
-  return NS_OK;
-}
-
-////////////////////////////////////////////////////////////////////////////////
 // nsAccessibilityService private (DON'T put methods here)
 
 #ifdef MOZ_XUL
 already_AddRefed<Accessible>
 nsAccessibilityService::CreateAccessibleForXULTree(nsIContent* aContent,
                                                    DocAccessible* aDoc)
 {
   nsIContent* child = nsTreeUtils::GetDescendantChild(aContent,
@@ -1864,16 +1784,60 @@ nsAccessibilityService::CreateAccessible
 
   // Table or tree table accessible.
   RefPtr<Accessible> accessible =
     new XULTreeGridAccessibleWrap(aContent, aDoc, treeFrame);
   return accessible.forget();
 }
 #endif
 
+nsAccessibilityService*
+GetOrCreateAccService(uint32_t aNewConsumer)
+{
+  if (!nsAccessibilityService::gAccessibilityService) {
+    RefPtr<nsAccessibilityService> service = new nsAccessibilityService();
+    if (!service->Init()) {
+      service->Shutdown();
+      return nullptr;
+    }
+  }
+
+  MOZ_ASSERT(nsAccessibilityService::gAccessibilityService,
+             "Accessible service is not initialized.");
+  nsAccessibilityService::gConsumers |= aNewConsumer;
+  return nsAccessibilityService::gAccessibilityService;
+}
+
+void
+MaybeShutdownAccService(uint32_t aFormerConsumer)
+{
+  nsAccessibilityService* accService =
+    nsAccessibilityService::gAccessibilityService;
+
+  if (!accService || accService->IsShutdown()) {
+    return;
+  }
+
+  if (nsCoreUtils::AccEventObserversExist() ||
+      xpcAccessibilityService::IsInUse() ||
+      accService->HasXPCDocuments()) {
+    // Still used by XPCOM
+    nsAccessibilityService::gConsumers =
+      (nsAccessibilityService::gConsumers & ~aFormerConsumer) |
+      nsAccessibilityService::eXPCOM;
+    return;
+  }
+
+  if (nsAccessibilityService::gConsumers & ~aFormerConsumer) {
+    nsAccessibilityService::gConsumers &= ~aFormerConsumer;
+  } else {
+    accService->Shutdown(); // Will unset all nsAccessibilityService::gConsumers
+  }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Services
 ////////////////////////////////////////////////////////////////////////////////
 
 namespace mozilla {
 namespace a11y {
 
 FocusManager*
--- a/accessible/base/nsAccessibilityService.h
+++ b/accessible/base/nsAccessibilityService.h
@@ -1,34 +1,39 @@
 /* -*- 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/. */
 
 #ifndef __nsAccessibilityService_h__
 #define __nsAccessibilityService_h__
 
-#include "nsIAccessibilityService.h"
-
 #include "mozilla/a11y/DocManager.h"
 #include "mozilla/a11y/FocusManager.h"
 #include "mozilla/a11y/Role.h"
 #include "mozilla/a11y/SelectionManager.h"
 #include "mozilla/Preferences.h"
 
 #include "nsIObserver.h"
+#include "nsIAccessibleEvent.h"
 #include "nsIEventListenerService.h"
+#include "xpcAccessibilityService.h"
 
 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.
  */
@@ -63,50 +68,70 @@ struct MarkupMapInfo {
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 class nsAccessibilityService final : public mozilla::a11y::DocManager,
                                      public mozilla::a11y::FocusManager,
                                      public mozilla::a11y::SelectionManager,
-                                     public nsIAccessibilityService,
                                      public nsIListenerChangeListener,
                                      public nsIObserver
 {
 public:
   typedef mozilla::a11y::Accessible Accessible;
   typedef mozilla::a11y::DocAccessible DocAccessible;
 
   // nsIListenerChangeListener
   NS_IMETHOD ListenersChanged(nsIArray* aEventChanges) override;
 
 protected:
-  virtual ~nsAccessibilityService();
+  ~nsAccessibilityService();
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIACCESSIBLERETRIEVAL
   NS_DECL_NSIOBSERVER
 
-  // nsIAccessibilityService
-  virtual Accessible* GetRootDocumentAccessible(nsIPresShell* aPresShell,
-                                                bool aCanCreate) override;
+  Accessible* GetRootDocumentAccessible(nsIPresShell* aPresShell,
+                                        bool aCanCreate);
   already_AddRefed<Accessible>
     CreatePluginAccessible(nsPluginFrame* aFrame, nsIContent* aContent,
                            Accessible* aContext);
 
   /**
    * Adds/remove ATK root accessible for gtk+ native window to/from children
    * of the application accessible.
    */
-  virtual Accessible* AddNativeRootAccessible(void* aAtkAccessible) override;
-  virtual void RemoveNativeRootAccessible(Accessible* aRootAccessible) override;
+  Accessible* AddNativeRootAccessible(void* aAtkAccessible);
+  void RemoveNativeRootAccessible(Accessible* aRootAccessible);
+
+  bool HasAccessible(nsIDOMNode* aDOMNode);
+
+  /**
+   * Get a string equivalent for an accessilbe role value.
+   */
+  void GetStringRole(uint32_t aRole, nsAString& aString);
 
-  virtual bool HasAccessible(nsIDOMNode* aDOMNode) override;
+  /**
+   * 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);
+
+  /**
+   * Get a string equivalent for an accessible relation type.
+   */
+  void GetStringRelationType(uint32_t aRelationType, nsAString& aString);
 
   // nsAccesibilityService
   /**
    * Notification used to update the accessible tree when deck panel is
    * switched.
    */
   void DeckPanelSwitched(nsIPresShell* aPresShell, nsIContent* aDeckNode,
                          nsIFrame* aPrevBoxFrame, nsIFrame* aCurrentBoxFrame);
@@ -118,35 +143,35 @@ public:
   void ContentRangeInserted(nsIPresShell* aPresShell, nsIContent* aContainer,
                             nsIContent* aStartChild, nsIContent* aEndChild);
 
   /**
    * Notification used to update the accessible tree when content is removed.
    */
   void ContentRemoved(nsIPresShell* aPresShell, nsIContent* aChild);
 
-  virtual void UpdateText(nsIPresShell* aPresShell, nsIContent* aContent);
+  void UpdateText(nsIPresShell* aPresShell, nsIContent* aContent);
 
   /**
    * Update XUL:tree accessible tree when treeview is changed.
    */
   void TreeViewChanged(nsIPresShell* aPresShell, nsIContent* aContent,
                        nsITreeView* aView);
 
   /**
    * Notify of input@type="element" value change.
    */
   void RangeValueChanged(nsIPresShell* aPresShell, nsIContent* aContent);
 
   /**
    * Update list bullet accessible.
    */
-  virtual void UpdateListBullet(nsIPresShell* aPresShell,
-                                nsIContent* aHTMLListItemContent,
-                                bool aHasBullet);
+  void UpdateListBullet(nsIPresShell* aPresShell,
+                        nsIContent* aHTMLListItemContent,
+                        bool aHasBullet);
 
   /**
    * Update the image map.
    */
   void UpdateImageMap(nsImageFrame* aImageFrame);
 
   /**
    * Update the label accessible tree when rendered @value is changed.
@@ -158,31 +183,34 @@ public:
    * Notify accessibility that anchor jump has been accomplished to the given
    * target. Used by layout.
    */
   void NotifyOfAnchorJumpTo(nsIContent *aTarget);
 
   /**
    * Notify that presshell is activated.
    */
-  virtual void PresShellActivated(nsIPresShell* aPresShell);
+  void PresShellActivated(nsIPresShell* aPresShell);
 
   /**
    * Recreate an accessible for the given content node in the presshell.
    */
   void RecreateAccessible(nsIPresShell* aPresShell, nsIContent* aContent);
 
-  virtual void FireAccessibleEvent(uint32_t aEvent, Accessible* aTarget) override;
+  void FireAccessibleEvent(uint32_t aEvent, Accessible* aTarget);
 
   // nsAccessibiltiyService
 
   /**
    * Return true if accessibility service has been shutdown.
    */
-  static bool IsShutdown() { return gIsShutdown; }
+  static bool IsShutdown()
+  {
+    return gConsumers == 0;
+  };
 
   /**
    * Creates an accessible for the given DOM node.
    *
    * @param  aNode             [in] the given node
    * @param  aContext          [in] context the accessible is created in
    * @param  aIsSubtreeHidden  [out, optional] indicates whether the node's
    *                             frame and its subtree is hidden
@@ -198,19 +226,38 @@ public:
   }
 
   /**
    * Set the object attribute defined by markup for the given element.
    */
   void MarkupAttributes(const nsIContent* aContent,
                         nsIPersistentProperties* aAttributes) const;
 
+  /**
+   * A list of possible accessibility service consumers. Accessibility service
+   * can only be shut down when there are no remaining consumers.
+   *
+   * eXPCOM       - accessibility service is used by XPCOM.
+   *
+   * eMainProcess - accessibility service was started by main process in the
+   *                content process.
+   *
+   * ePlatformAPI - accessibility service is used by the platform api in the
+   *                main process.
+   */
+  enum ServiceConsumer
+  {
+    eXPCOM       = 1 << 0,
+    eMainProcess = 1 << 1,
+    ePlatformAPI = 1 << 2,
+  };
+
 private:
   // nsAccessibilityService creation is controlled by friend
-  // NS_GetAccessibilityService, keep constructors private.
+  // GetOrCreateAccService, keep constructors private.
   nsAccessibilityService();
   nsAccessibilityService(const nsAccessibilityService&);
   nsAccessibilityService& operator =(const nsAccessibilityService&);
 
 private:
   /**
    * Initialize accessibility service.
    */
@@ -249,57 +296,64 @@ private:
 
   /**
    * Reference for application accessible instance.
    */
   static mozilla::a11y::ApplicationAccessible* gApplicationAccessible;
   static mozilla::a11y::xpcAccessibleApplication* gXPCApplicationAccessible;
 
   /**
-   * Indicates whether accessibility service was shutdown.
+   * Contains a set of accessibility service consumers.
    */
-  static bool gIsShutdown;
+  static uint32_t gConsumers;
 
   nsDataHashtable<nsPtrHashKey<const nsIAtom>, const mozilla::a11y::MarkupMapInfo*> mMarkupMaps;
 
   friend nsAccessibilityService* GetAccService();
+  friend nsAccessibilityService* GetOrCreateAccService(uint32_t);
+  friend void MaybeShutdownAccService(uint32_t);
   friend mozilla::a11y::FocusManager* mozilla::a11y::FocusMgr();
   friend mozilla::a11y::SelectionManager* mozilla::a11y::SelectionMgr();
   friend mozilla::a11y::ApplicationAccessible* mozilla::a11y::ApplicationAcc();
   friend mozilla::a11y::xpcAccessibleApplication* mozilla::a11y::XPCApplicationAcc();
-
-  friend nsresult NS_GetAccessibilityService(nsIAccessibilityService** aResult);
+  friend class xpcAccessibilityService;
 };
 
 /**
  * Return the accessibility service instance. (Handy global function)
  */
 inline nsAccessibilityService*
 GetAccService()
 {
   return nsAccessibilityService::gAccessibilityService;
 }
 
 /**
+ * Return accessibility service instance; creating one if necessary.
+ */
+nsAccessibilityService* GetOrCreateAccService(
+  uint32_t aNewConsumer = nsAccessibilityService::ePlatformAPI);
+
+/**
+ * Shutdown accessibility service if needed.
+ */
+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
- * nsIAccessibleRetrieval::getStringEventType() method.
+ * nsAccessibilityService::GetStringEventType() method.
  */
 static const char kEventTypeNames[][40] = {
   "unknown",                                 //
   "show",                                    // EVENT_SHOW
   "hide",                                    // EVENT_HIDE
   "reorder",                                 // EVENT_REORDER
   "active decendent change",                 // EVENT_ACTIVE_DECENDENT_CHANGED
   "focus",                                   // EVENT_FOCUS
@@ -382,10 +436,9 @@ static const char kEventTypeNames[][40] 
   "hyperlink start index changed",           // EVENT_HYPERLINK_START_INDEX_CHANGED
   "hypertext changed",                       // EVENT_HYPERTEXT_CHANGED
   "hypertext links count changed",           // EVENT_HYPERTEXT_NLINKS_CHANGED
   "object attribute changed",                // EVENT_OBJECT_ATTRIBUTE_CHANGED
   "virtual cursor changed",                   // EVENT_VIRTUALCURSOR_CHANGED
   "text value change",                       // EVENT_TEXT_VALUE_CHANGE
 };
 
-#endif /* __nsIAccessibilityService_h__ */
-
+#endif
--- 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();
 
@@ -149,18 +152,23 @@ nsCoreUtils::DispatchMouseEvent(EventMes
   aPresShell->HandleEventWithTarget(&event, aFrame, aContent, &status);
 }
 
 void
 nsCoreUtils::DispatchTouchEvent(EventMessage aMessage, int32_t aX, int32_t aY,
                                 nsIContent* aContent, nsIFrame* aFrame,
                                 nsIPresShell* aPresShell, nsIWidget* aRootWidget)
 {
-  if (!dom::TouchEvent::PrefEnabled())
+  nsIDocShell* docShell = nullptr;
+  if (aPresShell->GetDocument()) {
+    docShell = aPresShell->GetDocument()->GetDocShell();
+  }
+  if (!dom::TouchEvent::PrefEnabled(docShell)) {
     return;
+  }
 
   WidgetTouchEvent event(true, aMessage, aRootWidget);
 
   event.mTime = PR_IntervalNow();
 
   // XXX: Touch has an identifier of -1 to hint that it is synthesized.
   RefPtr<dom::Touch> t = new dom::Touch(-1, LayoutDeviceIntPoint(aX, aY),
                                         LayoutDeviceIntPoint(1, 1), 0.0f, 1.0f);
@@ -479,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/base/nsEventShell.cpp
+++ b/accessible/base/nsEventShell.cpp
@@ -14,17 +14,17 @@ using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsEventShell
 ////////////////////////////////////////////////////////////////////////////////
 
 void
 nsEventShell::FireEvent(AccEvent* aEvent)
 {
-  if (!aEvent)
+  if (!aEvent || aEvent->mEventRule == AccEvent::eDoNotEmit)
     return;
 
   Accessible* accessible = aEvent->GetAccessible();
   NS_ENSURE_TRUE_VOID(accessible);
 
   nsINode* node = accessible->GetNode();
   if (node) {
     sEventTargetNode = node;
@@ -38,16 +38,17 @@ nsEventShell::FireEvent(AccEvent* aEvent
     GetAccService()->GetStringEventType(aEvent->GetEventType(), type);
     logging::MsgEntry("type: %s", NS_ConvertUTF16toUTF8(type).get());
     logging::AccessibleInfo("target", aEvent->GetAccessible());
     logging::MsgEnd();
   }
 #endif
 
   accessible->HandleAccEvent(aEvent);
+  aEvent->mEventRule = AccEvent::eDoNotEmit;
 
   sEventTargetNode = nullptr;
 }
 
 void
 nsEventShell::FireEvent(uint32_t aEventType, Accessible* aAccessible,
                         EIsFromUserInput aIsFromUserInput)
 {
--- a/accessible/base/nsTextEquivUtils.cpp
+++ b/accessible/base/nsTextEquivUtils.cpp
@@ -122,17 +122,17 @@ nsTextEquivUtils::AppendTextEquivFromTex
     if (parentContent) {
       nsIFrame *frame = parentContent->GetPrimaryFrame();
       if (frame) {
         // If this text is inside a block level frame (as opposed to span
         // level), we need to add spaces around that block's text, so we don't
         // get words jammed together in final name.
         const nsStyleDisplay* display = frame->StyleDisplay();
         if (display->IsBlockOutsideStyle() ||
-            display->mDisplay == NS_STYLE_DISPLAY_TABLE_CELL) {
+            display->mDisplay == StyleDisplay::TableCell) {
           isHTMLBlock = true;
           if (!aString->IsEmpty()) {
             aString->Append(char16_t(' '));
           }
         }
       }
     }
     
--- a/accessible/generic/Accessible-inl.h
+++ b/accessible/generic/Accessible-inl.h
@@ -6,77 +6,130 @@
 
 #ifndef mozilla_a11y_Accessible_inl_h_
 #define mozilla_a11y_Accessible_inl_h_
 
 #include "DocAccessible.h"
 #include "ARIAMap.h"
 #include "nsCoreUtils.h"
 
+#ifdef A11Y_LOG
+#include "Logging.h"
+#endif
+
 namespace mozilla {
 namespace a11y {
 
 inline mozilla::a11y::role
 Accessible::Role()
 {
-  if (!mRoleMapEntry || mRoleMapEntry->roleRule != kUseMapRole)
+  const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+  if (!roleMapEntry || roleMapEntry->roleRule != kUseMapRole)
     return ARIATransformRole(NativeRole());
 
-  return ARIATransformRole(mRoleMapEntry->role);
+  return ARIATransformRole(roleMapEntry->role);
+}
+
+inline bool
+Accessible::HasARIARole() const
+{
+  return mRoleMapEntryIndex != aria::NO_ROLE_MAP_ENTRY_INDEX;
 }
 
 inline bool
 Accessible::IsARIARole(nsIAtom* aARIARole) const
 {
-  return mRoleMapEntry && mRoleMapEntry->Is(aARIARole);
+  const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+  return roleMapEntry && roleMapEntry->Is(aARIARole);
 }
 
 inline bool
 Accessible::HasStrongARIARole() const
 {
-  return mRoleMapEntry && mRoleMapEntry->roleRule == kUseMapRole;
+  const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+  return roleMapEntry && roleMapEntry->roleRule == kUseMapRole;
+}
+
+inline const nsRoleMapEntry*
+Accessible::ARIARoleMap() const
+{
+  return aria::GetRoleMapFromIndex(mRoleMapEntryIndex);
 }
 
 inline mozilla::a11y::role
 Accessible::ARIARole()
 {
-  if (!mRoleMapEntry || mRoleMapEntry->roleRule != kUseMapRole)
+  const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+  if (!roleMapEntry || roleMapEntry->roleRule != kUseMapRole)
     return mozilla::a11y::roles::NOTHING;
 
-  return ARIATransformRole(mRoleMapEntry->role);
+  return ARIATransformRole(roleMapEntry->role);
+}
+
+inline void
+Accessible::SetRoleMapEntry(const nsRoleMapEntry* aRoleMapEntry)
+{
+  mRoleMapEntryIndex = aria::GetIndexFromRoleMap(aRoleMapEntry);
 }
 
 inline bool
 Accessible::IsSearchbox() const
 {
-  return (mRoleMapEntry && mRoleMapEntry->Is(nsGkAtoms::searchbox)) ||
+  const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+  return (roleMapEntry && roleMapEntry->Is(nsGkAtoms::searchbox)) ||
     (mContent->IsHTMLElement(nsGkAtoms::input) &&
      mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
                            nsGkAtoms::textInputType, eCaseMatters));
 }
 
 inline bool
 Accessible::HasGenericType(AccGenericType aType) const
 {
+  const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
   return (mGenericTypes & aType) ||
-    (mRoleMapEntry && mRoleMapEntry->IsOfType(aType));
+    (roleMapEntry && roleMapEntry->IsOfType(aType));
 }
 
 inline bool
 Accessible::HasNumericValue() const
 {
   if (mStateFlags & eHasNumericValue)
     return true;
 
-  return mRoleMapEntry && mRoleMapEntry->valueRule != eNoValue;
+  const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+  return roleMapEntry && roleMapEntry->valueRule != eNoValue;
 }
 
 inline void
 Accessible::ScrollTo(uint32_t aHow) const
 {
   if (mContent)
     nsCoreUtils::ScrollTo(mDoc->PresShell(), mContent, aHow);
 }
 
+inline bool
+Accessible::InsertAfter(Accessible* aNewChild, Accessible* aRefChild)
+{
+  MOZ_ASSERT(aNewChild, "No new child to insert");
+
+  if (aRefChild && aRefChild->Parent() != this) {
+#ifdef A11Y_LOG
+    logging::TreeInfo("broken accessible tree", 0,
+                      "parent", this, "prev sibling parent",
+                      aRefChild->Parent(), "child", aNewChild, nullptr);
+    if (logging::IsEnabled(logging::eVerbose)) {
+      logging::Tree("TREE", "Document tree", mDoc);
+      logging::DOMTree("TREE", "DOM document tree", mDoc);
+    }
+#endif
+    MOZ_ASSERT_UNREACHABLE("Broken accessible tree");
+    mDoc->UnbindFromDocument(aNewChild);
+    return false;
+  }
+
+  return InsertChildAt(aRefChild ? aRefChild->IndexInParent() + 1 : 0,
+                       aNewChild);
+}
+
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -13,17 +13,16 @@
 #include "nsAccUtils.h"
 #include "nsAccessibilityService.h"
 #include "ApplicationAccessible.h"
 #include "NotificationController.h"
 #include "nsEventShell.h"
 #include "nsTextEquivUtils.h"
 #include "DocAccessibleChild.h"
 #include "EventTree.h"
-#include "Logging.h"
 #include "Relation.h"
 #include "Role.h"
 #include "RootAccessible.h"
 #include "States.h"
 #include "StyleInfo.h"
 #include "TableAccessible.h"
 #include "TableCellAccessible.h"
 #include "TreeWalker.h"
@@ -74,48 +73,55 @@
 #include "nsIDOMCharacterData.h"
 #endif
 
 #include "mozilla/Assertions.h"
 #include "mozilla/BasicEvents.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/MouseEvents.h"
-#include "mozilla/unused.h"
+#include "mozilla/Unused.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/CanvasRenderingContext2D.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/HTMLCanvasElement.h"
 #include "mozilla/dom/HTMLBodyElement.h"
 #include "mozilla/dom/TreeWalker.h"
 
 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),
-  mRoleMapEntry(nullptr)
+  mReorderEventTarget(false), mShowEventTarget(false), mHideEventTarget(false)
 {
   mBits.groupInfo = nullptr;
   mInt.mIndexOfEmbeddedChild = -1;
 }
 
 Accessible::~Accessible()
 {
   NS_ASSERTION(!mDoc, "LastRelease was never called!?!");
@@ -424,32 +430,33 @@ Accessible::NativeState()
       state |= states::FLOATING;
 
     // XXX we should look at layout for non XUL box frames, but need to decide
     // how that interacts with ARIA.
     if (HasOwnContent() && mContent->IsXULElement() && frame->IsXULBoxFrame()) {
       const nsStyleXUL* xulStyle = frame->StyleXUL();
       if (xulStyle && frame->IsXULBoxFrame()) {
         // In XUL all boxes are either vertical or horizontal
-        if (xulStyle->mBoxOrient == NS_STYLE_BOX_ORIENT_VERTICAL)
+        if (xulStyle->mBoxOrient == StyleBoxOrient::Vertical)
           state |= states::VERTICAL;
         else
           state |= states::HORIZONTAL;
       }
     }
   }
 
   // Check if a XUL element has the popup attribute (an attached popup menu).
   if (HasOwnContent() && mContent->IsXULElement() &&
       mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::popup))
     state |= states::HASPOPUP;
 
   // Bypass the link states specialization for non links.
-  if (!mRoleMapEntry || mRoleMapEntry->roleRule == kUseNativeRole ||
-      mRoleMapEntry->role == roles::LINK)
+  const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+  if (!roleMapEntry || roleMapEntry->roleRule == kUseNativeRole ||
+      roleMapEntry->role == roles::LINK)
     state |= NativeLinkState();
 
   return state;
 }
 
 uint64_t
 Accessible::NativeInteractiveState() const
 {
@@ -520,18 +527,17 @@ Accessible::ChildAtPoint(int32_t aX, int
   NS_ENSURE_TRUE(rootFrame, nullptr);
 
   nsIFrame* startFrame = rootFrame;
 
   // Check whether the point is at popup content.
   nsIWidget* rootWidget = rootFrame->GetView()->GetNearestWidget(nullptr);
   NS_ENSURE_TRUE(rootWidget, nullptr);
 
-  LayoutDeviceIntRect rootRect;
-  rootWidget->GetScreenBounds(rootRect);
+  LayoutDeviceIntRect rootRect = rootWidget->GetScreenBounds();
 
   WidgetMouseEvent dummyEvent(true, eMouseMove, rootWidget,
                               WidgetMouseEvent::eSynthesized);
   dummyEvent.mRefPoint = LayoutDeviceIntPoint(aX - rootRect.x, aY - rootRect.y);
 
   nsIFrame* popupFrame = nsLayoutUtils::
     GetPopupFrameForEventCoordinates(accDocument->PresContext()->GetRootPresContext(),
                                      &dummyEvent);
@@ -686,17 +692,17 @@ void
 Accessible::SetSelected(bool aSelect)
 {
   if (!HasOwnContent())
     return;
 
   Accessible* select = nsAccUtils::GetSelectableContainer(this, State());
   if (select) {
     if (select->State() & states::MULTISELECTABLE) {
-      if (mRoleMapEntry) {
+      if (ARIARoleMap()) {
         if (aSelect) {
           mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected,
                             NS_LITERAL_STRING("true"), true);
         } else {
           mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected, true);
         }
       }
       return;
@@ -850,47 +856,47 @@ Accessible::HandleAccEvent(AccEvent* aEv
 
         case nsIAccessibleEvent::EVENT_REORDER:
           // reorder events on the application acc aren't necessary to tell the parent
           // about new top level documents.
           if (!aEvent->GetAccessible()->IsApplication())
             ipcDoc->SendEvent(id, aEvent->GetEventType());
           break;
         case nsIAccessibleEvent::EVENT_STATE_CHANGE: {
-                                                       AccStateChangeEvent* event = downcast_accEvent(aEvent);
-                                                       ipcDoc->SendStateChangeEvent(id, event->GetState(),
-                                                                                    event->IsStateEnabled());
-                                                       break;
-                                                     }
+          AccStateChangeEvent* event = downcast_accEvent(aEvent);
+          ipcDoc->SendStateChangeEvent(id, event->GetState(),
+                                       event->IsStateEnabled());
+          break;
+        }
         case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED: {
           AccCaretMoveEvent* event = downcast_accEvent(aEvent);
           ipcDoc->SendCaretMoveEvent(id, event->GetCaretOffset());
           break;
         }
         case nsIAccessibleEvent::EVENT_TEXT_INSERTED:
         case nsIAccessibleEvent::EVENT_TEXT_REMOVED: {
           AccTextChangeEvent* event = downcast_accEvent(aEvent);
           ipcDoc->SendTextChangeEvent(id, event->ModifiedText(),
                                       event->GetStartOffset(),
                                       event->GetLength(),
                                       event->IsTextInserted(),
                                       event->IsFromUserInput());
           break;
-                                                     }
+        }
         case nsIAccessibleEvent::EVENT_SELECTION:
         case nsIAccessibleEvent::EVENT_SELECTION_ADD:
         case nsIAccessibleEvent::EVENT_SELECTION_REMOVE: {
           AccSelChangeEvent* selEvent = downcast_accEvent(aEvent);
           uint64_t widgetID = selEvent->Widget()->IsDoc() ? 0 :
             reinterpret_cast<uintptr_t>(selEvent->Widget());
           ipcDoc->SendSelectionEvent(id, widgetID, aEvent->GetEventType());
           break;
-                                                         }
+        }
         default:
-                                                         ipcDoc->SendEvent(id, aEvent->GetEventType());
+          ipcDoc->SendEvent(id, aEvent->GetEventType());
       }
     }
   }
 
   if (nsCoreUtils::AccEventObserversExist()) {
     nsCoreUtils::DispatchAccEvent(MakeXPCEvent(aEvent));
   }
 
@@ -925,26 +931,27 @@ Accessible::Attributes()
 
   if (IsARIAHidden()) {
     nsAccUtils::SetAccAttr(attributes, nsGkAtoms::hidden,
                            NS_LITERAL_STRING("true"));
   }
 
   // If there is no aria-live attribute then expose default value of 'live'
   // object attribute used for ARIA role of this accessible.
-  if (mRoleMapEntry) {
-    if (mRoleMapEntry->Is(nsGkAtoms::searchbox)) {
+  const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+  if (roleMapEntry) {
+    if (roleMapEntry->Is(nsGkAtoms::searchbox)) {
       nsAccUtils::SetAccAttr(attributes, nsGkAtoms::textInputType,
                              NS_LITERAL_STRING("search"));
     }
 
     nsAutoString live;
     nsAccUtils::GetAccAttr(attributes, nsGkAtoms::live, live);
     if (live.IsEmpty()) {
-      if (nsAccUtils::GetLiveAttrValue(mRoleMapEntry->liveAttRule, live))
+      if (nsAccUtils::GetLiveAttrValue(roleMapEntry->liveAttRule, live))
         nsAccUtils::SetAccAttr(attributes, nsGkAtoms::live, live);
     }
   }
 
   return attributes.forget();
 }
 
 already_AddRefed<nsIPersistentProperties>
@@ -1139,23 +1146,24 @@ Accessible::State()
 
   uint64_t state = NativeState();
   // Apply ARIA states to be sure accessible states will be overridden.
   ApplyARIAState(&state);
 
   // If this is an ARIA item of the selectable widget and if it's focused and
   // not marked unselected explicitly (i.e. aria-selected="false") then expose
   // it as selected to make ARIA widget authors life easier.
-  if (mRoleMapEntry && !(state & states::SELECTED) &&
+  const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+  if (roleMapEntry && !(state & states::SELECTED) &&
       !mContent->AttrValueIs(kNameSpaceID_None,
                              nsGkAtoms::aria_selected,
                              nsGkAtoms::_false, eCaseMatters)) {
     // Special case for tabs: focused tab or focus inside related tab panel
     // implies selected state.
-    if (mRoleMapEntry->role == roles::PAGETAB) {
+    if (roleMapEntry->role == roles::PAGETAB) {
       if (state & states::FOCUSED) {
         state |= states::SELECTED;
       } else {
         // If focus is in a child of the tab panel surely the tab is selected!
         Relation rel = RelationByType(RelationType::LABEL_FOR);
         Accessible* relTarget = nullptr;
         while ((relTarget = rel.Next())) {
           if (relTarget->Role() == roles::PROPERTYPAGE &&
@@ -1218,22 +1226,23 @@ Accessible::ApplyARIAState(uint64_t* aSt
   if (!mContent->IsElement())
     return;
 
   dom::Element* element = mContent->AsElement();
 
   // Test for universal states first
   *aState |= aria::UniversalStatesFor(element);
 
-  if (mRoleMapEntry) {
+  const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+  if (roleMapEntry) {
 
     // We only force the readonly bit off if we have a real mapping for the aria
     // role. This preserves the ability for screen readers to use readonly
     // (primarily on the document) as the hint for creating a virtual buffer.
-    if (mRoleMapEntry->role != roles::NOTHING)
+    if (roleMapEntry->role != roles::NOTHING)
       *aState &= ~states::READONLY;
 
     if (mContent->HasID()) {
       // If has a role & ID and aria-activedescendant on the container, assume
       // focusable.
       const Accessible* ancestor = this;
       while ((ancestor = ancestor->Parent()) && !ancestor->IsDoc()) {
         dom::Element* el = ancestor->Elm();
@@ -1259,31 +1268,31 @@ Accessible::ApplyARIAState(uint64_t* aSt
     }
   }
 
   // special case: A native button element whose role got transformed by ARIA to a toggle button
   // Also applies to togglable button menus, like in the Dev Tools Web Console.
   if (IsButton() || IsMenuButton())
     aria::MapToState(aria::eARIAPressed, element, aState);
 
-  if (!mRoleMapEntry)
+  if (!roleMapEntry)
     return;
 
-  *aState |= mRoleMapEntry->state;
-
-  if (aria::MapToState(mRoleMapEntry->attributeMap1, element, aState) &&
-      aria::MapToState(mRoleMapEntry->attributeMap2, element, aState) &&
-      aria::MapToState(mRoleMapEntry->attributeMap3, element, aState))
-    aria::MapToState(mRoleMapEntry->attributeMap4, element, aState);
+  *aState |= roleMapEntry->state;
+
+  if (aria::MapToState(roleMapEntry->attributeMap1, element, aState) &&
+      aria::MapToState(roleMapEntry->attributeMap2, element, aState) &&
+      aria::MapToState(roleMapEntry->attributeMap3, element, aState))
+    aria::MapToState(roleMapEntry->attributeMap4, element, aState);
 
   // ARIA gridcell inherits editable/readonly states from the grid until it's
   // overridden.
-  if ((mRoleMapEntry->Is(nsGkAtoms::gridcell) ||
-       mRoleMapEntry->Is(nsGkAtoms::columnheader) ||
-       mRoleMapEntry->Is(nsGkAtoms::rowheader)) &&
+  if ((roleMapEntry->Is(nsGkAtoms::gridcell) ||
+       roleMapEntry->Is(nsGkAtoms::columnheader) ||
+       roleMapEntry->Is(nsGkAtoms::rowheader)) &&
       !(*aState & (states::READONLY | states::EDITABLE))) {
     const TableCellAccessible* cell = AsTableCell();
     if (cell) {
       TableAccessible* table = cell->Table();
       if (table) {
         Accessible* grid = table->AsAccessible();
         uint64_t gridState = 0;
         grid->ApplyARIAState(&gridState);
@@ -1291,39 +1300,40 @@ Accessible::ApplyARIAState(uint64_t* aSt
       }
     }
   }
 }
 
 void
 Accessible::Value(nsString& aValue)
 {
-  if (!mRoleMapEntry)
+  const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+  if (!roleMapEntry)
     return;
 
-  if (mRoleMapEntry->valueRule != eNoValue) {
+  if (roleMapEntry->valueRule != eNoValue) {
     // aria-valuenow is a number, and aria-valuetext is the optional text
     // equivalent. For the string value, we will try the optional text
     // equivalent first.
     if (!mContent->GetAttr(kNameSpaceID_None,
                            nsGkAtoms::aria_valuetext, aValue)) {
       mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_valuenow,
                         aValue);
     }
     return;
   }
 
   // Value of textbox is a textified subtree.
-  if (mRoleMapEntry->Is(nsGkAtoms::textbox)) {
+  if (roleMapEntry->Is(nsGkAtoms::textbox)) {
     nsTextEquivUtils::GetTextEquivFromSubtree(this, aValue);
     return;
   }
 
   // Value of combobox is a text of current or selected item.
-  if (mRoleMapEntry->Is(nsGkAtoms::combobox)) {
+  if (roleMapEntry->Is(nsGkAtoms::combobox)) {
     Accessible* option = CurrentItem();
     if (!option) {
       uint32_t childCount = ChildCount();
       for (uint32_t idx = 0; idx < childCount; idx++) {
         Accessible* child = mChildren.ElementAt(idx);
         if (child->IsListControl()) {
           option = child->GetSelectedItem(0);
           break;
@@ -1358,17 +1368,18 @@ double
 Accessible::CurValue() const
 {
   return AttrNumericValue(nsGkAtoms::aria_valuenow);
 }
 
 bool
 Accessible::SetCurValue(double aValue)
 {
-  if (!mRoleMapEntry || mRoleMapEntry->valueRule == eNoValue)
+  const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+  if (!roleMapEntry || roleMapEntry->valueRule == eNoValue)
     return false;
 
   const uint32_t kValueCannotChange = states::READONLY | states::UNAVAILABLE;
   if (State() & kValueCannotChange)
     return false;
 
   double checkValue = MinValue();
   if (!IsNaN(checkValue) && aValue < checkValue)
@@ -1432,18 +1443,19 @@ Accessible::ARIATransformRole(role aRole
   }
 
   return aRole;
 }
 
 nsIAtom*
 Accessible::LandmarkRole() const
 {
-  return mRoleMapEntry && mRoleMapEntry->IsOfType(eLandmark) ?
-    *(mRoleMapEntry->roleAtom) : nullptr;
+  const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+  return roleMapEntry && roleMapEntry->IsOfType(eLandmark) ?
+    *(roleMapEntry->roleAtom) : nullptr;
 }
 
 role
 Accessible::NativeRole()
 {
   return roles::NOTHING;
 }
 
@@ -1546,16 +1558,18 @@ Accessible::GetAtomicRegion() const
 }
 
 Relation
 Accessible::RelationByType(RelationType aType)
 {
   if (!HasOwnContent())
     return Relation();
 
+  const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+
   // Relationships are defined on the same content node that the role would be
   // defined on.
   switch (aType) {
     case RelationType::LABELLED_BY: {
       Relation rel(new IDRefsIterator(mDoc, mContent,
                                       nsGkAtoms::aria_labelledby));
       if (mContent->IsHTMLElement()) {
         rel.AppendIter(new HTMLLabelIterator(Document(), this));
@@ -1597,19 +1611,19 @@ Accessible::RelationByType(RelationType 
 
       return rel;
     }
 
     case RelationType::NODE_CHILD_OF: {
       Relation rel;
       // This is an ARIA tree or treegrid that doesn't use owns, so we need to
       // get the parent the hard way.
-      if (mRoleMapEntry && (mRoleMapEntry->role == roles::OUTLINEITEM ||
-                            mRoleMapEntry->role == roles::LISTITEM ||
-                            mRoleMapEntry->role == roles::ROW)) {
+      if (roleMapEntry && (roleMapEntry->role == roles::OUTLINEITEM ||
+                            roleMapEntry->role == roles::LISTITEM ||
+                            roleMapEntry->role == roles::ROW)) {
         rel.AppendTarget(GetGroupInfo()->ConceptualParent());
       }
 
       // If accessible is in its own Window, or is the root of a document,
       // then we should provide NODE_CHILD_OF relation so that MSAA clients
       // can easily get to true parent instead of getting to oleacc's
       // ROLE_WINDOW accessible which will prevent us from going up further
       // (because it is system generated and has no idea about the hierarchy
@@ -1625,23 +1639,23 @@ Accessible::RelationByType(RelationType 
       }
 
       return rel;
     }
 
     case RelationType::NODE_PARENT_OF: {
       // ARIA tree or treegrid can do the hierarchy by @aria-level, ARIA trees
       // also can be organized by groups.
-      if (mRoleMapEntry &&
-          (mRoleMapEntry->role == roles::OUTLINEITEM ||
-           mRoleMapEntry->role == roles::LISTITEM ||
-           mRoleMapEntry->role == roles::ROW ||
-           mRoleMapEntry->role == roles::OUTLINE ||
-           mRoleMapEntry->role == roles::LIST ||
-           mRoleMapEntry->role == roles::TREE_TABLE)) {
+      if (roleMapEntry &&
+          (roleMapEntry->role == roles::OUTLINEITEM ||
+           roleMapEntry->role == roles::LISTITEM ||
+           roleMapEntry->role == roles::ROW ||
+           roleMapEntry->role == roles::OUTLINE ||
+           roleMapEntry->role == roles::LIST ||
+           roleMapEntry->role == roles::TREE_TABLE)) {
         return Relation(new ItemIterator(this));
       }
 
       return Relation();
     }
 
     case RelationType::CONTROLLED_BY:
       return Relation(new RelatedAccIterator(Document(), mContent,
@@ -1735,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)
 {
@@ -1799,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;
@@ -2100,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.
@@ -2167,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;
@@ -2206,43 +2237,43 @@ Accessible::IndexInParent() const
   return mIndexInParent;
 }
 
 uint32_t
 Accessible::EmbeddedChildCount()
 {
   if (mStateFlags & eHasTextKids) {
     if (!mEmbeddedObjCollector)
-      mEmbeddedObjCollector = new EmbeddedObjCollector(this);
+      mEmbeddedObjCollector.reset(new EmbeddedObjCollector(this));
     return mEmbeddedObjCollector->Count();
   }
 
   return ChildCount();
 }
 
 Accessible*
 Accessible::GetEmbeddedChildAt(uint32_t aIndex)
 {
   if (mStateFlags & eHasTextKids) {
     if (!mEmbeddedObjCollector)
-      mEmbeddedObjCollector = new EmbeddedObjCollector(this);
-    return mEmbeddedObjCollector ?
+      mEmbeddedObjCollector.reset(new EmbeddedObjCollector(this));
+    return mEmbeddedObjCollector.get() ?
       mEmbeddedObjCollector->GetAccessibleAt(aIndex) : nullptr;
   }
 
   return GetChildAt(aIndex);
 }
 
 int32_t
 Accessible::GetIndexOfEmbeddedChild(Accessible* aChild)
 {
   if (mStateFlags & eHasTextKids) {
     if (!mEmbeddedObjCollector)
-      mEmbeddedObjCollector = new EmbeddedObjCollector(this);
-    return mEmbeddedObjCollector ?
+      mEmbeddedObjCollector.reset(new EmbeddedObjCollector(this));
+    return mEmbeddedObjCollector.get() ?
       mEmbeddedObjCollector->GetIndexAt(aChild) : -1;
   }
 
   return GetIndexOf(aChild);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // HyperLinkAccessible methods
@@ -2439,17 +2470,18 @@ Accessible::IsWidget() const
 bool
 Accessible::IsActiveWidget() const
 {
   if (FocusMgr()->HasDOMFocus(mContent))
     return true;
 
   // If text entry of combobox widget has a focus then the combobox widget is
   // active.
-  if (mRoleMapEntry && mRoleMapEntry->Is(nsGkAtoms::combobox)) {
+  const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+  if (roleMapEntry && roleMapEntry->Is(nsGkAtoms::combobox)) {
     uint32_t childCount = ChildCount();
     for (uint32_t idx = 0; idx < childCount; idx++) {
       Accessible* child = mChildren.ElementAt(idx);
       if (child->Role() == roles::ENTRY)
         return FocusMgr()->HasDOMFocus(child->GetContent());
     }
   }
 
@@ -2568,17 +2600,18 @@ Accessible::GetSiblingAtOffset(int32_t a
     *aError = NS_ERROR_UNEXPECTED;
 
   return child;
 }
 
 double
 Accessible::AttrNumericValue(nsIAtom* aAttr) const
 {
-  if (!mRoleMapEntry || mRoleMapEntry->valueRule == eNoValue)
+  const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+  if (!roleMapEntry || roleMapEntry->valueRule == eNoValue)
     return UnspecifiedNaN<double>();
 
   nsAutoString attrValue;
   if (!mContent->GetAttr(kNameSpaceID_None, aAttr, attrValue))
     return UnspecifiedNaN<double>();
 
   nsresult error = NS_OK;
   double value = attrValue.ToDouble(&error);
@@ -2598,19 +2631,20 @@ Accessible::GetActionRule() const
 
   // Has registered 'click' event handler.
   bool isOnclick = nsCoreUtils::HasClickListener(mContent);
 
   if (isOnclick)
     return eClickAction;
 
   // Get an action based on ARIA role.
-  if (mRoleMapEntry &&
-      mRoleMapEntry->actionRule != eNoAction)
-    return mRoleMapEntry->actionRule;
+  const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+  if (roleMapEntry &&
+      roleMapEntry->actionRule != eNoAction)
+    return roleMapEntry->actionRule;
 
   // Get an action based on ARIA attribute.
   if (nsAccUtils::HasDefinedARIAToken(mContent,
                                       nsGkAtoms::aria_expanded))
     return eExpandAction;
 
   return eNoAction;
 }
@@ -2757,46 +2791,46 @@ KeyBinding::ToPlatformFormat(nsAString& 
     stringBundleService->CreateBundle(
       "chrome://global-platform/locale/platformKeys.properties",
       getter_AddRefs(keyStringBundle));
 
   if (!keyStringBundle)
     return;
 
   nsAutoString separator;
-  keyStringBundle->GetStringFromName(MOZ_UTF16("MODIFIER_SEPARATOR"),
+  keyStringBundle->GetStringFromName(u"MODIFIER_SEPARATOR",
                                      getter_Copies(separator));
 
   nsAutoString modifierName;
   if (mModifierMask & kControl) {
-    keyStringBundle->GetStringFromName(MOZ_UTF16("VK_CONTROL"),
+    keyStringBundle->GetStringFromName(u"VK_CONTROL",
                                        getter_Copies(modifierName));
 
     aValue.Append(modifierName);
     aValue.Append(separator);
   }
 
   if (mModifierMask & kAlt) {
-    keyStringBundle->GetStringFromName(MOZ_UTF16("VK_ALT"),
+    keyStringBundle->GetStringFromName(u"VK_ALT",
                                        getter_Copies(modifierName));
 
     aValue.Append(modifierName);
     aValue.Append(separator);
   }
 
   if (mModifierMask & kShift) {
-    keyStringBundle->GetStringFromName(MOZ_UTF16("VK_SHIFT"),
+    keyStringBundle->GetStringFromName(u"VK_SHIFT",
                                        getter_Copies(modifierName));
 
     aValue.Append(modifierName);
     aValue.Append(separator);
   }
 
   if (mModifierMask & kMeta) {
-    keyStringBundle->GetStringFromName(MOZ_UTF16("VK_META"),
+    keyStringBundle->GetStringFromName(u"VK_META",
                                        getter_Copies(modifierName));
 
     aValue.Append(modifierName);
     aValue.Append(separator);
   }
 
   aValue.Append(mKey);
 }
--- a/accessible/generic/Accessible.h
+++ b/accessible/generic/Accessible.h
@@ -6,18 +6,20 @@
 #ifndef _Accessible_H_
 #define _Accessible_H_
 
 #include "mozilla/a11y/AccTypes.h"
 #include "mozilla/a11y/RelationType.h"
 #include "mozilla/a11y/Role.h"
 #include "mozilla/a11y/States.h"
 
-#include "nsAutoPtr.h"
+#include "mozilla/UniquePtr.h"
+
 #include "nsIContent.h"
+#include "nsIContentInlines.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsRefPtrHashtable.h"
 #include "nsRect.h"
 
 struct nsRoleMapEntry;
 
 struct nsRect;
@@ -48,17 +50,17 @@ class TableAccessible;
 class TableCellAccessible;
 class TextLeafAccessible;
 class XULLabelAccessible;
 class XULTreeAccessible;
 
 #ifdef A11Y_LOG
 namespace logging {
   typedef const char* (*GetTreePrefix)(void* aData, Accessible*);
-  void Tree(const char* aTitle, const char* aMsgText, DocAccessible* aDoc,
+  void Tree(const char* aTitle, const char* aMsgText, Accessible* aRoot,
             GetTreePrefix aPrefixFunc, void* GetTreePrefixData);
 };
 #endif
 
 /**
  * Name type flags.
  */
 enum ENameValueFlag {
@@ -224,24 +226,24 @@ public:
   /**
    * Return enumerated accessible role (see constants in Role.h).
    */
   mozilla::a11y::role Role();
 
   /**
    * Return true if ARIA role is specified on the element.
    */
-  bool HasARIARole() const { return mRoleMapEntry; }
+  bool HasARIARole() const;
   bool IsARIARole(nsIAtom* aARIARole) const;
   bool HasStrongARIARole() const;
 
   /**
    * Retrun ARIA role map if any.
    */
-  const nsRoleMapEntry* ARIARoleMap() const { return mRoleMapEntry; }
+  const nsRoleMapEntry* ARIARoleMap() const;
 
   /**
    * Return accessible role specified by ARIA (see constants in
    * roles).
    */
   mozilla::a11y::role ARIARole();
 
   /**
@@ -377,32 +379,31 @@ public:
   /**
    * Shutdown this accessible object.
    */
   virtual void Shutdown();
 
   /**
    * Set the ARIA role map entry for a new accessible.
    */
-  void SetRoleMapEntry(const nsRoleMapEntry* aRoleMapEntry)
-    { mRoleMapEntry = aRoleMapEntry; }
+  void SetRoleMapEntry(const nsRoleMapEntry* aRoleMapEntry);
 
   /**
    * Append/insert/remove a child. Return true if operation was successful.
    */
   bool AppendChild(Accessible* aChild)
     { return InsertChildAt(mChildren.Length(), aChild); }
   virtual bool InsertChildAt(uint32_t aIndex, Accessible* aChild);
 
-  bool InsertAfter(Accessible* aNewChild, Accessible* aRefChild)
-  {
-    MOZ_ASSERT(aNewChild, "No new child to insert");
-    return InsertChildAt(aRefChild ? aRefChild->IndexInParent() + 1 : 0,
-                         aNewChild);
-  }
+  /**
+   * Inserts a child after given sibling. If the child cannot be inserted,
+   * then the child is unbound from the document, and false is returned. Make
+   * sure to null out any references on the child object as it may be destroyed.
+   */
+  bool InsertAfter(Accessible* aNewChild, Accessible* aRefChild);
 
   virtual bool RemoveChild(Accessible* aChild);
 
   /**
    * Reallocates the child withing its parent.
    */
   void MoveChild(uint32_t aNewIndex, Accessible* aChild);
 
@@ -950,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);
@@ -1102,67 +1133,71 @@ 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;
   static const uint8_t kGenericTypesBits = 16;
 
   /**
+   * Non-NO_ROLE_MAP_ENTRY_INDEX indicates author-supplied role;
+   * possibly state & value as well
+   */
+  uint8_t mRoleMapEntryIndex;
+
+  /**
    * 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,
-                            DocAccessible* aDoc,
+                            Accessible* aRoot,
                             logging::GetTreePrefix aPrefixFunc,
                             void* aGetTreePrefixData);
 #endif
   friend class DocAccessible;
   friend class xpcAccessible;
   friend class TreeMutation;
 
-  nsAutoPtr<mozilla::a11y::EmbeddedObjCollector> mEmbeddedObjCollector;
+  UniquePtr<mozilla::a11y::EmbeddedObjCollector> mEmbeddedObjCollector;
   union {
     int32_t mIndexOfEmbeddedChild;
     uint32_t mProxyInterfaces;
   } mInt;
 
   friend class EmbeddedObjCollector;
 
   union
   {
     AccGroupInfo* groupInfo;
     ProxyAccessible* proxy;
   } mBits;
   friend class AccGroupInfo;
 
-  /**
-   * Non-null indicates author-supplied role; possibly state & value as well
-   */
-  const nsRoleMapEntry* mRoleMapEntry;
-
 private:
   Accessible() = delete;
   Accessible(const Accessible&) = delete;
   Accessible& operator =(const Accessible&) = delete;
 
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(Accessible,
--- a/accessible/generic/ApplicationAccessible.cpp
+++ b/accessible/generic/ApplicationAccessible.cpp
@@ -49,17 +49,17 @@ ApplicationAccessible::Name(nsString& aN
 
   nsCOMPtr<nsIStringBundle> bundle;
   nsresult rv = bundleService->CreateBundle("chrome://branding/locale/brand.properties",
                                             getter_AddRefs(bundle));
   if (NS_FAILED(rv))
     return eNameOK;
 
   nsXPIDLString appName;
-  rv = bundle->GetStringFromName(MOZ_UTF16("brandShortName"),
+  rv = bundle->GetStringFromName(u"brandShortName",
                                  getter_Copies(appName));
   if (NS_FAILED(rv) || appName.IsEmpty()) {
     NS_WARNING("brandShortName not found, using default app name");
     appName.AssignLiteral("Gecko based application");
   }
 
   aName.Assign(appName);
   return eNameOK;
--- a/accessible/generic/DocAccessible-inl.h
+++ b/accessible/generic/DocAccessible-inl.h
@@ -152,16 +152,22 @@ DocAccessible::CreateSubtree(Accessible*
 {
   // If a focused node has been shown then it could mean its frame was recreated
   // while the node stays focused and we need to fire focus event on
   // the accessible we just created. If the queue contains a focus event for
   // this node already then it will be suppressed by this one.
   Accessible* focusedAcc = nullptr;
   CacheChildrenInSubtree(aChild, &focusedAcc);
 
+#ifdef A11Y_LOG
+  if (logging::IsEnabled(logging::eVerbose)) {
+    logging::Tree("TREE", "Created subtree", aChild);
+  }
+#endif
+
   // Fire events for ARIA elements.
   if (aChild->HasARIARole()) {
     roles::Role role = aChild->ARIARole();
     if (role == roles::MENUPOPUP) {
       FireDelayedEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START, aChild);
     }
     else if (role == roles::ALERT) {
       FireDelayedEvent(nsIAccessibleEvent::EVENT_ALERT, aChild);
--- 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;
 }
@@ -124,16 +133,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
       cb.NoteXPCOMChild(provider->mContent);
 
       NS_ASSERTION(provider->mContent->IsInUncomposedDoc(),
                    "Referred content is not in document!");
     }
   }
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAccessibleCache)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnchorJumpElm)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInvalidationList)
   for (auto it = tmp->mARIAOwnsHash.ConstIter(); !it.Done(); it.Next()) {
     nsTArray<RefPtr<Accessible> >* ar = it.UserData();
     for (uint32_t i = 0; i < ar->Length(); i++) {
       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
                                          "mARIAOwnsHash entry item");
       cb.NoteXPCOMChild(ar->ElementAt(i));
     }
   }
@@ -142,16 +152,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DocAccessible, Accessible)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mNotificationController)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mVirtualCursor)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildDocuments)
   tmp->mDependentIDsHash.Clear();
   tmp->mNodeToAccessibleMap.Clear();
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mAccessibleCache)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnchorJumpElm)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mInvalidationList)
   tmp->mARIAOwnsHash.Clear();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DocAccessible)
   NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver)
   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_INTERFACE_MAP_ENTRY(nsIObserver)
@@ -467,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
@@ -759,16 +780,19 @@ DocAccessible::AttributeChanged(nsIDocum
   Accessible* accessible = GetAccessible(aElement);
   if (!accessible) {
     if (mContent != aElement)
       return;
 
     accessible = this;
   }
 
+  MOZ_ASSERT(accessible->IsBoundToParent() || accessible->IsDoc(),
+             "DOM attribute change on an accessible detached from the tree");
+
   // Fire accessible events iff there's an accessible, otherwise we consider
   // the accessible state wasn't changed, i.e. its state is initial state.
   AttributeChangedImpl(accessible, aNameSpaceID, aAttribute);
 
   // Update dependent IDs cache. Take care of accessible elements because no
   // accessible element means either the element is not accessible at all or
   // its accessible will be created later. It doesn't make sense to keep
   // dependent IDs for non accessible elements. For the second case we'll update
@@ -970,17 +994,17 @@ DocAccessible::ARIAAttributeChanged(Acce
   nsIContent* elm = aAccessible->GetContent();
 
   // Update aria-hidden flag for the whole subtree iff aria-hidden is changed
   // on the root, i.e. ignore any affiliated aria-hidden changes in the subtree
   // of top aria-hidden.
   if (aAttribute == nsGkAtoms::aria_hidden) {
     bool isDefined = aria::HasDefinedARIAHidden(elm);
     if (isDefined != aAccessible->IsARIAHidden() &&
-        !aAccessible->Parent()->IsARIAHidden()) {
+        (!aAccessible->Parent() || !aAccessible->Parent()->IsARIAHidden())) {
       aAccessible->SetARIAHidden(isDefined);
 
       RefPtr<AccEvent> event =
         new AccObjectAttrChangedEvent(aAccessible, aAttribute);
       FireDelayedEvent(event);
     }
     return;
   }
@@ -1125,20 +1149,36 @@ DocAccessible::CharacterDataChanged(nsID
 
 void
 DocAccessible::ContentInserted(nsIDocument* aDocument, nsIContent* aContainer,
                                nsIContent* aChild, int32_t /* unused */)
 {
 }
 
 void
-DocAccessible::ContentRemoved(nsIDocument* aDocument, nsIContent* aContainer,
-                              nsIContent* aChild, int32_t /* unused */,
-                              nsIContent* aPreviousSibling)
+DocAccessible::ContentRemoved(nsIDocument* aDocument,
+                              nsIContent* aContainerNode,
+                              nsIContent* aChildNode, int32_t /* unused */,
+                              nsIContent* aPreviousSiblingNode)
 {
+#ifdef A11Y_LOG
+  if (logging::IsEnabled(logging::eTree)) {
+    logging::MsgBegin("TREE", "DOM content removed; doc: %p", this);
+    logging::Node("container node", aContainerNode);
+    logging::Node("content node", aChildNode);
+    logging::MsgEnd();
+  }
+#endif
+  // This one and content removal notification from layout may result in
+  // double processing of same subtrees. If it pops up in profiling, then
+  // consider reusing a document node cache to reject these notifications early.
+  Accessible* container = GetAccessibleOrContainer(aContainerNode);
+  if (container) {
+    UpdateTreeOnRemoval(container, aChildNode);
+  }
 }
 
 void
 DocAccessible::ParentChainChanged(nsIContent* aContent)
 {
 }
 
 
@@ -1349,20 +1389,36 @@ DocAccessible::RecreateAccessible(nsICon
 void
 DocAccessible::ProcessInvalidationList()
 {
   // Invalidate children of container accessible for each element in
   // invalidation list. Allow invalidation list insertions while container
   // children are recached.
   for (uint32_t idx = 0; idx < mInvalidationList.Length(); idx++) {
     nsIContent* content = mInvalidationList[idx];
-    if (!HasAccessible(content)) {
+    if (!HasAccessible(content) && content->HasID()) {
       Accessible* container = GetContainerAccessible(content);
       if (container) {
-        ProcessContentInserted(container, content);
+        // Check if the node is a target of aria-owns, and if so, don't process
+        // it here and let DoARIAOwnsRelocation process it.
+        AttrRelProviderArray* list =
+          mDependentIDsHash.Get(nsDependentAtomString(content->GetID()));
+        bool shouldProcess = !!list;
+        if (shouldProcess) {
+          for (uint32_t idx = 0; idx < list->Length(); idx++) {
+            if (list->ElementAt(idx)->mRelAttr == nsGkAtoms::aria_owns) {
+              shouldProcess = false;
+              break;
+            }
+          }
+
+          if (shouldProcess) {
+            ProcessContentInserted(container, content);
+          }
+        }
       }
     }
   }
 
   mInvalidationList.Clear();
 }
 
 Accessible*
@@ -1416,42 +1472,65 @@ 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);
+#ifdef A11Y_LOG
+  if (logging::IsEnabled(logging::eVerbose)) {
+    logging::Tree("TREE", "Initial subtree", this);
+  }
+#endif
 
   // Fire reorder event after the document tree is constructed. Note, since
   // this reorder event is processed by parent document then events targeted to
   // this document may be fired prior to this reorder event. If this is
   // a problem then consider to keep event processing per tab document.
   if (!IsRoot()) {
     RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(Parent());
     ParentDocument()->FireDelayedEvent(reorderEvent);
   }
 
+  TreeMutation mt(this);
   uint32_t childCount = ChildCount();
   for (uint32_t i = 0; i < childCount; i++) {
     Accessible* child = GetChildAt(i);
-    RefPtr<AccShowEvent> event = new AccShowEvent(child);
-  FireDelayedEvent(event);
+    mt.AfterInsertion(child);
   }
+  mt.Done();
 }
 
 void
 DocAccessible::ProcessLoad()
 {
   mLoadState |= eCompletelyLoaded;
 
 #ifdef A11Y_LOG
@@ -1658,17 +1737,17 @@ DocAccessible::UpdateRootElIfNeeded()
  * Content insertion helper.
  */
 class InsertIterator final
 {
 public:
   InsertIterator(Accessible* aContext,
                  const nsTArray<nsCOMPtr<nsIContent> >* aNodes) :
     mChild(nullptr), mChildBefore(nullptr), mWalker(aContext),
-    mStopNode(nullptr), mNodes(aNodes), mNodesIdx(0)
+    mNodes(aNodes), mNodesIdx(0)
   {
     MOZ_ASSERT(aContext, "No context");
     MOZ_ASSERT(aNodes, "No nodes to search for accessible elements");
     MOZ_COUNT_CTOR(InsertIterator);
   }
   ~InsertIterator() { MOZ_COUNT_DTOR(InsertIterator); }
 
   Accessible* Context() const { return mWalker.Context(); }
@@ -1676,31 +1755,36 @@ public:
   Accessible* ChildBefore() const { return mChildBefore; }
   DocAccessible* Document() const { return mWalker.Document(); }
 
   /**
    * Iterates to a next accessible within the inserted content.
    */
   bool Next();
 
+  void Rejected()
+  {
+    mChild = nullptr;
+    mChildBefore = nullptr;
+  }
+
 private:
   Accessible* mChild;
   Accessible* mChildBefore;
   TreeWalker mWalker;
-  nsIContent* mStopNode;
 
   const nsTArray<nsCOMPtr<nsIContent> >* mNodes;
   uint32_t mNodesIdx;
 };
 
 bool
 InsertIterator::Next()
 {
   if (mNodesIdx > 0) {
-    Accessible* nextChild = mWalker.Next(mStopNode);
+    Accessible* nextChild = mWalker.Next();
     if (nextChild) {
       mChildBefore = mChild;
       mChild = nextChild;
       return true;
     }
   }
 
   while (mNodesIdx < mNodes->Length()) {
@@ -1731,31 +1815,32 @@ InsertIterator::Next()
     }
 
 #ifdef A11Y_LOG
     logging::TreeInfo("traversing an inserted node", logging::eVerbose,
                       "container", container, "node", node);
 #endif
 
     // If inserted nodes are siblings then just move the walker next.
-    if (prevNode && prevNode->GetNextSibling() == node) {
-      mStopNode = node;
-      Accessible* nextChild = mWalker.Next(mStopNode);
+    if (mChild && prevNode && prevNode->GetNextSibling() == node) {
+      Accessible* nextChild = mWalker.Scope(node);
       if (nextChild) {
         mChildBefore = mChild;
         mChild = nextChild;
         return true;
       }
     }
-    else if (mWalker.Seek(node)) {
-      mStopNode = node;
-      mChildBefore = mWalker.Prev();
-      mChild = mWalker.Next(mStopNode);
-      if (mChild) {
-        return true;
+    else {
+      TreeWalker finder(container);
+      if (finder.Seek(node)) {
+        mChild = mWalker.Scope(node);
+        if (mChild) {
+          mChildBefore = finder.Prev();
+          return true;
+        }
       }
     }
   }
 
   return false;
 }
 
 void
@@ -1804,22 +1889,23 @@ 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();
 
 #ifdef A11Y_LOG
   logging::TreeInfo("children after insertion", logging::eVerbose,
                     aContainer);
 #endif
@@ -1847,21 +1933,23 @@ DocAccessible::ProcessContentInserted(Ac
   if (aContainer->IsAcceptableChild(aNode) && walker.Seek(aNode)) {
     Accessible* child = GetAccessible(aNode);
     if (!child) {
       child = GetAccService()->CreateAccessible(aNode, aContainer);
     }
 
     if (child) {
       TreeMutation mt(aContainer);
-      aContainer->InsertAfter(child, walker.Prev());
+      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
 }
@@ -2004,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);
@@ -2123,16 +2213,18 @@ DocAccessible::MoveChild(Accessible* aCh
 #endif
 
   // If the child was taken from from an ARIA owns element.
   if (aChild->IsRelocated()) {
     nsTArray<RefPtr<Accessible> >* children = mARIAOwnsHash.Get(curParent);
     children->RemoveElement(aChild);
   }
 
+  NotificationController::MoveGuard mguard(mNotificationController);
+
   if (curParent == aNewParent) {
     MOZ_ASSERT(aChild->IndexInParent() != aIdxInParent, "No move case");
     curParent->MoveChild(aIdxInParent, aChild);
 
 #ifdef A11Y_LOG
     logging::TreeInfo("move child: parent tree after",
                       logging::eVerbose, curParent);
 #endif
@@ -2176,19 +2268,16 @@ DocAccessible::CacheChildrenInSubtree(Ac
   // If the accessible is focused then report a focus event after all related
   // mutation events.
   if (aFocusedAcc && !*aFocusedAcc &&
       FocusMgr()->HasDOMFocus(aRoot->GetContent()))
     *aFocusedAcc = aRoot;
 
   Accessible* root = aRoot->IsHTMLCombobox() ? aRoot->FirstChild() : aRoot;
   if (root->KidsFromDOM()) {
-#ifdef A11Y_LOG
-  logging::TreeInfo("caching children", logging::eVerbose, aRoot);
-#endif
     TreeMutation mt(root, TreeMutation::kNoEvents);
     TreeWalker walker(root);
     while (Accessible* child = walker.Next()) {
       if (child->IsBoundToParent()) {
         MoveChild(child, root, root->ChildCount());
         continue;
       }
 
@@ -2215,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);
 
   /**
@@ -572,17 +572,17 @@ protected:
   bool IsLoadEventTarget() const;
 
   /*
    * Set the object responsible for communicating with the main process on
    * behalf of this document.
    */
   void SetIPCDoc(DocAccessibleChild* aIPCDoc) { mIPCDoc = aIPCDoc; }
 
-  friend class DocAccessibleChild;
+  friend class DocAccessibleChildBase;
 
   /**
    * Used to fire scrolling end event after page scroll.
    *
    * @param aTimer    [in] the timer object
    * @param aClosure  [in] the document accessible where scrolling happens
    */
   static void ScrollTimerCallback(nsITimer* aTimer, void* aClosure);
@@ -678,17 +678,17 @@ protected:
   friend class RelatedAccIterator;
 
   /**
    * Used for our caching algorithm. We store the list of nodes that should be
    * invalidated.
    *
    * @see ProcessInvalidationList
    */
-  nsTArray<nsIContent*> mInvalidationList;
+  nsTArray<RefPtr<nsIContent>> mInvalidationList;
 
   /**
    * Holds a list of aria-owns relocations.
    */
   nsClassHashtable<nsPtrHashKey<Accessible>, nsTArray<RefPtr<Accessible> > >
     mARIAOwnsHash;
 
   /**
--- a/accessible/generic/HyperTextAccessible.cpp
+++ b/accessible/generic/HyperTextAccessible.cpp
@@ -439,27 +439,27 @@ HyperTextAccessible::OffsetToDOMPoint(in
 DOMPoint
 HyperTextAccessible::ClosestNotGeneratedDOMPoint(const DOMPoint& aDOMPoint,
                                                  nsIContent* aElementContent)
 {
   MOZ_ASSERT(aDOMPoint.node, "The node must not be null");
 
   // ::before pseudo element
   if (aElementContent &&
-      aElementContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentbefore) {
+      aElementContent->IsGeneratedContentContainerForBefore()) {
     MOZ_ASSERT(aElementContent->GetParent(),
                "::before must have parent element");
     // The first child of its parent (i.e., immediately after the ::before) is
     // good point for a DOM range.
     return DOMPoint(aElementContent->GetParent(), 0);
   }
 
   // ::after pseudo element
   if (aElementContent &&
-      aElementContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentafter) {
+      aElementContent->IsGeneratedContentContainerForAfter()) {
     MOZ_ASSERT(aElementContent->GetParent(),
                "::after must have parent element");
     // The end of its parent (i.e., immediately before the ::after) is good
     // point for a DOM range.
     return DOMPoint(aElementContent->GetParent(),
                     aElementContent->GetParent()->GetChildCount());
   }
 
@@ -2212,18 +2212,19 @@ HyperTextAccessible::GetSpellTextAttr(ns
 
   if (startOffset > *aStartOffset)
     *aStartOffset = startOffset;
 }
 
 bool
 HyperTextAccessible::IsTextRole()
 {
-  if (mRoleMapEntry &&
-      (mRoleMapEntry->role == roles::GRAPHIC ||
-       mRoleMapEntry->role == roles::IMAGE_MAP ||
-       mRoleMapEntry->role == roles::SLIDER ||
-       mRoleMapEntry->role == roles::PROGRESSBAR ||
-       mRoleMapEntry->role == roles::SEPARATOR))
+  const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+  if (roleMapEntry &&
+      (roleMapEntry->role == roles::GRAPHIC ||
+       roleMapEntry->role == roles::IMAGE_MAP ||
+       roleMapEntry->role == roles::SLIDER ||
+       roleMapEntry->role == roles::PROGRESSBAR ||
+       roleMapEntry->role == roles::SEPARATOR))
     return false;
 
   return true;
 }
--- a/accessible/generic/ImageAccessible.cpp
+++ b/accessible/generic/ImageAccessible.cpp
@@ -133,16 +133,18 @@ ImageAccessible::DoAction(uint8_t aIndex
 
   nsIDocument* document = mContent->OwnerDoc();
   nsCOMPtr<nsPIDOMWindowOuter> piWindow = document->GetWindow();
   if (!piWindow)
     return false;
 
   nsCOMPtr<nsPIDOMWindowOuter> tmp;
   return NS_SUCCEEDED(piWindow->Open(spec, EmptyString(), EmptyString(),
+                                     /* aLoadInfo = */ nullptr,
+                                     /* aForceNoOpener = */ false,
                                      getter_AddRefs(tmp)));
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // ImageAccessible
 
 nsIntPoint
 ImageAccessible::Position(uint32_t aCoordType)
--- 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);
   }
@@ -110,18 +116,19 @@ OuterDocAccessible::Shutdown()
   }
 
   AccessibleWrap::Shutdown();
 }
 
 bool
 OuterDocAccessible::InsertChildAt(uint32_t aIdx, Accessible* aAccessible)
 {
-  NS_ASSERTION(aAccessible->IsDoc(),
-               "OuterDocAccessible should only have document child!");
+  MOZ_RELEASE_ASSERT(aAccessible->IsDoc(),
+                     "OuterDocAccessible can have a document child only!");
+
   // We keep showing the old document for a bit after creating the new one,
   // and while building the new DOM and frame tree. That's done on purpose
   // to avoid weird flashes of default background color.
   // The old viewer will be destroyed after the new one is created.
   // For a11y, it should be safe to shut down the old document now.
   if (mChildren.Length())
     mChildren[0]->Shutdown();
 
@@ -159,17 +166,59 @@ OuterDocAccessible::RemoveChild(Accessib
   bool wasRemoved = AccessibleWrap::RemoveChild(child);
 
   NS_ASSERTION(!mChildren.Length(),
                "This child document of outerdoc accessible wasn't removed!");
 
   return wasRemoved;
 }
 
-ProxyAccessible*
+bool
+OuterDocAccessible::IsAcceptableChild(nsIContent* aEl) const
+{
+  // outer document accessible doesn't not participate in ordinal tree
+  // mutations.
+  return false;
+}
+
+#if defined(XP_WIN)
+
+// On Windows e10s, since we don't cache in the chrome process, these next two
+// functions must be implemented so that we properly cross the chrome-to-content
+// boundary when traversing.
+
+uint32_t
+OuterDocAccessible::ChildCount() const
+{
+  uint32_t result = mChildren.Length();
+  if (!result && RemoteChildDoc()) {
+    result = 1;
+  }
+  return result;
+}
+
+Accessible*
+OuterDocAccessible::GetChildAt(uint32_t aIndex) const
+{
+  Accessible* result = AccessibleWrap::GetChildAt(aIndex);
+  if (result || aIndex) {
+    return result;
+  }
+  // If we are asking for child 0 and GetChildAt doesn't return anything, try
+  // to get the remote child doc and return that instead.
+  ProxyAccessible* remoteChild = RemoteChildDoc();
+  if (!remoteChild) {
+    return nullptr;
+  }
+  return WrapperFor(remoteChild);
+}
+
+#endif // defined(XP_WIN)
+
+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,33 +23,39 @@ 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;
   virtual bool RemoveChild(Accessible* aAccessible) override;
+  virtual bool IsAcceptableChild(nsIContent* aEl) const override;
+
+#if defined(XP_WIN)
+  virtual uint32_t ChildCount() const override;
+  virtual Accessible* GetChildAt(uint32_t aIndex) const override;
+#endif // defined(XP_WIN)
 
 protected:
   virtual ~OuterDocAccessible() override;
 };
 
 inline OuterDocAccessible*
 Accessible::AsOuterDoc()
 {
   return IsOuterDoc() ? static_cast<OuterDocAccessible*>(this) : nullptr;
 }
 
 } // namespace a11y
 } // namespace mozilla
 
-#endif  
+#endif
--- a/accessible/generic/RootAccessible.cpp
+++ b/accessible/generic/RootAccessible.cpp
@@ -72,17 +72,17 @@ RootAccessible::~RootAccessible()
 ////////////////////////////////////////////////////////////////////////////////
 // Accessible
 
 ENameValueFlag
 RootAccessible::Name(nsString& aName)
 {
   aName.Truncate();
 
-  if (mRoleMapEntry) {
+  if (ARIARoleMap()) {
     Accessible::Name(aName);
     if (!aName.IsEmpty())
       return eNameOK;
   }
 
   mDocumentNode->GetTitle(aName);
   return eNameOK;
 }
--- a/accessible/generic/moz.build
+++ b/accessible/generic/moz.build
@@ -1,9 +1,9 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# -*- 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/.
 
 EXPORTS.mozilla.a11y += [
     'Accessible.h',
     'DocAccessible.h',
@@ -23,24 +23,32 @@ UNIFIED_SOURCES += [
     'RootAccessible.cpp',
     'TableCellAccessible.cpp',
     'TextLeafAccessible.cpp',
 ]
 
 LOCAL_INCLUDES += [
     '/accessible/base',
     '/accessible/html',
-    '/accessible/ipc',
     '/accessible/xpcom',
     '/accessible/xul',
     '/dom/base',
     '/layout/generic',
     '/layout/xul',
 ]
 
+if CONFIG['OS_ARCH'] == 'WINNT':
+    LOCAL_INCLUDES += [
+        '/accessible/ipc/win',
+    ]
+else:
+    LOCAL_INCLUDES += [
+        '/accessible/ipc/other',
+    ]
+
 if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
     LOCAL_INCLUDES += [
         '/accessible/atk',
     ]
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     LOCAL_INCLUDES += [
         '/accessible/windows/ia2',
         '/accessible/windows/msaa',
--- a/accessible/html/HTMLFormControlAccessible.cpp
+++ b/accessible/html/HTMLFormControlAccessible.cpp
@@ -303,17 +303,17 @@ HTMLTextFieldAccessible::NativeAttribute
   nsCOMPtr<nsIPersistentProperties> attributes =
     HyperTextAccessibleWrap::NativeAttributes();
 
   // Expose type for text input elements as it gives some useful context,
   // especially for mobile.
   nsAutoString type;
   if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type)) {
     nsAccUtils::SetAccAttr(attributes, nsGkAtoms::textInputType, type);
-    if (!mRoleMapEntry && type.EqualsLiteral("search")) {
+    if (!ARIARoleMap() && type.EqualsLiteral("search")) {
       nsAccUtils::SetAccAttr(attributes, nsGkAtoms::xmlroles,
                              NS_LITERAL_STRING("searchbox"));
     }
   }
 
   return attributes.forget();
 }
 
@@ -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/HTMLSelectAccessible.cpp
+++ b/accessible/html/HTMLSelectAccessible.cpp
@@ -11,16 +11,17 @@
 #include "DocAccessible.h"
 #include "nsEventShell.h"
 #include "nsTextEquivUtils.h"
 #include "Role.h"
 #include "States.h"
 
 #include "nsCOMPtr.h"
 #include "mozilla/dom/HTMLOptionElement.h"
+#include "mozilla/dom/HTMLSelectElement.h"
 #include "nsIComboboxControlFrame.h"
 #include "nsContainerFrame.h"
 #include "nsIListControlFrame.h"
 
 using namespace mozilla::a11y;
 using namespace mozilla::dom;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -493,29 +494,25 @@ HTMLComboboxAccessible::SetCurrentItem(A
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // HTMLComboboxAccessible: protected
 
 Accessible*
 HTMLComboboxAccessible::SelectedOption() const
 {
-  nsIFrame* frame = GetFrame();
-  nsIComboboxControlFrame* comboboxFrame = do_QueryFrame(frame);
-  if (!comboboxFrame)
-    return nullptr;
+  HTMLSelectElement* select = HTMLSelectElement::FromContent(mContent);
+  int32_t selectedIndex = select->SelectedIndex();
 
-  nsIListControlFrame* listControlFrame =
-    do_QueryFrame(comboboxFrame->GetDropDown());
-  if (listControlFrame) {
-    nsCOMPtr<nsIContent> activeOptionNode = listControlFrame->GetCurrentOption();
-    if (activeOptionNode) {
+  if (selectedIndex >= 0) {
+    HTMLOptionElement* option = select->Item(selectedIndex);
+    if (option) {
       DocAccessible* document = Document();
       if (document)
-        return document->GetAccessible(activeOptionNode);
+        return document->GetAccessible(option);
     }
   }
 
   return nullptr;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
--- 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;
--- a/accessible/html/moz.build
+++ b/accessible/html/moz.build
@@ -1,9 +1,9 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# -*- 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/.
 
 UNIFIED_SOURCES += [
     'HTMLCanvasAccessible.cpp',
     'HTMLElementAccessibles.cpp',
@@ -37,12 +37,14 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'co
     LOCAL_INCLUDES += [
         '/accessible/mac',
     ]
 else:
     LOCAL_INCLUDES += [
         '/accessible/other',
     ]
 
+include('/ipc/chromium/chromium-config.mozbuild')
+
 FINAL_LIBRARY = 'xul'
 
 if CONFIG['GNU_CXX']:
     CXXFLAGS += ['-Wno-error=shadow']
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']
--- a/accessible/interfaces/ia2/IA2Marshal.def
+++ b/accessible/interfaces/ia2/IA2Marshal.def
@@ -2,9 +2,10 @@
 ;+# 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/.
 
 LIBRARY        IA2Marshal.dll
 EXPORTS        DllGetClassObject      PRIVATE
                DllCanUnloadNow        PRIVATE
                DllRegisterServer      PRIVATE
                DllUnregisterServer    PRIVATE
+               GetProxyDllInfo        PRIVATE
 
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>
new file mode 100644
--- /dev/null
+++ b/accessible/interfaces/ia2/IA2Marshal.rc
@@ -0,0 +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 IA2Typelib.tlb
new file mode 100644
--- /dev/null
+++ b/accessible/interfaces/ia2/IA2Typelib.idl
@@ -0,0 +1,61 @@
+/* -*- 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/. */
+
+typedef struct _MozRemotableHandle
+{
+  long fContext;
+  long hRemote;
+} MozRemotableHandle;
+
+typedef [unique] MozRemotableHandle * mozHWND;
+typedef [unique] MozRemotableHandle * mozHMENU;
+typedef [unique] MozRemotableHandle * mozHACCEL;
+typedef [unique] MozRemotableHandle * mozHBRUSH;
+typedef [unique] MozRemotableHandle * mozHFONT;
+typedef [unique] MozRemotableHandle * mozHDC;
+typedef [unique] MozRemotableHandle * mozHICON;
+typedef [unique] MozRemotableHandle * mozHRGN;
+typedef [unique] MozRemotableHandle * mozHMONITOR;
+
+cpp_quote("#if 0")
+typedef [wire_marshal(mozHWND)] void* HWND;
+typedef [wire_marshal(mozHMENU)] void* HMENU;
+typedef [wire_marshal(mozHACCEL)] void* HACCEL;
+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 "IA2TypeLibrary.idl"
--- a/accessible/interfaces/ia2/Makefile.in
+++ b/accessible/interfaces/ia2/Makefile.in
@@ -1,15 +1,19 @@
 # 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)
+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 \
   AccessibleAction.idl \
@@ -34,52 +38,76 @@ MIDL_INTERFACES = \
 # Makefile is ported over.
 MIDL_ENUMS = \
   AccessibleEventId.idl \
   AccessibleRole.idl \
   AccessibleStates.idl \
   IA2CommonTypes.idl \
   $(NULL)
 
-CSRCS	= \
+MIDL_LIBRARIES = \
+  IA2Typelib.idl \
+  $(NULL)
+
+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
+$(MIDL_GENERATED_FILES) : midl_done typelib_done
 
 ifneq ("$(missing)","")
 midl_done : FORCE
 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 $@
 
-# This marshall dll is also registered in the installer
+# The intent of this rule is to generate the .tlb file that is referenced in the
+# .rc file for IA2Marshal.dll
+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; \
+	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
@@ -1,9 +1,9 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# -*- 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/.
 
 GeckoSharedLibrary('IA2Marshal', linkage=None)
 
 DEFINES['REGISTER_PROXY_DLL'] = True
@@ -13,15 +13,83 @@ DEFFILE = SRCDIR + '/IA2Marshal.def'
 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_
 #
 # which clang-cl complains about.  MSVC doesn't, so turn this warning off.
 if CONFIG['CLANG_CL']:
     CXXFLAGS += ['-Wno-extra-tokens']
--- a/accessible/interfaces/moz.build
+++ b/accessible/interfaces/moz.build
@@ -1,45 +1,40 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# -*- 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',
     'nsIAccessibleEvent.idl',
     'nsIAccessibleHideEvent.idl',
     'nsIAccessibleHyperLink.idl',
     'nsIAccessibleHyperText.idl',
     'nsIAccessibleImage.idl',
     'nsIAccessibleObjectAttributeChangedEvent.idl',
     'nsIAccessiblePivot.idl',
     'nsIAccessibleRelation.idl',
-    'nsIAccessibleRetrieval.idl',
     'nsIAccessibleRole.idl',
     'nsIAccessibleSelectable.idl',
     'nsIAccessibleStateChangeEvent.idl',
     'nsIAccessibleStates.idl',
     'nsIAccessibleTable.idl',
     'nsIAccessibleTableChangeEvent.idl',
     'nsIAccessibleText.idl',
     'nsIAccessibleTextChangeEvent.idl',
     'nsIAccessibleTextRange.idl',
     'nsIAccessibleTypes.idl',
     'nsIAccessibleValue.idl',
     'nsIAccessibleVirtualCursorChangeEvent.idl',
     'nsIXBLAccessible.idl',
 ]
 
 XPIDL_MODULE = 'accessibility'
-
-EXPORTS += [
-    'nsIAccessibilityService.h',
-]
-
new file mode 100644
--- /dev/null
+++ b/accessible/interfaces/msaa/AccessibleMarshal.rc
@@ -0,0 +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 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
@@ -1,35 +1,44 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# -*- 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/.
 
 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 += [
+    '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_
 #
 # which clang-cl complains about.  MSVC doesn't, so turn this warning off.
 if CONFIG['CLANG_CL']:
     CFLAGS += ['-Wno-extra-tokens']
deleted file mode 100644
--- a/accessible/interfaces/nsIAccessibilityService.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* -*- 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/. */
-
-#ifndef _nsIAccessibilityService_h_
-#define _nsIAccessibilityService_h_
-
-#include "nsIAccessibleRetrieval.h"
-#include "nsIAccessibleEvent.h"
-
-namespace mozilla {
-namespace a11y {
-
-class Accessible;
-
-} // namespace a11y
-} // namespace mozilla
-
-class nsIPresShell;
-
-// 0e7e6879-854b-4260-bc6e-525b5fb5cf34
-#define NS_IACCESSIBILITYSERVICE_IID \
-{ 0x0e7e6879, 0x854b, 0x4260, \
- { 0xbc, 0x6e, 0x52, 0x5b, 0x5f, 0xb5, 0xcf, 0x34 } }
-
-class nsIAccessibilityService : public nsIAccessibleRetrieval
-{
-public:
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IACCESSIBILITYSERVICE_IID)
-
-  /**
-   * Return root document accessible that is or contains a document accessible
-   * for the given presshell.
-   *
-   * @param aPresShell  [in] the presshell
-   * @param aCanCreate  [in] points whether the root document accessible
-   *                        should be returned from the cache or can be created
-   */
-  virtual mozilla::a11y::Accessible*
-    GetRootDocumentAccessible(nsIPresShell* aPresShell, bool aCanCreate) = 0;
-
-   /**
-   * Adds/remove ATK root accessible for gtk+ native window to/from children
-   * of the application accessible.
-   */
-  virtual mozilla::a11y::Accessible*
-    AddNativeRootAccessible(void* aAtkAccessible) = 0;
-  virtual void
-    RemoveNativeRootAccessible(mozilla::a11y::Accessible* aRootAccessible) = 0;
-
-  /**
-   * Fire accessible event of the given type for the given target.
-   *
-   * @param aEvent   [in] accessible event type
-   * @param aTarget  [in] target of accessible event
-   */
-  virtual void FireAccessibleEvent(uint32_t aEvent,
-                                   mozilla::a11y::Accessible* aTarget) = 0;
-
-  /**
-   * Return true if the given DOM node has accessible object.
-   */
-  virtual bool HasAccessible(nsIDOMNode* aDOMNode) = 0;
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(nsIAccessibilityService,
-                              NS_IACCESSIBILITYSERVICE_IID)
-
-// for component registration
-// {DE401C37-9A7F-4278-A6F8-3DE2833989EF}
-#define NS_ACCESSIBILITY_SERVICE_CID \
-{ 0xde401c37, 0x9a7f, 0x4278, { 0xa6, 0xf8, 0x3d, 0xe2, 0x83, 0x39, 0x89, 0xef } }
-
-extern nsresult
-NS_GetAccessibilityService(nsIAccessibilityService** aResult);
-
-#endif
new file mode 100644
--- /dev/null
+++ b/accessible/interfaces/nsIAccessibilityService.idl
@@ -0,0 +1,108 @@
+/* -*- 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 "nsISupports.idl"
+
+interface nsIDOMNode;
+interface nsIAccessible;
+interface nsIWeakReference;
+interface nsIPresShell;
+interface nsIAccessiblePivot;
+
+/**
+ * An interface for in-process accessibility clients wishing to get an
+ * nsIAccessible for a given DOM node.  More documentation at:
+ *   http://www.mozilla.org/projects/ui/accessibility
+ */
+[scriptable, builtinclass, uuid(9a6f80fe-25cc-405c-9f8f-25869bc9f94e)]
+interface nsIAccessibilityService : nsISupports
+{
+  /**
+   * Return application accessible.
+   */
+  nsIAccessible getApplicationAccessible();
+
+  /**
+   * Return an nsIAccessible for a DOM node in pres shell 0.
+   * Create a new accessible of the appropriate type if necessary,
+   * or use one from the accessibility cache if it already exists.
+   * @param aNode The DOM node to get an accessible for.
+   * @return The nsIAccessible for the given DOM node.
+   */
+  nsIAccessible getAccessibleFor(in nsIDOMNode aNode);
+
+   /**
+    * Returns accessible role as a string.
+    *
+    * @param aRole - the accessible role constants.
+    */
+  AString getStringRole(in unsigned long aRole);
+
+   /**
+    * Returns list which contains accessible states as a strings.
+    *
+    * @param aStates - accessible states.
+    * @param aExtraStates - accessible extra states.
+    */
+  nsISupports getStringStates(in unsigned long aStates,
+                              in unsigned long aExtraStates);
+
+  /**
+   * Get the type of accessible event as a string.
+   *
+   * @param aEventType - the accessible event type constant
+   * @return - accessible event type presented as human readable string
+   */
+  AString getStringEventType(in unsigned long aEventType);
+
+  /**
+   * Get the type of accessible relation as a string.
+   *
+   * @param aRelationType - the accessible relation type constant
+   * @return - accessible relation type presented as human readable string
+   */
+  AString getStringRelationType(in unsigned long aRelationType);
+
+  /**
+   * Return an accessible for the given DOM node from the cache.
+   * @note  the method is intended for testing purposes
+   *
+   * @param aNode  [in] the DOM node to get an accessible for
+   *
+   * @return       cached accessible for the given DOM node if any
+   */
+  nsIAccessible getAccessibleFromCache(in nsIDOMNode aNode);
+
+  /**
+   * Create a new pivot for tracking a position and traversing a subtree.
+   *
+   * @param aRoot [in] the accessible root for the pivot
+   * @return a new pivot
+   */
+  nsIAccessiblePivot createAccessiblePivot(in nsIAccessible aRoot);
+
+  /**
+   * Enable logging for the given modules, all other modules aren't logged.
+   *
+   * @param aModules [in] list of modules, format is comma separated list
+   *                      like 'docload,doccreate'.
+   * @note Works on debug build only.
+   * @see Logging.cpp for list of possible values.
+   */
+  void setLogging(in ACString aModules);
+
+  /**
+   * Return true if the given module is logged.
+   */
+  boolean isLogged(in AString aModule);
+};
+
+/**
+ * @deprecated, use nsIAccessibilityService instead.
+ */
+[scriptable, builtinclass, uuid(d85e0cbe-47ce-490c-8488-f821dd2be0c2)]
+interface nsIAccessibleRetrieval : nsIAccessibilityService
+{
+};
--- a/accessible/interfaces/nsIAccessible.idl
+++ b/accessible/interfaces/nsIAccessible.idl
@@ -25,17 +25,17 @@ class Accessible;
  * accessibility APIs like MSAA and ATK. Contains the sum of what's needed
  * to support IAccessible as well as ATK's generic accessibility objects.
  * Can also be used by in-process accessibility clients to get information
  * about objects in the accessible tree. The accessible tree is a subset of 
  * nodes in the DOM tree -- such as documents, focusable elements and text.
  * Mozilla creates the implementations of nsIAccessible on demand.
  * See http://www.mozilla.org/projects/ui/accessibility for more information.
  */
-[scriptable, uuid(de2869d9-563c-4943-996b-31a4daa4d097)]
+[scriptable, builtinclass, uuid(de2869d9-563c-4943-996b-31a4daa4d097)]
 interface nsIAccessible : nsISupports
 {
   /**
    * Parent node in accessible tree.
    */
   readonly attribute nsIAccessible parent;
 
   /**
--- a/accessible/interfaces/nsIAccessibleApplication.idl
+++ b/accessible/interfaces/nsIAccessibleApplication.idl
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 /**
  * This interface is implemented by top level accessible object in hierarchy and
  * provides information about application.
  */
-[scriptable, uuid(79251626-387c-4531-89f3-680d31d6cf05)]
+[scriptable, builtinclass, uuid(79251626-387c-4531-89f3-680d31d6cf05)]
 interface nsIAccessibleApplication : nsISupports
 {
   /**
    * Returns the application name.
    */
   readonly attribute DOMString appName;
 
   /**
--- a/accessible/interfaces/nsIAccessibleDocument.idl
+++ b/accessible/interfaces/nsIAccessibleDocument.idl
@@ -14,17 +14,17 @@ interface mozIDOMWindowProxy;
  * that wish to retrieve information about a document.
  * When accessibility is turned on in Gecko,
  * there is an nsIAccessibleDocument for each document
  * whether it is XUL, HTML or whatever.
  * You can QueryInterface to nsIAccessibleDocument from the nsIAccessible for
  * the root node of a document or you can get one from
  * nsIAccessible::GetDocument().
  */
-[scriptable, uuid(5cad5f91-fcce-40e7-913e-4671701d19b4)]
+[scriptable, builtinclass, uuid(5cad5f91-fcce-40e7-913e-4671701d19b4)]
 interface nsIAccessibleDocument : nsISupports
 {
   /**
    * The URL of the document
    */
   readonly attribute AString URL;
 
   /**
--- a/accessible/interfaces/nsIAccessibleEditableText.idl
+++ b/accessible/interfaces/nsIAccessibleEditableText.idl
@@ -1,17 +1,17 @@
 /* -*- 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 "nsISupports.idl"
 
-[scriptable, uuid(28915cca-3366-4034-ba1d-b7afb9b37639)]
+[scriptable, builtinclass, uuid(28915cca-3366-4034-ba1d-b7afb9b37639)]
 interface nsIAccessibleEditableText : nsISupports
 {
   /**
    * Replaces the text represented by this object by the given text.
    */
   void setTextContents (in AString text);
 
   /**
--- a/accessible/interfaces/nsIAccessibleHyperLink.idl
+++ b/accessible/interfaces/nsIAccessibleHyperLink.idl
@@ -8,17 +8,17 @@
 
 interface nsIURI;
 interface nsIAccessible;
 
 /**
  * A cross-platform interface that supports hyperlink-specific properties and
  * methods.  Anchors, image maps, xul:labels with class="text-link" implement this interface.
  */
-[scriptable, uuid(883643d4-93a5-4f32-922c-6f06e01363c1)]
+[scriptable, builtinclass, uuid(883643d4-93a5-4f32-922c-6f06e01363c1)]
 interface nsIAccessibleHyperLink : nsISupports
 {
   /**
    * Returns the offset of the link within the parent accessible.
    */
   readonly attribute long startIndex;
 
   /**
--- a/accessible/interfaces/nsIAccessibleHyperText.idl
+++ b/accessible/interfaces/nsIAccessibleHyperText.idl
@@ -10,17 +10,17 @@
 /**
  * A cross-platform interface that deals with text which contains hyperlinks.
  * Each link is an embedded object representing exactly 1 character within
  * the hypertext.
  *
  * Current implementation assumes every embedded object is a link.
  */
 
-[scriptable, uuid(b33684e2-090c-4e1d-a3d9-f4b46f4237b9)]
+[scriptable, builtinclass, uuid(b33684e2-090c-4e1d-a3d9-f4b46f4237b9)]
 interface nsIAccessibleHyperText : nsISupports
 {
   /**
    * Return the number of links contained within this hypertext object.
    */
   readonly attribute long linkCount;
 
   /**
--- a/accessible/interfaces/nsIAccessibleImage.idl
+++ b/accessible/interfaces/nsIAccessibleImage.idl
@@ -1,16 +1,16 @@
 /* -*- 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 "nsISupports.idl"
 
-[scriptable, uuid(09086623-0f09-4310-ac56-c2cda7c29648)]
+[scriptable, builtinclass, uuid(09086623-0f09-4310-ac56-c2cda7c29648)]
 interface nsIAccessibleImage : nsISupports
 {
   /**
    * Returns the coordinates of the image.
    *
    * @param coordType  specifies coordinates origin (for available constants
    *                   refer to nsIAccessibleCoordinateType)
    * @param x          the x coordinate
--- a/accessible/interfaces/nsIAccessibleRelation.idl
+++ b/accessible/interfaces/nsIAccessibleRelation.idl
@@ -6,17 +6,17 @@
 #include "nsISupports.idl"
 #include "nsIArray.idl"
 
 interface nsIAccessible;
 
 /**
  * This interface gives access to an accessible's set of relations.
  */
-[scriptable, uuid(55b308c4-2ae4-46bc-b4cd-4d4370e0a660)]
+[scriptable, builtinclass, uuid(55b308c4-2ae4-46bc-b4cd-4d4370e0a660)]
 interface nsIAccessibleRelation : nsISupports
 {
   /**
    * This object is labelled by a target object.
    */
   const unsigned long RELATION_LABELLED_BY = 0x00;
 
   /**
@@ -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;
deleted file mode 100644
--- a/accessible/interfaces/nsIAccessibleRetrieval.idl
+++ /dev/null
@@ -1,110 +0,0 @@
-/* -*- 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 "nsISupports.idl"
-
-interface nsIDOMNode;
-interface nsIAccessible;
-interface nsIWeakReference;
-interface nsIPresShell;
-interface nsIAccessiblePivot;
-
-/**
- * An interface for in-process accessibility clients wishing to get an
- * nsIAccessible for a given DOM node.  More documentation at:
- *   http://www.mozilla.org/projects/ui/accessibility
- */
-[scriptable, uuid(17f86615-1a3d-4021-b227-3a2ef5cbffd8)]
-interface nsIAccessibleRetrieval : nsISupports
-{
-  /**
-   * Return application accessible.
-   */
-  nsIAccessible getApplicationAccessible();
-
-  /**
-   * Return an nsIAccessible for a DOM node in pres shell 0.
-   * Create a new accessible of the appropriate type if necessary,
-   * or use one from the accessibility cache if it already exists.
-   * @param aNode The DOM node to get an accessible for.
-   * @return The nsIAccessible for the given DOM node.
-   */
-  nsIAccessible getAccessibleFor(in nsIDOMNode aNode);
-
-   /**
-    * Returns accessible role as a string.
-    *
-    * @param aRole - the accessible role constants.
-    */
-  AString getStringRole(in unsigned long aRole);
-
-   /**
-    * Returns list which contains accessible states as a strings.
-    *
-    * @param aStates - accessible states.
-    * @param aExtraStates - accessible extra states.
-    */
-  nsISupports getStringStates(in unsigned long aStates,
-                              in unsigned long aExtraStates);
-
-  /**
-   * Get the type of accessible event as a string.
-   *
-   * @param aEventType - the accessible event type constant
-   * @return - accessible event type presented as human readable string
-   */
-  AString getStringEventType(in unsigned long aEventType);
-
-  /**
-   * Get the type of accessible relation as a string.
-   *
-   * @param aRelationType - the accessible relation type constant
-   * @return - accessible relation type presented as human readable string
-   */
-  AString getStringRelationType(in unsigned long aRelationType);
-
-  /**
-   * Return an accessible for the given DOM node from the cache.
-   * @note  the method is intended for testing purposes
-   *
-   * @param aNode  [in] the DOM node to get an accessible for
-   *
-   * @return       cached accessible for the given DOM node if any
-   */
-  nsIAccessible getAccessibleFromCache(in nsIDOMNode aNode);
-
-  /**
-   * Create a new pivot for tracking a position and traversing a subtree.
-   *
-   * @param aRoot [in] the accessible root for the pivot
-   * @return a new pivot
-   */
-  nsIAccessiblePivot createAccessiblePivot(in nsIAccessible aRoot);
-
-  /**
-   * Enable logging for the given modules, all other modules aren't logged.
-   *
-   * @param aModules [in] list of modules, format is comma separated list
-   *                      like 'docload,doccreate'.
-   * @note Works on debug build only.
-   * @see Logging.cpp for list of possible values.
-   */
-  void setLogging(in ACString aModules);
-
-  /**
-   * Return true if the given module is logged.
-   */
-  boolean isLogged(in AString aModule);
-};
-
-
-%{ C++
-
-// for component registration
-// {663CA4A8-D219-4000-925D-D8F66406B626}
-#define NS_ACCESSIBLE_RETRIEVAL_CID \
-{ 0x663ca4a8, 0xd219, 0x4000, { 0x92, 0x5d, 0xd8, 0xf6, 0x64, 0x6, 0xb6, 0x26 } }
-
-%}
--- a/accessible/interfaces/nsIAccessibleRole.idl
+++ b/accessible/interfaces/nsIAccessibleRole.idl
@@ -3,17 +3,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/. */
 
 #include "nsISupports.idl"
 
 /**
  * Defines cross platform (Gecko) roles.
  */
-[scriptable, uuid(05a9f33f-dcfd-4e7b-b825-138ba784c1f5)]
+[scriptable, builtinclass, uuid(05a9f33f-dcfd-4e7b-b825-138ba784c1f5)]
 interface nsIAccessibleRole : nsISupports
 {
   /**
    * Used when accessible hans't strong defined role.
    */
   const unsigned long ROLE_NOTHING = 0;
 
   /**
--- a/accessible/interfaces/nsIAccessibleSelectable.idl
+++ b/accessible/interfaces/nsIAccessibleSelectable.idl
@@ -6,17 +6,17 @@
 #include "nsISupports.idl"
 
 interface nsIAccessible;
 interface nsIArray;
 
 /**
  * An accessibility interface for selectable widgets.
  */
-[scriptable, uuid(8efb03d4-1354-4875-94cf-261336057626)]
+[scriptable, builtinclass, uuid(8efb03d4-1354-4875-94cf-261336057626)]
 interface nsIAccessibleSelectable : nsISupports
 {
   /**
    * Return an nsIArray of selected items within the widget.
    */
   readonly attribute nsIArray selectedItems;
 
   /**
--- a/accessible/interfaces/nsIAccessibleTable.idl
+++ b/accessible/interfaces/nsIAccessibleTable.idl
@@ -4,17 +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/. */
 
 #include "nsISupports.idl"
 
 interface nsIAccessible;
 interface nsIArray;
 
-[scriptable, uuid(cb0bf7b9-117e-40e2-9e46-189c3d43ce4a)]
+[scriptable, builtinclass, uuid(cb0bf7b9-117e-40e2-9e46-189c3d43ce4a)]
 interface nsIAccessibleTable : nsISupports
 {
   /**
    * Return the caption accessible for the table. For example, html:caption
    * element of html:table element.
    */
   readonly attribute nsIAccessible caption;
 
@@ -216,17 +216,17 @@ interface nsIAccessibleTable : nsISuppor
 
   /**
    * Use heuristics to determine if table is most likely used for layout.
    */
   boolean isProbablyForLayout();
 };
 
 
-[scriptable, uuid(654e296d-fae6-452b-987d-746b20b9514b)]
+[scriptable, builtinclass, uuid(654e296d-fae6-452b-987d-746b20b9514b)]
 interface nsIAccessibleTableCell : nsISupports
 {
   /**
    * Return host table accessible.
    */
   readonly attribute nsIAccessibleTable table;
 
   /**
--- a/accessible/interfaces/nsIAccessibleText.idl
+++ b/accessible/interfaces/nsIAccessibleText.idl
@@ -8,17 +8,17 @@
 
 typedef long AccessibleTextBoundary;
 
 interface nsIAccessible;
 interface nsIArray;
 interface nsIPersistentProperties;
 interface nsIAccessibleTextRange;
 
-[scriptable, uuid(93ad2ca1-f12b-4ab9-a793-95d9fa9d1774)]
+[scriptable, builtinclass, uuid(93ad2ca1-f12b-4ab9-a793-95d9fa9d1774)]
 interface nsIAccessibleText : nsISupports
 {
   // In parameters for character offsets:
   //  -1 will be treated as the equal to the end of the text
   //  -2 will be treated as the caret position
   const int32_t TEXT_OFFSET_END_OF_TEXT = -1;
   const int32_t TEXT_OFFSET_CARET       = -2;
 
--- a/accessible/interfaces/nsIAccessibleTextRange.idl
+++ b/accessible/interfaces/nsIAccessibleTextRange.idl
@@ -8,17 +8,17 @@
 interface nsIAccessible;
 interface nsIAccessibleText;
 interface nsIArray;
 interface nsIVariant;
 
 /**
  * A range representing a piece of text in the document.
  */
-[scriptable, uuid(c4515623-55f9-4543-a3d5-c1e9afa588f4)]
+[scriptable, builtinclass, uuid(c4515623-55f9-4543-a3d5-c1e9afa588f4)]
 interface nsIAccessibleTextRange : nsISupports
 {
   readonly attribute nsIAccessibleText startContainer;
   readonly attribute long startOffset;
   readonly attribute nsIAccessibleText endContainer;
   readonly attribute long endOffset;
 
   /**
--- a/accessible/interfaces/nsIAccessibleTypes.idl
+++ b/accessible/interfaces/nsIAccessibleTypes.idl
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 /**
  * These constants control the scrolling of an object or substring into a
  * window. Note, keep them synchronized with IA2ScrollType.
  */
-[scriptable, uuid(05cd38b1-94b3-4cdf-8371-3935a9611405)]
+[scriptable, builtinclass, uuid(05cd38b1-94b3-4cdf-8371-3935a9611405)]
 interface nsIAccessibleScrollType : nsISupports
 {
   /**
    * Scroll the top left of the object or substring to the top left of the
    * window (or as close as possible).
    */
   const unsigned long SCROLL_TYPE_TOP_LEFT =0x00;
 
@@ -54,17 +54,17 @@ interface nsIAccessibleScrollType : nsIS
    */
   const unsigned long SCROLL_TYPE_ANYWHERE = 0x06;
 };
 
 
 /**
  * These constants define which coordinate system a point is located in.
  */
-[scriptable, uuid(c9fbdf10-619e-436f-bf4b-8566686f1577)]
+[scriptable, builtinclass, uuid(c9fbdf10-619e-436f-bf4b-8566686f1577)]
 interface nsIAccessibleCoordinateType : nsISupports
 {
   /**
    * The coordinates are relative to the screen.
    */
   const unsigned long COORDTYPE_SCREEN_RELATIVE = 0x00;
 
   /**
--- a/accessible/interfaces/nsIAccessibleValue.idl
+++ b/accessible/interfaces/nsIAccessibleValue.idl
@@ -1,17 +1,17 @@
 /* -*- 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 "nsISupports.idl"
 
-[scriptable, uuid(42a1e1dc-58cf-419d-bff0-ed3314c70016)]
+[scriptable, builtinclass, uuid(42a1e1dc-58cf-419d-bff0-ed3314c70016)]
 interface nsIAccessibleValue : nsISupports
 {
   readonly attribute double maximumValue;
   readonly attribute double minimumValue;
   attribute double currentValue;
   readonly attribute double minimumIncrement;
 };
 
--- a/accessible/interfaces/nsIXBLAccessible.idl
+++ b/accessible/interfaces/nsIXBLAccessible.idl
@@ -5,16 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 /**
  * XBL controls can implement this interface to provide own implementation of
  * accessible properties.
  */
-[scriptable, uuid(3716eb86-166b-445b-a94a-9b522fee96e6)]
+[scriptable, builtinclass, uuid(3716eb86-166b-445b-a94a-9b522fee96e6)]
 interface nsIXBLAccessible : nsISupports
 {
   /**
    * Return accessible name.
    */
   readonly attribute DOMString accessibleName;
 };
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/DocAccessibleChildBase.cpp
@@ -0,0 +1,97 @@
+/* -*- 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 "mozilla/a11y/DocAccessibleChildBase.h"
+#include "mozilla/a11y/ProxyAccessible.h"
+
+#include "Accessible-inl.h"
+
+namespace mozilla {
+namespace a11y {
+
+/* static */ uint32_t
+DocAccessibleChildBase::InterfacesFor(Accessible* aAcc)
+{
+  uint32_t interfaces = 0;
+  if (aAcc->IsHyperText() && aAcc->AsHyperText()->IsTextRole())
+    interfaces |= Interfaces::HYPERTEXT;
+
+  if (aAcc->IsLink())
+    interfaces |= Interfaces::HYPERLINK;
+
+  if (aAcc->HasNumericValue())
+    interfaces |= Interfaces::VALUE;
+
+  if (aAcc->IsImage())
+    interfaces |= Interfaces::IMAGE;
+
+  if (aAcc->IsTable()) {
+    interfaces |= Interfaces::TABLE;
+  }
+
+  if (aAcc->IsTableCell())
+    interfaces |= Interfaces::TABLECELL;
+
+  if (aAcc->IsDoc())
+    interfaces |= Interfaces::DOCUMENT;
+
+  if (aAcc->IsSelect()) {
+    interfaces |= Interfaces::SELECTION;
+  }
+
+  if (aAcc->ActionCount()) {
+    interfaces |= Interfaces::ACTION;
+  }
+
+  return interfaces;
+}
+
+/* static */ void
+DocAccessibleChildBase::SerializeTree(Accessible* aRoot,
+                                      nsTArray<AccessibleData>& aTree)
+{
+  uint64_t id = reinterpret_cast<uint64_t>(aRoot->UniqueID());
+#if defined(XP_WIN)
+  int32_t msaaId = AccessibleWrap::GetChildIDFor(aRoot);
+#endif
+  uint32_t role = aRoot->Role();
+  uint32_t childCount = aRoot->ChildCount();
+  uint32_t interfaces = InterfacesFor(aRoot);
+
+  // OuterDocAccessibles are special because we don't want to serialize the
+  // child doc here, we'll call PDocAccessibleConstructor in
+  // NotificationController.
+  MOZ_ASSERT(!aRoot->IsDoc(), "documents shouldn't be serialized");
+  if (aRoot->IsOuterDoc()) {
+    childCount = 0;
+  }
+
+#if defined(XP_WIN)
+  aTree.AppendElement(AccessibleData(id, msaaId, role, childCount, interfaces));
+#else
+  aTree.AppendElement(AccessibleData(id, role, childCount, interfaces));
+#endif
+
+  for (uint32_t i = 0; i < childCount; i++) {
+    SerializeTree(aRoot->GetChildAt(i), aTree);
+  }
+}
+
+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->GetAccessible()->IndexInParent();
+  nsTArray<AccessibleData> shownTree;
+  ShowEventData data(parentID, idxInParent, shownTree);
+  SerializeTree(aShowEvent->GetAccessible(), data.NewTree());
+  MaybeSendShowEvent(data, aShowEvent->IsFromUserInput());
+}
+
+} // namespace a11y
+} // namespace mozilla
+
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/DocAccessibleChildBase.h
@@ -0,0 +1,81 @@
+/* -*- 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/. */
+
+#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;
+
+class DocAccessibleChildBase : public PDocAccessibleChild
+{
+public:
+  explicit DocAccessibleChildBase(DocAccessible* aDoc)
+    : mDoc(aDoc)
+  {
+    MOZ_COUNT_CTOR(DocAccessibleChildBase);
+  }
+
+  ~DocAccessibleChildBase()
+  {
+    // Shutdown() should have been called, but maybe it isn't if the process is
+    // killed?
+    MOZ_ASSERT(!mDoc);
+    if (mDoc) {
+      mDoc->SetIPCDoc(nullptr);
+    }
+
+    MOZ_COUNT_DTOR(DocAccessibleChildBase);
+  }
+
+  virtual void Shutdown()
+  {
+    DetachDocument();
+    SendShutdown();
+  }
+
+  void ShowEvent(AccShowEvent* aShowEvent);
+
+  virtual void ActorDestroy(ActorDestroyReason) override
+  {
+    if (!mDoc) {
+      return;
+    }
+
+    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
@@ -1,89 +1,104 @@
 /* -*- 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 "DocAccessibleParent.h"
 #include "mozilla/a11y/Platform.h"
-#include "ProxyAccessible.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) {
@@ -98,64 +113,70 @@ DocAccessibleParent::AddSubtree(ProxyAcc
   }
 
   if (mAccessibles.Contains(newChild.ID())) {
     NS_ERROR("ID already in use");
     return 0;
   }
 
   auto role = static_cast<a11y::role>(newChild.Role());
+
   ProxyAccessible* newProxy =
     new ProxyAccessible(newChild.ID(), aParent, this, role,
                         newChild.Interfaces());
+
   aParent->AddChildAt(aIdxInParent, newProxy);
   mAccessibles.PutEntry(newChild.ID())->mProxy = newProxy;
   ProxyCreated(newProxy, newChild.Interfaces());
 
+#if defined(XP_WIN)
+  WrapperFor(newProxy)->SetID(newChild.MsaaID());
+#endif
+
   uint32_t accessibles = 1;
   uint32_t kids = newChild.ChildrenCount();
   for (uint32_t i = 0; i < kids; i++) {
     uint32_t consumed = AddSubtree(newProxy, aNewTree, aIdx + accessibles, i);
     if (!consumed)
       return 0;
 
     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;
@@ -169,288 +190,505 @@ 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();
   }