Merge review head draft
authorGregory Szorc <gps@mozilla.com>
Fri, 24 Mar 2017 11:14:10 -0700
changeset 515465 23eef77fb5e759a8618094df7ce35ba37b7fdebd
parent 515464 4503e00444e2be6b7be68b4fceb531c60250d998 (diff)
parent 336597 dc6069f44349fa8cf3c1e5728f464dc273c76c9b (current diff)
child 515466 421c15bb1a7aff8eade76affab467f9c55b81c17
push id50896
push usergszorc@mozilla.com
push dateFri, 24 Mar 2017 18:17:32 +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,190 +1,332 @@
 # 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.
-accessible/**
+# 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/**
+tools/update-packaging/**
 uriloader/**
 view/**
-webapprt/**
 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/*.js
 devtools/client/canvasdebugger/**
 devtools/client/commandline/**
 devtools/client/debugger/**
-devtools/client/eyedropper/**
 devtools/client/framework/**
-# devtools/client/inspector/shared/*.js files are eslint-clean, so they aren't
-# included in the ignore list.
-devtools/client/inspector/computed/**
-devtools/client/inspector/fonts/**
-devtools/client/inspector/markup/test/**
-devtools/client/inspector/shared/test/**
-devtools/client/inspector/test/**
-devtools/client/inspector/*.js
-devtools/client/jsonview/**
-devtools/client/memory/**
-devtools/client/netmonitor/**
-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/**
-devtools/client/sourceeditor/**
+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/widgets/*.jsm
+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/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/server/**
-devtools/shared/**
+!devtools/client/webide/components/webideCli.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/shared/d3.js
-devtools/client/webaudioeditor/lib/dagre-d3.js
 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/markupview/test/lib_*
+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
 
 # 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,
+  },
+};
new file mode 100644
--- /dev/null
+++ b/.flake8
@@ -0,0 +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
@@ -174,8 +181,10 @@ end
 
 def js
   call DumpJSStack()
 end
 
 def ft
   call $arg0->DumpFrameTree()
 end
+
+source .gdbinit_python
new file mode 100644
--- /dev/null
+++ b/.gdbinit_python
@@ -0,0 +1,5 @@
+python
+import sys
+sys.path.append('python/gdbpp/')
+import gdbpp
+end
--- a/.gitignore
+++ b/.gitignore
@@ -6,34 +6,32 @@
 *.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*
 /mozconfig
 /configure
 /old-configure
 /config.cache
 /config.log
 /.clang_complete
-/mach.ini
+/machrc
+/.machrc
 
 # Empty marker file that's generated when we check out NSS
 security/manager/.nss.checkout
 
 # Build directories
 /obj*/
 
 # Build directories for js shell
@@ -71,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/
@@ -94,24 +95,30 @@ embedding/ios/GeckoEmbed/GeckoEmbed.xcod
 
 # Ignore mozharness execution files
 testing/mozharness/.tox/
 testing/mozharness/build/
 testing/mozharness/logs/
 testing/mozharness/.coverage
 testing/mozharness/nosetests.xml
 
-# Ignore node_modules from eslint-plugin-mozilla
-testing/eslint-plugin-mozilla/node_modules/
+# 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
 # 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
 testing/talos/talos/tests/devtools/damp.manifest.develop
+
+# Ignore files created when running a reftest.
+lextab.py
+
+# tup database
+/.tup
--- a/.hgignore
+++ b/.hgignore
@@ -19,17 +19,17 @@
 # User files that may appear at the root
 ^\.mozconfig
 ^mozconfig*
 ^configure$
 ^old-configure$
 ^config\.cache$
 ^config\.log$
 ^\.clang_complete
-^mach.ini$
+^\.?machrc$
 
 # Empty marker file that's generated when we check out NSS
 ^security/manager/\.nss\.checkout$
 
 # Build directories
 ^obj
 
 # Build directories for js shell
@@ -38,16 +38,19 @@
 ^js/src/.*-obj/
 
 # 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
@@ -72,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
@@ -111,24 +107,35 @@ GPATH
 ^testing/mozharness/build/
 ^testing/mozharness/logs/
 ^testing/mozharness/.coverage
 ^testing/mozharness/nosetests.xml
 
 # Ignore tox generated dir
 .tox/
 
-# Ignore node_modules from eslint-plugin-mozilla
-^testing/eslint-plugin-mozilla/node_modules/
+# 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
@@ -119,8 +119,16 @@ 98086da94ccdc88f6de86774ce3d1fa258dc7c44
 1b6bf6612c0f4d4fee81d18bf18016e692f874e1 FIREFOX_AURORA_39_BASE
 66a95a483d2c77dfc387019336d18093acd6aac2 FIREFOX_AURORA_40_BASE
 312c68b16549de9cea1557f461d5d234bd5e0a7d FIREFOX_AURORA_41_BASE
 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/.lldbinit
+++ b/.lldbinit
@@ -4,17 +4,17 @@
 # For documentation on all of the commands and type summaries defined here
 # and in the accompanying Python scripts, see python/lldbutils/README.txt.
 # -----------------------------------------------------------------------------
 
 # Import the module that defines complex Gecko debugging commands.  This assumes
 # you are either running lldb from the top level source directory, the objdir,
 # or the dist/bin directory.  (.lldbinit files in the objdir and dist/bin set
 # topsrcdir appropriately.)
-script topsrcdir = topsrcdir if locals().has_key("topsrcdir") else "."; sys.path.append(os.path.join(topsrcdir, "python/lldbutils")); import lldbutils; lldbutils.init()
+script topsrcdir = topsrcdir if locals().has_key("topsrcdir") else os.getcwd(); sys.path.append(os.path.join(topsrcdir, "python/lldbutils")); import lldbutils; lldbutils.init()
 
 # Mozilla's use of UNIFIED_SOURCES to include multiple source files into a
 # single compiled file breaks lldb breakpoint setting. This works around that.
 # See http://lldb.llvm.org/troubleshooting.html for more info.
 settings set target.inline-breakpoint-strategy always
 
 # Show the dynamic type of an object when using "expr".  This, for example,
 # will show a variable declared as "nsIFrame *" that points to an nsBlockFrame
rename from testing/taskcluster/tasks/decision/try.yml
rename to .taskcluster.yml
--- a/testing/taskcluster/tasks/decision/try.yml
+++ b/.taskcluster.yml
@@ -1,101 +1,123 @@
 ---
+version: 0
 metadata:
-  name: 'Taskcluster decision task for {{project}}'
-  description: |
-    Try push for {{owner}}.
+  name: 'Taskcluster tasks for Gecko'
+  description: "The taskcluster task graph for Gecko trees"
   owner: mozilla-taskcluster-maintenance@mozilla.com
-  source: "{{{source}}}"
+  source: {{{source}}}
 
 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:*
 
+# 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:       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}}'
-    reruns: 3
     task:
       created: '{{now}}'
       deadline: '{{#from_now}}1 day{{/from_now}}'
+      expires: '{{#from_now}}365 day{{/from_now}}'
       metadata:
         owner: mozilla-taskcluster-maintenance@mozilla.com
         source: {{{source}}}
-        name: "[tc] Initial decision task for try"
+        name: "Gecko Decision Task"
         description: |
-          This is the single most important task as it decides how all other tasks
-          get built.
+            The task that creates all of the other tasks in the task graph
 
       workerType: "gecko-decision"
       provisionerId: "aws-provisioner-v1"
 
       tags:
         createdForUser: {{owner}}
 
-      scopes:
-        - "docker-worker:cache:level-{{level}}-{{project}}-tc-vcs-public-sources"
-        - "docker-worker:cache:level-{{level}}-{{project}}-gecko-decision"
-        - "queue:route:tc-treeherder-stage.{{project}}.{{revision_hash}}"
-        - "queue:route:tc-treeherder.{{project}}.{{revision_hash}}"
-
       routes:
         - "index.gecko.v2.{{project}}.latest.firefox.decision"
-        - "tc-treeherder.{{project}}.{{revision_hash}}"
-        - "tc-treeherder-stage.{{project}}.{{revision_hash}}"
+        - "tc-treeherder.v2.{{project}}.{{revision}}.{{pushlog_id}}"
+        - "tc-treeherder-stage.v2.{{project}}.{{revision}}.{{pushlog_id}}"
 
       payload:
         env:
-          GECKO_BASE_REPOSITORY: 'https://hg.mozilla.org/mozilla-central'
+          # 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-unified'
           GECKO_HEAD_REPOSITORY: '{{{url}}}'
           GECKO_HEAD_REF: '{{revision}}'
           GECKO_HEAD_REV: '{{revision}}'
+          HG_STORE_PATH: /home/worker/checkouts/hg-store
 
         cache:
-          # The taskcluster-vcs tooling stores the large clone caches in this
-          # directory and will reuse them for new requests this saves about 20s~ and
-          # is the most generic cache possible.
-          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/builder:0.5.11'
+        # exist in tree so we must hard code the hash
+        image: 'taskcluster/decision:0.1.8@sha256:195d8439c8e90d59311d877bd2a8964849b2e43bfc6c234092618518d8b2891b'
 
-        # Virtually no network or other potentially risky operations happen as part
-        # of the task timeout aside from the initial clone. We intentionally have
-        # set this to a lower value _all_ decision tasks should use a root
-        # repository which is cached.
         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 &&
-            ./mach taskcluster-graph
-            --pushlog-id='{{pushlog_id}}'
-            --project='{{project}}'
-            --message='{{comment}}'
-            --owner='{{owner}}'
-            --level='{{level}}'
-            --revision-hash='{{revision_hash}}'
-            --extend-graph > /home/worker/artifacts/graph.json
-
-        graphs:
-          - /home/worker/artifacts/graph.json
+              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'
-            # Arbitrary value for keeping these artifacts around.  They are just the
-            # graph.json and context directories for now, so nothing that needs
-            # to stay around for long.
-            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,10 +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 1246756 - Update Skia to m49 branch.
-
+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
@@ -12,17 +12,17 @@ ifneq ($(make_min_ver),$(firstword $(sor
 endif
 
 export TOPLEVEL_BUILD := 1
 
 default::
 
 ifndef TEST_MOZBUILD
 ifdef MOZ_BUILD_APP
-include $(topsrcdir)/$(MOZ_BUILD_APP)/build.mk
+include $(wildcard $(topsrcdir)/$(MOZ_BUILD_APP)/build.mk)
 endif
 endif
 
 include $(topsrcdir)/config/config.mk
 
 GARBAGE_DIRS += _javagen _profile staticlib
 DIST_GARBAGE = config.cache config.log config.status* config-defs.h \
    config/autoconf.mk \
@@ -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,41 +140,61 @@ 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/% ;
 
-# For compatibility
 .PHONY: install-tests
-install-tests: install-_tests
+install-tests: install-test-files
+
+# 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
 # purged during PGO builds because they contain some auto-generated files.
 ifneq ($(filter-out maybe_clobber_profiledbuild,$(MAKECMDGOALS)),)
 GARBAGE_DIRS += dist _tests
 endif
@@ -223,129 +217,126 @@ recurse_pre-export:: install-manifests
 binaries::
 	@$(MAKE) install-manifests NO_REMOVE=1 install_manifests=dist/include
 endif
 
 # For historical reasons that are unknown, $(DIST)/sdk is always blown away
 # with no regard for PGO passes. This decision could probably be revisited.
 recurse_pre-export:: install-dist/sdk
 
+recurse_artifact:
+	$(topsrcdir)/mach --log-no-times artifact install
+
 ifndef JS_STANDALONE
 ifdef ENABLE_TESTS
 # Additional makefile targets to call automated test suites
 include $(topsrcdir)/testing/testsuite-targets.mk
 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
 endif
+ifdef MSVC_HAS_DIA_SDK
+DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_syms.exe
+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
 
 SYM_STORE_SOURCE_DIRS := $(topsrcdir)
 
+ifdef MOZ_CRASHREPORTER
 include $(topsrcdir)/toolkit/mozapps/installer/package-name.mk
 
-ifdef MOZ_SYMBOLS_EXTRA_BUILDID
-EXTRA_BUILDID := -$(MOZ_SYMBOLS_EXTRA_BUILDID)
+SYMBOL_INDEX_NAME = \
+  $(MOZ_APP_NAME)-$(MOZ_APP_VERSION)-$(OS_TARGET)-$(BUILDID)-$(CPU_ARCH)-symbols.txt
 endif
 
-SYMBOL_INDEX_NAME = \
-  $(MOZ_APP_NAME)-$(MOZ_APP_VERSION)-$(OS_TARGET)-$(BUILDID)-$(CPU_ARCH)$(EXTRA_BUILDID)-symbols.txt
-
-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 -r9D '../$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip' . -x '*test*' -x '*Test*'
+          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 -r9D '../$(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'
-else
-	$(SHELL) $(topsrcdir)/toolkit/crashreporter/tools/upload_symbols.sh $(SYMBOL_INDEX_NAME) '$(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/
new file mode 100644
--- /dev/null
+++ b/accessible/.eslintrc.js
@@ -0,0 +1,17 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "../.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,33 +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 "nsAutoPtr.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;
@@ -62,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:
@@ -90,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,
@@ -281,17 +286,17 @@ AccessibleWrap::Shutdown()
 }
 
 void
 AccessibleWrap::GetNativeInterface(void** aOutAccessible)
 {
   *aOutAccessible = nullptr;
 
   if (!mAtkObject) {
-    if (IsDefunct() || !nsAccUtils::IsEmbeddedObject(this)) {
+    if (IsDefunct() || IsText()) {
       // We don't create ATK objects for node which has been shutdown or
       // plain text leaves
       return;
     }
 
     GType type = GetMaiAtkType(CreateMaiInterfaces());
     if (!type)
       return;
@@ -363,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;
 }
@@ -421,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()
 {
@@ -592,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.
@@ -788,34 +803,23 @@ GetLocaleCB(AtkObject* aAtkObj)
 }
 
 AtkObject *
 getParentCB(AtkObject *aAtkObj)
 {
   if (aAtkObj->accessible_parent)
     return aAtkObj->accessible_parent;
 
-  AtkObject* atkParent = nullptr;
-  if (AccessibleWrap* wrapper = GetAccessibleWrap(aAtkObj)) {
-    Accessible* parent = wrapper->Parent();
-    atkParent = parent ? AccessibleWrap::GetAtkObject(parent) : nullptr;
-  } else if (ProxyAccessible* proxy = GetProxy(aAtkObj)) {
-    ProxyAccessible* parent = proxy->Parent();
-    if (parent) {
-      atkParent = GetWrapperFor(parent);
-    } else {
-      // Otherwise this should be the proxy for the tab's top level document.
-      Accessible* outerDocParent = proxy->OuterDocOfRemoteBrowser();
-      NS_ASSERTION(outerDocParent, "this document should have an outerDoc as a parent");
-      if (outerDocParent) {
-        atkParent = AccessibleWrap::GetAtkObject(outerDocParent);
-      }
-    }
+  AccessibleOrProxy acc = GetInternalObj(aAtkObj);
+  if (acc.IsNull()) {
+    return nullptr;
   }
 
+  AccessibleOrProxy parent = acc.Parent();
+  AtkObject* atkParent = !parent.IsNull() ? GetWrapperFor(parent) : nullptr;
   if (atkParent)
     atk_object_set_parent(aAtkObj, atkParent);
 
   return aAtkObj->accessible_parent;
 }
 
 gint
 getChildCountCB(AtkObject *aAtkObj)
@@ -1096,16 +1100,26 @@ GetInternalObj(AtkObject* aObj)
 }
 
 AtkObject*
 GetWrapperFor(ProxyAccessible* aProxy)
 {
   return reinterpret_cast<AtkObject*>(aProxy->GetWrapper() & ~IS_PROXY);
 }
 
+AtkObject*
+GetWrapperFor(AccessibleOrProxy aObj)
+{
+  if (aObj.IsProxy()) {
+    return GetWrapperFor(aObj.AsProxy());
+  }
+
+  return AccessibleWrap::GetAtkObject(aObj.AsAccessible());
+}
+
 static uint16_t
 GetInterfacesForProxy(ProxyAccessible* aProxy, uint32_t aInterfaces)
 {
   uint16_t interfaces = 1 << MAI_INTERFACE_COMPONENT;
   if (aInterfaces & Interfaces::HYPERTEXT)
     interfaces |= (1 << MAI_INTERFACE_HYPERTEXT) | (1 << MAI_INTERFACE_TEXT)
         | (1 << MAI_INTERFACE_EDITABLE_TEXT);
 
@@ -1113,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;
@@ -1153,16 +1170,20 @@ a11y::ProxyCreated(ProxyAccessible* aPro
   obj->layer = ATK_LAYER_INVALID;
   aProxy->SetWrapper(reinterpret_cast<uintptr_t>(obj) | IS_PROXY);
 }
 
 void
 a11y::ProxyDestroyed(ProxyAccessible* aProxy)
 {
   auto obj = reinterpret_cast<MaiAtkObject*>(aProxy->GetWrapper() & ~IS_PROXY);
+  if (!obj) {
+    return;
+  }
+
   obj->Shutdown();
   g_object_unref(obj);
   aProxy->SetWrapper(0);
 }
 
 nsresult
 AccessibleWrap::HandleAccEvent(AccEvent* aEvent)
 {
@@ -1350,26 +1371,43 @@ AccessibleWrap::HandleAccEvent(AccEvent*
         g_signal_emit_by_name(atkObj, "column_reordered");
         break;
 
     case nsIAccessibleEvent::EVENT_SECTION_CHANGED:
         g_signal_emit_by_name(atkObj, "visible_data_changed");
         break;
 
     case nsIAccessibleEvent::EVENT_SHOW:
-        return FireAtkShowHideEvent(aEvent, atkObj, true);
+      {
+        AccMutationEvent* event = downcast_accEvent(aEvent);
+        Accessible* parentAcc = event ? event->Parent() : accessible->Parent();
+        AtkObject* parent = AccessibleWrap::GetAtkObject(parentAcc);
+        NS_ENSURE_STATE(parent);
+        auto obj = reinterpret_cast<MaiAtkObject*>(atkObj);
+        obj->FireAtkShowHideEvent(parent, true, aEvent->IsFromUserInput());
+        return NS_OK;
+      }
 
     case nsIAccessibleEvent::EVENT_HIDE:
+      {
         // XXX - Handle native dialog accessibles.
         if (!accessible->IsRoot() && accessible->HasARIARole() &&
             accessible->ARIARole() == roles::DIALOG) {
           guint id = g_signal_lookup("deactivate", MAI_TYPE_ATK_OBJECT);
           g_signal_emit(atkObj, id, 0);
         }
-        return FireAtkShowHideEvent(aEvent, atkObj, false);
+
+        AccMutationEvent* event = downcast_accEvent(aEvent);
+        Accessible* parentAcc = event ? event->Parent() : accessible->Parent();
+        AtkObject* parent = AccessibleWrap::GetAtkObject(parentAcc);
+        NS_ENSURE_STATE(parent);
+        auto obj = reinterpret_cast<MaiAtkObject*>(atkObj);
+        obj->FireAtkShowHideEvent(parent, false, aEvent->IsFromUserInput());
+        return NS_OK;
+      }
 
         /*
          * Because dealing with menu is very different between nsIAccessible
          * and ATK, and the menu activity is important, specially transfer the
          * following two event.
          * Need more verification by AT test.
          */
     case nsIAccessibleEvent::EVENT_MENU_START:
@@ -1474,16 +1512,20 @@ a11y::ProxyEvent(ProxyAccessible* aTarge
     break;
   case nsIAccessibleEvent::EVENT_ALERT:
     // A hack using state change showing events as alert events.
     atk_object_notify_state_change(wrapper, ATK_STATE_SHOWING, true);
     break;
   case nsIAccessibleEvent::EVENT_VALUE_CHANGE:
     g_object_notify((GObject*)wrapper, "accessible-value");
     break;
+  case nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED:
+  case nsIAccessibleEvent::EVENT_SELECTION_WITHIN:
+    g_signal_emit_by_name(wrapper, "selection_changed");
+    break;
   }
 }
 
 void
 a11y::ProxyStateChangeEvent(ProxyAccessible* aTarget, uint64_t aState,
                             bool aEnabled)
 {
   MaiAtkObject* atkObj = MAI_ATK_OBJECT(GetWrapperFor(aTarget));
@@ -1564,37 +1606,46 @@ MaiAtkObject::FireTextChangeEvent(const 
   } else {
     const char* signal_name =
       textChangedStrings[aFromUser][aIsInsert];
     g_signal_emit_by_name(this, signal_name, aStart, aLen,
                           NS_ConvertUTF16toUTF8(aStr).get());
   }
 }
 
+void
+a11y::ProxyShowHideEvent(ProxyAccessible* aTarget, ProxyAccessible* aParent,
+                         bool aInsert, bool aFromUser)
+{
+  MaiAtkObject* obj = MAI_ATK_OBJECT(GetWrapperFor(aTarget));
+  obj->FireAtkShowHideEvent(GetWrapperFor(aParent), aInsert, aFromUser);
+}
+
 #define ADD_EVENT "children_changed::add"
 #define HIDE_EVENT "children_changed::remove"
 
 static const char *kMutationStrings[2][2] = {
   { HIDE_EVENT NON_USER_EVENT, ADD_EVENT NON_USER_EVENT },
   { HIDE_EVENT, ADD_EVENT },
 };
 
-nsresult
-AccessibleWrap::FireAtkShowHideEvent(AccEvent* aEvent,
-                                     AtkObject* aObject, bool aIsAdded)
+void
+MaiAtkObject::FireAtkShowHideEvent(AtkObject* aParent, bool aIsAdded,
+                                   bool aFromUser)
 {
-    int32_t indexInParent = getIndexInParentCB(aObject);
-    AtkObject *parentObject = getParentCB(aObject);
-    NS_ENSURE_STATE(parentObject);
+    int32_t indexInParent = getIndexInParentCB(&this->parent);
+    const char *signal_name = kMutationStrings[aFromUser][aIsAdded];
+    g_signal_emit_by_name(aParent, signal_name, indexInParent, this, nullptr);
+}
 
-    bool isFromUserInput = aEvent->IsFromUserInput();
-    const char *signal_name = kMutationStrings[isFromUserInput][aIsAdded];
-    g_signal_emit_by_name(parentObject, signal_name, indexInParent, aObject, nullptr);
-
-    return NS_OK;
+void
+a11y::ProxySelectionEvent(ProxyAccessible*, ProxyAccessible* aWidget, uint32_t)
+{
+  MaiAtkObject* obj = MAI_ATK_OBJECT(GetWrapperFor(aWidget));
+    g_signal_emit_by_name(obj, "selection_changed");
 }
 
 // static
 void
 AccessibleWrap::GetKeyBinding(Accessible* aAccessible, nsAString& aResult)
 {
   // Return all key bindings including access key and keyboard shortcut.
 
--- a/accessible/atk/AccessibleWrap.h
+++ b/accessible/atk/AccessibleWrap.h
@@ -74,18 +74,16 @@ public:
   static Accessible* GetColumnHeader(TableAccessible* aAccessible,
                                      int32_t aColIdx);
   static Accessible* GetRowHeader(TableAccessible* aAccessible,
                                   int32_t aRowIdx);
 protected:
 
   nsresult FireAtkStateChangeEvent(AccEvent* aEvent, AtkObject *aObject);
   nsresult FireAtkTextChangedEvent(AccEvent* aEvent, AtkObject *aObject);
-  nsresult FireAtkShowHideEvent(AccEvent* aEvent, AtkObject *aObject,
-                                bool aIsAdded);
 
   AtkObject *mAtkObject;
 
 private:
   uint16_t CreateMaiInterfaces();
 };
 
 } // namespace a11y
--- a/accessible/atk/ApplicationAccessibleWrap.cpp
+++ b/accessible/atk/ApplicationAccessibleWrap.cpp
@@ -3,17 +3,16 @@
 /* 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 "ApplicationAccessibleWrap.h"
 
 #include "nsCOMPtr.h"
 #include "nsMai.h"
-#include "nsAutoPtr.h"
 #include "nsAccessibilityService.h"
 
 #include <gtk/gtk.h>
 #include <atk/atk.h>
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
--- 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,40 +19,45 @@ 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 CONFIG['MOZ_ENABLE_GTK']:
+if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
     CFLAGS += CONFIG['TK_CFLAGS']
     CXXFLAGS += CONFIG['TK_CFLAGS']
 
 if CONFIG['MOZ_ENABLE_DBUS']:
     CXXFLAGS += CONFIG['MOZ_DBUS_CFLAGS']
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 if CONFIG['CLANG_CXX'] or CONFIG['GNU_CXX']:
     # Used in G_DEFINE_TYPE_EXTENDED macro, probably fixed in newer glib /
     # gobject headers. See bug 1243331 comment 3.
-    CXXFLAGS += ['-Wno-unused-local-typedefs']
+    CXXFLAGS += [
+        '-Wno-error=shadow',
+        '-Wno-unused-local-typedefs',
+    ]
--- a/accessible/atk/nsMai.h
+++ b/accessible/atk/nsMai.h
@@ -60,20 +60,25 @@ 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;
 
 /**
  * Return true if the loaded version of libatk-1.0.so is at least
  * aMajor.aMinor.0.
  */
 static inline bool
@@ -115,16 +120,22 @@ struct MaiAtkObject
   void FireStateChangeEvent(uint64_t aState, bool aEnabled);
 
   /*
    * Notify ATK of a text change within this ATK object.
    */
   void FireTextChangeEvent(const nsString& aStr, int32_t aStart, uint32_t aLen,
                            bool aIsInsert, bool aIsFromUser);
 
+  /**
+   * Notify ATK of a shown or hidden subtree rooted at aObject whose parent is
+   * aParent
+   */
+  void FireAtkShowHideEvent(AtkObject* aParent, bool aIsAdded, bool aFromUser);
+
 private:
   /*
    * do we have text-remove and text-insert signals if not we need to use
    * text-changed see AccessibleWrap::FireAtkTextChangedEvent() and
    * bug 619002
    */
   enum EAvailableAtkSignals {
     eUnknown,
--- 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
@@ -11,16 +11,17 @@
 #include "nsCoreUtils.h"
 #include "Role.h"
 #include "States.h"
 
 #include "nsAttrName.h"
 #include "nsWhitespaceTokenizer.h"
 
 #include "mozilla/BinarySearch.h"
+#include "mozilla/dom/Element.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 using namespace mozilla::a11y::aria;
 
 static const uint32_t kGenericAccType = 0;
 
 /**
@@ -29,17 +30,17 @@ static const uint32_t kGenericAccType = 
  *  Using RDF will also allow for role extensibility. See bug 280138.
  *
  *  Definition of nsRoleMapEntry contains comments explaining this table.
  *
  *  When no Role enum mapping exists for an ARIA role, the role will be exposed
  *  via the object attribute "xml-roles".
  */
 
-static nsRoleMapEntry sWAIRoleMaps[] =
+static const nsRoleMapEntry sWAIRoleMaps[] =
 {
   { // alert
     &nsGkAtoms::alert,
     roles::ALERT,
     kUseMapRole,
     eNoValue,
     eNoAction,
     eNoLiveAttr,
@@ -178,29 +179,39 @@ static 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,
@@ -754,17 +765,17 @@ static nsRoleMapEntry sWAIRoleMaps[] =
     eNoLiveAttr,
     kGenericAccType,
     kNoReqStates,
     eARIASelectable,
     eARIACheckedMixed
   }
 };
 
-static nsRoleMapEntry sLandmarkRoleMap = {
+static const nsRoleMapEntry sLandmarkRoleMap = {
   &nsGkAtoms::_empty,
   roles::NOTHING,
   kUseNativeRole,
   eNoValue,
   eNoAction,
   eNoLiveAttr,
   kGenericAccType,
   kNoReqStates
@@ -811,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 },
@@ -855,42 +868,76 @@ struct RoleComparator
   explicit RoleComparator(const nsDependentSubstring& aRole) : mRole(aRole) {}
   int operator()(const nsRoleMapEntry& aEntry) const {
     return Compare(mRole, aEntry.ARIARoleString());
   }
 };
 
 }
 
-nsRoleMapEntry*
-aria::GetRoleMap(nsINode* aNode)
+const nsRoleMapEntry*
+aria::GetRoleMap(dom::Element* aEl)
 {
-  nsIContent* content = nsCoreUtils::GetRoleContent(aNode);
+  return GetRoleMapFromIndex(GetRoleMapIndex(aEl));
+}
+
+uint8_t
+aria::GetRoleMapIndex(dom::Element* aEl)
+{
   nsAutoString roles;
-  if (!content ||
-      !content->GetAttr(kNameSpaceID_None, nsGkAtoms::role, 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,24 +198,65 @@ 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
  */
-nsRoleMapEntry* GetRoleMap(nsINode* aNode);
+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);
 
 /**
deleted file mode 100644
--- a/accessible/base/AccCollector.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/* 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 "AccCollector.h"
-
-#include "Accessible.h"
-
-using namespace mozilla::a11y;
-
-////////////////////////////////////////////////////////////////////////////////
-// nsAccCollector
-////////////////////////////////////////////////////////////////////////////////
-
-AccCollector::
-  AccCollector(Accessible* aRoot, filters::FilterFuncPtr aFilterFunc) :
-  mFilterFunc(aFilterFunc), mRoot(aRoot), mRootChildIdx(0)
-{
-}
-
-AccCollector::~AccCollector()
-{
-}
-
-uint32_t
-AccCollector::Count()
-{
-  EnsureNGetIndex(nullptr);
-  return mObjects.Length();
-}
-
-Accessible*
-AccCollector::GetAccessibleAt(uint32_t aIndex)
-{
-  Accessible* accessible = mObjects.SafeElementAt(aIndex, nullptr);
-  if (accessible)
-    return accessible;
-
-  return EnsureNGetObject(aIndex);
-}
-
-int32_t
-AccCollector::GetIndexAt(Accessible* aAccessible)
-{
-  int32_t index = mObjects.IndexOf(aAccessible);
-  if (index != -1)
-    return index;
-
-  return EnsureNGetIndex(aAccessible);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// nsAccCollector protected
-
-Accessible*
-AccCollector::EnsureNGetObject(uint32_t aIndex)
-{
-  uint32_t childCount = mRoot->ChildCount();
-  while (mRootChildIdx < childCount) {
-    Accessible* child = mRoot->GetChildAt(mRootChildIdx++);
-    if (!(mFilterFunc(child) & filters::eMatch))
-      continue;
-
-    AppendObject(child);
-    if (mObjects.Length() - 1 == aIndex)
-      return mObjects[aIndex];
-  }
-
-  return nullptr;
-}
-
-int32_t
-AccCollector::EnsureNGetIndex(Accessible* aAccessible)
-{
-  uint32_t childCount = mRoot->ChildCount();
-  while (mRootChildIdx < childCount) {
-    Accessible* child = mRoot->GetChildAt(mRootChildIdx++);
-    if (!(mFilterFunc(child) & filters::eMatch))
-      continue;
-
-    AppendObject(child);
-    if (child == aAccessible)
-      return mObjects.Length() - 1;
-  }
-
-  return -1;
-}
-
-void
-AccCollector::AppendObject(Accessible* aAccessible)
-{
-  mObjects.AppendElement(aAccessible);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// EmbeddedObjCollector
-////////////////////////////////////////////////////////////////////////////////
-
-int32_t
-EmbeddedObjCollector::GetIndexAt(Accessible* aAccessible)
-{
-  if (aAccessible->mParent != mRoot)
-    return -1;
-
-  MOZ_ASSERT(!aAccessible->IsProxy());
-  if (aAccessible->mInt.mIndexOfEmbeddedChild != -1)
-    return aAccessible->mInt.mIndexOfEmbeddedChild;
-
-  return mFilterFunc(aAccessible) & filters::eMatch ?
-    EnsureNGetIndex(aAccessible) : -1;
-}
-
-void
-EmbeddedObjCollector::AppendObject(Accessible* aAccessible)
-{
-  MOZ_ASSERT(!aAccessible->IsProxy());
-  aAccessible->mInt.mIndexOfEmbeddedChild = mObjects.Length();
-  mObjects.AppendElement(aAccessible);
-}
deleted file mode 100644
--- a/accessible/base/AccCollector.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/* 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_AccCollector_h__
-#define mozilla_a11y_AccCollector_h__
-
-#include "Filters.h"
-
-#include "nsTArray.h"
-
-namespace mozilla {
-namespace a11y {
-
-class Accessible;
-
-/**
- * Collect accessible children complying with filter function. Provides quick
- * access to accessible by index.
- */
-class AccCollector
-{
-public:
-  AccCollector(Accessible* aRoot, filters::FilterFuncPtr aFilterFunc);
-  virtual ~AccCollector();
-
-  /**
-   * Return accessible count within the collection.
-   */
-  uint32_t Count();
-
-  /**
-   * Return an accessible from the collection at the given index.
-   */
-  Accessible* GetAccessibleAt(uint32_t aIndex);
-
-  /**
-   * Return index of the given accessible within the collection.
-   */
-  virtual int32_t GetIndexAt(Accessible* aAccessible);
-
-protected:
-  /**
-   * Ensure accessible at the given index is stored and return it.
-   */
-  Accessible* EnsureNGetObject(uint32_t aIndex);
-
-  /**
-   * Ensure index for the given accessible is stored and return it.
-   */
-  int32_t EnsureNGetIndex(Accessible* aAccessible);
-
-  /**
-   * Append the object to collection.
-   */
-  virtual void AppendObject(Accessible* aAccessible);
-
-  filters::FilterFuncPtr mFilterFunc;
-  Accessible* mRoot;
-  uint32_t mRootChildIdx;
-
-  nsTArray<Accessible*> mObjects;
-
-private:
-  AccCollector();
-  AccCollector(const AccCollector&);
-  AccCollector& operator =(const AccCollector&);
-};
-
-/**
- * Collect embedded objects. Provide quick access to accessible by index and
- * vice versa.
- */
-class EmbeddedObjCollector final : public AccCollector
-{
-public:
-  virtual ~EmbeddedObjCollector() { }
-
-public:
-  virtual int32_t GetIndexAt(Accessible* aAccessible) override;
-
-protected:
-  // Make sure it's used by Accessible class only.
-  explicit EmbeddedObjCollector(Accessible* aRoot) :
-    AccCollector(aRoot, filters::GetEmbeddedObject) { }
-
-  virtual void AppendObject(Accessible* aAccessible) override;
-
-  friend class Accessible;
-};
-
-} // namespace a11y
-} // namespace mozilla
-
-#endif
--- 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
 ////////////////////////////////////////////////////////////////////////////////
@@ -72,38 +88,16 @@ AccTextChangeEvent::
   , mModifiedText(aModifiedText)
 {
   // XXX We should use IsFromUserInput here, but that isn't always correct
   // when the text change isn't related to content insertion or removal.
    mIsFromUserInput = mAccessible->State() &
     (states::FOCUSED | states::EDITABLE);
 }
 
-
-////////////////////////////////////////////////////////////////////////////////
-// AccReorderEvent
-////////////////////////////////////////////////////////////////////////////////
-
-uint32_t
-AccReorderEvent::IsShowHideEventTarget(const Accessible* aTarget) const
-{
-  uint32_t count = mDependentEvents.Length();
-  for (uint32_t index = count - 1; index < count; index--) {
-    if (mDependentEvents[index]->mAccessible == aTarget) {
-      uint32_t eventType = mDependentEvents[index]->mEventType;
-      if (eventType == nsIAccessibleEvent::EVENT_SHOW ||
-          eventType == nsIAccessibleEvent::EVENT_HIDE) {
-        return mDependentEvents[index]->mEventType;
-      }
-    }
-  }
-
-  return 0;
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // AccHideEvent
 ////////////////////////////////////////////////////////////////////////////////
 
 AccHideEvent::
   AccHideEvent(Accessible* aTarget, bool aNeedsShutdown) :
   AccMutationEvent(::nsIAccessibleEvent::EVENT_HIDE, aTarget),
   mNeedsShutdown(aNeedsShutdown)
@@ -116,16 +110,19 @@ AccHideEvent::
 ////////////////////////////////////////////////////////////////////////////////
 // AccShowEvent
 ////////////////////////////////////////////////////////////////////////////////
 
 AccShowEvent::
   AccShowEvent(Accessible* aTarget) :
   AccMutationEvent(::nsIAccessibleEvent::EVENT_SHOW, aTarget)
 {
+  int32_t idx = aTarget->IndexInParent();
+  MOZ_ASSERT(idx >= 0);
+  mInsertionIndex = idx;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // AccTextSelChangeEvent
 ////////////////////////////////////////////////////////////////////////////////
 
 AccTextSelChangeEvent::AccTextSelChangeEvent(HyperTextAccessible* aTarget,
@@ -194,17 +191,17 @@ AccVCChangeEvent::
     mOldAccessible(aOldAccessible), mOldStart(aOldStart), mOldEnd(aOldEnd),
     mReason(aReason)
 {
 }
 
 already_AddRefed<nsIAccessibleEvent>
 a11y::MakeXPCEvent(AccEvent* aEvent)
 {
-  DocAccessible* doc = aEvent->GetDocAccessible();
+  DocAccessible* doc = aEvent->Document();
   Accessible* acc = aEvent->GetAccessible();
   nsINode* node = acc->GetNode();
   nsIDOMNode* domNode = node ? node->AsDOMNode() : nullptr;
   bool fromUser = aEvent->IsFromUserInput();
   uint32_t type = aEvent->GetEventType();
   uint32_t eventGroup = aEvent->GetEventGroups();
   nsCOMPtr<nsIAccessibleEvent> xpEvent;
 
--- 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.
@@ -83,25 +80,26 @@ public:
   // AccEvent
   uint32_t GetEventType() const { return mEventType; }
   EEventRule GetEventRule() const { return mEventRule; }
   bool IsFromUserInput() const { return mIsFromUserInput; }
   EIsFromUserInput FromUserInput() const
     { return static_cast<EIsFromUserInput>(mIsFromUserInput); }
 
   Accessible* GetAccessible() const { return mAccessible; }
-  DocAccessible* GetDocAccessible() const { return mAccessible->Document(); }
+  DocAccessible* Document() const { return mAccessible->Document(); }
 
   /**
    * Down casting.
    */
   enum EventGroup {
     eGenericEvent,
     eStateChangeEvent,
     eTextChangeEvent,
+    eTreeMutationEvent,
     eMutationEvent,
     eReorderEvent,
     eHideEvent,
     eShowEvent,
     eCaretMoveEvent,
     eTextSelChangeEvent,
     eSelectionChangeEvent,
     eTableChangeEvent,
@@ -125,17 +123,19 @@ protected:
   virtual ~AccEvent() {}
 
   bool mIsFromUserInput;
   uint32_t mEventType;
   EEventRule mEventRule;
   RefPtr<Accessible> mAccessible;
 
   friend class EventQueue;
-  friend class AccReorderEvent;
+  friend class EventTree;
+  friend class ::nsEventShell;
+  friend class NotificationController;
 };
 
 
 /**
  * Accessible state change event.
  */
 class AccStateChangeEvent: public AccEvent
 {
@@ -196,55 +196,89 @@ public:
     { aModifiedText = mModifiedText; }
   const nsString& ModifiedText() const { return mModifiedText; }
 
 private:
   int32_t mStart;
   bool mIsInserted;
   nsString mModifiedText;
 
-  friend class EventQueue;
-  friend class AccReorderEvent;
+  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 EventQueue;
+  friend class EventTree;
+  friend class NotificationController;
 };
 
 
 /**
  * Accessible hide event.
  */
 class AccHideEvent: public AccMutationEvent
 {
@@ -264,17 +298,18 @@ public:
   Accessible* TargetPrevSibling() const { return mPrevSibling; }
   bool NeedsShutdown() const { return mNeedsShutdown; }
 
 protected:
   bool mNeedsShutdown;
   RefPtr<Accessible> mNextSibling;
   RefPtr<Accessible> mPrevSibling;
 
-  friend class EventQueue;
+  friend class EventTree;
+  friend class NotificationController;
 };
 
 
 /**
  * Accessible show event.
  */
 class AccShowEvent: public AccMutationEvent
 {
@@ -282,67 +317,43 @@ public:
   explicit AccShowEvent(Accessible* aTarget);
 
   // Event
   static const EventGroup kEventGroup = eShowEvent;
   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);
   }
-
-  /**
-   * Get connected with mutation event.
-   */
-  void AddSubMutationEvent(AccMutationEvent* aEvent)
-    { mDependentEvents.AppendElement(aEvent); }
-
-  /**
-   * Do not emit the reorder event and its connected mutation events.
-   */
-  void DoNotEmitAll()
-  {
-    mEventRule = AccEvent::eDoNotEmit;
-    uint32_t eventsCount = mDependentEvents.Length();
-    for (uint32_t idx = 0; idx < eventsCount; idx++)
-      mDependentEvents[idx]->mEventRule = AccEvent::eDoNotEmit;
-  }
-
-  /**
-   * Return true if the given accessible is a target of connected mutation
-   * event.
-   */
-  uint32_t IsShowHideEventTarget(const Accessible* aTarget) const;
-
-protected:
-  /**
-   * Show and hide events causing this reorder event.
-   */
-  nsTArray<AccMutationEvent*> mDependentEvents;
-
-  friend class EventQueue;
 };
 
 
 /**
  * Accessible caret move event.
  */
 class AccCaretMoveEvent: public AccEvent
 {
--- a/accessible/base/AccIterator.cpp
+++ b/accessible/base/AccIterator.cpp
@@ -252,17 +252,17 @@ XULDescriptionIterator::Next()
 // IDRefsIterator
 ////////////////////////////////////////////////////////////////////////////////
 
 IDRefsIterator::
   IDRefsIterator(DocAccessible* aDoc, nsIContent* aContent,
                  nsIAtom* aIDRefsAttr) :
   mContent(aContent), mDoc(aDoc), mCurrIdx(0)
 {
-  if (mContent->IsInDoc())
+  if (mContent->IsInUncomposedDoc())
     mContent->GetAttr(kNameSpaceID_None, aIDRefsAttr, mIDs);
 }
 
 const nsDependentSubstring
 IDRefsIterator::NextID()
 {
   for (; mCurrIdx < mIDs.Length(); mCurrIdx++) {
     if (!NS_IsAsciiWhitespace(mIDs[mCurrIdx]))
--- a/accessible/base/AccIterator.h
+++ b/accessible/base/AccIterator.h
@@ -5,33 +5,35 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_a11y_AccIterator_h__
 #define mozilla_a11y_AccIterator_h__
 
 #include "DocAccessible.h"
 #include "Filters.h"
 
+#include <memory>
+
 class nsITreeView;
 
 namespace mozilla {
 namespace a11y {
 
 /**
  * AccIterable is a basic interface for iterators over accessibles.
  */
 class AccIterable
 {
 public:
   virtual ~AccIterable() { }
   virtual Accessible* Next() = 0;
 
 private:
   friend class Relation;
-  nsAutoPtr<AccIterable> mNextIter;
+  std::unique_ptr<AccIterable> mNextIter;
 };
 
 /**
  * Allows to iterate through accessible children or subtree complying with
  * filter function.
  */
 class AccIterator : public AccIterable
 {
--- a/accessible/base/AccTypes.h
+++ b/accessible/base/AccTypes.h
@@ -78,16 +78,17 @@ enum AccGenericType {
   eLandmark = 1 << 7,
   eList = 1 << 8,
   eListControl = 1 << 9,
   eMenuButton = 1 << 10,
   eSelect = 1 << 11,
   eTable = 1 << 12,
   eTableCell = 1 << 13,
   eTableRow = 1 << 14,
+  eText = 1 << 15,
 
-  eLastAccGenericType = eTableRow
+  eLastAccGenericType = eText
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif // mozilla_a11y_AccTypes_h
new file mode 100644
--- /dev/null
+++ b/accessible/base/AccessibleOrProxy.cpp
@@ -0,0 +1,27 @@
+/* -*- 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 "AccessibleOrProxy.h"
+
+AccessibleOrProxy
+AccessibleOrProxy::Parent() const
+{
+  if (IsAccessible()) {
+    return AsAccessible()->Parent();
+  }
+
+  ProxyAccessible* proxy = AsProxy();
+  if (!proxy) {
+    return nullptr;
+  }
+
+  if (ProxyAccessible* parent = proxy->Parent()) {
+    return parent;
+  }
+
+  // Otherwise this should be the proxy for the tab's top level document.
+  return proxy->OuterDocOfRemoteBrowser();
+}
--- a/accessible/base/AccessibleOrProxy.h
+++ b/accessible/base/AccessibleOrProxy.h
@@ -21,17 +21,17 @@ namespace a11y {
  * with size sizeof(void*).
  */
 class AccessibleOrProxy
 {
 public:
   MOZ_IMPLICIT AccessibleOrProxy(Accessible* aAcc) :
     mBits(reinterpret_cast<uintptr_t>(aAcc)) {}
   MOZ_IMPLICIT AccessibleOrProxy(ProxyAccessible* aProxy) :
-    mBits(reinterpret_cast<uintptr_t>(aProxy) | IS_PROXY) {}
+    mBits(aProxy ? (reinterpret_cast<uintptr_t>(aProxy) | IS_PROXY) : 0) {}
   MOZ_IMPLICIT AccessibleOrProxy(decltype(nullptr)) : mBits(0) {}
 
   bool IsProxy() const { return mBits & IS_PROXY; }
   ProxyAccessible* AsProxy() const
   {
     if (IsProxy()) {
       return reinterpret_cast<ProxyAccessible*>(mBits & ~IS_PROXY);
     }
@@ -101,16 +101,18 @@ public:
   {
     if (IsProxy()) {
       return AsProxy()->Role();
     }
 
     return AsAccessible()->Role();
   }
 
+  AccessibleOrProxy Parent() const;
+
   // XXX these are implementation details that ideally would not be exposed.
   uintptr_t Bits() const { return mBits; }
   void SetBits(uintptr_t aBits) { mBits = aBits; }
 
 private:
   uintptr_t mBits;
   static const uintptr_t IS_PROXY = 0x1;
 };
--- a/accessible/base/DocManager.cpp
+++ b/accessible/base/DocManager.cpp
@@ -55,19 +55,16 @@ DocManager::DocManager()
 // DocManager public
 
 DocAccessible*
 DocManager::GetDocAccessible(nsIDocument* aDocument)
 {
   if (!aDocument)
     return nullptr;
 
-  // Ensure CacheChildren is called before we query cache.
-  ApplicationAcc()->EnsureChildren();
-
   DocAccessible* docAcc = GetExistingDocAccessible(aDocument);
   if (docAcc)
     return docAcc;
 
   return CreateDocOrRootAccessible(aDocument);
 }
 
 Accessible*
@@ -84,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;
 
@@ -491,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 = do_GetInterface(docShell);
-
-        // 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();
@@ -528,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.
new file mode 100644
--- /dev/null
+++ b/accessible/base/EmbeddedObjCollector.cpp
@@ -0,0 +1,81 @@
+/* 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 "EmbeddedObjCollector.h"
+
+#include "Accessible.h"
+
+using namespace mozilla::a11y;
+
+uint32_t
+EmbeddedObjCollector::Count()
+{
+  EnsureNGetIndex(nullptr);
+  return mObjects.Length();
+}
+
+Accessible*
+EmbeddedObjCollector::GetAccessibleAt(uint32_t aIndex)
+{
+  Accessible* accessible = mObjects.SafeElementAt(aIndex, nullptr);
+  if (accessible)
+    return accessible;
+
+  return EnsureNGetObject(aIndex);
+}
+
+Accessible*
+EmbeddedObjCollector::EnsureNGetObject(uint32_t aIndex)
+{
+  uint32_t childCount = mRoot->ChildCount();
+  while (mRootChildIdx < childCount) {
+    Accessible* child = mRoot->GetChildAt(mRootChildIdx++);
+    if (child->IsText())
+      continue;
+
+    AppendObject(child);
+    if (mObjects.Length() - 1 == aIndex)
+      return mObjects[aIndex];
+  }
+
+  return nullptr;
+}
+
+int32_t
+EmbeddedObjCollector::EnsureNGetIndex(Accessible* aAccessible)
+{
+  uint32_t childCount = mRoot->ChildCount();
+  while (mRootChildIdx < childCount) {
+    Accessible* child = mRoot->GetChildAt(mRootChildIdx++);
+    if (child->IsText())
+      continue;
+
+    AppendObject(child);
+    if (child == aAccessible)
+      return mObjects.Length() - 1;
+  }
+
+  return -1;
+}
+
+int32_t
+EmbeddedObjCollector::GetIndexAt(Accessible* aAccessible)
+{
+  if (aAccessible->mParent != mRoot)
+    return -1;
+
+  MOZ_ASSERT(!aAccessible->IsProxy());
+  if (aAccessible->mInt.mIndexOfEmbeddedChild != -1)
+    return aAccessible->mInt.mIndexOfEmbeddedChild;
+
+  return !aAccessible->IsText() ?  EnsureNGetIndex(aAccessible) : -1;
+}
+
+void
+EmbeddedObjCollector::AppendObject(Accessible* aAccessible)
+{
+  MOZ_ASSERT(!aAccessible->IsProxy());
+  aAccessible->mInt.mIndexOfEmbeddedChild = mObjects.Length();
+  mObjects.AppendElement(aAccessible);
+}
new file mode 100644
--- /dev/null
+++ b/accessible/base/EmbeddedObjCollector.h
@@ -0,0 +1,69 @@
+/* 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_EmbeddedObjCollector_h__
+#define mozilla_a11y_EmbeddedObjCollector_h__
+
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace a11y {
+
+class Accessible;
+
+/**
+ * Collect embedded objects. Provide quick access to accessible by index and
+ * vice versa.
+ */
+class EmbeddedObjCollector final
+{
+public:
+  ~EmbeddedObjCollector() { }
+
+  /**
+   * Return index of the given accessible within the collection.
+   */
+  int32_t GetIndexAt(Accessible* aAccessible);
+
+  /**
+   * Return accessible count within the collection.
+   */
+  uint32_t Count();
+
+  /**
+   * Return an accessible from the collection at the given index.
+   */
+  Accessible* GetAccessibleAt(uint32_t aIndex);
+
+protected:
+  /**
+   * Ensure accessible at the given index is stored and return it.
+   */
+  Accessible* EnsureNGetObject(uint32_t aIndex);
+
+  /**
+   * Ensure index for the given accessible is stored and return it.
+   */
+  int32_t EnsureNGetIndex(Accessible* aAccessible);
+
+  // Make sure it's used by Accessible class only.
+  explicit EmbeddedObjCollector(Accessible* aRoot) :
+    mRoot(aRoot), mRootChildIdx(0) {}
+
+  /**
+   * Append the object to collection.
+   */
+  void AppendObject(Accessible* aAccessible);
+
+  friend class Accessible;
+
+  Accessible* mRoot;
+  uint32_t mRootChildIdx;
+  nsTArray<Accessible*> mObjects;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
--- a/accessible/base/EventQueue.cpp
+++ b/accessible/base/EventQueue.cpp
@@ -25,117 +25,85 @@ const unsigned int kSelChangeCountToPack
 ////////////////////////////////////////////////////////////////////////////////
 // EventQueue
 ////////////////////////////////////////////////////////////////////////////////
 
 bool
 EventQueue::PushEvent(AccEvent* aEvent)
 {
   NS_ASSERTION((aEvent->mAccessible && aEvent->mAccessible->IsApplication()) ||
-               aEvent->GetDocAccessible() == mDocument,
+               aEvent->Document() == mDocument,
                "Queued event belongs to another document!");
 
   if (!mEvents.AppendElement(aEvent))
     return false;
 
   // Filter events.
   CoalesceEvents();
 
+  if (aEvent->mEventRule != AccEvent::eDoNotEmit &&
+      (aEvent->mEventType == nsIAccessibleEvent::EVENT_NAME_CHANGE ||
+       aEvent->mEventType == nsIAccessibleEvent::EVENT_TEXT_REMOVED ||
+       aEvent->mEventType == nsIAccessibleEvent::EVENT_TEXT_INSERTED)) {
+    PushNameChange(aEvent->mAccessible);
+  }
+  return true;
+}
+
+bool
+EventQueue::PushNameChange(Accessible* aTarget)
+{
   // Fire name change event on parent given that this event hasn't been
   // coalesced, the parent's name was calculated from its subtree, and the
   // subtree was changed.
-  Accessible* target = aEvent->mAccessible;
-  if (aEvent->mEventRule != AccEvent::eDoNotEmit &&
-      target->HasNameDependentParent() &&
-      (aEvent->mEventType == nsIAccessibleEvent::EVENT_NAME_CHANGE ||
-       aEvent->mEventType == nsIAccessibleEvent::EVENT_TEXT_REMOVED ||
-       aEvent->mEventType == nsIAccessibleEvent::EVENT_TEXT_INSERTED ||
-       aEvent->mEventType == nsIAccessibleEvent::EVENT_SHOW ||
-       aEvent->mEventType == nsIAccessibleEvent::EVENT_HIDE)) {
+  if (aTarget->HasNameDependentParent()) {
     // Only continue traversing up the tree if it's possible that the parent
     // accessible's name can depend on this accessible's name.
-    Accessible* parent = target->Parent();
+    Accessible* parent = aTarget->Parent();
     while (parent &&
            nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeIfReqRule)) {
       // Test possible name dependent parent.
       if (nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeRule)) {
         nsAutoString name;
         ENameValueFlag nameFlag = parent->Name(name);
         // If name is obtained from subtree, fire name change event.
         if (nameFlag == eNameFromSubtree) {
           RefPtr<AccEvent> nameChangeEvent =
             new AccEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, parent);
-          PushEvent(nameChangeEvent);
+          return PushEvent(nameChangeEvent);
         }
         break;
       }
       parent = parent->Parent();
     }
   }
-
-  // Associate text change with hide event if it wasn't stolen from hiding
-  // siblings during coalescence.
-  AccMutationEvent* showOrHideEvent = downcast_accEvent(aEvent);
-  if (showOrHideEvent && !showOrHideEvent->mTextChangeEvent)
-    CreateTextChangeEventFor(showOrHideEvent);
-
-  return true;
+  return false;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // EventQueue: private
 
 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:
-      CoalesceReorderEvents(tailEvent);
+    {
+      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::eCoalesceMutationTextChange:
-    {
-      for (uint32_t index = tail - 1; index < tail; index--) {
-        AccEvent* thisEvent = mEvents[index];
-        if (thisEvent->mEventRule != tailEvent->mEventRule)
-          continue;
-
-        // We don't currently coalesce text change events from show/hide events.
-        if (thisEvent->mEventType != tailEvent->mEventType)
-          continue;
-
-        // Show events may be duped because of reinsertion (removal is ignored
-        // because initial insertion is not processed). Ignore initial
-        // insertion.
-        if (thisEvent->mAccessible == tailEvent->mAccessible)
-          thisEvent->mEventRule = AccEvent::eDoNotEmit;
-
-        AccMutationEvent* tailMutationEvent = downcast_accEvent(tailEvent);
-        AccMutationEvent* thisMutationEvent = downcast_accEvent(thisEvent);
-        if (tailMutationEvent->mParent != thisMutationEvent->mParent)
-          continue;
-
-        // Coalesce text change events for hide and show events.
-        if (thisMutationEvent->IsHide()) {
-          AccHideEvent* tailHideEvent = downcast_accEvent(tailEvent);
-          AccHideEvent* thisHideEvent = downcast_accEvent(thisEvent);
-          CoalesceTextChangeEventsFor(tailHideEvent, thisHideEvent);
-          break;
-        }
-
-        AccShowEvent* tailShowEvent = downcast_accEvent(tailEvent);
-        AccShowEvent* thisShowEvent = downcast_accEvent(thisEvent);
-        CoalesceTextChangeEventsFor(tailShowEvent, thisShowEvent);
-        break;
-      }
-    } break; // case eCoalesceMutationTextChange
+    }
 
     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) {
@@ -222,105 +190,16 @@ EventQueue::CoalesceEvents()
     } break; // case eRemoveDupes
 
     default:
       break; // case eAllowDupes, eDoNotEmit
   } // switch
 }
 
 void
-EventQueue::CoalesceReorderEvents(AccEvent* aTailEvent)
-{
-  uint32_t count = mEvents.Length();
-  for (uint32_t index = count - 2; index < count; index--) {
-    AccEvent* thisEvent = mEvents[index];
-
-    // Skip events of different types and targeted to application accessible.
-    if (thisEvent->mEventType != aTailEvent->mEventType ||
-        thisEvent->mAccessible->IsApplication())
-      continue;
-
-    // If thisEvent target is not in document longer, i.e. if it was
-    // removed from the tree then do not emit the event.
-    if (!thisEvent->mAccessible->IsDoc() &&
-        !thisEvent->mAccessible->IsInDocument()) {
-      thisEvent->mEventRule = AccEvent::eDoNotEmit;
-      continue;
-    }
-
-    // Coalesce earlier event of the same target.
-    if (thisEvent->mAccessible == aTailEvent->mAccessible) {
-      thisEvent->mEventRule = AccEvent::eDoNotEmit;
-
-      return;
-    }
-
-    // If tailEvent contains thisEvent
-    // then
-    //   if show or hide of tailEvent contains a grand parent of thisEvent
-    //   then ignore thisEvent and its show and hide events
-    //   otherwise ignore thisEvent but not its show and hide events
-    Accessible* thisParent = thisEvent->mAccessible;
-    while (thisParent && thisParent != mDocument) {
-      if (thisParent->Parent() == aTailEvent->mAccessible) {
-        AccReorderEvent* tailReorder = downcast_accEvent(aTailEvent);
-        uint32_t eventType = tailReorder->IsShowHideEventTarget(thisParent);
-
-        // Sometimes InvalidateChildren() and
-        // DocAccessible::CacheChildrenInSubtree() can conspire to reparent an
-        // accessible in this case no need for mutation events.  Se bug 883708
-        // for details.
-        if (eventType == nsIAccessibleEvent::EVENT_SHOW ||
-            eventType == nsIAccessibleEvent::EVENT_HIDE) {
-          AccReorderEvent* thisReorder = downcast_accEvent(thisEvent);
-          thisReorder->DoNotEmitAll();
-        } else {
-          thisEvent->mEventRule = AccEvent::eDoNotEmit;
-        }
-
-        return;
-      }
-
-      thisParent = thisParent->Parent();
-    }
-
-    // If tailEvent is contained by thisEvent
-    // then
-    //   if show of thisEvent contains the tailEvent
-    //   then ignore tailEvent
-    //   if hide of thisEvent contains the tailEvent
-    //   then assert
-    //   otherwise ignore tailEvent but not its show and hide events
-    Accessible* tailParent = aTailEvent->mAccessible;
-    while (tailParent && tailParent != mDocument) {
-      if (tailParent->Parent() == thisEvent->mAccessible) {
-        AccReorderEvent* thisReorder = downcast_accEvent(thisEvent);
-        AccReorderEvent* tailReorder = downcast_accEvent(aTailEvent);
-        uint32_t eventType = thisReorder->IsShowHideEventTarget(tailParent);
-        if (eventType == nsIAccessibleEvent::EVENT_SHOW) {
-          tailReorder->DoNotEmitAll();
-        }
-        else if (eventType == nsIAccessibleEvent::EVENT_HIDE) {
-          NS_ERROR("Accessible tree was modified after it was removed! Huh?");
-        }
-        else {
-          aTailEvent->mEventRule = AccEvent::eDoNotEmit;
-          mEvents[index].swap(mEvents[count - 1]);
-        }
-
-        return;
-      }
-
-      tailParent = tailParent->Parent();
-    }
-
-  } // for (index)
-}
-
-void
 EventQueue::CoalesceSelChangeEvents(AccSelChangeEvent* aTailEvent,
                                     AccSelChangeEvent* aThisEvent,
                                     uint32_t aThisIndex)
 {
   aTailEvent->mPreceedingCount = aThisEvent->mPreceedingCount + 1;
 
   // Pack all preceding events into single selection within event
   // when we receive too much selection add/remove events.
@@ -390,100 +269,16 @@ EventQueue::CoalesceSelChangeEvents(AccS
   }
 
   // Convert into selection add since control has single selection but other
   // selection events for this control are queued.
   if (aTailEvent->mEventType == nsIAccessibleEvent::EVENT_SELECTION)
     aTailEvent->mEventType = nsIAccessibleEvent::EVENT_SELECTION_ADD;
 }
 
-void
-EventQueue::CoalesceTextChangeEventsFor(AccHideEvent* aTailEvent,
-                                        AccHideEvent* aThisEvent)
-{
-  // XXX: we need a way to ignore SplitNode and JoinNode() when they do not
-  // affect the text within the hypertext.
-
-  AccTextChangeEvent* textEvent = aThisEvent->mTextChangeEvent;
-  if (!textEvent)
-    return;
-
-  if (aThisEvent->mNextSibling == aTailEvent->mAccessible) {
-    aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText);
-
-  } else if (aThisEvent->mPrevSibling == aTailEvent->mAccessible) {
-    uint32_t oldLen = textEvent->GetLength();
-    aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText);
-    textEvent->mStart -= textEvent->GetLength() - oldLen;
-  }
-
-  aTailEvent->mTextChangeEvent.swap(aThisEvent->mTextChangeEvent);
-}
-
-void
-EventQueue::CoalesceTextChangeEventsFor(AccShowEvent* aTailEvent,
-                                        AccShowEvent* aThisEvent)
-{
-  AccTextChangeEvent* textEvent = aThisEvent->mTextChangeEvent;
-  if (!textEvent)
-    return;
-
-  if (aTailEvent->mAccessible->IndexInParent() ==
-      aThisEvent->mAccessible->IndexInParent() + 1) {
-    // If tail target was inserted after this target, i.e. tail target is next
-    // sibling of this target.
-    aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText);
-
-  } else if (aTailEvent->mAccessible->IndexInParent() ==
-             aThisEvent->mAccessible->IndexInParent() -1) {
-    // If tail target was inserted before this target, i.e. tail target is
-    // previous sibling of this target.
-    nsAutoString startText;
-    aTailEvent->mAccessible->AppendTextTo(startText);
-    textEvent->mModifiedText = startText + textEvent->mModifiedText;
-    textEvent->mStart -= startText.Length();
-  }
-
-  aTailEvent->mTextChangeEvent.swap(aThisEvent->mTextChangeEvent);
-}
-
-void
-EventQueue::CreateTextChangeEventFor(AccMutationEvent* aEvent)
-{
-  Accessible* container = aEvent->mAccessible->Parent();
-  if (!container)
-    return;
-
-  HyperTextAccessible* textAccessible = container->AsHyperText();
-  if (!textAccessible)
-    return;
-
-  // Don't fire event for the first html:br in an editor.
-  if (aEvent->mAccessible->Role() == roles::WHITESPACE) {
-    nsCOMPtr<nsIEditor> editor = textAccessible->GetEditor();
-    if (editor) {
-      bool isEmpty = false;
-      editor->GetDocumentIsEmpty(&isEmpty);
-      if (isEmpty)
-        return;
-    }
-  }
-
-  int32_t offset = textAccessible->GetChildOffset(aEvent->mAccessible);
-
-  nsAutoString text;
-  aEvent->mAccessible->AppendTextTo(text);
-  if (text.IsEmpty())
-    return;
-
-  aEvent->mTextChangeEvent =
-    new AccTextChangeEvent(textAccessible, offset, text, aEvent->IsShow(),
-                           aEvent->mIsFromUserInput ? eFromUserInput : eNoUserInput);
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // EventQueue: event queue
 
 void
 EventQueue::ProcessEventQueue()
 {
   // Process only currently queued events.
   nsTArray<RefPtr<AccEvent> > events;
@@ -536,26 +331,14 @@ EventQueue::ProcessEventQueue()
           nsEventShell::FireEvent(selChangeEvent->mPackedEvent->mAccessible,
                                   states::SELECTED,
                                   (selChangeEvent->mPackedEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd),
                                   selChangeEvent->mPackedEvent->mIsFromUserInput);
         }
       }
 
       nsEventShell::FireEvent(event);
-
-      // Fire text change events.
-      AccMutationEvent* mutationEvent = downcast_accEvent(event);
-      if (mutationEvent) {
-        if (mutationEvent->mTextChangeEvent)
-          nsEventShell::FireEvent(mutationEvent->mTextChangeEvent);
-      }
-    }
-
-    AccHideEvent* hideEvent = downcast_accEvent(event);
-    if (hideEvent && hideEvent->NeedsShutdown()) {
-      mDocument->ShutdownChildrenInSubtree(event->mAccessible);
     }
 
     if (!mDocument)
       return;
   }
 }
--- a/accessible/base/EventQueue.h
+++ b/accessible/base/EventQueue.h
@@ -22,16 +22,21 @@ protected:
   explicit EventQueue(DocAccessible* aDocument) : mDocument(aDocument) { }
 
   /**
    * Put an accessible event into the queue to process it later.
    */
   bool PushEvent(AccEvent* aEvent);
 
   /**
+   * Puts a name change event into the queue, if needed.
+   */
+  bool PushNameChange(Accessible* aTarget);
+
+  /**
    * Process events from the queue and fires events.
    */
   void ProcessEventQueue();
 
 private:
   EventQueue(const EventQueue&) = delete;
   EventQueue& operator = (const EventQueue&) = delete;
 
@@ -48,41 +53,25 @@ private:
 
   /**
    * Coalesce two selection change events within the same select control.
    */
   void CoalesceSelChangeEvents(AccSelChangeEvent* aTailEvent,
                                AccSelChangeEvent* aThisEvent,
                                uint32_t aThisIndex);
 
-  /**
-   * Coalesce text change events caused by sibling hide events.
-   */
-  void CoalesceTextChangeEventsFor(AccHideEvent* aTailEvent,
-                                   AccHideEvent* aThisEvent);
-  void CoalesceTextChangeEventsFor(AccShowEvent* aTailEvent,
-                                   AccShowEvent* aThisEvent);
-
-  /**
-    * Create text change event caused by hide or show event. When a node is
-    * hidden/removed or shown/appended, the text in an ancestor hyper text will
-    * lose or get new characters.
-    */
-   void CreateTextChangeEventFor(AccMutationEvent* aEvent);
-
 protected:
-
   /**
    * The document accessible reference owning this queue.
    */
   DocAccessible* mDocument;
 
   /**
    * Pending events array. Don't make this an AutoTArray; we use
    * SwapElements() on it.
    */
-  nsTArray<RefPtr<AccEvent> > mEvents;
+  nsTArray<RefPtr<AccEvent>> mEvents;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif // mozilla_a11y_EventQueue_h_
new file mode 100644
--- /dev/null
+++ b/accessible/base/EventTree.cpp
@@ -0,0 +1,618 @@
+/* -*- 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 "EventTree.h"
+
+#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),
+  mQueueEvents(!aNoEvents)
+{
+#ifdef DEBUG
+  mIsDone = false;
+#endif
+
+#ifdef A11Y_LOG
+  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));
+    }
+  }
+#endif
+
+  mParent->mStateFlags |= Accessible::eKidsMutating;
+}
+
+TreeMutation::~TreeMutation()
+{
+  MOZ_ASSERT(mIsDone, "Done() must be called explicitly");
+}
+
+void
+TreeMutation::AfterInsertion(Accessible* aChild)
+{
+  MOZ_ASSERT(aChild->Parent() == mParent);
+
+  if (static_cast<uint32_t>(aChild->mIndexInParent) < mStartIdx) {
+    mStartIdx = aChild->mIndexInParent + 1;
+  }
+
+  if (!mQueueEvents) {
+    return;
+  }
+
+  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 (!mQueueEvents) {
+    return;
+  }
+
+  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;
+
+  uint32_t length = mParent->mChildren.Length();
+#ifdef DEBUG
+  for (uint32_t idx = 0; idx < mStartIdx && idx < length; idx++) {
+    MOZ_ASSERT(mParent->mChildren[idx]->mIndexInParent == static_cast<int32_t>(idx),
+               "Wrong index detected");
+  }
+#endif
+
+  for (uint32_t idx = mStartIdx; idx < length; idx++) {
+    mParent->mChildren[idx]->mInt.mIndexOfEmbeddedChild = -1;
+    mParent->mChildren[idx]->mStateFlags |= Accessible::eGroupInfoDirty;
+  }
+
+  mParent->mEmbeddedObjCollector = nullptr;
+  mParent->mStateFlags |= mStateFlagsCopy & Accessible::eKidsMutating;
+
+#ifdef DEBUG
+  mIsDone = true;
+#endif
+
+#ifdef A11Y_LOG
+  if (mQueueEvents && logging::IsEnabled(logging::eEventTree)) {
+    logging::MsgBegin("EVENTS_TREE", "reordering tree after");
+    logging::AccessibleInfo("reordering for", mParent);
+    Controller()->RootEventTree().Log();
+    logging::MsgEnd();
+  }
+#endif
+}
+
+#ifdef A11Y_LOG
+const char*
+TreeMutation::PrefixLog(void* aData, Accessible* aAcc)
+{
+  TreeMutation* thisObj = reinterpret_cast<TreeMutation*>(aData);
+  if (thisObj->mParent == aAcc) {
+    return "_X_";
+  }
+  const EventTree& ret = thisObj->Controller()->RootEventTree();
+  if (ret.Find(aAcc)) {
+    return "_с_";
+  }
+  return "";
+}
+#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 = 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->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()) {
+        return;
+      }
+    }
+
+    if (mtEvent->IsHide()) {
+      // 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 (mtEvent->mAccessible->ARIARole() == roles::MENUPOPUP) {
+        nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END,
+                                mtEvent->mAccessible);
+        if (aDeathGrip->IsDefunct()) {
+          return;
+        }
+      }
+
+      AccHideEvent* hideEvent = downcast_accEvent(mtEvent);
+      if (hideEvent->NeedsShutdown()) {
+        aDeathGrip->ShutdownChildrenInSubtree(mtEvent->mAccessible);
+      }
+    }
+  }
+
+  // Fire reorder event at last.
+  if (mFireReorder) {
+    nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_REORDER, mContainer);
+    mContainer->Document()->MaybeNotifyOfValueChange(mContainer);
+  }
+
+  mDependentEvents.Clear();
+}
+
+EventTree*
+EventTree::FindOrInsert(Accessible* aContainer)
+{
+  if (!mFirst) {
+    mFirst.reset(new EventTree(aContainer, mDependentEvents.IsEmpty()));
+    return mFirst.get();
+  }
+
+  EventTree* prevNode = nullptr;
+  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;
+    }
+
+    // Check if the given container is contained by a current node
+    Accessible* top = mContainer ? mContainer : aContainer->Document();
+    Accessible* parent = aContainer;
+    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
+    // then
+    //   if show or hide of the given node contains a grand parent of the current node
+    //   then ignore the current node and its show and hide events
+    //   otherwise ignore the current node, but not its show and hide events
+    Accessible* curParent = node->mContainer;
+    while (curParent && !curParent->IsDoc()) {
+      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;
+      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.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.get();
+
+          prevNode->mNext = Move(node->mNext);
+          node = prevNode;
+          break;
+        }
+
+        prevNode = node;
+        nodeRef = &node->mNext;
+        node = node->mNext.get();
+      }
+
+      return nodeOwnerRef.get();
+    }
+
+    prevNode = node;
+  } 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)
+
+  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();
+}
+
+const EventTree*
+EventTree::Find(const Accessible* aContainer) const
+{
+  const EventTree* et = this;
+  while (et) {
+    if (et->mContainer == aContainer) {
+      return et;
+    }
+
+    if (et->mFirst) {
+      et = et->mFirst.get();
+      const EventTree* cet = et->Find(aContainer);
+      if (cet) {
+        return cet;
+      }
+    }
+
+    et = et->mNext.get();
+    const EventTree* cet = et->Find(aContainer);
+    if (cet) {
+      return cet;
+    }
+  }
+
+  return nullptr;
+}
+
+#ifdef A11Y_LOG
+void
+EventTree::Log(uint32_t aLevel) const
+{
+  if (aLevel == UINT32_MAX) {
+    if (mFirst) {
+      mFirst->Log(0);
+    }
+    return;
+  }
+
+  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 + 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 + 1; i++) {
+        printf("  ");
+      }
+      logging::AccessibleInfo("hidden", ev->mAccessible);
+    }
+  }
+
+  if (mFirst) {
+    mFirst->Log(aLevel + 1);
+  }
+
+  if (mNext) {
+    mNext->Log(aLevel);
+  }
+}
+#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.
+  UniquePtr<EventTree>* node = &mFirst;
+  while (*node) {
+    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.
+  if (prevEvent && aEv->mEventType == prevEvent->mEventType) {
+    if (aEv->IsHide()) {
+      // XXX: we need a way to ignore SplitNode and JoinNode() when they do not
+      // affect the text within the hypertext.
+      AccTextChangeEvent* prevTextEvent = prevEvent->mTextChangeEvent;
+      if (prevTextEvent) {
+        AccHideEvent* hideEvent = downcast_accEvent(aEv);
+        AccHideEvent* prevHideEvent = downcast_accEvent(prevEvent);
+
+        if (prevHideEvent->mNextSibling == hideEvent->mAccessible) {
+          hideEvent->mAccessible->AppendTextTo(prevTextEvent->mModifiedText);
+        }
+        else if (prevHideEvent->mPrevSibling == hideEvent->mAccessible) {
+          uint32_t oldLen = prevTextEvent->GetLength();
+          hideEvent->mAccessible->AppendTextTo(prevTextEvent->mModifiedText);
+          prevTextEvent->mStart -= prevTextEvent->GetLength() - oldLen;
+        }
+
+        hideEvent->mTextChangeEvent.swap(prevEvent->mTextChangeEvent);
+      }
+    }
+    else {
+      AccTextChangeEvent* prevTextEvent = prevEvent->mTextChangeEvent;
+      if (prevTextEvent) {
+        if (aEv->mAccessible->IndexInParent() ==
+            prevEvent->mAccessible->IndexInParent() + 1) {
+          // If tail target was inserted after this target, i.e. tail target is next
+          // sibling of this target.
+          aEv->mAccessible->AppendTextTo(prevTextEvent->mModifiedText);
+        }
+        else if (aEv->mAccessible->IndexInParent() ==
+                 prevEvent->mAccessible->IndexInParent() - 1) {
+          // If tail target was inserted before this target, i.e. tail target is
+          // previous sibling of this target.
+          nsAutoString startText;
+          aEv->mAccessible->AppendTextTo(startText);
+          prevTextEvent->mModifiedText = startText + prevTextEvent->mModifiedText;
+          prevTextEvent->mStart -= startText.Length();
+        }
+
+        aEv->mTextChangeEvent.swap(prevEvent->mTextChangeEvent);
+      }
+    }
+  }
+
+  // Create a text change event caused by this hide/show event. When a node is
+  // hidden/removed or shown/appended, the text in an ancestor hyper text will
+  // lose or get new characters.
+  if (aEv->mTextChangeEvent || !mContainer->IsHyperText()) {
+    return;
+  }
+
+  nsAutoString text;
+  aEv->mAccessible->AppendTextTo(text);
+  if (text.IsEmpty()) {
+    return;
+  }
+
+  int32_t offset = mContainer->AsHyperText()->GetChildOffset(aEv->mAccessible);
+  aEv->mTextChangeEvent =
+    new AccTextChangeEvent(mContainer, offset, text, aEv->IsShow(),
+                           aEv->mIsFromUserInput ? eFromUserInput : eNoUserInput);
+}
new file mode 100644
--- /dev/null
+++ b/accessible/base/EventTree.h
@@ -0,0 +1,121 @@
+/* -*- 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 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
+ * the accessible tree.
+ */
+class TreeMutation final
+{
+public:
+  static const bool kNoEvents = true;
+  static const bool kNoShutdown = true;
+
+  explicit TreeMutation(Accessible* aParent, bool aNoEvents = false);
+  ~TreeMutation();
+
+  void AfterInsertion(Accessible* aChild);
+  void BeforeRemoval(Accessible* aChild, bool aNoShutdown = false);
+  void Done();
+
+private:
+  NotificationController* Controller() const
+    { return mParent->Document()->Controller(); }
+
+  static EventTree* const kNoEventTree;
+
+#ifdef A11Y_LOG
+  static const char* PrefixLog(void* aData, Accessible*);
+#endif
+
+  Accessible* mParent;
+  uint32_t mStartIdx;
+  uint32_t mStateFlagsCopy;
+
+  /*
+   * True if mutation events should be queued.
+   */
+  bool mQueueEvents;
+
+#ifdef DEBUG
+  bool mIsDone;
+#endif
+};
+
+
+/**
+ * A mutation events coalescence structure.
+ */
+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* 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 Clear();
+
+  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/Filters.cpp
+++ b/accessible/base/Filters.cpp
@@ -44,15 +44,8 @@ filters::GetRow(Accessible* aAccessible)
   return eSkipSubtree;
 }
 
 uint32_t
 filters::GetCell(Accessible* aAccessible)
 {
   return aAccessible->IsTableCell() ? eMatch : eSkipSubtree;
 }
-
-uint32_t
-filters::GetEmbeddedObject(Accessible* aAccessible)
-{
-  return nsAccUtils::IsEmbeddedObject(aAccessible) ?
-    eMatch | eSkipSubtree : eSkipSubtree;
-}
--- a/accessible/base/Filters.h
+++ b/accessible/base/Filters.h
@@ -38,19 +38,13 @@ uint32_t GetSelectable(Accessible* aAcce
  * Matches row accessibles in subtree.
  */
 uint32_t GetRow(Accessible* aAccessible);
 
 /**
  * Matches cell accessibles in children.
  */
 uint32_t GetCell(Accessible* aAccessible);
-
-/**
- * Matches embedded objects in children.
- */
-uint32_t GetEmbeddedObject(Accessible* aAccessible);
-
 } // namespace filters
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/base/FocusManager.cpp
+++ b/accessible/base/FocusManager.cpp
@@ -274,17 +274,17 @@ FocusManager::ProcessFocusEvent(AccEvent
 
   // Emit focus event if event target is the active item. Otherwise then check
   // if it's still focused and then update active item and emit focus event.
   Accessible* target = aEvent->GetAccessible();
   if (target != mActiveItem) {
 
     // Check if still focused. Otherwise we can end up with storing the active
     // item for control that isn't focused anymore.
-    DocAccessible* document = aEvent->GetDocAccessible();
+    DocAccessible* document = aEvent->Document();
     nsINode* focusedNode = FocusedDOMNode();
     if (!focusedNode)
       return;
 
     Accessible* DOMFocus =
       document->GetAccessibleEvenIfNotInMapOrContainer(focusedNode);
     if (target != DOMFocus)
       return;
--- a/accessible/base/FocusManager.h
+++ b/accessible/base/FocusManager.h
@@ -1,17 +1,15 @@
 /* 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_FocusManager_h_
 #define mozilla_a11y_FocusManager_h_
 
-#include "nsAutoPtr.h"
-
 class nsINode;
 class nsIDocument;
 class nsISupports;
 
 namespace mozilla {
 namespace a11y {
 
 class AccEvent;
--- a/accessible/base/Logging.cpp
+++ b/accessible/base/Logging.cpp
@@ -39,16 +39,17 @@ struct ModuleRep {
 
 static ModuleRep sModuleMap[] = {
   { "docload", logging::eDocLoad },
   { "doccreate", logging::eDocCreate },
   { "docdestroy", logging::eDocDestroy },
   { "doclifecycle", logging::eDocLifeCycle },
 
   { "events", logging::eEvents },
+  { "eventTree", logging::eEventTree },
   { "platforms", logging::ePlatforms },
   { "text", logging::eText },
   { "tree", logging::eTree },
 
   { "DOMEvents", logging::eDOMEvents },
   { "focus", logging::eFocus },
   { "selection", logging::eSelection },
   { "notifications", logging::eNotifications },
@@ -84,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"));
@@ -164,18 +164,22 @@ LogDocState(nsIDocument* aDocumentNode)
 
   printf("doc state: %s", docState);
   printf(", %sinitial", aDocumentNode->IsInitialDocument() ? "" : "not ");
   printf(", %sshowing", aDocumentNode->IsShowing() ? "" : "not ");
   printf(", %svisible", aDocumentNode->IsVisible() ? "" : "not ");
   printf(", %svisible considering ancestors", aDocumentNode->IsVisibleConsideringAncestors() ? "" : "not ");
   printf(", %sactive", aDocumentNode->IsActive() ? "" : "not ");
   printf(", %sresource", aDocumentNode->IsResourceDoc() ? "" : "not ");
-  printf(", has %srole content",
-         nsCoreUtils::GetRoleContent(aDocumentNode) ? "" : "no ");
+
+  dom::Element* rootEl = aDocumentNode->GetBodyElement();
+  if (!rootEl) {
+    rootEl = aDocumentNode->GetRootElement();
+  }
+  printf(", has %srole content", rootEl ? "" : "no ");
 }
 
 static void
 LogPresShell(nsIDocument* aDocumentNode)
 {
   nsIPresShell* ps = aDocumentNode->GetShell();
   printf("presshell: %p", static_cast<void*>(ps));
 
@@ -607,68 +611,145 @@ logging::SelChange(nsISelection* aSelect
 
   Stack();
 }
 
 void
 logging::TreeInfo(const char* aMsg, uint32_t aExtraFlags, ...)
 {
   if (IsEnabledAll(logging::eTree | aExtraFlags)) {
-    MsgBegin("TREE", aMsg);
-
     va_list vl;
     va_start(vl, aExtraFlags);
-    const char* descr = nullptr;
-    while ((descr = va_arg(vl, const char*))) {
-      AccessibleInfo(descr, va_arg(vl, Accessible*));
+    const char* descr = va_arg(vl, const char*);
+    if (descr) {
+      Accessible* acc = va_arg(vl, Accessible*);
+      MsgBegin("TREE", "%s; doc: %p", aMsg, acc ? acc->Document() : nullptr);
+      AccessibleInfo(descr, acc);
+      while ((descr = va_arg(vl, const char*))) {
+        AccessibleInfo(descr, va_arg(vl, Accessible*));
+      }
+    }
+    else {
+      MsgBegin("TREE", aMsg);
     }
     va_end(vl);
-
     MsgEnd();
 
     if (aExtraFlags & eStack) {
       Stack();
     }
   }
 }
 
 void
 logging::TreeInfo(const char* aMsg, uint32_t aExtraFlags,
                   const char* aMsg1, Accessible* aAcc,
                   const char* aMsg2, nsINode* aNode)
 {
-  if (IsEnabledAll(logging::eTree | logging::eVerbose)) {
-    MsgBegin("TREE", aMsg);
+  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();
   }
 }
 
 
 void
 logging::TreeInfo(const char* aMsg, uint32_t aExtraFlags, Accessible* aParent)
 {
   if (IsEnabledAll(logging::eTree | aExtraFlags)) {
-    MsgBegin("TREE", aMsg);
+    MsgBegin("TREE", "%s; doc: %p", aMsg, aParent->Document());
     AccessibleInfo("container", aParent);
     for (uint32_t idx = 0; idx < aParent->ChildCount(); idx++) {
       AccessibleInfo("child", aParent->GetChildAt(idx));
     }
     MsgEnd();
   }
 }
 
 void
+logging::Tree(const char* aTitle, const char* aMsgText,
+              Accessible* aRoot, GetTreePrefix aPrefixFunc,
+              void* aGetTreePrefixData)
+{
+  logging::MsgBegin(aTitle, aMsgText);
+
+  nsAutoString level;
+  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 != 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 != 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 != aRoot);
+
+  logging::MsgEnd();
+}
+
+void
+logging::DOMTree(const char* aTitle, const char* aMsgText,
+                 DocAccessible* aDocument)
+{
+  logging::MsgBegin(aTitle, aMsgText);
+  nsAutoString level;
+  nsINode* root = aDocument->DocumentNode();
+  do {
+    printf("%s", NS_ConvertUTF16toUTF8(level).get());
+    logging::Node("", root);
+    if (root->GetFirstChild()) {
+      level.Append(NS_LITERAL_STRING("  "));
+      root = root->GetFirstChild();
+      continue;
+    }
+    if (root->GetNextSibling()) {
+      root = root->GetNextSibling();
+      continue;
+    }
+    while ((root = root->GetParentNode())) {
+      level.Cut(0, 2);
+      if (root->GetNextSibling()) {
+        root = root->GetNextSibling();
+        break;
+      }
+    }
+  }
+  while (root);
+  logging::MsgEnd();
+}
+
+void
 logging::MsgBegin(const char* aTitle, const char* aMsgText, ...)
 {
   printf("\nA11Y %s: ", aTitle);
 
   va_list argptr;
   va_start(argptr, aMsgText);
   vprintf(aMsgText, argptr);
   va_end(argptr);
--- a/accessible/base/Logging.h
+++ b/accessible/base/Logging.h
@@ -29,28 +29,29 @@ namespace logging {
 
 enum EModules {
   eDocLoad = 1 << 0,
   eDocCreate = 1 << 1,
   eDocDestroy = 1 << 2,
   eDocLifeCycle = eDocLoad | eDocCreate | eDocDestroy,
 
   eEvents = 1 << 3,
-  ePlatforms = 1 << 4,
-  eText = 1 << 5,
-  eTree = 1 << 6,
+  eEventTree = 1 << 4,
+  ePlatforms = 1 << 5,
+  eText = 1 << 6,
+  eTree = 1 << 7,
 
-  eDOMEvents = 1 << 7,
-  eFocus = 1 << 8,
-  eSelection = 1 << 9,
+  eDOMEvents = 1 << 8,
+  eFocus = 1 << 9,
+  eSelection = 1 << 10,
   eNotifications = eDOMEvents | eSelection | eFocus,
 
   // extras
-  eStack = 1 << 10,
-  eVerbose = 1 << 11
+  eStack = 1 << 11,
+  eVerbose = 1 << 12
 };
 
 /**
  * Return true if any of the given modules is logged.
  */
 bool IsEnabled(uint32_t aModules);
 
 /**
@@ -134,16 +135,24 @@ void SelChange(nsISelection* aSelection,
  */
 void TreeInfo(const char* aMsg, uint32_t aExtraFlags, ...);
 void TreeInfo(const char* aMsg, uint32_t aExtraFlags,
               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, 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).
  */
 void MsgBegin(const char* aTitle, const char* aMsgText, ...);
 void MsgEnd();
 
 /**
--- a/accessible/base/MarkupMap.h
+++ b/accessible/base/MarkupMap.h
@@ -29,16 +29,20 @@ MARKUPMAP(aside,
 MARKUPMAP(blockquote,
           New_HyperText,
           roles::SECTION)
 
 MARKUPMAP(dd,
           New_HTMLDefinition,
           roles::DEFINITION)
 
+MARKUPMAP(details,
+          New_HyperText,
+          roles::DETAILS)
+
 MARKUPMAP(div,
           nullptr,
           roles::SECTION)
 
 MARKUPMAP(dl,
           New_HTMLList,
           roles::DEFINITION_LIST)
 
@@ -308,16 +312,20 @@ MARKUPMAP(q,
           New_HyperText,
           0)
 
 MARKUPMAP(section,
           New_HyperText,
           roles::SECTION,
           Attr(xmlroles, region))
 
+MARKUPMAP(summary,
+          New_HTMLSummary,
+          roles::SUMMARY)
+
 MARKUPMAP(time,
           New_HyperText,
           0,
           Attr(xmlroles, time),
           AttrFromDOM(datetime, datetime))
 
 MARKUPMAP(td,
           New_HTMLTableHeaderCellIfScope,
--- 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();
@@ -92,16 +96,317 @@ NotificationController::Shutdown()
   mDocument = nullptr;
   mPresShell = nullptr;
 
   mTextHash.Clear();
   mContentInsertions.Clear();
   mNotifications.Clear();
   mEvents.Clear();
   mRelocations.Clear();
+  mEventTree.Clear();
+}
+
+EventTree*
+NotificationController::QueueMutation(Accessible* aContainer)
+{
+  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();
@@ -134,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
@@ -152,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;
@@ -203,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.
@@ -255,31 +664,31 @@ NotificationController::WillRefresh(mozi
         UINT32_MAX, nsIFrame::TextOffsetType::OFFSETS_IN_CONTENT_TEXT,
         nsIFrame::TrailingWhitespace::DONT_TRIM_TRAILING_WHITESPACE);
 
     // Remove text accessible if rendered text is empty.
     if (textAcc) {
       if (text.mString.IsEmpty()) {
   #ifdef A11Y_LOG
         if (logging::IsEnabled(logging::eTree | logging::eText)) {
-          logging::MsgBegin("TREE", "text node lost its content");
+          logging::MsgBegin("TREE", "text node lost its content; doc: %p", mDocument);
           logging::Node("container", containerElm);
           logging::Node("content", textNode);
           logging::MsgEnd();
         }
   #endif
 
         mDocument->ContentRemoved(containerElm, textNode);
         continue;
       }
 
       // Update text of the accessible and fire text change events.
   #ifdef A11Y_LOG
       if (logging::IsEnabled(logging::eText)) {
-        logging::MsgBegin("TEXT", "text may be changed");
+        logging::MsgBegin("TEXT", "text may be changed; doc: %p", mDocument);
         logging::Node("container", containerElm);
         logging::Node("content", textNode);
         logging::MsgEntry("old text '%s'",
                           NS_ConvertUTF16toUTF8(textAcc->AsTextLeaf()->Text()).get());
         logging::MsgEntry("new text: '%s'",
                           NS_ConvertUTF16toUTF8(text.mString).get());
         logging::MsgEnd();
       }
@@ -288,36 +697,44 @@ NotificationController::WillRefresh(mozi
       TextUpdater::Run(mDocument, textAcc->AsTextLeaf(), text.mString);
       continue;
     }
 
     // Append an accessible if rendered text is not empty.
     if (!text.mString.IsEmpty()) {
   #ifdef A11Y_LOG
       if (logging::IsEnabled(logging::eTree | logging::eText)) {
-        logging::MsgBegin("TREE", "text node gains new content");
+        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->GetAccessibleOrContainer(containerNode);
-      NS_ASSERTION(container,
-                   "Text node having rendered text hasn't accessible document!");
+      Accessible* container = mDocument->AccessibleOrTrueContainer(containerNode);
+      MOZ_ASSERT(container,
+                 "Text node having rendered text hasn't accessible document!");
       if (container) {
-        nsTArray<nsCOMPtr<nsIContent> > insertedContents;
-        insertedContents.AppendElement(textNode);
-        mDocument->ProcessContentInserted(container, &insertedContents);
+        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;
 
@@ -333,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++) {
@@ -376,58 +796,154 @@ NotificationController::WillRefresh(mozi
   mDocument->ProcessInvalidationList();
 
   // We cannot rely on DOM tree to keep aria-owns relations updated. Make
   // a validation to remove dead links.
   mDocument->ValidateARIAOwned();
 
   // Process relocation list.
   for (uint32_t idx = 0; idx < mRelocations.Length(); idx++) {
-    mDocument->DoARIAOwnsRelocation(mRelocations[idx]);
+    if (mRelocations[idx]->IsInDocument()) {
+      mDocument->DoARIAOwnsRelocation(mRelocations[idx]);
+    }
   }
   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;
 
+  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
@@ -2,16 +2,17 @@
 /* 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_NotificationController_h_
 #define mozilla_a11y_NotificationController_h_
 
 #include "EventQueue.h"
+#include "EventTree.h"
 
 #include "mozilla/IndexSequence.h"
 #include "mozilla/Tuple.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsRefreshDriver.h"
 
 #ifdef A11Y_LOG
 #include "Logging.h"
@@ -99,25 +100,82 @@ public:
   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(NotificationController)
 
   /**
    * Shutdown the notification controller.
    */
   void Shutdown();
 
   /**
-   * Put an accessible event into the queue to process it later.
+   * Add an accessible event into the queue to process it later.
    */
   void QueueEvent(AccEvent* aEvent)
   {
-    if (PushEvent(aEvent))
+    if (PushEvent(aEvent)) {
+      ScheduleProcessing();
+    }
+  }
+
+  /**
+   * Creates and adds a name change event into the queue for a container of
+   * the given accessible, if the accessible is a part of name computation of
+   * the container.
+   */
+  void QueueNameChange(Accessible* aChangeTarget)
+  {
+    if (PushNameChange(aChangeTarget)) {
       ScheduleProcessing();
+    }
   }
 
   /**
+   * 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)
@@ -218,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
@@ -286,14 +374,66 @@ private:
    * use SwapElements() on it.
    */
   nsTArray<RefPtr<Notification> > mNotifications;
 
   /**
    * 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;
@@ -70,11 +73,16 @@ void ProxyDestroyed(ProxyAccessible*);
  */
 void ProxyEvent(ProxyAccessible* aTarget, uint32_t aEventType);
 void ProxyStateChangeEvent(ProxyAccessible* aTarget, uint64_t aState,
                            bool aEnabled);
 void ProxyCaretMoveEvent(ProxyAccessible* aTarget, int32_t aOffset);
 void ProxyTextChangeEvent(ProxyAccessible* aTarget, const nsString& aStr,
                           int32_t aStart, uint32_t aLen, bool aIsInsert,
                           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/Relation.h
+++ b/accessible/base/Relation.h
@@ -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/. */
 
 #ifndef mozilla_a11y_relation_h_
 #define mozilla_a11y_relation_h_
 
 #include "AccIterator.h"
 
-#include "mozilla/Move.h"
+#include <memory>
 
 namespace mozilla {
 namespace a11y {
 
 /**
  * A collection of relation targets of a certain type.  Targets are computed
  * lazily while enumerating.
  */
@@ -46,19 +46,19 @@ public:
     mLastIter = aRH.mLastIter;
     aRH.mLastIter = nullptr;
     return *this;
   }
 
   inline void AppendIter(AccIterable* aIter)
   {
     if (mLastIter)
-      mLastIter->mNextIter = aIter;
+      mLastIter->mNextIter.reset(aIter);
     else
-      mFirstIter = aIter;
+      mFirstIter.reset(aIter);
 
     mLastIter = aIter;
   }
 
   /**
    * Append the given accessible to the set of related accessibles.
    */
   inline void AppendTarget(Accessible* aAcc)
@@ -79,31 +79,30 @@ public:
 
   /**
    * compute and return the next related accessible.
    */
   inline Accessible* Next()
   {
     Accessible* target = nullptr;
 
-    // a trick nsAutoPtr deletes what it used to point to when assigned to
     while (mFirstIter && !(target = mFirstIter->Next()))
-      mFirstIter = mFirstIter->mNextIter;
+      mFirstIter = std::move(mFirstIter->mNextIter);
 
     if (!mFirstIter)
       mLastIter = nullptr;
 
     return target;
   }
 
 private:
   Relation& operator = (const Relation&) = delete;
   Relation(const Relation&) = delete;
 
-  nsAutoPtr<AccIterable> mFirstIter;
+  std::unique_ptr<AccIterable> mFirstIter;
   AccIterable* mLastIter;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
 
--- 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/Role.h
+++ b/accessible/base/Role.h
@@ -967,17 +967,27 @@ enum Role {
   RADIO_GROUP = 165,
 
   /**
    * A text container exposing brief amount of information. See related
    * TEXT_CONTAINER role.
    */
   TEXT = 166,
 
-  LAST_ROLE = TEXT
+  /**
+   * The html:details element.
+   */
+  DETAILS = 167,
+
+  /**
+   * The html:summary element.
+   */
+  SUMMARY = 168,
+
+  LAST_ROLE = SUMMARY
 };
 
 } // namespace role
 
 typedef enum mozilla::a11y::roles::Role role;
 
 } // namespace a11y
 } // namespace mozilla
--- a/accessible/base/RoleMap.h
+++ b/accessible/base/RoleMap.h
@@ -1347,8 +1347,24 @@ ROLE(RADIO_GROUP,
 ROLE(TEXT,
      "text",
      ATK_ROLE_STATIC,
      NSAccessibilityGroupRole,
      USE_ROLE_STRING,
      IA2_ROLE_TEXT_FRAME,
      eNameFromSubtreeIfReqRule)
 
+ROLE(DETAILS,
+     "details",
+     ATK_ROLE_PANEL,
+     NSAccessibilityGroupRole,
+     ROLE_SYSTEM_GROUPING,
+     ROLE_SYSTEM_GROUPING,
+     eNoNameRule)
+
+ROLE(SUMMARY,
+     "summary",
+     ATK_ROLE_PUSH_BUTTON,
+     NSAccessibilityGroupRole,
+     ROLE_SYSTEM_PUSHBUTTON,
+     ROLE_SYSTEM_PUSHBUTTON,
+     eNameFromSubtreeRule)
+
--- a/accessible/base/SelectionManager.cpp
+++ b/accessible/base/SelectionManager.cpp
@@ -54,24 +54,22 @@ SelectionManager::ClearControlSelectionL
   const nsFrameSelection* frameSel = mCurrCtrlFrame->GetConstFrameSelection();
   NS_ASSERTION(frameSel, "No frame selection for the element!");
 
   mCurrCtrlFrame = nullptr;
   if (!frameSel)
     return;
 
   // Remove 'this' registered as selection listener for the normal selection.
-  Selection* normalSel =
-    frameSel->GetSelection(nsISelectionController::SELECTION_NORMAL);
+  Selection* normalSel = frameSel->GetSelection(SelectionType::eNormal);
   normalSel->RemoveSelectionListener(this);
 
   // Remove 'this' registered as selection listener for the spellcheck
   // selection.
-  Selection* spellSel =
-    frameSel->GetSelection(nsISelectionController::SELECTION_SPELLCHECK);
+  Selection* spellSel = frameSel->GetSelection(SelectionType::eSpellCheck);
   spellSel->RemoveSelectionListener(this);
 }
 
 void
 SelectionManager::SetControlSelectionListener(dom::Element* aFocusedElm)
 {
   // When focus moves such that the caret is part of a new frame selection
   // this removes the old selection listener and attaches a new one for
@@ -83,56 +81,50 @@ SelectionManager::SetControlSelectionLis
     return;
 
   const nsFrameSelection* frameSel = mCurrCtrlFrame->GetConstFrameSelection();
   NS_ASSERTION(frameSel, "No frame selection for focused element!");
   if (!frameSel)
     return;
 
   // Register 'this' as selection listener for the normal selection.
-  Selection* normalSel =
-    frameSel->GetSelection(nsISelectionController::SELECTION_NORMAL);
+  Selection* normalSel = frameSel->GetSelection(SelectionType::eNormal);
   normalSel->AddSelectionListener(this);
 
   // Register 'this' as selection listener for the spell check selection.
-  Selection* spellSel =
-    frameSel->GetSelection(nsISelectionController::SELECTION_SPELLCHECK);
+  Selection* spellSel = frameSel->GetSelection(SelectionType::eSpellCheck);
   spellSel->AddSelectionListener(this);
 }
 
 void
 SelectionManager::AddDocSelectionListener(nsIPresShell* aPresShell)
 {
   const nsFrameSelection* frameSel = aPresShell->ConstFrameSelection();
 
   // Register 'this' as selection listener for the normal selection.
-  Selection* normalSel =
-    frameSel->GetSelection(nsISelectionController::SELECTION_NORMAL);
+  Selection* normalSel = frameSel->GetSelection(SelectionType::eNormal);
   normalSel->AddSelectionListener(this);
 
   // Register 'this' as selection listener for the spell check selection.
-  Selection* spellSel =
-    frameSel->GetSelection(nsISelectionController::SELECTION_SPELLCHECK);
+  Selection* spellSel = frameSel->GetSelection(SelectionType::eSpellCheck);
   spellSel->AddSelectionListener(this);
 }
 
 void
 SelectionManager::RemoveDocSelectionListener(nsIPresShell* aPresShell)
 {
   const nsFrameSelection* frameSel = aPresShell->ConstFrameSelection();
 
   // Remove 'this' registered as selection listener for the normal selection.
-  Selection* normalSel =
-    frameSel->GetSelection(nsISelectionController::SELECTION_NORMAL);
+  Selection* normalSel = frameSel->GetSelection(SelectionType::eNormal);
   normalSel->RemoveSelectionListener(this);
 
   // Remove 'this' registered as selection listener for the spellcheck
   // selection.
-  Selection* spellSel =
-    frameSel->GetSelection(nsISelectionController::SELECTION_SPELLCHECK);
+  Selection* spellSel = frameSel->GetSelection(SelectionType::eSpellCheck);
   spellSel->RemoveSelectionListener(this);
 }
 
 void
 SelectionManager::ProcessTextSelChangeEvent(AccEvent* aEvent)
 {
   // Fire selection change event if it's not pure caret-move selection change,
   // i.e. the accessible has or had not collapsed selection.
@@ -170,32 +162,34 @@ SelectionManager::ProcessTextSelChangeEv
   }
 }
 
 NS_IMETHODIMP
 SelectionManager::NotifySelectionChanged(nsIDOMDocument* aDOMDocument,
                                          nsISelection* aSelection,
                                          int16_t aReason)
 {
-  NS_ENSURE_ARG(aDOMDocument);
+  if (NS_WARN_IF(!aDOMDocument) || NS_WARN_IF(!aSelection)) {
+    return NS_ERROR_INVALID_ARG;
+  }
 
   nsCOMPtr<nsIDocument> documentNode(do_QueryInterface(aDOMDocument));
   DocAccessible* document = GetAccService()->GetDocAccessible(documentNode);
 
 #ifdef A11Y_LOG
   if (logging::IsEnabled(logging::eSelection))
     logging::SelChange(aSelection, document, aReason);
 #endif
 
   if (document) {
     // Selection manager has longer lifetime than any document accessible,
     // so that we are guaranteed that the notification is processed before
     // the selection manager is destroyed.
     RefPtr<SelData> selData =
-      new SelData(static_cast<Selection*>(aSelection), aReason);
+      new SelData(aSelection->AsSelection(), aReason);
     document->HandleNotification<SelectionManager, SelData>
       (this, &SelectionManager::ProcessSelectionChanged, selData);
   }
 
   return NS_OK;
 }
 
 void
@@ -220,20 +214,20 @@ SelectionManager::ProcessSelectionChange
   }
 
   HyperTextAccessible* text = nsAccUtils::GetTextContainer(cntrNode);
   if (!text) {
     NS_NOTREACHED("We must reach document accessible implementing text interface!");
     return;
   }
 
-  if (selection->GetType() == nsISelectionController::SELECTION_NORMAL) {
+  if (selection->GetType() == SelectionType::eNormal) {
     RefPtr<AccEvent> event =
       new AccTextSelChangeEvent(text, selection, aSelData->mReason);
     text->Document()->FireDelayedEvent(event);
 
-  } else if (selection->GetType() == nsISelectionController::SELECTION_SPELLCHECK) {
+  } else if (selection->GetType() == SelectionType::eSpellCheck) {
     // XXX: fire an event for container accessible of the focus/anchor range
     // of the spelcheck selection.
     text->Document()->FireDelayedEvent(nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED,
                                        text);
   }
 }
--- 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
@@ -44,57 +40,58 @@ TextAttrsMgr::GetAttributes(nsIPersisten
                   ((mOffsetAcc && mOffsetAccIdx != -1 &&
                     aStartOffset && aEndOffset) ||
                   (!mOffsetAcc && mOffsetAccIdx == -1 &&
                     !aStartOffset && !aEndOffset &&
                    mIncludeDefAttrs && aAttributes)),
                   "Wrong usage of TextAttrsMgr!");
 
   // Embedded objects are combined into own range with empty attributes set.
-  if (mOffsetAcc && nsAccUtils::IsEmbeddedObject(mOffsetAcc)) {
+  if (mOffsetAcc && !mOffsetAcc->IsText()) {
     for (int32_t childIdx = mOffsetAccIdx - 1; childIdx >= 0; childIdx--) {
       Accessible* currAcc = mHyperTextAcc->GetChildAt(childIdx);
-      if (!nsAccUtils::IsEmbeddedObject(currAcc))
+      if (currAcc->IsText())
         break;
 
       (*aStartOffset)--;
     }
 
     uint32_t childCount = mHyperTextAcc->ChildCount();
     for (uint32_t childIdx = mOffsetAccIdx + 1; childIdx < childCount;
          childIdx++) {
       Accessible* currAcc = mHyperTextAcc->GetChildAt(childIdx);
-      if (!nsAccUtils::IsEmbeddedObject(currAcc))
+      if (currAcc->IsText())
         break;
 
       (*aEndOffset)++;
     }
 
     return;
   }
 
   // Get the content and frame of the accessible. In the case of document
   // accessible it's role content and root frame.
   nsIContent* hyperTextElm = mHyperTextAcc->GetContent();
   if (!hyperTextElm)
     return; // XXX: we don't support text attrs on document with no body
 
   nsIFrame* rootFrame = mHyperTextAcc->GetFrame();
-  NS_ASSERTION(rootFrame, "No frame for accessible!");
+  MOZ_ASSERT(rootFrame, "No frame for accessible!");
   if (!rootFrame)
     return;
 
   nsIContent *offsetNode = nullptr, *offsetElm = nullptr;
   nsIFrame *frame = nullptr;
   if (mOffsetAcc) {
     offsetNode = mOffsetAcc->GetContent();
     offsetElm = nsCoreUtils::GetDOMElementFor(offsetNode);
-    NS_ASSERTION(offsetElm, "No element for offset accessible!");
+    MOZ_ASSERT(offsetElm, "No element for offset accessible!");
     if (!offsetElm)
       return;
+
     frame = offsetElm->GetPrimaryFrame();
   }
 
   // "language" text attribute
   LangTextAttr langTextAttr(mHyperTextAcc, hyperTextElm, offsetNode);
 
   // "aria-invalid" text attribute
   InvalidTextAttr invalidTextAttr(hyperTextElm, offsetNode);
@@ -157,19 +154,22 @@ TextAttrsMgr::GetRange(TextAttr* aAttrAr
                        uint32_t* aStartOffset, uint32_t* aEndOffset)
 {
   // Navigate backward from anchor accessible to find start offset.
   for (int32_t childIdx = mOffsetAccIdx - 1; childIdx >= 0; childIdx--) {
     Accessible* currAcc = mHyperTextAcc->GetChildAt(childIdx);
 
     // Stop on embedded accessible since embedded accessibles are combined into
     // own range.
-    if (nsAccUtils::IsEmbeddedObject(currAcc))
+    if (!currAcc->IsText())
       break;
 
+    MOZ_ASSERT(nsCoreUtils::GetDOMElementFor(currAcc->GetContent()),
+               "Text accessible has to have an associated DOM element");
+
     bool offsetFound = false;
     for (uint32_t attrIdx = 0; attrIdx < aAttrArrayLen; attrIdx++) {
       TextAttr* textAttr = aAttrArray[attrIdx];
       if (!textAttr->Equal(currAcc)) {
         offsetFound = true;
         break;
       }
     }
@@ -179,19 +179,22 @@ TextAttrsMgr::GetRange(TextAttr* aAttrAr
 
     *(aStartOffset) -= nsAccUtils::TextLength(currAcc);
   }
 
   // Navigate forward from anchor accessible to find end offset.
   uint32_t childLen = mHyperTextAcc->ChildCount();
   for (uint32_t childIdx = mOffsetAccIdx + 1; childIdx < childLen; childIdx++) {
     Accessible* currAcc = mHyperTextAcc->GetChildAt(childIdx);
-    if (nsAccUtils::IsEmbeddedObject(currAcc))
+    if (!currAcc->IsText())
       break;
 
+    MOZ_ASSERT(nsCoreUtils::GetDOMElementFor(currAcc->GetContent()),
+               "Text accessible has to have an associated DOM element");
+
     bool offsetFound = false;
     for (uint32_t attrIdx = 0; attrIdx < aAttrArrayLen; attrIdx++) {
       TextAttr* textAttr = aAttrArray[attrIdx];
 
       // Alter the end offset when text attribute changes its value and stop
       // the search.
       if (!textAttr->Equal(currAcc)) {
         offsetFound = true;
@@ -339,38 +342,42 @@ TextAttrsMgr::BGColorTextAttr::
     mIsDefined = GetColor(aFrame, &mNativeValue);
 }
 
 bool
 TextAttrsMgr::BGColorTextAttr::
   GetValueFor(Accessible* aAccessible, nscolor* aValue)
 {
   nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
-  nsIFrame* frame = elm->GetPrimaryFrame();
-  return frame ? GetColor(frame, aValue) : false;
+  if (elm) {
+    nsIFrame* frame = elm->GetPrimaryFrame();
+    if (frame) {
+      return GetColor(frame, aValue);
+    }
+  }
+  return false;
 }
 
 void
 TextAttrsMgr::BGColorTextAttr::
   ExposeValue(nsIPersistentProperties* aAttributes, const nscolor& aValue)
 {
   nsAutoString formattedValue;
   StyleInfo::FormatColor(aValue, formattedValue);
   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;
   }
@@ -402,22 +409,23 @@ TextAttrsMgr::ColorTextAttr::
   }
 }
 
 bool
 TextAttrsMgr::ColorTextAttr::
   GetValueFor(Accessible* aAccessible, nscolor* aValue)
 {
   nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
-  nsIFrame* frame = elm->GetPrimaryFrame();
-  if (frame) {
-    *aValue = frame->StyleColor()->mColor;
-    return true;
+  if (elm) {
+    nsIFrame* frame = elm->GetPrimaryFrame();
+    if (frame) {
+      *aValue = frame->StyleColor()->mColor;
+      return true;
+    }
   }
-
   return false;
 }
 
 void
 TextAttrsMgr::ColorTextAttr::
   ExposeValue(nsIPersistentProperties* aAttributes, const nscolor& aValue)
 {
   nsAutoString formattedValue;
@@ -440,33 +448,38 @@ TextAttrsMgr::FontFamilyTextAttr::
     mIsDefined = GetFontFamily(aFrame, mNativeValue);
 }
 
 bool
 TextAttrsMgr::FontFamilyTextAttr::
   GetValueFor(Accessible* aAccessible, nsString* aValue)
 {
   nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
-  nsIFrame* frame = elm->GetPrimaryFrame();
-  return frame ? GetFontFamily(frame, *aValue) : false;
+  if (elm) {
+    nsIFrame* frame = elm->GetPrimaryFrame();
+    if (frame) {
+      return GetFontFamily(frame, *aValue);
+    }
+  }
+  return false;
 }
 
 void
 TextAttrsMgr::FontFamilyTextAttr::
   ExposeValue(nsIPersistentProperties* aAttributes, const nsString& aValue)
 {
   nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::font_family, aValue);
 }
 
 bool
 TextAttrsMgr::FontFamilyTextAttr::
   GetFontFamily(nsIFrame* aFrame, nsString& aFamily)
 {
-  RefPtr<nsFontMetrics> fm;
-  nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fm));
+  RefPtr<nsFontMetrics> fm =
+    nsLayoutUtils::GetFontMetricsForFrame(aFrame, 1.0f);
 
   gfxFontGroup* fontGroup = fm->GetThebesFontGroup();
   gfxFont* font = fontGroup->GetFirstValidFont();
   gfxFontEntry* fontEntry = font->GetFontEntry();
   aFamily = fontEntry->FamilyName();
   return true;
 }
 
@@ -489,23 +502,24 @@ TextAttrsMgr::FontSizeTextAttr::
     mIsDefined = true;
   }
 }
 
 bool
 TextAttrsMgr::FontSizeTextAttr::
   GetValueFor(Accessible* aAccessible, nscoord* aValue)
 {
-  nsIContent* content = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
-  nsIFrame* frame = content->GetPrimaryFrame();
-  if (frame) {
-    *aValue = frame->StyleFont()->mSize;
-    return true;
+  nsIContent* el = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
+  if (el) {
+    nsIFrame* frame = el->GetPrimaryFrame();
+    if (frame) {
+      *aValue = frame->StyleFont()->mSize;
+      return true;
+    }
   }
-
   return false;
 }
 
 void
 TextAttrsMgr::FontSizeTextAttr::
   ExposeValue(nsIPersistentProperties* aAttributes, const nscoord& aValue)
 {
   // Convert from nscoord to pt.
@@ -546,22 +560,23 @@ TextAttrsMgr::FontStyleTextAttr::
   }
 }
 
 bool
 TextAttrsMgr::FontStyleTextAttr::
   GetValueFor(Accessible* aAccessible, nscoord* aValue)
 {
   nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
-  nsIFrame* frame = elm->GetPrimaryFrame();
-  if (frame) {
-    *aValue = frame->StyleFont()->mFont.style;
-    return true;
+  if (elm) {
+    nsIFrame* frame = elm->GetPrimaryFrame();
+    if (frame) {
+      *aValue = frame->StyleFont()->mFont.style;
+      return true;
+    }
   }
-
   return false;
 }
 
 void
 TextAttrsMgr::FontStyleTextAttr::
   ExposeValue(nsIPersistentProperties* aAttributes, const nscoord& aValue)
 {
   nsAutoString formattedValue;
@@ -588,22 +603,23 @@ TextAttrsMgr::FontWeightTextAttr::
   }
 }
 
 bool
 TextAttrsMgr::FontWeightTextAttr::
   GetValueFor(Accessible* aAccessible, int32_t* aValue)
 {
   nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
-  nsIFrame* frame = elm->GetPrimaryFrame();
-  if (frame) {
-    *aValue = GetFontWeight(frame);
-    return true;
+  if (elm) {
+    nsIFrame* frame = elm->GetPrimaryFrame();
+    if (frame) {
+      *aValue = GetFontWeight(frame);
+      return true;
+    }
   }
-
   return false;
 }
 
 void
 TextAttrsMgr::FontWeightTextAttr::
   ExposeValue(nsIPersistentProperties* aAttributes, const int32_t& aValue)
 {
   nsAutoString formattedValue;
@@ -613,54 +629,38 @@ TextAttrsMgr::FontWeightTextAttr::
 }
 
 int32_t
 TextAttrsMgr::FontWeightTextAttr::
   GetFontWeight(nsIFrame* aFrame)
 {
   // nsFont::width isn't suitable here because it's necessary to expose real
   // value of font weight (used font might not have some font weight values).
-  RefPtr<nsFontMetrics> fm;
-  nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fm));
+  RefPtr<nsFontMetrics> fm =
+    nsLayoutUtils::GetFontMetricsForFrame(aFrame, 1.0f);
 
   gfxFontGroup *fontGroup = fm->GetThebesFontGroup();
   gfxFont *font = fontGroup->GetFirstValidFont();
 
   // 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) :
@@ -692,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)
@@ -722,22 +718,23 @@ TextAttrsMgr::TextDecorTextAttr::
   }
 }
 
 bool
 TextAttrsMgr::TextDecorTextAttr::
   GetValueFor(Accessible* aAccessible, TextDecorValue* aValue)
 {
   nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
-  nsIFrame* frame = elm->GetPrimaryFrame();
-  if (frame) {
-    *aValue = TextDecorValue(frame);
-    return aValue->IsDefined();
+  if (elm) {
+    nsIFrame* frame = elm->GetPrimaryFrame();
+    if (frame) {
+      *aValue = TextDecorValue(frame);
+      return aValue->IsDefined();
+    }
   }
-
   return false;
 }
 
 void
 TextAttrsMgr::TextDecorTextAttr::
   ExposeValue(nsIPersistentProperties* aAttributes, const TextDecorValue& aValue)
 {
   if (aValue.IsUnderline()) {
@@ -785,22 +782,23 @@ TextAttrsMgr::TextPosTextAttr::
   }
 }
 
 bool
 TextAttrsMgr::TextPosTextAttr::
   GetValueFor(Accessible* aAccessible, TextPosValue* aValue)
 {
   nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
-  nsIFrame* frame = elm->GetPrimaryFrame();
-  if (frame) {
-    *aValue = GetTextPosValue(frame);
-    return *aValue != eTextPosNone;
+  if (elm) {
+    nsIFrame* frame = elm->GetPrimaryFrame();
+    if (frame) {
+      *aValue = GetTextPosValue(frame);
+      return *aValue != eTextPosNone;
+    }
   }
-
   return false;
 }
 
 void
 TextAttrsMgr::TextPosTextAttr::
   ExposeValue(nsIPersistentProperties* aAttributes, const TextPosValue& aValue)
 {
   switch (aValue) {
@@ -823,17 +821,17 @@ TextAttrsMgr::TextPosTextAttr::
       break;
   }
 }
 
 TextAttrsMgr::TextPosValue
 TextAttrsMgr::TextPosTextAttr::
   GetTextPosValue(nsIFrame* aFrame) const
 {
-  const nsStyleCoord& styleCoord = aFrame->StyleTextReset()->mVerticalAlign;
+  const nsStyleCoord& styleCoord = aFrame->StyleDisplay()->mVerticalAlign;
   switch (styleCoord.GetUnit()) {
     case eStyleUnit_Enumerated:
       switch (styleCoord.GetIntValue()) {
         case NS_STYLE_VERTICAL_ALIGN_BASELINE:
           return eTextPosBaseline;
         case NS_STYLE_VERTICAL_ALIGN_SUB:
           return eTextPosSub;
         case NS_STYLE_VERTICAL_ALIGN_SUPER:
--- 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/TextRange.cpp
+++ b/accessible/base/TextRange.cpp
@@ -61,18 +61,19 @@ TextRange::TextRange(HyperTextAccessible
 void
 TextRange::EmbeddedChildren(nsTArray<Accessible*>* aChildren) const
 {
   if (mStartContainer == mEndContainer) {
     int32_t startIdx = mStartContainer->GetChildIndexAtOffset(mStartOffset);
     int32_t endIdx = mStartContainer->GetChildIndexAtOffset(mEndOffset);
     for (int32_t idx = startIdx; idx <= endIdx; idx++) {
       Accessible* child = mStartContainer->GetChildAt(idx);
-      if (nsAccUtils::IsEmbeddedObject(child))
+      if (!child->IsText()) {
         aChildren->AppendElement(child);
+      }
     }
     return;
   }
 
   Accessible* p1 = mStartContainer->GetChildAtOffset(mStartOffset);
   Accessible* p2 = mEndContainer->GetChildAtOffset(mEndOffset);
 
   uint32_t pos1 = 0, pos2 = 0;
@@ -82,39 +83,42 @@ TextRange::EmbeddedChildren(nsTArray<Acc
 
   // Traverse the tree up to the container and collect embedded objects.
   for (uint32_t idx = 0; idx < pos1 - 1; idx++) {
     Accessible* parent = parents1[idx + 1];
     Accessible* child = parents1[idx];
     uint32_t childCount = parent->ChildCount();
     for (uint32_t childIdx = child->IndexInParent(); childIdx < childCount; childIdx++) {
       Accessible* next = parent->GetChildAt(childIdx);
-      if (nsAccUtils::IsEmbeddedObject(next))
+      if (!next->IsText()) {
         aChildren->AppendElement(next);
+      }
     }
   }
 
   // Traverse through direct children in the container.
   int32_t endIdx = parents2[pos2 - 1]->IndexInParent();
   int32_t childIdx = parents1[pos1 - 1]->IndexInParent() + 1;
   for (; childIdx < endIdx; childIdx++) {
     Accessible* next = container->GetChildAt(childIdx);
-    if (nsAccUtils::IsEmbeddedObject(next))
+    if (!next->IsText()) {
       aChildren->AppendElement(next);
+    }
   }
 
   // Traverse down from the container to end point.
   for (int32_t idx = pos2 - 2; idx > 0; idx--) {
     Accessible* parent = parents2[idx];
     Accessible* child = parents2[idx - 1];
     int32_t endIdx = child->IndexInParent();
     for (int32_t childIdx = 0; childIdx < endIdx; childIdx++) {
       Accessible* next = parent->GetChildAt(childIdx);
-      if (nsAccUtils::IsEmbeddedObject(next))
+      if (!next->IsText()) {
         aChildren->AppendElement(next);
+      }
     }
   }
 }
 
 void
 TextRange::Text(nsAString& aText) const
 {
   Accessible* current = mStartContainer->GetChildAtOffset(mStartOffset);
--- a/accessible/base/TextRange.h
+++ b/accessible/base/TextRange.h
@@ -3,17 +3,16 @@
 /* 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_TextRange_h__
 #define mozilla_a11y_TextRange_h__
 
 #include "mozilla/Move.h"
-#include "nsAutoPtr.h"
 #include "nsCaseTreatment.h"
 #include "nsRect.h"
 #include "nsTArray.h"
 
  class nsIVariant;
 
 namespace mozilla {
 namespace a11y {
--- a/accessible/base/TreeWalker.cpp
+++ b/accessible/base/TreeWalker.cpp
@@ -19,121 +19,307 @@ using namespace mozilla::a11y;
 ////////////////////////////////////////////////////////////////////////////////
 // TreeWalker
 ////////////////////////////////////////////////////////////////////////////////
 
 TreeWalker::
   TreeWalker(Accessible* aContext) :
   mDoc(aContext->Document()), mContext(aContext), mAnchorNode(nullptr),
   mARIAOwnsIdx(0),
-  mChildFilter(nsIContent::eSkipPlaceholderContent), mFlags(0)
+  mChildFilter(nsIContent::eSkipPlaceholderContent), mFlags(0),
+  mPhase(eAtStart)
 {
   mChildFilter |= mContext->NoXBLKids() ?
     nsIContent::eAllButXBL : nsIContent::eAllChildren;
 
   mAnchorNode = mContext->IsDoc() ?
     mDoc->DocumentNode()->GetRootElement() : mContext->GetContent();
 
-  if (mAnchorNode) {
-    PushState(mAnchorNode);
-  }
-
   MOZ_COUNT_CTOR(TreeWalker);
 }
 
 TreeWalker::
   TreeWalker(Accessible* aContext, nsIContent* aAnchorNode, uint32_t aFlags) :
   mDoc(aContext->Document()), mContext(aContext), mAnchorNode(aAnchorNode),
   mARIAOwnsIdx(0),
-  mChildFilter(nsIContent::eSkipPlaceholderContent), mFlags(aFlags)
+  mChildFilter(nsIContent::eSkipPlaceholderContent), mFlags(aFlags),
+  mPhase(eAtStart)
 {
+  MOZ_ASSERT(mFlags & eWalkCache, "This constructor cannot be used for tree creation");
   MOZ_ASSERT(aAnchorNode, "No anchor node for the accessible tree walker");
-  MOZ_ASSERT(mDoc->GetAccessibleOrContainer(aAnchorNode) == mContext,
-             "Unexpected anchor node was given");
 
   mChildFilter |= mContext->NoXBLKids() ?
     nsIContent::eAllButXBL : nsIContent::eAllChildren;
 
-  PushState(aAnchorNode);
-
   MOZ_COUNT_CTOR(TreeWalker);
 }
 
 TreeWalker::~TreeWalker()
 {
   MOZ_COUNT_DTOR(TreeWalker);
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// TreeWalker: private
+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");
+
+  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();
+
+    if (!parentNode || !parentNode->IsElement()) {
+      return false;
+    }
+
+    // If ARIA owned child.
+    Accessible* child = mDoc->GetAccessible(childNode);
+    if (child && child->IsRelocated()) {
+      if (child->Parent() != mContext) {
+        return false;
+      }
+
+      Accessible* ownedChild = nullptr;
+      while ((ownedChild = mDoc->ARIAOwnedAt(mContext, mARIAOwnsIdx++)) &&
+             ownedChild != child);
+
+      MOZ_ASSERT(ownedChild, "A child has to be in ARIA owned elements");
+      mPhase = eAtARIAOwns;
+      return true;
+    }
+
+    // Look in DOM.
+    dom::AllChildrenIterator* iter = PrependState(parentNode->AsElement(), true);
+    if (!iter->Seek(childNode)) {
+      return false;
+    }
+
+    if (parentNode == mAnchorNode) {
+      mPhase = eAtDOM;
+      return true;
+    }
+  } while (true);
+
+  return false;
+}
 
 Accessible*
 TreeWalker::Next()
 {
   if (mStateStack.IsEmpty()) {
-    return mDoc->ARIAOwnedAt(mContext, mARIAOwnsIdx++);
+    if (mPhase == eAtEnd) {
+      return nullptr;
+    }
+
+    if (mPhase == eAtDOM || mPhase == eAtARIAOwns) {
+      mPhase = eAtARIAOwns;
+      Accessible* child = mDoc->ARIAOwnedAt(mContext, mARIAOwnsIdx);
+      if (child) {
+        mARIAOwnsIdx++;
+        return child;
+      }
+      mPhase = eAtEnd;
+      return nullptr;
+    }
+
+    if (!mAnchorNode) {
+      mPhase = eAtEnd;
+      return nullptr;
+    }
+
+    mPhase = eAtDOM;
+    PushState(mAnchorNode, true);
   }
 
   dom::AllChildrenIterator* top = &mStateStack[mStateStack.Length() - 1];
   while (top) {
     while (nsIContent* childNode = top->GetNextChild()) {
       bool skipSubtree = false;
-      Accessible* child = nullptr;
-      if (mFlags & eWalkCache) {
-        child = mDoc->GetAccessible(childNode);
-      }
-      else if (mContext->IsAcceptableChild(childNode)) {
-        child = GetAccService()->
-          GetOrCreateAccessible(childNode, mContext, &skipSubtree);
-      }
-
-      // Ignore the accessible and its subtree if it was repositioned by means
-      // of aria-owns.
+      Accessible* child = AccessibleFor(childNode, mFlags, &skipSubtree);
       if (child) {
-        if (child->IsRelocated()) {
-          continue;
-        }
         return child;
       }
 
-      // Walk down into subtree to find accessibles.
+      // Walk down the subtree if allowed.
       if (!skipSubtree && childNode->IsElement()) {
-        top = PushState(childNode);
+        top = PushState(childNode, true);
       }
     }
     top = PopState();
   }
 
   // If we traversed the whole subtree of the anchor node. Move to next node
-  // relative anchor node within the context subtree if possible.
-  if (mFlags != eWalkContextTree)
+  // 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();
+  }
 
   nsINode* contextNode = mContext->GetNode();
   while (mAnchorNode != contextNode) {
     nsINode* parentNode = mAnchorNode->GetFlattenedTreeParent();
     if (!parentNode || !parentNode->IsElement())
       return nullptr;
 
     nsIContent* parent = parentNode->AsElement();
-    top = PushState(parent);
+    top = PushState(parent, true);
     if (top->Seek(mAnchorNode)) {
       mAnchorNode = parent;
       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();
 }
 
+Accessible*
+TreeWalker::Prev()
+{
+  if (mStateStack.IsEmpty()) {
+    if (mPhase == eAtStart || mPhase == eAtDOM) {
+      mPhase = eAtStart;
+      return nullptr;
+    }
+
+    if (mPhase == eAtEnd) {
+      mARIAOwnsIdx = mDoc->ARIAOwnedCount(mContext);
+      mPhase = eAtARIAOwns;
+    }
+
+    if (mPhase == eAtARIAOwns) {
+      if (mARIAOwnsIdx > 0) {
+        return mDoc->ARIAOwnedAt(mContext, --mARIAOwnsIdx);
+      }
+
+      if (!mAnchorNode) {
+        mPhase = eAtStart;
+        return nullptr;
+      }
+
+      mPhase = eAtDOM;
+      PushState(mAnchorNode, false);
+    }
+  }
+
+  dom::AllChildrenIterator* top = &mStateStack[mStateStack.Length() - 1];
+  while (top) {
+    while (nsIContent* childNode = top->GetPreviousChild()) {
+      // No accessible creation on the way back.
+      bool skipSubtree = false;
+      Accessible* child = AccessibleFor(childNode, eWalkCache, &skipSubtree);
+      if (child) {
+        return child;
+      }
+
+      // Walk down into subtree to find accessibles.
+      if (!skipSubtree && childNode->IsElement()) {
+        top = PushState(childNode, false);
+      }
+    }
+    top = PopState();
+  }
+
+  // Move to a previous node relative the anchor node within the context
+  // subtree if asked.
+  if (mFlags != eWalkContextTree) {
+    mPhase = eAtStart;
+    return nullptr;
+  }
+
+  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 Prev();
+    }
+
+    mAnchorNode = parent;
+  }
+
+  mPhase = eAtStart;
+  return nullptr;
+}
+
+Accessible*
+TreeWalker::AccessibleFor(nsIContent* aNode, uint32_t aFlags, bool* aSkipSubtree)
+{
+  // Ignore the accessible and its subtree if it was repositioned by means
+  // of aria-owns.
+  Accessible* child = mDoc->GetAccessible(aNode);
+  if (child) {
+    if (child->IsRelocated()) {
+      *aSkipSubtree = true;
+      return nullptr;
+    }
+    return child;
+  }
+
+  // Create an accessible if allowed.
+  if (!(aFlags & eWalkCache) && mContext->IsAcceptableChild(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;
+}
+
 dom::AllChildrenIterator*
 TreeWalker::PopState()
 {
   size_t length = mStateStack.Length();
   mStateStack.RemoveElementAt(length - 1);
-  return mStateStack.IsEmpty() ? nullptr : &mStateStack[mStateStack.Length() - 1];
+  return mStateStack.IsEmpty() ? nullptr : &mStateStack.LastElement();
 }
--- a/accessible/base/TreeWalker.h
+++ b/accessible/base/TreeWalker.h
@@ -40,58 +40,105 @@ public:
   /**
    * Used to navigate the accessible children relative to the anchor.
    *
    * @param aContext [in] container accessible for the given node, used to
    *                   define accessible context
    * @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 = 0);
+  TreeWalker(Accessible* aContext, nsIContent* aAnchorNode, uint32_t aFlags = eWalkCache);
 
   ~TreeWalker();
 
   /**
-   * Return the next accessible.
+   * 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();
+  Accessible* Prev();
+
+  Accessible* Context() const { return mContext; }
+  DocAccessible* Document() const { return mDoc; }
 
 private:
   TreeWalker();
   TreeWalker(const TreeWalker&);
   TreeWalker& operator =(const TreeWalker&);
 
   /**
-   * Create new state for the given node and push it on top of stack.
+   * Return an accessible for the given node if any.
+   */
+  Accessible* AccessibleFor(nsIContent* aNode, uint32_t aFlags,
+                            bool* aSkipSubtree);
+
+  /**
+   * Create new state for the given node and push it on top of stack / at bottom
+   * of stack.
    *
    * @note State stack is used to navigate up/down the DOM subtree during
    *        accessible children search.
    */
-  dom::AllChildrenIterator* PushState(nsIContent* aContent)
+  dom::AllChildrenIterator* PushState(nsIContent* aContent,
+                                      bool aStartAtBeginning)
   {
     return mStateStack.AppendElement(
-      dom::AllChildrenIterator(aContent, mChildFilter));
+      dom::AllChildrenIterator(aContent, mChildFilter, aStartAtBeginning));
+  }
+  dom::AllChildrenIterator* PrependState(nsIContent* aContent,
+                                         bool aStartAtBeginning)
+  {
+    return mStateStack.InsertElementAt(0,
+      dom::AllChildrenIterator(aContent, mChildFilter, aStartAtBeginning));
   }
 
   /**
    * Pop state from stack.
    */
   dom::AllChildrenIterator* PopState();
 
   DocAccessible* mDoc;
   Accessible* mContext;
   nsIContent* mAnchorNode;
 
   AutoTArray<dom::AllChildrenIterator, 20> mStateStack;
   uint32_t mARIAOwnsIdx;
 
   int32_t mChildFilter;
   uint32_t mFlags;
+
+  enum Phase {
+    eAtStart,
+    eAtDOM,
+    eAtARIAOwns,
+    eAtEnd
+  };
+  Phase mPhase;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif // mozilla_a11y_TreeWalker_h_
--- 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'
@@ -21,25 +21,27 @@ EXPORTS.mozilla.a11y += [
 ]
 
 if CONFIG['MOZ_DEBUG']:
     EXPORTS.mozilla.a11y += [
         'Logging.h',
     ]
 
 UNIFIED_SOURCES += [
-    'AccCollector.cpp',
+    'AccessibleOrProxy.cpp',
     'AccEvent.cpp',
     'AccGroupInfo.cpp',
     'AccIterator.cpp',
     'ARIAMap.cpp',
     'ARIAStateMap.cpp',
     'Asserts.cpp',
     'DocManager.cpp',
+    'EmbeddedObjCollector.cpp',
     'EventQueue.cpp',
+    'EventTree.cpp',
     'Filters.cpp',
     'FocusManager.cpp',
     'NotificationController.cpp',
     'nsAccessibilityService.cpp',
     'nsAccessiblePivot.cpp',
     'nsAccUtils.cpp',
     'nsCoreUtils.cpp',
     'nsEventShell.cpp',
@@ -56,44 +58,59 @@ 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',
     '/layout/xul',
     '/layout/xul/tree/',
 ]
 
-if CONFIG['MOZ_ENABLE_GTK']:
+if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
     LOCAL_INCLUDES += [
         '/accessible/atk',
     ]
+    CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
 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',
     ]
 
 FINAL_LIBRARY = 'xul'
 
-if CONFIG['MOZ_ENABLE_GTK']:
-    CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
+include('/ipc/chromium/chromium-config.mozbuild')
 
-include('/ipc/chromium/chromium-config.mozbuild')
+if CONFIG['GNU_CXX']:
+    CXXFLAGS += ['-Wno-error=shadow']
--- 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/nsAccUtils.cpp
+++ b/accessible/base/nsAccUtils.cpp
@@ -126,35 +126,37 @@ nsAccUtils::GetLevelForXULContainerItem(
     parentContainer.swap(container);
   }
 
   return level;
 }
 
 void
 nsAccUtils::SetLiveContainerAttributes(nsIPersistentProperties *aAttributes,
-                                       nsIContent *aStartContent,
-                                       nsIContent *aTopContent)
+                                       nsIContent* aStartContent,
+                                       dom::Element* aTopEl)
 {
   nsAutoString live, relevant, busy;
-  nsIContent *ancestor = aStartContent;
+  nsIContent* ancestor = aStartContent;
   while (ancestor) {
 
     // container-relevant attribute
     if (relevant.IsEmpty() &&
         HasDefinedARIAToken(ancestor, nsGkAtoms::aria_relevant) &&
         ancestor->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_relevant, relevant))
       SetAccAttr(aAttributes, nsGkAtoms::containerRelevant, relevant);
 
     // container-live, and container-live-role attributes
     if (live.IsEmpty()) {
-      nsRoleMapEntry* role = aria::GetRoleMap(ancestor);
+      const nsRoleMapEntry* role = nullptr;
+      if (ancestor->IsElement()) {
+        role = aria::GetRoleMap(ancestor->AsElement());
+      }
       if (HasDefinedARIAToken(ancestor, nsGkAtoms::aria_live)) {
-        ancestor->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_live,
-                          live);
+        ancestor->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_live, live);
       } else if (role) {
         GetLiveAttrValue(role->liveAttRule, live);
       }
       if (!live.IsEmpty()) {
         SetAccAttr(aAttributes, nsGkAtoms::containerLive, live);
         if (role) {
           SetAccAttr(aAttributes, nsGkAtoms::containerLiveRole,
                      role->ARIARoleString());
@@ -170,22 +172,22 @@ nsAccUtils::SetLiveContainerAttributes(n
     }
 
     // container-busy attribute
     if (busy.IsEmpty() &&
         HasDefinedARIAToken(ancestor, nsGkAtoms::aria_busy) &&
         ancestor->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_busy, busy))
       SetAccAttr(aAttributes, nsGkAtoms::containerBusy, busy);
 
-    if (ancestor == aTopContent)
+    if (ancestor == aTopEl)
       break;
 
     ancestor = ancestor->GetParent();
     if (!ancestor)
-      ancestor = aTopContent; // Use <body>/<frameset>
+      ancestor = aTopEl; // Use <body>/<frameset>
   }
 }
 
 bool
 nsAccUtils::HasDefinedARIAToken(nsIContent *aContent, nsIAtom *aAtom)
 {
   NS_ASSERTION(aContent, "aContent is null in call to HasDefinedARIAToken!");
 
@@ -385,31 +387,32 @@ nsAccUtils::IsTextInterfaceSupportCorrec
   // early and fire mutation events before we need to
   if (aAccessible->IsDoc())
     return true;
 
   bool foundText = false;
   uint32_t childCount = aAccessible->ChildCount();
   for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) {
     Accessible* child = aAccessible->GetChildAt(childIdx);
-    if (!IsEmbeddedObject(child)) {
+    if (child->IsText()) {
       foundText = true;
       break;
     }
   }
 
   return !foundText || aAccessible->IsHyperText();
 }
 #endif
 
 uint32_t
 nsAccUtils::TextLength(Accessible* aAccessible)
 {
-  if (IsEmbeddedObject(aAccessible))
+  if (!aAccessible->IsText()) {
     return 1;
+  }
 
   TextLeafAccessible* textLeaf = aAccessible->AsTextLeaf();
   if (textLeaf)
     return textLeaf->Text().Length();
 
   // For list bullets (or anything other accessible which would compute its own
   // text. They don't have their own frame.
   // XXX In the future, list bullets may have frame and anon content, so 
--- a/accessible/base/nsAccUtils.h
+++ b/accessible/base/nsAccUtils.h
@@ -80,18 +80,18 @@ public:
   /**
    * Set container-foo live region attributes for the given node.
    *
    * @param aAttributes    where to store the attributes
    * @param aStartContent  node to start from
    * @param aTopContent    node to end at
    */
   static void SetLiveContainerAttributes(nsIPersistentProperties *aAttributes,
-                                         nsIContent *aStartContent,
-                                         nsIContent *aTopContent);
+                                         nsIContent* aStartContent,
+                                         mozilla::dom::Element* aTopEl);
 
   /**
    * Any ARIA property of type boolean or NMTOKEN is undefined if the ARIA
    * property is not present, or is "" or "undefined". Do not call 
    * this method for properties of type string, decimal, IDREF or IDREFS.
    * 
    * Return true if the ARIA property is defined, otherwise false
    */
@@ -199,27 +199,16 @@ public:
 #endif
 
   /**
    * Return text length of the given accessible, return 0 on failure.
    */
   static uint32_t TextLength(Accessible* aAccessible);
 
   /**
-   * Return true if the given accessible is embedded object.
-   */
-  static bool IsEmbeddedObject(Accessible* aAcc)
-  {
-    uint32_t role = aAcc->Role();
-    return role != roles::TEXT_LEAF &&
-           role != roles::WHITESPACE &&
-           role != roles::STATICTEXT;
-  }
-
-  /**
    * Transform nsIAccessibleStates constants to internal state constant.
    */
   static inline uint64_t To64State(uint32_t aState1, uint32_t aState2)
   {
     return static_cast<uint64_t>(aState1) +
         (static_cast<uint64_t>(aState2) << 31);
   }
 
--- 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"
@@ -137,17 +137,17 @@ MustBeAccessible(nsIContent* aContent, D
 ////////////////////////////////////////////////////////////////////////////////
 // Accessible constructors
 
 static Accessible*
 New_HTMLLink(nsIContent* aContent, Accessible* aContext)
 {
   // Only some roles truly enjoy life as HTMLLinkAccessibles, for details
   // see closed bug 494807.
-  nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aContent);
+  const nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aContent->AsElement());
   if (roleMapEntry && roleMapEntry->role != roles::NOTHING &&
       roleMapEntry->role != roles::LINK) {
     return new HyperTextAccessibleWrap(aContent, aContext->Document());
   }
 
   return new HTMLLinkAccessible(aContent, aContext->Document());
 }
 
@@ -196,16 +196,19 @@ static Accessible* New_HTMLLabel(nsICont
   { return new HTMLLabelAccessible(aContent, aContext->Document()); }
 
 static Accessible* New_HTMLOutput(nsIContent* aContent, Accessible* aContext)
   { return new HTMLOutputAccessible(aContent, aContext->Document()); }
 
 static Accessible* New_HTMLProgress(nsIContent* aContent, Accessible* aContext)
   { return new HTMLProgressMeterAccessible(aContent, aContext->Document()); }
 
+static Accessible* New_HTMLSummary(nsIContent* aContent, Accessible* aContext)
+  { return new HTMLSummaryAccessible(aContent, aContext->Document()); }
+
 static Accessible*
 New_HTMLTableAccessible(nsIContent* aContent, Accessible* aContext)
   { return new HTMLTableAccessible(aContent, aContext->Document()); }
 
 static Accessible*
 New_HTMLTableRowAccessible(nsIContent* aContent, Accessible* aContext)
   { return new HTMLTableRowAccessible(aContent, aContext->Document()); }
 
@@ -256,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)
@@ -309,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
@@ -351,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->GetCurrentDoc();
+  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());
@@ -405,23 +398,23 @@ 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->IsInDoc())
+    if (!mContent->IsInUncomposedDoc())
       return NS_OK;
 
     nsIPresShell* ps = mContent->OwnerDoc()->GetShell();
     if (ps) {
       DocAccessible* doc = ps->GetDocAccessible();
       if (doc) {
         // Make sure that if we created an accessible for the plugin that wasn't
         // a plugin accessible we remove it before creating the right accessible.
@@ -550,61 +543,64 @@ nsAccessibilityService::DeckPanelSwitche
 }
 
 void
 nsAccessibilityService::ContentRangeInserted(nsIPresShell* aPresShell,
                                              nsIContent* aContainer,
                                              nsIContent* aStartChild,
                                              nsIContent* aEndChild)
 {
+  DocAccessible* document = GetDocAccessible(aPresShell);
 #ifdef A11Y_LOG
   if (logging::IsEnabled(logging::eTree)) {
-    logging::MsgBegin("TREE", "content inserted");
+    logging::MsgBegin("TREE", "content inserted; doc: %p", document);
     logging::Node("container", aContainer);
     for (nsIContent* child = aStartChild; child != aEndChild;
          child = child->GetNextSibling()) {
       logging::Node("content", child);
     }
     logging::MsgEnd();
     logging::Stack();
   }
 #endif
 
-  DocAccessible* docAccessible = GetDocAccessible(aPresShell);
-  if (docAccessible)
-    docAccessible->ContentInserted(aContainer, aStartChild, aEndChild);
+  if (document) {
+    document->ContentInserted(aContainer, aStartChild, aEndChild);
+  }
 }
 
 void
 nsAccessibilityService::ContentRemoved(nsIPresShell* aPresShell,
                                        nsIContent* aChildNode)
 {
+  DocAccessible* document = GetDocAccessible(aPresShell);
 #ifdef A11Y_LOG
   if (logging::IsEnabled(logging::eTree)) {
-    logging::MsgBegin("TREE", "content removed");
-    logging::Node("container", aChildNode->GetFlattenedTreeParent());
-    logging::Node("content", aChildNode);
+    logging::MsgBegin("TREE", "content removed; doc: %p", document);
+    logging::Node("container node", aChildNode->GetFlattenedTreeParent());
+    logging::Node("content node", aChildNode);
+    logging::MsgEnd();
   }
 #endif
 
-  DocAccessible* document = GetDocAccessible(aPresShell);
   if (document) {
     // Flatten hierarchy may be broken at this point so we cannot get a true
     // container by traversing up the DOM tree. Find a parent of first accessible
     // from the subtree of the given DOM node, that'll be a container. If no
     // accessibles in subtree then we don't care about the change.
     Accessible* child = document->GetAccessible(aChildNode);
     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
     }
   }
 
@@ -727,324 +723,265 @@ 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::GetOrCreateAccessible(nsINode* aNode,
-                                              Accessible* aContext,
-                                              bool* aIsSubtreeHidden)
+nsAccessibilityService::CreateAccessible(nsINode* aNode,
+                                         Accessible* aContext,
+                                         bool* aIsSubtreeHidden)
 {
-  NS_PRECONDITION(aContext && aNode && !gIsShutdown,
-                  "Maybe let'd do a crash? Oh, yes, baby!");
+  MOZ_ASSERT(aContext, "No context provided");
+  MOZ_ASSERT(aNode, "No node to create an accessible for");
+  MOZ_ASSERT(gConsumers, "No creation after shutdown");
 
   if (aIsSubtreeHidden)
     *aIsSubtreeHidden = false;
 
   DocAccessible* document = aContext->Document();
-
-  // Check to see if we already have an accessible for this node in the cache.
-  // XXX: we don't have context check here. It doesn't really necessary until
-  // we have in-law children adoption.
-  Accessible* cachedAccessible = document->GetAccessible(aNode);
-  if (cachedAccessible)
-    return cachedAccessible;
-
-  // No cache entry, so we must create the accessible.
+  MOZ_ASSERT(!document->GetAccessible(aNode),
+             "We already have an accessible for this node.");
 
   if (aNode->IsNodeOfType(nsINode::eDOCUMENT)) {
     // If it's document node then ask accessible document loader for
     // document accessible, otherwise return null.
     nsCOMPtr<nsIDocument> document(do_QueryInterface(aNode));
     return GetDocAccessible(document);
   }
 
   // We have a content node.
-  if (!aNode->GetCrossShadowCurrentDoc()) {
+  if (!aNode->GetComposedDoc()) {
     NS_WARNING("Creating accessible for node with no document");
     return nullptr;
   }
 
   if (aNode->OwnerDoc() != document->DocumentNode()) {
     NS_ERROR("Creating accessible for wrong document");
     return nullptr;
   }
@@ -1123,21 +1060,21 @@ nsAccessibilityService::GetOrCreateAcces
                                               frame->GetParent()).IsEmpty()) {
       if (aIsSubtreeHidden)
         *aIsSubtreeHidden = true;
 
       return nullptr;
     }
 
     newAcc = new HyperTextAccessibleWrap(content, document);
-    document->BindToDocument(newAcc, aria::GetRoleMap(aNode));
+    document->BindToDocument(newAcc, aria::GetRoleMap(content->AsElement()));
     return newAcc;
   }
 
-  nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aNode);
+  const nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(content->AsElement());
 
   // If the element is focusable or global ARIA attribute is applied to it or
   // it is referenced by ARIA relationship then treat role="presentation" on
   // the element as the role is not there.
   if (roleMapEntry &&
       (roleMapEntry->Is(nsGkAtoms::presentation) ||
        roleMapEntry->Is(nsGkAtoms::none))) {
     if (!MustBeAccessible(content, document))
@@ -1179,29 +1116,29 @@ nsAccessibilityService::GetOrCreateAcces
         newAcc = new ARIAGridAccessibleWrap(content, document);
       }
     }
 
     // If table has strong ARIA role then all table descendants shouldn't
     // expose their native roles.
     if (!roleMapEntry && newAcc && aContext->HasStrongARIARole()) {
       if (frame->AccessibleType() == eHTMLTableRowType) {
-        nsRoleMapEntry* contextRoleMap = aContext->ARIARoleMap();
+        const nsRoleMapEntry* contextRoleMap = aContext->ARIARoleMap();
         if (!contextRoleMap->IsOfType(eTable))
           roleMapEntry = &aria::gEmptyRoleMap;
 
       } else if (frame->AccessibleType() == eHTMLTableCellType &&
                  aContext->ARIARoleMap() == &aria::gEmptyRoleMap) {
         roleMapEntry = &aria::gEmptyRoleMap;
 
       } else if (content->IsAnyOfHTMLElements(nsGkAtoms::dt,
                                               nsGkAtoms::li,
                                               nsGkAtoms::dd) ||
                  frame->AccessibleType() == eHTMLLiType) {
-        nsRoleMapEntry* contextRoleMap = aContext->ARIARoleMap();
+        const nsRoleMapEntry* contextRoleMap = aContext->ARIARoleMap();
         if (!contextRoleMap->IsOfType(eList))
           roleMapEntry = &aria::gEmptyRoleMap;
       }
     }
   }
 
   // Accessible XBL types and deck stuff are used in XUL only currently.
   if (!newAcc && content->IsXULElement()) {
@@ -1229,18 +1166,18 @@ nsAccessibilityService::GetOrCreateAcces
           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,46 +1259,72 @@ nsAccessibilityService::Init()
 
   for (uint32_t i = 0; i < ArrayLength(sMarkupMapList); i++)
     mMarkupMaps.Put(*sMarkupMapList[i].tag, &sMarkupMapList[i]);
 
 #ifdef A11Y_LOG
   logging::CheckEnv();
 #endif
 
-  if (XRE_IsParentProcess())
+  gAccessibilityService = this;
+  NS_ADDREF(gAccessibilityService); // will release in Shutdown()
+
+  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);
@@ -1377,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);
@@ -1672,22 +1629,22 @@ nsAccessibilityService::CreateAccessible
       // accessible HTML table or a direct child of accessible of HTML table.
       Accessible* table = aContext->IsTable() ? aContext : nullptr;
       if (!table && aContext->Parent() && aContext->Parent()->IsTable())
         table = aContext->Parent();
 
       if (table) {
         nsIContent* parentContent = aContent->GetParent();
         nsIFrame* parentFrame = parentContent->GetPrimaryFrame();
-        if (parentFrame->GetType() != nsGkAtoms::tableOuterFrame) {
+        if (parentFrame->GetType() != nsGkAtoms::tableWrapperFrame) {
           parentContent = parentContent->GetParent();
           parentFrame = parentContent->GetPrimaryFrame();
         }
 
-        if (parentFrame->GetType() == nsGkAtoms::tableOuterFrame &&
+        if (parentFrame->GetType() == nsGkAtoms::tableWrapperFrame &&
             table->GetContent() == parentContent) {
           newAcc = new HTMLTableRowAccessible(aContent, document);
         }
       }
       break;
     }
     case eHTMLTextFieldType:
       newAcc = new HTMLTextFieldAccessible(aContent, document);
@@ -1749,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;
 
@@ -1796,50 +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();
-
-  nsAccessibilityService::gAccessibilityService = service;
-  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,60 +183,81 @@ 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;
+  };
 
   /**
-   * Return an accessible for the given DOM node from the cache or create new
-   * one.
+   * 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
    */
-  Accessible* GetOrCreateAccessible(nsINode* aNode, Accessible* aContext,
-                                    bool* aIsSubtreeHidden = nullptr);
+  Accessible* CreateAccessible(nsINode* aNode, Accessible* aContext,
+                               bool* aIsSubtreeHidden = nullptr);
 
   mozilla::a11y::role MarkupRole(const nsIContent* aContent) const
   {
     const mozilla::a11y::MarkupMapInfo* markupMap =
       mMarkupMaps.Get(aContent->NodeInfo()->NameAtom());
     return markupMap ? markupMap->role : mozilla::a11y::roles::NOTHING;
   }
 
   /**
    * 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.
    */
@@ -250,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
@@ -383,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/nsAccessiblePivot.cpp
+++ b/accessible/base/nsAccessiblePivot.cpp
@@ -388,25 +388,25 @@ nsAccessiblePivot::MoveNextByText(TextBo
     tempStart = potentialStart > tempStart ? potentialStart : currentEnd;
 
     // The offset range we've obtained might have embedded characters in it,
     // limit the range to the start of the first occurrence of an embedded
     // character.
     Accessible* childAtOffset = nullptr;
     for (int32_t i = tempStart; i < tempEnd; i++) {
       childAtOffset = text->GetChildAtOffset(i);
-      if (childAtOffset && nsAccUtils::IsEmbeddedObject(childAtOffset)) {
+      if (childAtOffset && !childAtOffset->IsText()) {
         tempEnd = i;
         break;
       }
     }
     // If there's an embedded character at the very start of the range, we
     // instead want to traverse into it. So restart the movement with
     // the child as the starting point.
-    if (childAtOffset && nsAccUtils::IsEmbeddedObject(childAtOffset) &&
+    if (childAtOffset && !childAtOffset->IsText() &&
         tempStart == static_cast<int32_t>(childAtOffset->StartOffset())) {
       tempPosition = childAtOffset;
       tempStart = tempEnd = -1;
       continue;
     }
 
     *aResult = true;
 
@@ -519,25 +519,25 @@ nsAccessiblePivot::MovePreviousByText(Te
     tempEnd = potentialEnd < tempEnd ? potentialEnd : currentStart;
 
     // The offset range we've obtained might have embedded characters in it,
     // limit the range to the start of the last occurrence of an embedded
     // character.
     Accessible* childAtOffset = nullptr;
     for (int32_t i = tempEnd - 1; i >= tempStart; i--) {
       childAtOffset = text->GetChildAtOffset(i);
-      if (childAtOffset && nsAccUtils::IsEmbeddedObject(childAtOffset)) {
+      if (childAtOffset && !childAtOffset->IsText()) {
         tempStart = childAtOffset->EndOffset();
         break;
       }
     }
     // If there's an embedded character at the very end of the range, we
     // instead want to traverse into it. So restart the movement with
     // the child as the starting point.
-    if (childAtOffset && nsAccUtils::IsEmbeddedObject(childAtOffset) &&
+    if (childAtOffset && !childAtOffset->IsText() &&
         tempEnd == static_cast<int32_t>(childAtOffset->EndOffset())) {
       tempPosition = childAtOffset;
       tempStart = tempEnd = childAtOffset->AsHyperText()->CharacterCount();
       continue;
     }
 
     *aResult = true;
 
@@ -896,17 +896,17 @@ RuleCache::ApplyFilter(Accessible* aAcce
         *aResult |= nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
         return NS_OK;
       }
     }
 
     if ((nsIAccessibleTraversalRule::PREFILTER_TRANSPARENT & mPreFilter) &&
         !(state & states::OPAQUE1)) {
       nsIFrame* frame = aAccessible->GetFrame();
-      if (frame->StyleDisplay()->mOpacity == 0.0f) {
+      if (frame->StyleEffects()->mOpacity == 0.0f) {
         *aResult |= nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
         return NS_OK;
       }
     }
   }
 
   if (mAcceptRolesLength > 0) {
     uint32_t accessibleRole = aAccessible->Role();
--- a/accessible/base/nsAccessiblePivot.h
+++ b/accessible/base/nsAccessiblePivot.h
@@ -5,17 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _nsAccessiblePivot_H_
 #define _nsAccessiblePivot_H_
 
 #include "nsIAccessiblePivot.h"
 
 #include "Accessible-inl.h"
-#include "nsAutoPtr.h"
 #include "nsTObserverArray.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/Attributes.h"
 
 class RuleCache;
 
 /**
  * Class represents an accessible pivot.
--- 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"
@@ -73,17 +75,17 @@ nsCoreUtils::DispatchClickEvent(nsITreeB
                                 const nsAString& aPseudoElt)
 {
   nsCOMPtr<nsIDOMElement> tcElm;
   aTreeBoxObj->GetTreeBody(getter_AddRefs(tcElm));
   if (!tcElm)
     return;
 
   nsCOMPtr<nsIContent> tcContent(do_QueryInterface(tcElm));
-  nsIDocument *document = tcContent->GetCurrentDoc();
+  nsIDocument *document = tcContent->GetUncomposedDoc();
   if (!document)
     return;
 
   nsCOMPtr<nsIPresShell> presShell = document->GetShell();
   if (!presShell)
     return;
 
   // Ensure row is visible.
@@ -92,33 +94,34 @@ 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->GetViewExternal()->GetNearestWidget(&offset);
+    rootFrame->GetView()->GetNearestWidget(&offset);
 
   RefPtr<nsPresContext> presContext = presShell->GetPresContext();
 
   int32_t cnvdX = presContext->CSSPixelsToDevPixels(tcX + x + 1) +
     presContext->AppUnitsToDevPixels(offset.x);
   int32_t cnvdY = presContext->CSSPixelsToDevPixels(tcY + y + 1) +
     presContext->AppUnitsToDevPixels(offset.y);
 
@@ -133,44 +136,49 @@ nsCoreUtils::DispatchClickEvent(nsITreeB
 void
 nsCoreUtils::DispatchMouseEvent(EventMessage aMessage, int32_t aX, int32_t aY,
                                 nsIContent *aContent, nsIFrame *aFrame,
                                 nsIPresShell *aPresShell, nsIWidget *aRootWidget)
 {
   WidgetMouseEvent event(true, aMessage, aRootWidget,
                          WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
 
-  event.refPoint = LayoutDeviceIntPoint(aX, aY);
+  event.mRefPoint = LayoutDeviceIntPoint(aX, aY);
 
-  event.clickCount = 1;
+  event.mClickCount = 1;
   event.button = WidgetMouseEvent::eLeftButton;
-  event.time = PR_IntervalNow();
+  event.mTime = PR_IntervalNow();
   event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
 
   nsEventStatus status = nsEventStatus_eIgnore;
   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.time = PR_IntervalNow();
+  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);
   t->SetTarget(aContent);
-  event.touches.AppendElement(t);
+  event.mTouches.AppendElement(t);
   nsEventStatus status = nsEventStatus_eIgnore;
   aPresShell->HandleEventWithTarget(&event, aFrame, aContent, &status);
 }
 
 uint32_t
 nsCoreUtils::GetAccessKeyFor(nsIContent* aContent)
 {
   // Accesskeys are registered by @accesskey attribute only. At first check
@@ -218,38 +226,16 @@ nsCoreUtils::GetDOMNodeFromDOMPoint(nsIN
     // from the given DOM point is used as result node.
     if (aOffset != childCount)
       return aNode->GetChildAt(aOffset);
   }
 
   return aNode;
 }
 
-nsIContent*
-nsCoreUtils::GetRoleContent(nsINode *aNode)
-{
-  nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
-  if (!content) {
-    nsCOMPtr<nsIDocument> doc(do_QueryInterface(aNode));
-    if (doc) {
-      nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(aNode));
-      if (htmlDoc) {
-        nsCOMPtr<nsIDOMHTMLElement> bodyElement;
-        htmlDoc->GetBody(getter_AddRefs(bodyElement));
-        content = do_QueryInterface(bodyElement);
-      }
-      else {
-        return doc->GetDocumentElement();
-      }
-    }
-  }
-
-  return content;
-}
-
 bool
 nsCoreUtils::IsAncestorOf(nsINode *aPossibleAncestorNode,
                           nsINode *aPossibleDescendantNode,
                           nsINode *aRootNode)
 {
   NS_ENSURE_TRUE(aPossibleAncestorNode && aPossibleDescendantNode, false);
 
   nsINode *parentNode = aPossibleDescendantNode;
@@ -501,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/nsCoreUtils.h
+++ b/accessible/base/nsCoreUtils.h
@@ -104,27 +104,16 @@ public:
   static nsIContent* GetDOMElementFor(nsIContent *aContent);
 
   /**
    * Return DOM node for the given DOM point.
    */
   static nsINode *GetDOMNodeFromDOMPoint(nsINode *aNode, uint32_t aOffset);
 
   /**
-   * Return the nsIContent* to check for ARIA attributes on -- this may not
-   * always be the DOM node for the accessible. Specifically, for doc
-   * accessibles, it is not the document node, but either the root element or
-   * <body> in HTML.
-   *
-   * @param aNode  [in] DOM node for the accessible that may be affected by ARIA
-   * @return        the nsIContent which may have ARIA markup
-   */
-  static nsIContent* GetRoleContent(nsINode *aNode);
-
-  /**
    * Is the first passed in node an ancestor of the second?
    * Note: A node is not considered to be the ancestor of itself.
    *
    * @param  aPossibleAncestorNode   [in] node to test for ancestor-ness of
    *                                   aPossibleDescendantNode
    * @param  aPossibleDescendantNode [in] node to test for descendant-ness of
    *                                   aPossibleAncestorNode
    * @param  aRootNode               [in, optional] the root node that search
--- a/accessible/base/nsEventShell.cpp
+++ b/accessible/base/nsEventShell.cpp
@@ -14,29 +14,41 @@ 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;
     sEventFromUserInput = aEvent->IsFromUserInput();
   }
 
+#ifdef A11Y_LOG
+  if (logging::IsEnabled(logging::eEvents)) {
+    logging::MsgBegin("EVENTS", "events fired");
+    nsAutoString type;
+    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
@@ -2,25 +2,27 @@
 /* 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 "Accessible-inl.h"
 
 #include "nsIXBLAccessible.h"
 
-#include "AccCollector.h"
+#include "EmbeddedObjCollector.h"
 #include "AccGroupInfo.h"
 #include "AccIterator.h"
 #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 "Relation.h"
 #include "Role.h"
 #include "RootAccessible.h"
 #include "States.h"
 #include "StyleInfo.h"
 #include "TableAccessible.h"
 #include "TableCellAccessible.h"
 #include "TreeWalker.h"
@@ -71,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, mParent, mChildren)
+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), mChildrenFlags(eChildrenUninitialized),
+  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!?!");
@@ -182,26 +191,17 @@ Accessible::Description(nsString& aDescr
   if (!HasOwnContent() || mContent->IsNodeOfType(nsINode::eTEXT))
     return;
 
   nsTextEquivUtils::
     GetTextEquivFromIDRefs(this, nsGkAtoms::aria_describedby,
                            aDescription);
 
   if (aDescription.IsEmpty()) {
-    bool isXUL = mContent->IsXULElement();
-    if (isXUL) {
-      // Try XUL <description control="[id]">description text</description>
-      XULDescriptionIterator iter(Document(), mContent);
-      Accessible* descr = nullptr;
-      while ((descr = iter.Next())) {
-        nsTextEquivUtils::AppendTextEquivFromContent(this, descr->GetContent(),
-                                                     &aDescription);
-      }
-    }
+    NativeDescription(aDescription);
 
     if (aDescription.IsEmpty()) {
       // Keep the Name() method logic.
       if (mContent->IsHTMLElement()) {
         mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aDescription);
       } else if (mContent->IsXULElement()) {
         mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext, aDescription);
       } else if (mContent->IsSVGElement()) {
@@ -269,17 +269,17 @@ Accessible::AccessKey() const
     return KeyBinding(key, KeyBinding::kAlt);
   case nsIDOMKeyEvent::DOM_VK_META:
     return KeyBinding(key, KeyBinding::kMeta);
   default:
     return KeyBinding();
   }
 
   // Determine the access modifier used in this context.
-  nsIDocument* document = mContent->GetCurrentDoc();
+  nsIDocument* document = mContent->GetUncomposedDoc();
   if (!document)
     return KeyBinding();
 
   nsCOMPtr<nsIDocShellTreeItem> treeItem(document->GetDocShell());
   if (!treeItem)
     return KeyBinding();
 
   nsresult rv = NS_ERROR_FAILURE;
@@ -426,36 +426,37 @@ Accessible::NativeState()
 
   nsIFrame *frame = GetFrame();
   if (frame) {
     if (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
       sta