Bug 1249802 - Merge closed branch head into default
authorGregory Szorc <gps@mozilla.com>
Fri, 03 Jun 2016 14:29:06 -0700
changeset 379278 f281c2356eff2de868ba25acb3d59cecb106af8d
parent 379277 3f2a877008a6b494d0f4e533452143888901eada (diff)
parent 379095 4cf6aa9fadc7060605c317cfe9931a0dd3b80539 (current diff)
child 379279 cba5797a2ba80d73be6d14f05132a411a241a009
push id21011
push usermak77@bonardo.net
push dateThu, 16 Jun 2016 13:40:45 +0000
bugs1249802
milestone47.0
Bug 1249802 - Merge closed branch head into default
new file mode 100644
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,189 @@
+# 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/**
+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/**
+startupcache/**
+testing/**
+tools/**
+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/base/content/nsContextMenu.js
+browser/base/content/sanitizeDialog.js
+browser/base/content/test/**
+browser/base/content/newtab/**
+browser/components/downloads/**
+browser/components/feeds/**
+browser/components/preferences/**
+browser/components/privatebrowsing/**
+browser/components/sessionstore/**
+browser/components/shell/**
+browser/components/tabview/**
+browser/components/translation/**
+browser/extensions/pdfjs/**
+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/**
+
+# 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/shared/test/**
+devtools/client/inspector/test/**
+devtools/client/inspector/*.js
+devtools/client/jsonview/**
+devtools/client/memory/**
+devtools/client/netmonitor/**
+devtools/client/performance/**
+devtools/client/projecteditor/**
+devtools/client/promisedebugger/**
+devtools/client/responsivedesign/**
+devtools/client/scratchpad/**
+devtools/client/shadereditor/**
+devtools/client/shared/**
+devtools/client/sourceeditor/**
+devtools/client/webaudioeditor/**
+devtools/client/webconsole/**
+devtools/client/webide/**
+devtools/server/**
+devtools/shared/**
+
+# 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/pretty-fast/*
+devtools/shared/sourcemap/*
+devtools/shared/qrcode/decoder/*
+devtools/shared/qrcode/encoder/*
+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/test/codemirror/*
+devtools/client/inspector/markup/test/lib_*
+
+# 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/components/Snippets.js
+
+# Bug 1178739: Ignore this file as a quick fix for "Illegal yield expression"
+mobile/android/modules/HomeProvider.jsm
+
+# services/ exclusions
+
+# Uses `#filter substitution`
+services/sync/modules/constants.js
+
+# 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/**
+
+# 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/**
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,5 +1,12 @@
 {
+  // When adding items to this file please check for effects on sub-directories.
   "plugins": [
     "mozilla"
-  ]
+  ],
+  "rules": {
+    "mozilla/import-globals": 1,
+  },
+  "env": {
+    "es6": true
+  },
 }
--- a/.gitignore
+++ b/.gitignore
@@ -4,27 +4,32 @@
 *~
 *.pyc
 *.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
 
 # Empty marker file that's generated when we check out NSS
 security/manager/.nss.checkout
 
@@ -32,30 +37,41 @@ security/manager/.nss.checkout
 /obj*/
 
 # Build directories for js shell
 _DBG.OBJ/
 _OPT.OBJ/
 
 # SpiderMonkey configury
 js/src/configure
+js/src/old-configure
 js/src/autom4te.cache
 # SpiderMonkey test result logs
 js/src/tests/results-*.html
 js/src/tests/results-*.txt
 
 # Java HTML5 parser classes
 parser/html/java/htmlparser/
 parser/html/java/javaparser/
 
 # Ignore the files and directory that Eclipse IDE creates
 .project
 .cproject
 .settings/
 
+# Ignore the files and directory that JetBrains IDEs create.
+/.idea/
+*.iml
+
+# Gradle cache.
+/.gradle/
+
+# Local Gradle configuration properties.
+/local.properties
+
 # Python virtualenv artifacts.
 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
@@ -67,22 +83,35 @@ GSYMS
 GPATH
 
 # 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
+embedding/ios/GeckoEmbed/GeckoEmbed.xcodeproj/xcuserdata
+
+# 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 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/page_load_test/tp5n/
+testing/talos/talos/tests/tp5n.zip
+testing/talos/talos/tests/tp5n
+testing/talos/talos/tests/devtools/damp.manifest.develop
--- a/.hgignore
+++ b/.hgignore
@@ -1,29 +1,31 @@
 # .hgignore - List of filenames hg should ignore
 
 # Filenames that should be ignored wherever they appear
 ~$
 \.py(c|o)$
 (?i)(^|/)TAGS$
 (^|/)ID$
 (^|/)\.DS_Store$
-.*\.egg-info
+\.pdb
+\.egg-info
 
 # Vim swap files.
 ^\.sw.$
 .[^/]*\.sw.$
 
 # 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$
 
 # Empty marker file that's generated when we check out NSS
 ^security/manager/\.nss\.checkout$
 
@@ -32,16 +34,17 @@
 
 # Build directories for js shell
 _DBG\.OBJ/
 _OPT\.OBJ/
 ^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)$
 
 # Java HTML5 parser classes
 ^parser/html/java/(html|java)parser/
 
 # SVN directories
@@ -54,16 +57,19 @@
 
 # Ignore the files and directory that JetBrains IDEs create.
 \.idea/
 \.iml$
 
 # Gradle cache.
 ^.gradle/
 
+# Local Gradle configuration properties.
+^local.properties$
+
 # Python stuff installed at build time.
 ^python/psutil/.*\.so
 ^python/psutil/.*\.pyd
 ^python/psutil/build/
 
 # Git repositories
 .git/
 
@@ -75,40 +81,54 @@
 ^media/libstagefright/android$
 
 # Tag files generated by GNU Global
 GTAGS
 GRTAGS
 GSYMS
 GPATH
 
-# Unit tests for Loop
+# Various items for Loop
 ^browser/components/loop/standalone/content/config\.js$
-^browser/components/loop/standalone/node_modules/
+^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
 ^embedding/ios/GeckoEmbed/GeckoEmbed.xcodeproj/xcuserdata
 
 # Ignore mozharness execution files
+^testing/mozharness/.tox/
+^testing/mozharness/build/
 ^testing/mozharness/logs/
-^testing/mozharness/build/
+^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 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/page_load_test/tp5n/
+^testing/talos/talos/tests/tp5n.zip
+^testing/talos/talos/tests/tp5n
+^testing/talos/talos/tests/devtools/damp.manifest.develop
--- a/.hgtags
+++ b/.hgtags
@@ -212,10 +212,72 @@ b0e20ff87b175424edec414215b325918ccb4792
 41fdefd640f368bccdeafe6446d42c0a5ad22797 FIREFOX_BETA_43_BASE
 0ec8472a93ac0c7ef0e98ebb91ac780bde12d5a5 FIREFOX_BETA_42_END
 38ffeba26f3e420312e04cb3afb408f4c66a6f2e FIREFOX_RELEASE_43_BASE
 9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
 67a788db9f07822cfef52351bbbe3745dff8bd7f FIREFOX_AURORA_44_BASE
 9d3bc275a924a84ab5f34df58c566af0f87479d0 FIREFOX_AURORA_43_END
 b717b80eec62a7ba9b8842487f157b68c1419edd FIREFOX_BETA_44_BASE
 366dd290472633b06f0942d7737c34e942e0916a FIREFOX_BETA_43_END
-9ebad515bc39afdea1e656bf15218a0511a5d1e2 FIREFOX_44_0b6_RELEASE
-9ebad515bc39afdea1e656bf15218a0511a5d1e2 FIREFOX_44_0b6_BUILD1
+ef3cfadfccb97588653ae06eefdac28ec447c1f6 FIREFOX_RELEASE_44_BASE
+9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
+99137d6d4061f408ae0869122649d8bdf489cc30 FIREFOX_AURORA_45_BASE
+4fbd53613240c431522521b953d5a62692909e65 FIREFOX_AURORA_44_END
+3bfa5bc61b626761d487b45c170b115259f69d6b FIREFOX_BETA_45_BASE
+6a7547e4a0f0e213bb8487c773e16543cbea8c73 FIREFOX_BETA_44_END
+3a9789adadcd0de9ee31b16a89a11985822c6a11 FENNEC_45_0b1_RELEASE
+6c0fd1f666e70f2b11f7083f9e7bf4c844a3716a FENNEC_45_0b1_RELEASE
+3a9789adadcd0de9ee31b16a89a11985822c6a11 FENNEC_45_0b1_BUILD1
+6c0fd1f666e70f2b11f7083f9e7bf4c844a3716a FENNEC_45_0b1_BUILD1
+5e1da6523e97d7f8b01004bbe33118ac784b40ea FIREFOX_45_0b1_RELEASE
+6c0fd1f666e70f2b11f7083f9e7bf4c844a3716a FIREFOX_45_0b1_RELEASE
+5e1da6523e97d7f8b01004bbe33118ac784b40ea FIREFOX_45_0b1_BUILD1
+6c0fd1f666e70f2b11f7083f9e7bf4c844a3716a FIREFOX_45_0b1_BUILD1
+bbe048ab30ad3321a6505697703e5fee20e91343 FIREFOX_RELEASE_45_BASE
+9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
+67c66c2878aed17ae3096d7db483ddbb2293c503 FIREFOX_AURORA_46_BASE
+d82221ba4219e4ac04ecfe2a5301703411e176fa FIREFOX_AURORA_45_END
+89effb961712d4a5f84e90bcdd4e421ed6645eea FIREFOX_BETA_46_BASE
+78fe98c670fcc9a1548ac655ae9a488d940fd9c8 FIREFOX_BETA_45_END
+fb3494d06dfb73e26df72ca7a4bc4ef5ebf8795c FIREFOX_46_0b1_RELEASE
+5904e3eb711dd263a6d2deb63b14e0c44e577054 FIREFOX_46_0b2_BUILD3
+5904e3eb711dd263a6d2deb63b14e0c44e577054 FIREFOX_46_0b2_RELEASE
+2f6f69a19150e03ad68062f2ac92342afb1ef787 FIREFOX_46_0b4_BUILD2
+2f6f69a19150e03ad68062f2ac92342afb1ef787 FIREFOX_46_0b4_RELEASE
+53d6e6648f97402a740687a82a297c66f5396548 FIREFOX_46_0b5_BUILD2
+53d6e6648f97402a740687a82a297c66f5396548 FIREFOX_46_0b5_RELEASE
+97b81104ac035d6a8f6ed59a1aad63fcc23e73c8 FIREFOX_46_0b6_BUILD1
+97b81104ac035d6a8f6ed59a1aad63fcc23e73c8 FIREFOX_46_0b6_RELEASE
+191f5eb4cbd72590277296cdb90d355adb347d45 FIREFOX_46_0b7_BUILD2
+191f5eb4cbd72590277296cdb90d355adb347d45 FIREFOX_46_0b7_RELEASE
+0334bcac4033f4f163476677165acd406e08fed8 FIREFOX_46_0b8_BUILD1
+0334bcac4033f4f163476677165acd406e08fed8 FIREFOX_46_0b8_RELEASE
+b007110e90053e58946b59765605bfca766c30d1 FIREFOX_46_0b9_BUILD1
+b007110e90053e58946b59765605bfca766c30d1 FIREFOX_46_0b9_RELEASE
+9ea83990839bd513869018e57bcbedb3454b63bb FIREFOX_46_0b10_BUILD1
+9ea83990839bd513869018e57bcbedb3454b63bb FIREFOX_46_0b10_RELEASE
+6c4646c7a6d6506e744c92a8170310191904c98e FIREFOX_RELEASE_46_BASE
+076bf6a0ac85ec6a4f3ee7c3efe653964d92b9f2 FIREFOX_46_0b11_BUILD1
+076bf6a0ac85ec6a4f3ee7c3efe653964d92b9f2 FIREFOX_46_0b11_RELEASE
+9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
+68d3781deda0d4d58ec9877862830db89669b3a5 FIREFOX_AURORA_47_BASE
+43d92f7052e7bab870c9b994d4b0a0f42d26b7a7 FIREFOX_AURORA_46_END
+8551b253f4061db31e4be7829c2f70c2610caf42 FIREFOX_BETA_47_BASE
+a2290938ee6cf794896a9347980bcb00ebb24c68 FIREFOX_BETA_46_END
+5bbf2e7c2fc6ff9010b1948e2f11477f48ee36e2 FIREFOX_47_0b1_BUILD2
+5bbf2e7c2fc6ff9010b1948e2f11477f48ee36e2 FIREFOX_47_0b1_RELEASE
+6f82d30fe05e1412e744cb76af86f0c9ffe509d4 FIREFOX_47_0b2_BUILD1
+6f82d30fe05e1412e744cb76af86f0c9ffe509d4 FIREFOX_47_0b2_RELEASE
+609000bcc11211d7c27ceea36fa2d2262fa0523f FIREFOX_47_0b3_BUILD1
+609000bcc11211d7c27ceea36fa2d2262fa0523f FIREFOX_47_0b3_RELEASE
+2991f214d4f4d8a3c5cfd95e6223f0660006767d FIREFOX_47_0b4_BUILD1
+2991f214d4f4d8a3c5cfd95e6223f0660006767d FIREFOX_47_0b4_RELEASE
+93a53170dedffdff45bf9eb8dac6e5ef7a13c4ba FIREFOX_47_0b5_BUILD1
+93a53170dedffdff45bf9eb8dac6e5ef7a13c4ba FIREFOX_47_0b5_RELEASE
+7d1f3450acc47025876964c1eca854ae027934f3 FIREFOX_47_0b6_BUILD1
+7d1f3450acc47025876964c1eca854ae027934f3 FIREFOX_47_0b6_RELEASE
+0723a0212f5e0b30d7532d4e35eba7759fb54507 FIREFOX_47_0b7_BUILD1
+0723a0212f5e0b30d7532d4e35eba7759fb54507 FIREFOX_47_0b7_RELEASE
+cb27eacbe04abc5f91a0379c23617715aab432ec FIREFOX_47_0b8_BUILD1
+cb27eacbe04abc5f91a0379c23617715aab432ec FIREFOX_47_0b8_RELEASE
+2ee4473c729acb2ba7dc723e7affe79ce14bff85 FIREFOX_47_0b9_BUILD1
+2ee4473c729acb2ba7dc723e7affe79ce14bff85 FIREFOX_47_0b9_RELEASE
+cf6ec12bd62001b93387ffb184a8841644255b5e FIREFOX_RELEASE_47_BASE
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,10 @@
 #
 # 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.
 
+
 Merge day clobber
\ No newline at end of file
--- a/Makefile.in
+++ b/Makefile.in
@@ -10,134 +10,193 @@ make_min_ver := 3.81
 ifneq ($(make_min_ver),$(firstword $(sort $(make_min_ver) $(MAKE_VERSION))))
 $(error GNU Make $(make_min_ver) or higher is required)
 endif
 
 export TOPLEVEL_BUILD := 1
 
 default::
 
+ifndef TEST_MOZBUILD
 ifdef MOZ_BUILD_APP
 include $(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 \
    mozilla-config.h \
    netwerk/necko-config.h xpcom/xpcom-config.h xpcom/xpcom-private.h \
    .mozconfig.mk
 
+ifndef MOZ_PROFILE_USE
+buildid.h source-repo.h: FORCE
+endif
+
 ifdef JS_STANDALONE
 configure_dir = $(topsrcdir)/js/src
 else
 configure_dir = $(topsrcdir)
 endif
 
+BUILD_BACKEND_FILES := $(addprefix backend.,$(addsuffix Backend,$(BUILD_BACKENDS)))
+
+ifndef TEST_MOZBUILD
 ifndef MOZ_PROFILE_USE
-# We need to explicitly put backend.RecursiveMakeBackend here
-# otherwise the rule in rules.mk doesn't run early enough.
-$(TIERS) binaries:: CLOBBER $(configure_dir)/configure config.status backend.RecursiveMakeBackend
+# We need to explicitly put BUILD_BACKEND_FILES here otherwise the rule in
+# rules.mk doesn't run early enough.
+$(TIERS) binaries:: CLOBBER $(configure_dir)/configure config.status $(BUILD_BACKEND_FILES)
 ifndef JS_STANDALONE
 ifdef COMPILE_ENVIRONMENT
 $(TIERS) binaries:: $(topsrcdir)/js/src/configure js/src/config.status
 endif
 endif
 endif
+endif
 
 ifdef JS_STANDALONE
 .PHONY: CLOBBER
 CLOBBER:
 else
 CLOBBER: $(topsrcdir)/CLOBBER
 	@echo 'STOP!  The CLOBBER file has changed.'
 	@echo 'Please run the build through a sanctioned build wrapper, such as'
 	@echo '"mach build" or client.mk.'
 	@exit 1
 endif
 
-$(topsrcdir)/configure: $(topsrcdir)/configure.in
-$(topsrcdir)/js/src/configure: $(topsrcdir)/js/src/configure.in
+$(topsrcdir)/configure: $(topsrcdir)/configure.in $(topsrcdir)/old-configure.in
+$(topsrcdir)/js/src/configure: $(topsrcdir)/js/src/configure.in $(topsrcdir)/js/src/old-configure.in
 $(topsrcdir)/configure $(topsrcdir)/js/src/configure:
-	@echo 'STOP!  $^ has changed, and your configure is out of date.'
+	@echo 'STOP!  $? has changed, and your configure is out of date.'
 	@echo 'Please rerun autoconf and re-configure your build directory.'
 	@echo 'To ignore this message, touch "$@",'
 	@echo 'but your build might not succeed.'
 	@exit 1
 
-config.status: $(configure_dir)/configure
-js/src/config.status: $(topsrcdir)/js/src/configure
+config.status: $(configure_dir)/configure $(configure_dir)/old-configure
+js/src/config.status: $(topsrcdir)/js/src/configure $(topsrcdir)/js/src/old-configure
 config.status js/src/config.status:
-	@echo 'STOP!  $^ has changed and needs to be run again.'
+	@echo 'STOP!  $? has changed and needs to be run again.'
 	@echo 'Please rerun it.'
 	@echo 'To ignore this message, touch "$(CURDIR)/$@",'
 	@echo 'but your build might not succeed.'
 	@exit 1
 
 # Regenerate the build backend if it is out of date. We only have this rule in
 # this main make file because having it in rules.mk and applied to partial tree
 # builds resulted in a world of hurt. Gory details are in bug 877308.
 #
 # The mach build driver will ensure the backend is up to date for partial tree
 # builds. This cleanly avoids most of the pain.
 
-backend.RecursiveMakeBackend:
+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
 
-Makefile: backend.RecursiveMakeBackend
+Makefile: $(BUILD_BACKEND_FILES)
 	@$(TOUCH) $@
 
-include backend.RecursiveMakeBackend.pp
+define build_backend_rule
+$(1)_files := $$(shell cat $(1).in)
+$(1): $$($(1)_files)
+$$($(1)_files):
 
-default:: backend.RecursiveMakeBackend
+endef
+$(foreach file,$(BUILD_BACKEND_FILES),$(eval $(call build_backend_rule,$(file))))
+
+default:: $(BUILD_BACKEND_FILES)
+endif
 
 install_manifests := \
-  $(addprefix dist/,bin branding idl include public private sdk xpi-stage) \
+  $(addprefix dist/,branding idl include public private sdk xpi-stage) \
   _tests \
   $(NULL)
+# Skip the dist/bin install manifest when using the hybrid
+# FasterMake/RecursiveMake backend. This is a hack until bug 1241744 moves
+# xpidl handling to FasterMake in that case, mechanically making the dist/bin
+# install manifest non-existent (non-existent manifests being skipped)
+ifeq (,$(filter FasterMake+RecursiveMake,$(BUILD_BACKENDS)))
+install_manifests += dist/bin
+endif
 install_manifest_depends = \
   CLOBBER \
   $(configure_dir)/configure \
   config.status \
-  backend.RecursiveMakeBackend \
+  $(BUILD_BACKEND_FILES) \
   $(NULL)
 
 ifndef JS_STANDALONE
 ifdef COMPILE_ENVIRONMENT
 install_manifest_depends += \
   $(topsrcdir)/js/src/configure \
   js/src/config.status \
   $(NULL)
 endif
 endif
 
 .PHONY: install-manifests
 install-manifests: $(addprefix install-,$(install_manifests))
 
+# If we're using the hybrid FasterMake/RecursiveMake backend, we want
+# to recurse in the faster/ directory in parallel of install manifests.
+# But dist/idl needs to happen before (cf. dependencies in
+# 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
+
 # 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
 
-.PHONY: $(addprefix install-,$(install_manifests))
-$(addprefix install-,$(filter dist/%,$(install_manifests))): install-dist/%: $(install_manifest_depends)
-	$(call py_action,process_install_manifest,$(if $(NO_REMOVE),--no-remove )$(DIST)/$* _build_manifests/install/dist_$*)
+.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
-install-dist_%: install-dist/% ;
-
-install-_tests: $(install_manifest_depends)
-	$(call py_action,process_install_manifest,$(if $(NO_REMOVE),--no-remove )_tests _build_manifests/install/tests)
+$(addprefix install-,$(subst /,_,$(filter dist/%,$(install_manifests)))): install-dist_%: install-dist/% ;
 
 # For compatibility
 .PHONY: install-tests
 install-tests: install-_tests
 
 include $(topsrcdir)/build/moz-automation.mk
 
 # dist and _tests should be purged during cleaning. However, we don't want them
@@ -149,30 +208,30 @@ endif
 # Windows PGO builds don't perform a clean before the 2nd pass. So, we want
 # to preserve content for the 2nd pass on Windows. Everywhere else, we always
 # process the install manifests as part of export.
 # For the binaries rule, not all the install manifests matter, so force only
 # the interesting ones to be done.
 ifdef MOZ_PROFILE_USE
 ifndef NO_PROFILE_GUIDED_OPTIMIZE
 ifneq ($(OS_ARCH)_$(GNU_CC), WINNT_)
-export:: install-manifests
+recurse_pre-export:: install-manifests
 binaries::
 	@$(MAKE) install-manifests NO_REMOVE=1 install_manifests=dist/include
 endif
 endif
 else # !MOZ_PROFILE_USE (normal build)
-export:: install-manifests
+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.
-export:: install-dist/sdk
+recurse_pre-export:: install-dist/sdk
 
 ifndef JS_STANDALONE
 ifdef ENABLE_TESTS
 # Additional makefile targets to call automated test suites
 include $(topsrcdir)/testing/testsuite-targets.mk
 endif
 endif
 
@@ -209,17 +268,16 @@ ifeq (,$(filter-out Linux SunOS,$(OS_ARC
 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)
 
-ifndef JS_STANDALONE
 include $(topsrcdir)/toolkit/mozapps/installer/package-name.mk
 
 ifdef MOZ_SYMBOLS_EXTRA_BUILDID
 EXTRA_BUILDID := -$(MOZ_SYMBOLS_EXTRA_BUILDID)
 endif
 
 SYMBOL_INDEX_NAME = \
   $(MOZ_APP_NAME)-$(MOZ_APP_VERSION)-$(OS_TARGET)-$(BUILDID)-$(CPU_ARCH)$(EXTRA_BUILDID)-symbols.txt
@@ -254,23 +312,16 @@ 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
 
-# MOZ_SOURCE_STAMP is defined in package-name.mk with a deferred assignment.
-# exporting it makes make run its $(shell) command for each invoked submake,
-# so transform it to an immediate assignment.
-MOZ_SOURCE_STAMP := $(MOZ_SOURCE_STAMP)
-export MOZ_SOURCE_STAMP
-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
 
--- a/accessible/atk/AccessibleWrap.cpp
+++ b/accessible/atk/AccessibleWrap.cpp
@@ -140,17 +140,17 @@ MaiAtkObject::GetAtkHyperlink()
   }
 
   return maiHyperlink->GetAtkHyperlink();
 }
 
 void
 MaiAtkObject::Shutdown()
 {
-  accWrap = 0;
+  accWrap.SetBits(0);
   MaiHyperlink* maiHyperlink =
     (MaiHyperlink*)g_object_get_qdata(G_OBJECT(this), quark_mai_hyperlink);
   if (maiHyperlink) {
     delete maiHyperlink;
     g_object_set_qdata(G_OBJECT(this), quark_mai_hyperlink, nullptr);
   }
 }
 
@@ -554,25 +554,25 @@ initializeCB(AtkObject *aAtkObj, gpointe
     /* AtkObjectClass has not a "initialize" function now,
      * maybe it has later
      */
 
     if (ATK_OBJECT_CLASS(parent_class)->initialize)
         ATK_OBJECT_CLASS(parent_class)->initialize(aAtkObj, aData);
 
   /* initialize object */
-  MAI_ATK_OBJECT(aAtkObj)->accWrap = reinterpret_cast<uintptr_t>(aData);
+  MAI_ATK_OBJECT(aAtkObj)->accWrap.SetBits(reinterpret_cast<uintptr_t>(aData));
 }
 
 void
 finalizeCB(GObject *aObj)
 {
     if (!IS_MAI_OBJECT(aObj))
         return;
-    NS_ASSERTION(MAI_ATK_OBJECT(aObj)->accWrap == 0, "AccWrap NOT null");
+    NS_ASSERTION(MAI_ATK_OBJECT(aObj)->accWrap.IsNull(), "AccWrap NOT null");
 
     // call parent finalize function
     // finalize of GObjectClass will unref the accessible parent if has
     if (G_OBJECT_CLASS (parent_class)->finalize)
         G_OBJECT_CLASS (parent_class)->finalize(aObj);
 }
 
 const gchar*
@@ -592,17 +592,18 @@ getNameCB(AtkObject* aAtkObj)
 
   return aAtkObj->name;
 }
 
 static void
 MaybeFireNameChange(AtkObject* aAtkObj, const nsString& aNewName)
 {
   NS_ConvertUTF16toUTF8 newNameUTF8(aNewName);
-  if (aAtkObj->name && newNameUTF8.Equals(aAtkObj->name))
+  if (aAtkObj->name &&
+      !strncmp(aAtkObj->name, newNameUTF8.get(), newNameUTF8.Length()))
     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.
@@ -644,44 +645,39 @@ getDescriptionCB(AtkObject *aAtkObj)
 }
 
 AtkRole
 getRoleCB(AtkObject *aAtkObj)
 {
   if (aAtkObj->role != ATK_ROLE_INVALID)
     return aAtkObj->role;
 
-  AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
-  a11y::role role;
-  if (!accWrap) {
-    ProxyAccessible* proxy = GetProxy(aAtkObj);
-    if (!proxy)
-      return ATK_ROLE_INVALID;
+  AccessibleOrProxy acc = GetInternalObj(aAtkObj);
+  if (acc.IsNull()) {
+    return ATK_ROLE_INVALID;
+  }
 
-    role = proxy->Role();
-  } else {
 #ifdef DEBUG
+  if (AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj)) {
     NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(accWrap),
                  "Does not support Text interface when it should");
+  }
 #endif
 
-    role = accWrap->Role();
-  }
-
 #define ROLE(geckoRole, stringRole, atkRole, macRole, \
              msaaRole, ia2Role, nameRule) \
   case roles::geckoRole: \
     aAtkObj->role = atkRole; \
     break;
 
-  switch (role) {
+  switch (acc.Role()) {
 #include "RoleMap.h"
     default:
       MOZ_CRASH("Unknown role.");
-  };
+  }
 
 #undef ROLE
 
   if (aAtkObj->role == ATK_ROLE_LIST_BOX && !IsAtkVersionAtLeast(2, 1))
     aAtkObj->role = ATK_ROLE_LIST;
   else if (aAtkObj->role == ATK_ROLE_TABLE_ROW && !IsAtkVersionAtLeast(2, 1))
     aAtkObj->role = ATK_ROLE_LIST_ITEM;
   else if (aAtkObj->role == ATK_ROLE_MATH && !IsAtkVersionAtLeast(2, 12))
@@ -758,17 +754,17 @@ getAttributesCB(AtkObject *aAtkObj)
   AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
   if (accWrap)
     return GetAttributeSet(accWrap);
 
   ProxyAccessible* proxy = GetProxy(aAtkObj);
   if (!proxy)
     return nullptr;
 
-  nsAutoTArray<Attribute, 10> attrs;
+  AutoTArray<Attribute, 10> attrs;
   proxy->Attributes(&attrs);
   if (attrs.IsEmpty())
     return nullptr;
 
   AtkAttributeSet* objAttributeSet = nullptr;
   for (uint32_t i = 0; i < attrs.Length(); i++) {
     AtkAttribute *objAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute));
     objAttr->name = g_strdup(attrs[i].Name().get());
@@ -1018,17 +1014,17 @@ refRelationSetCB(AtkObject *aAtkObj)
     proxy->Relations(&types, &targetSets);
 
     size_t relationCount = types.Length();
     for (size_t i = 0; i < relationCount; i++) {
       if (typeMap[static_cast<uint32_t>(types[i])] == ATK_RELATION_NULL)
         continue;
 
       size_t targetCount = targetSets[i].Length();
-      nsAutoTArray<AtkObject*, 5> wrappers;
+      AutoTArray<AtkObject*, 5> wrappers;
       for (size_t j = 0; j < targetCount; j++)
         wrappers.AppendElement(GetWrapperFor(targetSets[i][j]));
 
       AtkRelationType atkType = typeMap[static_cast<uint32_t>(types[i])];
       AtkRelation* atkRelation =
         atk_relation_set_get_relation_by_type(relation_set, atkType);
       if (atkRelation)
         atk_relation_set_remove(relation_set, atkRelation);
@@ -1058,23 +1054,23 @@ refRelationSetCB(AtkObject *aAtkObj)
 // for it.
 AccessibleWrap*
 GetAccessibleWrap(AtkObject* aAtkObj)
 {
   bool isMAIObject = IS_MAI_OBJECT(aAtkObj);
   NS_ENSURE_TRUE(isMAIObject || MAI_IS_ATK_SOCKET(aAtkObj),
                  nullptr);
 
-  uintptr_t accWrapPtr = isMAIObject ?
-    MAI_ATK_OBJECT(aAtkObj)->accWrap :
-    reinterpret_cast<uintptr_t>(MAI_ATK_SOCKET(aAtkObj)->accWrap);
-  if (accWrapPtr & IS_PROXY)
-    return nullptr;
-
-  AccessibleWrap* accWrap = reinterpret_cast<AccessibleWrap*>(accWrapPtr);
+  AccessibleWrap* accWrap = nullptr;
+  if (isMAIObject) {
+    Accessible* acc = MAI_ATK_OBJECT(aAtkObj)->accWrap.AsAccessible();
+    accWrap = static_cast<AccessibleWrap*>(acc);
+  } else {
+    accWrap = MAI_ATK_SOCKET(aAtkObj)->accWrap;
+  }
 
   // Check if the accessible was deconstructed.
   if (!accWrap)
     return nullptr;
 
   NS_ENSURE_TRUE(accWrap->GetAtkObject() == aAtkObj, nullptr);
 
   AccessibleWrap* appAccWrap = ApplicationAcc();
@@ -1082,22 +1078,26 @@ GetAccessibleWrap(AtkObject* aAtkObj)
     return nullptr;
 
   return accWrap;
 }
 
 ProxyAccessible*
 GetProxy(AtkObject* aObj)
 {
-  if (!aObj || !IS_MAI_OBJECT(aObj) ||
-      !(MAI_ATK_OBJECT(aObj)->accWrap & IS_PROXY))
+  return GetInternalObj(aObj).AsProxy();
+}
+
+AccessibleOrProxy
+GetInternalObj(AtkObject* aObj)
+{
+  if (!aObj || !IS_MAI_OBJECT(aObj))
     return nullptr;
 
-  return reinterpret_cast<ProxyAccessible*>(MAI_ATK_OBJECT(aObj)->accWrap
-      & ~IS_PROXY);
+  return MAI_ATK_OBJECT(aObj)->accWrap;
 }
 
 AtkObject*
 GetWrapperFor(ProxyAccessible* aProxy)
 {
   return reinterpret_cast<AtkObject*>(aProxy->GetWrapper() & ~IS_PROXY);
 }
 
@@ -1240,16 +1240,17 @@ AccessibleWrap::HandleAccEvent(AccEvent*
         accessible->Name(newName);
 
         MaybeFireNameChange(atkObj, newName);
 
         break;
       }
 
   case nsIAccessibleEvent::EVENT_VALUE_CHANGE:
+  case nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE:
     if (accessible->HasNumericValue()) {
       // Make sure this is a numeric value. Don't fire for string value changes
       // (e.g. text editing) ATK values are always numeric.
       g_object_notify((GObject*)atkObj, "accessible-value");
     }
     break;
 
     case nsIAccessibleEvent::EVENT_SELECTION:
@@ -1470,16 +1471,19 @@ a11y::ProxyEvent(ProxyAccessible* aTarge
   case nsIAccessibleEvent::EVENT_MENUPOPUP_END:
     atk_object_notify_state_change(wrapper, ATK_STATE_VISIBLE, false);
     atk_object_notify_state_change(wrapper, ATK_STATE_SHOWING, false);
     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;
   }
 }
 
 void
 a11y::ProxyStateChangeEvent(ProxyAccessible* aTarget, uint64_t aState,
                             bool aEnabled)
 {
   MaiAtkObject* atkObj = MAI_ATK_OBJECT(GetWrapperFor(aTarget));
@@ -1655,17 +1659,17 @@ AccessibleWrap::GetColumnHeader(TableAcc
   }
 
   // otherwise get column header for the data cell at the first row.
   TableCellAccessible* tableCell = cell->AsTableCell();
   if (!tableCell) {
     return nullptr;
   }
 
-  nsAutoTArray<Accessible*, 10> headerCells;
+  AutoTArray<Accessible*, 10> headerCells;
   tableCell->ColHeaderCells(&headerCells);
   if (headerCells.IsEmpty()) {
     return nullptr;
   }
 
   return headerCells[0];
 }
 
@@ -1689,16 +1693,16 @@ AccessibleWrap::GetRowHeader(TableAccess
   }
 
   // otherwise get row header for the data cell at the first column.
   TableCellAccessible* tableCell = cell->AsTableCell();
   if (!tableCell) {
     return nullptr;
   }
 
-  nsAutoTArray<Accessible*, 10> headerCells;
+  AutoTArray<Accessible*, 10> headerCells;
   tableCell->RowHeaderCells(&headerCells);
   if (headerCells.IsEmpty()) {
     return nullptr;
   }
 
   return headerCells[0];
 }
--- a/accessible/atk/DocAccessibleWrap.cpp
+++ b/accessible/atk/DocAccessibleWrap.cpp
@@ -9,18 +9,17 @@
 
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // DocAccessibleWrap
 ////////////////////////////////////////////////////////////////////////////////
 
 DocAccessibleWrap::
-  DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
-                    nsIPresShell* aPresShell) :
-  DocAccessible(aDocument, aRootContent, aPresShell), mActivated(false)
+  DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
+  DocAccessible(aDocument, aPresShell), mActivated(false)
 {
 }
 
 DocAccessibleWrap::~DocAccessibleWrap()
 {
 }
 
--- a/accessible/atk/DocAccessibleWrap.h
+++ b/accessible/atk/DocAccessibleWrap.h
@@ -14,18 +14,17 @@
 #include "DocAccessible.h"
 
 namespace mozilla {
 namespace a11y {
 
 class DocAccessibleWrap : public DocAccessible
 {
 public:
-  DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
-                    nsIPresShell* aPresShell);
+  DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
   virtual ~DocAccessibleWrap();
 
   bool mActivated;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/atk/moz.build
+++ b/accessible/atk/moz.build
@@ -47,11 +47,12 @@ if CONFIG['MOZ_ENABLE_GTK']:
     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']:
-    # Suppress clang warning about unused function from gobject's RTTI macros.
-    CXXFLAGS += ['-Wno-unused-function']
+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']
--- a/accessible/atk/nsMai.h
+++ b/accessible/atk/nsMai.h
@@ -6,16 +6,17 @@
 
 #ifndef __NS_MAI_H__
 #define __NS_MAI_H__
 
 #include <atk/atk.h>
 #include <glib.h>
 #include <glib-object.h>
 
+#include "AccessibleOrProxy.h"
 #include "AccessibleWrap.h"
 
 namespace mozilla {
 namespace a11y {
 class ProxyAccessible;
 }
 }
 
@@ -61,16 +62,17 @@ typedef struct _MaiAtkSocket
 
 typedef struct _MaiAtkSocketClass
 {
   AtkSocketClass parent_class;
 } MaiAtkSocketClass;
 
 mozilla::a11y::AccessibleWrap* GetAccessibleWrap(AtkObject* aAtkObj);
 mozilla::a11y::ProxyAccessible* GetProxy(AtkObject* aAtkObj);
+mozilla::a11y::AccessibleOrProxy GetInternalObj(AtkObject* aObj);
 AtkObject* GetWrapperFor(mozilla::a11y::ProxyAccessible* aProxy);
 
 extern int atkMajorVersion, atkMinorVersion;
 
 /**
  * Return true if the loaded version of libatk-1.0.so is at least
  * aMajor.aMinor.0.
  */
@@ -90,17 +92,17 @@ static const uintptr_t IS_PROXY = 1;
  */
 struct MaiAtkObject
 {
   AtkObject parent;
   /*
    * The AccessibleWrap whose properties and features are exported
    * via this object instance.
    */
-  uintptr_t accWrap;
+  mozilla::a11y::AccessibleOrProxy accWrap;
 
   /*
    * Get the AtkHyperlink for this atk object.
    */
   AtkHyperlink* GetAtkHyperlink();
 
   /*
    * Shutdown this AtkObject.
--- a/accessible/atk/nsMaiHyperlink.cpp
+++ b/accessible/atk/nsMaiHyperlink.cpp
@@ -95,17 +95,17 @@ mai_atk_hyperlink_get_type(void)
 
         type = g_type_register_static(ATK_TYPE_HYPERLINK,
                                       "MaiAtkHyperlink",
                                       &tinfo, GTypeFlags(0));
     }
     return type;
 }
 
-MaiHyperlink::MaiHyperlink(uintptr_t aHyperLink) :
+MaiHyperlink::MaiHyperlink(AccessibleOrProxy aHyperLink) :
     mHyperlink(aHyperLink),
     mMaiAtkHyperlink(nullptr)
 {
     mMaiAtkHyperlink =
         reinterpret_cast<AtkHyperlink *>
                         (g_object_new(mai_atk_hyperlink_get_type(), nullptr));
     NS_ASSERTION(mMaiAtkHyperlink, "OUT OF MEMORY");
     if (!mMaiAtkHyperlink)
--- a/accessible/atk/nsMaiHyperlink.h
+++ b/accessible/atk/nsMaiHyperlink.h
@@ -18,40 +18,38 @@ namespace a11y {
 
 /*
  * MaiHyperlink is a auxiliary class for MaiInterfaceHyperText.
  */
 
 class MaiHyperlink
 {
 public:
-  explicit MaiHyperlink(uintptr_t aHyperLink);
+  explicit MaiHyperlink(AccessibleOrProxy aHyperLink);
   ~MaiHyperlink();
 
 public:
   AtkHyperlink* GetAtkHyperlink() const { return mMaiAtkHyperlink; }
   Accessible* GetAccHyperlink()
     {
-      if (!mHyperlink || mHyperlink & IS_PROXY)
+      if (!mHyperlink.IsAccessible())
         return nullptr;
 
-      Accessible* link = reinterpret_cast<Accessible*>(mHyperlink);
+      Accessible* link = mHyperlink.AsAccessible();
+      if (!link) {
+        return nullptr;
+      }
+
       NS_ASSERTION(link->IsLink(), "Why isn't it a link!");
       return link;
     }
 
-  ProxyAccessible* Proxy() const
-  {
-    if (!(mHyperlink & IS_PROXY))
-      return nullptr;
-
-    return reinterpret_cast<ProxyAccessible*>(mHyperlink & ~IS_PROXY);
-  }
+  ProxyAccessible* Proxy() const { return mHyperlink.AsProxy(); }
 
 protected:
-  uintptr_t mHyperlink;
+  AccessibleOrProxy mHyperlink;
   AtkHyperlink* mMaiAtkHyperlink;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif /* __MAI_HYPERLINK_H__ */
--- a/accessible/atk/nsMaiInterfaceTable.cpp
+++ b/accessible/atk/nsMaiInterfaceTable.cpp
@@ -268,17 +268,17 @@ getSummaryCB(AtkTable *aTable)
   return nullptr;
 }
 
 static gint
 getSelectedColumnsCB(AtkTable *aTable, gint** aSelected)
 {
   *aSelected = nullptr;
 
-  nsAutoTArray<uint32_t, 10> cols;
+  AutoTArray<uint32_t, 10> cols;
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
   if (accWrap) {
     accWrap->AsTable()->SelectedColIndices(&cols);
    } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
     proxy->TableSelectedColumnIndices(&cols);
   } else {
     return 0;
   }
@@ -295,17 +295,17 @@ getSelectedColumnsCB(AtkTable *aTable, g
   memcpy(atkColumns, cols.Elements(), cols.Length() * sizeof(uint32_t));
   *aSelected = atkColumns;
   return cols.Length();
 }
 
 static gint
 getSelectedRowsCB(AtkTable *aTable, gint **aSelected)
 {
-  nsAutoTArray<uint32_t, 10> rows;
+  AutoTArray<uint32_t, 10> rows;
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
   if (accWrap) {
     accWrap->AsTable()->SelectedRowIndices(&rows);
   } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
     proxy->TableSelectedRowIndices(&rows);
   } else {
     return 0;
   }
--- a/accessible/atk/nsMaiInterfaceText.cpp
+++ b/accessible/atk/nsMaiInterfaceText.cpp
@@ -306,17 +306,17 @@ getRunAttributesCB(AtkText *aText, gint 
     return ConvertToAtkTextAttributeSet(attributes);
   }
 
   ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText));
   if (!proxy) {
     return nullptr;
   }
 
-  nsAutoTArray<Attribute, 10> attrs;
+  AutoTArray<Attribute, 10> attrs;
   proxy->TextAttributes(false, aOffset, &attrs, &startOffset, &endOffset);
   *aStartOffset = startOffset;
   *aEndOffset = endOffset;
   return ConvertToAtkTextAttributeSet(attrs);
 }
 
 static AtkAttributeSet*
 getDefaultAttributesCB(AtkText *aText)
@@ -332,17 +332,17 @@ getDefaultAttributesCB(AtkText *aText)
     return ConvertToAtkTextAttributeSet(attributes);
   }
 
   ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText));
   if (!proxy) {
     return nullptr;
   }
 
-  nsAutoTArray<Attribute, 10> attrs;
+  AutoTArray<Attribute, 10> attrs;
   proxy->DefaultTextAttributes(&attrs);
   return ConvertToAtkTextAttributeSet(attrs);
 }
 
 static void
 getCharacterExtentsCB(AtkText *aText, gint aOffset,
                       gint *aX, gint *aY,
                       gint *aWidth, gint *aHeight,
--- 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;
 
 /**
@@ -38,17 +39,17 @@ static nsRoleMapEntry sWAIRoleMaps[] =
 {
   { // alert
     &nsGkAtoms::alert,
     roles::ALERT,
     kUseMapRole,
     eNoValue,
     eNoAction,
     eNoLiveAttr,
-    kGenericAccType,
+    eAlert,
     kNoReqStates
   },
   { // alertdialog
     &nsGkAtoms::alertdialog,
     roles::DIALOG,
     kUseMapRole,
     eNoValue,
     eNoAction,
@@ -856,22 +857,20 @@ struct RoleComparator
   int operator()(const nsRoleMapEntry& aEntry) const {
     return Compare(mRole, aEntry.ARIARoleString());
   }
 };
 
 }
 
 nsRoleMapEntry*
-aria::GetRoleMap(nsINode* aNode)
+aria::GetRoleMap(dom::Element* aEl)
 {
-  nsIContent* content = nsCoreUtils::GetRoleContent(aNode);
   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;
   }
 
   nsWhitespaceTokenizer tokenizer(roles);
   while (tokenizer.hasMoreTokens()) {
     // Do a binary search through table for the next role in role list
--- a/accessible/base/ARIAMap.h
+++ b/accessible/base/ARIAMap.h
@@ -205,17 +205,17 @@ extern nsRoleMapEntry gEmptyRoleMap;
 /**
  * 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
  * @return        a pointer to the role map entry for the ARIA role, or nullptr
  *                if none
  */
-nsRoleMapEntry* GetRoleMap(nsINode* aNode);
+nsRoleMapEntry* GetRoleMap(dom::Element* aEl);
 
 /**
  * Return accessible state from ARIA universal states applied to the given
  * element.
  */
 uint64_t UniversalStatesFor(mozilla::dom::Element* aElement);
 
 /**
--- a/accessible/base/AccEvent.cpp
+++ b/accessible/base/AccEvent.cpp
@@ -99,32 +99,32 @@ AccReorderEvent::IsShowHideEventTarget(c
   return 0;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // AccHideEvent
 ////////////////////////////////////////////////////////////////////////////////
 
 AccHideEvent::
-  AccHideEvent(Accessible* aTarget, nsINode* aTargetNode, bool aNeedsShutdown) :
-  AccMutationEvent(::nsIAccessibleEvent::EVENT_HIDE, aTarget, aTargetNode),
+  AccHideEvent(Accessible* aTarget, bool aNeedsShutdown) :
+  AccMutationEvent(::nsIAccessibleEvent::EVENT_HIDE, aTarget),
   mNeedsShutdown(aNeedsShutdown)
 {
   mNextSibling = mAccessible->NextSibling();
   mPrevSibling = mAccessible->PrevSibling();
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // AccShowEvent
 ////////////////////////////////////////////////////////////////////////////////
 
 AccShowEvent::
-  AccShowEvent(Accessible* aTarget, nsINode* aTargetNode) :
-  AccMutationEvent(::nsIAccessibleEvent::EVENT_SHOW, aTarget, aTargetNode)
+  AccShowEvent(Accessible* aTarget) :
+  AccMutationEvent(::nsIAccessibleEvent::EVENT_SHOW, aTarget)
 {
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // AccTextSelChangeEvent
 ////////////////////////////////////////////////////////////////////////////////
 
--- a/accessible/base/AccEvent.h
+++ b/accessible/base/AccEvent.h
@@ -207,18 +207,17 @@ private:
 
 
 /**
  * Base class for show and hide accessible events.
  */
 class AccMutationEvent: public AccEvent
 {
 public:
-  AccMutationEvent(uint32_t aEventType, Accessible* aTarget,
-                   nsINode* aTargetNode) :
+  AccMutationEvent(uint32_t aEventType, Accessible* aTarget) :
     AccEvent(aEventType, aTarget, eAutoDetect, eCoalesceMutationTextChange)
   {
     // Don't coalesce these since they are coalesced by reorder event. Coalesce
     // contained text change events.
     mParent = mAccessible->Parent();
   }
   virtual ~AccMutationEvent() { }
 
@@ -245,18 +244,17 @@ protected:
 
 
 /**
  * Accessible hide event.
  */
 class AccHideEvent: public AccMutationEvent
 {
 public:
-  AccHideEvent(Accessible* aTarget, nsINode* aTargetNode,
-               bool aNeedsShutdown = true);
+  explicit AccHideEvent(Accessible* aTarget, bool aNeedsShutdown = true);
 
   // Event
   static const EventGroup kEventGroup = eHideEvent;
   virtual unsigned int GetEventGroups() const override
   {
     return AccMutationEvent::GetEventGroups() | (1U << eHideEvent);
   }
 
@@ -276,17 +274,17 @@ protected:
 
 
 /**
  * Accessible show event.
  */
 class AccShowEvent: public AccMutationEvent
 {
 public:
-  AccShowEvent(Accessible* aTarget, nsINode* aTargetNode);
+  explicit AccShowEvent(Accessible* aTarget);
 
   // Event
   static const EventGroup kEventGroup = eShowEvent;
   virtual unsigned int GetEventGroups() const override
   {
     return AccMutationEvent::GetEventGroups() | (1U << eShowEvent);
   }
 };
--- a/accessible/base/AccIterator.cpp
+++ b/accessible/base/AccIterator.cpp
@@ -4,17 +4,17 @@
 
 #include "AccIterator.h"
 
 #include "AccGroupInfo.h"
 #ifdef MOZ_XUL
 #include "XULTreeAccessible.h"
 #endif
 
-#include "mozilla/dom/Element.h"
+#include "mozilla/dom/HTMLLabelElement.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // AccIterator
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -129,44 +129,53 @@ RelatedAccIterator::Next()
 HTMLLabelIterator::
   HTMLLabelIterator(DocAccessible* aDocument, const Accessible* aAccessible,
                     LabelFilter aFilter) :
   mRelIter(aDocument, aAccessible->GetContent(), nsGkAtoms::_for),
   mAcc(aAccessible), mLabelFilter(aFilter)
 {
 }
 
+bool
+HTMLLabelIterator::IsLabel(Accessible* aLabel)
+{
+  dom::HTMLLabelElement* labelEl =
+    dom::HTMLLabelElement::FromContent(aLabel->GetContent());
+  return labelEl && labelEl->GetControl() == mAcc->GetContent();
+}
+
 Accessible*
 HTMLLabelIterator::Next()
 {
   // Get either <label for="[id]"> element which explicitly points to given
   // element, or <label> ancestor which implicitly point to it.
   Accessible* label = nullptr;
   while ((label = mRelIter.Next())) {
-    if (label->GetContent()->IsHTMLElement(nsGkAtoms::label))
+    if (IsLabel(label)) {
       return label;
+    }
   }
 
   // Ignore ancestor label on not widget accessible.
   if (mLabelFilter == eSkipAncestorLabel || !mAcc->IsWidget())
     return nullptr;
 
   // Go up tree to get a name of ancestor label if there is one (an ancestor
   // <label> implicitly points to us). Don't go up farther than form or
   // document.
   Accessible* walkUp = mAcc->Parent();
   while (walkUp && !walkUp->IsDoc()) {
-    nsIContent* walkUpElm = walkUp->GetContent();
-    if (walkUpElm->IsHTMLElement(nsGkAtoms::label) &&
-        !walkUpElm->HasAttr(kNameSpaceID_None, nsGkAtoms::_for)) {
+    nsIContent* walkUpEl = walkUp->GetContent();
+    if (IsLabel(walkUp) &&
+        !walkUpEl->HasAttr(kNameSpaceID_None, nsGkAtoms::_for)) {
       mLabelFilter = eSkipAncestorLabel; // prevent infinite loop
       return walkUp;
     }
 
-    if (walkUpElm->IsHTMLElement(nsGkAtoms::form))
+    if (walkUpEl->IsHTMLElement(nsGkAtoms::form))
       break;
 
     walkUp = walkUp->Parent();
   }
 
   return nullptr;
 }
 
@@ -319,76 +328,24 @@ IDRefsIterator::GetElem(const nsDependen
   }
 
   return nullptr;
 }
 
 Accessible*
 IDRefsIterator::Next()
 {
-  nsIContent* nextElm = NextElem();
-  return nextElm ? mDoc->GetAccessible(nextElm) : nullptr;
-}
-
-
-////////////////////////////////////////////////////////////////////////////////
-// ARIAOwnedByIterator
-////////////////////////////////////////////////////////////////////////////////
-
-ARIAOwnedByIterator::ARIAOwnedByIterator(const Accessible* aDependent) :
-  RelatedAccIterator(aDependent->Document(), aDependent->GetContent(),
-                     nsGkAtoms::aria_owns), mDependent(aDependent)
-{
-}
-
-Accessible*
-ARIAOwnedByIterator::Next()
-{
-  Accessible* owner = RelatedAccIterator::Next();
-  Accessible* cur = owner;
-  while (cur) {
-    if (cur == mDependent)
-      return Next(); // owner cannot be a child of dependent.
-
-    if (cur->IsDoc())
-      break; // don't cross document boundaries
-
-    cur = cur->Parent();
+  nsIContent* nextEl = nullptr;
+  while ((nextEl = NextElem())) {
+    Accessible* acc = mDoc->GetAccessible(nextEl);
+    if (acc) {
+      return acc;
+    }
   }
-
-  return owner;
-}
-
-
-////////////////////////////////////////////////////////////////////////////////
-// ARIAOwnsIterator
-////////////////////////////////////////////////////////////////////////////////
-
-ARIAOwnsIterator::ARIAOwnsIterator(const Accessible* aOwner) :
-  mIter(aOwner->Document(), aOwner->GetContent(), nsGkAtoms::aria_owns),
-  mOwner(aOwner)
-{
-}
-
-Accessible*
-ARIAOwnsIterator::Next()
-{
-  Accessible* child = mIter.Next();
-  const Accessible* cur = mOwner;
-  while (cur) {
-    if (cur == child)
-      return Next(); // cannot own its own parent
-
-    if (cur->IsDoc())
-      break; // don't cross document boundaries
-
-    cur = cur->Parent();
-  }
-
-  return child;
+  return nullptr;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // SingleAccIterator
 ////////////////////////////////////////////////////////////////////////////////
 
 Accessible*
--- a/accessible/base/AccIterator.h
+++ b/accessible/base/AccIterator.h
@@ -125,16 +125,18 @@ public:
    */
   virtual Accessible* Next() override;
 
 private:
   HTMLLabelIterator();
   HTMLLabelIterator(const HTMLLabelIterator&);
   HTMLLabelIterator& operator = (const HTMLLabelIterator&);
 
+  bool IsLabel(Accessible* aLabel);
+
   RelatedAccIterator mRelIter;
   // XXX: replace it on weak reference (bug 678429), it's safe to use raw
   // pointer now because iterators life cycle is short.
   const Accessible* mAcc;
   LabelFilter mLabelFilter;
 };
 
 
@@ -244,57 +246,16 @@ private:
   nsString mIDs;
   nsIContent* mContent;
   DocAccessible* mDoc;
   nsAString::index_type mCurrIdx;
 };
 
 
 /**
- * Iterates over related accessible referred by aria-owns.
- */
-class ARIAOwnedByIterator final : public RelatedAccIterator
-{
-public:
-  explicit ARIAOwnedByIterator(const Accessible* aDependent);
-  virtual ~ARIAOwnedByIterator() { }
-
-  virtual Accessible* Next() override;
-
-private:
-  ARIAOwnedByIterator() = delete;
-  ARIAOwnedByIterator(const ARIAOwnedByIterator&) = delete;
-  ARIAOwnedByIterator& operator = (const ARIAOwnedByIterator&) = delete;
-
-  const Accessible* mDependent;
-};
-
-
-/**
- * Iterates over related accessible referred by aria-owns.
- */
-class ARIAOwnsIterator final : public AccIterable
-{
-public:
-  explicit ARIAOwnsIterator(const Accessible* aOwner);
-  virtual ~ARIAOwnsIterator() { }
-
-  virtual Accessible* Next() override;
-
-private:
-  ARIAOwnsIterator() = delete;
-  ARIAOwnsIterator(const ARIAOwnsIterator&) = delete;
-  ARIAOwnsIterator& operator = (const ARIAOwnsIterator&) = delete;
-
-  IDRefsIterator mIter;
-  const Accessible* mOwner;
-};
-
-
-/**
  * Iterator that points to a single accessible returning it on the first call
  * to Next().
  */
 class SingleAccIterator : public AccIterable
 {
 public:
   explicit SingleAccIterator(Accessible* aTarget): mAcc(aTarget) { }
   virtual ~SingleAccIterator() { }
--- a/accessible/base/AccTypes.h
+++ b/accessible/base/AccTypes.h
@@ -63,30 +63,31 @@ enum AccType {
   eLastAccType = eXULTreeType
 };
 
 /**
  * Generic accessible type, different accessible classes can share the same
  * type, the same accessible class can have several types.
  */
 enum AccGenericType {
-  eAutoComplete = 1 << 0,
-  eAutoCompletePopup = 1 << 1,
-  eButton = 1 << 2,
-  eCombobox = 1 << 3,
-  eDocument = 1 << 4,
-  eHyperText = 1 << 5,
-  eLandmark = 1 << 6,
-  eList = 1 << 7,
-  eListControl = 1 << 8,
-  eMenuButton = 1 << 9,
-  eSelect = 1 << 10,
-  eTable = 1 << 11,
-  eTableCell = 1 << 12,
-  eTableRow = 1 << 13,
+  eAlert = 1 << 0,
+  eAutoComplete = 1 << 1,
+  eAutoCompletePopup = 1 << 2,
+  eButton = 1 << 3,
+  eCombobox = 1 << 4,
+  eDocument = 1 << 5,
+  eHyperText = 1 << 6,
+  eLandmark = 1 << 7,
+  eList = 1 << 8,
+  eListControl = 1 << 9,
+  eMenuButton = 1 << 10,
+  eSelect = 1 << 11,
+  eTable = 1 << 12,
+  eTableCell = 1 << 13,
+  eTableRow = 1 << 14,
 
   eLastAccGenericType = eTableRow
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif // mozilla_a11y_AccTypes_h
new file mode 100644
--- /dev/null
+++ b/accessible/base/AccessibleOrProxy.h
@@ -0,0 +1,121 @@
+/* -*- 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_AccessibleOrProxy_h
+#define mozilla_a11y_AccessibleOrProxy_h
+
+#include "mozilla/a11y/Accessible.h"
+#include "mozilla/a11y/ProxyAccessible.h"
+#include "mozilla/a11y/Role.h"
+
+#include <stdint.h>
+
+namespace mozilla {
+namespace a11y {
+
+/**
+ * This class stores an Accessible* or a ProxyAccessible* in a safe manner
+ * 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) {}
+  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);
+    }
+
+    return nullptr;
+  }
+
+  bool IsAccessible() const { return !IsProxy(); }
+  Accessible* AsAccessible() const
+  {
+    if (IsAccessible()) {
+      return reinterpret_cast<Accessible*>(mBits);
+    }
+
+    return nullptr;
+  }
+
+  bool IsNull() const { return mBits == 0; }
+
+  uint32_t ChildCount() const
+  {
+    if (IsProxy()) {
+      return AsProxy()->ChildrenCount();
+    }
+
+    return AsAccessible()->ChildCount();
+  }
+
+  /**
+   * Return the child object either an accessible or a proxied accessible at
+   * the given index.
+   */
+  AccessibleOrProxy ChildAt(uint32_t aIdx)
+  {
+    if (IsProxy()) {
+      return AsProxy()->ChildAt(aIdx);
+    }
+
+    return AsAccessible()->GetChildAt(aIdx);
+  }
+
+  /**
+   * Return the first child object.
+   */
+  AccessibleOrProxy FirstChild()
+  {
+    if (IsProxy()) {
+      return AsProxy()->FirstChild();
+    }
+
+    return AsAccessible()->FirstChild();
+  }
+
+  /**
+   * Return the first child object.
+   */
+  AccessibleOrProxy LastChild()
+  {
+    if (IsProxy()) {
+      return AsProxy()->LastChild();
+    }
+
+    return AsAccessible()->LastChild();
+  }
+
+  role Role() const
+  {
+    if (IsProxy()) {
+      return AsProxy()->Role();
+    }
+
+    return AsAccessible()->Role();
+  }
+
+  // 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;
+};
+
+}
+}
+
+#endif
--- a/accessible/base/DocManager.cpp
+++ b/accessible/base/DocManager.cpp
@@ -21,30 +21,31 @@
 #endif
 
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
 #include "nsCURILoader.h"
 #include "nsDocShellLoadTypes.h"
 #include "nsIChannel.h"
 #include "nsIDOMDocument.h"
-#include "nsIDOMWindow.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIWebNavigation.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIWebProgress.h"
 #include "nsCoreUtils.h"
 #include "nsXULAppAPI.h"
 #include "mozilla/dom/TabChild.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 using namespace mozilla::dom;
 
 StaticAutoPtr<nsTArray<DocAccessibleParent*>> DocManager::sRemoteDocuments;
+nsRefPtrHashtable<nsPtrHashKey<const DocAccessibleParent>, xpcAccessibleDocument>*
+DocManager::sRemoteXPCDocumentCache = nullptr;
 
 ////////////////////////////////////////////////////////////////////////////////
 // DocManager
 ////////////////////////////////////////////////////////////////////////////////
 
 DocManager::DocManager()
   : mDocAccessibleCache(2), mXPCDocumentCache(0)
 {
@@ -96,30 +97,60 @@ DocManager::NotifyOfDocumentShutdown(Doc
     xpcDoc->Shutdown();
     mXPCDocumentCache.Remove(aDocument);
   }
 
   mDocAccessibleCache.Remove(aDOMDocument);
   RemoveListeners(aDOMDocument);
 }
 
+void
+DocManager::NotifyOfRemoteDocShutdown(DocAccessibleParent* aDoc)
+{
+  xpcAccessibleDocument* doc = GetCachedXPCDocument(aDoc);
+  if (doc) {
+    doc->Shutdown();
+    sRemoteXPCDocumentCache->Remove(aDoc);
+  }
+}
+
 xpcAccessibleDocument*
 DocManager::GetXPCDocument(DocAccessible* aDocument)
 {
   if (!aDocument)
     return nullptr;
 
   xpcAccessibleDocument* xpcDoc = mXPCDocumentCache.GetWeak(aDocument);
   if (!xpcDoc) {
     xpcDoc = new xpcAccessibleDocument(aDocument);
     mXPCDocumentCache.Put(aDocument, xpcDoc);
   }
   return xpcDoc;
 }
 
+xpcAccessibleDocument*
+DocManager::GetXPCDocument(DocAccessibleParent* aDoc)
+{
+  xpcAccessibleDocument* doc = GetCachedXPCDocument(aDoc);
+  if (doc) {
+    return doc;
+  }
+
+  if (!sRemoteXPCDocumentCache) {
+    sRemoteXPCDocumentCache =
+      new nsRefPtrHashtable<nsPtrHashKey<const DocAccessibleParent>, xpcAccessibleDocument>;
+  }
+
+  doc =
+    new xpcAccessibleDocument(aDoc, Interfaces::DOCUMENT | Interfaces::HYPERTEXT);
+  sRemoteXPCDocumentCache->Put(aDoc, doc);
+
+  return doc;
+}
+
 #ifdef DEBUG
 bool
 DocManager::IsProcessingRefreshDriverNotification() const
 {
   for (auto iter = mDocAccessibleCache.ConstIter(); !iter.Done(); iter.Next()) {
     DocAccessible* docAccessible = iter.UserData();
     NS_ASSERTION(docAccessible,
                  "No doc accessible for the object in doc accessible cache!");
@@ -181,21 +212,21 @@ DocManager::OnStateChange(nsIWebProgress
                           nsresult aStatus)
 {
   NS_ASSERTION(aStateFlags & STATE_IS_DOCUMENT, "Other notifications excluded");
 
   if (nsAccessibilityService::IsShutdown() || !aWebProgress ||
       (aStateFlags & (STATE_START | STATE_STOP)) == 0)
     return NS_OK;
 
-  nsCOMPtr<nsIDOMWindow> DOMWindow;
+  nsCOMPtr<mozIDOMWindowProxy> DOMWindow;
   aWebProgress->GetDOMWindow(getter_AddRefs(DOMWindow));
   NS_ENSURE_STATE(DOMWindow);
 
-  nsCOMPtr<nsPIDOMWindow> piWindow = do_QueryInterface(DOMWindow);
+  nsPIDOMWindowOuter* piWindow = nsPIDOMWindowOuter::From(DOMWindow);
   MOZ_ASSERT(piWindow);
 
   nsCOMPtr<nsIDocument> document = piWindow->GetDoc();
   NS_ENSURE_STATE(document);
 
   // Document was loaded.
   if (aStateFlags & STATE_STOP) {
 #ifdef A11Y_LOG
@@ -366,17 +397,17 @@ DocManager::HandleDOMDocumentLoad(nsIDoc
 
   docAcc->NotifyOfLoad(aLoadEventType);
 }
 
 void
 DocManager::AddListeners(nsIDocument* aDocument,
                          bool aAddDOMContentLoadedListener)
 {
-  nsPIDOMWindow* window = aDocument->GetWindow();
+  nsPIDOMWindowOuter* window = aDocument->GetWindow();
   EventTarget* target = window->GetChromeEventHandler();
   EventListenerManager* elm = target->GetOrCreateListenerManager();
   elm->AddEventListenerByType(this, NS_LITERAL_STRING("pagehide"),
                               TrustedEventsAtCapture());
 
 #ifdef A11Y_LOG
   if (logging::IsEnabled(logging::eDocCreate))
     logging::Text("added 'pagehide' listener");
@@ -390,17 +421,17 @@ DocManager::AddListeners(nsIDocument* aD
       logging::Text("added 'DOMContentLoaded' listener");
 #endif
   }
 }
 
 void
 DocManager::RemoveListeners(nsIDocument* aDocument)
 {
-  nsPIDOMWindow* window = aDocument->GetWindow();
+  nsPIDOMWindowOuter* window = aDocument->GetWindow();
   if (!window)
     return;
 
   EventTarget* target = window->GetChromeEventHandler();
   if (!target)
     return;
 
   EventListenerManager* elm = target->GetOrCreateListenerManager();
@@ -434,27 +465,25 @@ DocManager::CreateDocOrRootAccessible(ns
     NS_ASSERTION(parentDocAcc,
                  "Can't create an accessible for the document!");
     if (!parentDocAcc)
       return nullptr;
   }
 
   // We only create root accessibles for the true root, otherwise create a
   // doc accessible.
-  nsIContent *rootElm = nsCoreUtils::GetRoleContent(aDocument);
   RefPtr<DocAccessible> docAcc = isRootDoc ?
-    new RootAccessibleWrap(aDocument, rootElm, presShell) :
-    new DocAccessibleWrap(aDocument, rootElm, presShell);
+    new RootAccessibleWrap(aDocument, presShell) :
+    new DocAccessibleWrap(aDocument, presShell);
 
   // Cache the document accessible into document cache.
   mDocAccessibleCache.Put(aDocument, docAcc);
 
   // Initialize the document accessible.
   docAcc->Init();
-  docAcc->SetRoleMapEntry(aria::GetRoleMap(aDocument));
 
   // Bind the document to the tree.
   if (isRootDoc) {
     if (!ApplicationAcc()->AppendChild(docAcc)) {
       docAcc->Shutdown();
       return nullptr;
     }
 
--- a/accessible/base/DocManager.h
+++ b/accessible/base/DocManager.h
@@ -85,16 +85,31 @@ public:
   /*
    * Notify of a new top level document in a content process.
    */
   static void RemoteDocAdded(DocAccessibleParent* aDoc);
 
   static const nsTArray<DocAccessibleParent*>* TopLevelRemoteDocs()
     { return sRemoteDocuments; }
 
+  /**
+   * Remove the xpc document for a remote document if there is one.
+   */
+  static void NotifyOfRemoteDocShutdown(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;
+  }
+
 #ifdef DEBUG
   bool IsProcessingRefreshDriverNotification() const;
 #endif
 
 protected:
   DocManager();
   virtual ~DocManager() { }
 
@@ -142,16 +157,18 @@ private:
 
   typedef nsRefPtrHashtable<nsPtrHashKey<const nsIDocument>, DocAccessible>
     DocAccessibleHashtable;
   DocAccessibleHashtable mDocAccessibleCache;
 
   typedef nsRefPtrHashtable<nsPtrHashKey<const DocAccessible>, xpcAccessibleDocument>
     XPCDocumentHashtable;
   XPCDocumentHashtable mXPCDocumentCache;
+  static nsRefPtrHashtable<nsPtrHashKey<const DocAccessibleParent>, xpcAccessibleDocument>*
+    sRemoteXPCDocumentCache;
 
   /*
    * The list of remote top level documents.
    */
   static StaticAutoPtr<nsTArray<DocAccessibleParent*>> sRemoteDocuments;
 };
 
 /**
--- a/accessible/base/EventQueue.cpp
+++ b/accessible/base/EventQueue.cpp
@@ -290,22 +290,26 @@ EventQueue::CoalesceReorderEvents(AccEve
     //   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)
+        if (eventType == nsIAccessibleEvent::EVENT_SHOW) {
           tailReorder->DoNotEmitAll();
-        else if (eventType == nsIAccessibleEvent::EVENT_HIDE)
+        }
+        else if (eventType == nsIAccessibleEvent::EVENT_HIDE) {
           NS_ERROR("Accessible tree was modified after it was removed! Huh?");
-        else
+        }
+        else {
           aTailEvent->mEventRule = AccEvent::eDoNotEmit;
+          mEvents[index].swap(mEvents[count - 1]);
+        }
 
         return;
       }
 
       tailParent = tailParent->Parent();
     }
 
   } // for (index)
--- a/accessible/base/EventQueue.h
+++ b/accessible/base/EventQueue.h
@@ -71,17 +71,17 @@ private:
 protected:
 
   /**
    * The document accessible reference owning this queue.
    */
   DocAccessible* mDocument;
 
   /**
-   * Pending events array. Don't make this an nsAutoTArray; we use
+   * Pending events array. Don't make this an AutoTArray; we use
    * SwapElements() on it.
    */
   nsTArray<RefPtr<AccEvent> > mEvents;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/base/FocusManager.cpp
+++ b/accessible/base/FocusManager.cpp
@@ -294,43 +294,28 @@ FocusManager::ProcessFocusEvent(AccEvent
       mActiveItem = activeItem;
       target = activeItem;
     }
   }
 
   // Fire menu start/end events for ARIA menus.
   if (target->IsARIARole(nsGkAtoms::menuitem)) {
     // The focus was moved into menu.
-    bool tryOwnsParent = true;
     Accessible* ARIAMenubar = nullptr;
-    Accessible* child = target;
-    Accessible* parent = child->Parent();
-    while (parent) {
-      nsRoleMapEntry* roleMap = parent->ARIARoleMap();
-      if (roleMap) {
-        if (roleMap->Is(nsGkAtoms::menubar)) {
-          ARIAMenubar = parent;
-          break;
-        }
-
-        // Go up in the parent chain of the menu hierarchy.
-        if (roleMap->Is(nsGkAtoms::menuitem) || roleMap->Is(nsGkAtoms::menu)) {
-          child = parent;
-          parent = child->Parent();
-          tryOwnsParent = true;
-          continue;
-        }
+    for (Accessible* parent = target->Parent(); parent; parent = parent->Parent()) {
+      if (parent->IsARIARole(nsGkAtoms::menubar)) {
+        ARIAMenubar = parent;
+        break;
       }
 
-      // If no required context role then check aria-owns relation.
-      if (!tryOwnsParent)
+      // Go up in the parent chain of the menu hierarchy.
+      if (!parent->IsARIARole(nsGkAtoms::menuitem) &&
+          !parent->IsARIARole(nsGkAtoms::menu)) {
         break;
-
-      parent = ARIAOwnedByIterator(child).Next();
-      tryOwnsParent = false;
+      }
     }
 
     if (ARIAMenubar != mActiveARIAMenubar) {
       // Leaving ARIA menu. Fire menu_end event on current menubar.
       if (mActiveARIAMenubar) {
         RefPtr<AccEvent> menuEndEvent =
           new AccEvent(nsIAccessibleEvent::EVENT_MENU_END, mActiveARIAMenubar,
                        aEvent->FromUserInput());
@@ -399,17 +384,17 @@ FocusManager::FocusedDOMNode() const
   if (focusedElm) {
     if (EventStateManager::IsRemoteTarget(focusedElm)) {
       return nullptr;
     }
     return focusedElm;
   }
 
   // Otherwise the focus can be on DOM document.
-  nsPIDOMWindow* focusedWnd = DOMFocusManager->GetFocusedWindow();
+  nsPIDOMWindowOuter* focusedWnd = DOMFocusManager->GetFocusedWindow();
   return focusedWnd ? focusedWnd->GetExtantDoc() : nullptr;
 }
 
 nsIDocument*
 FocusManager::FocusedDOMDocument() const
 {
   nsINode* focusedNode = FocusedDOMNode();
   return focusedNode ? focusedNode->OwnerDoc() : nullptr;
--- a/accessible/base/Logging.cpp
+++ b/accessible/base/Logging.cpp
@@ -40,24 +40,26 @@ struct ModuleRep {
 static ModuleRep sModuleMap[] = {
   { "docload", logging::eDocLoad },
   { "doccreate", logging::eDocCreate },
   { "docdestroy", logging::eDocDestroy },
   { "doclifecycle", logging::eDocLifeCycle },
 
   { "events", logging::eEvents },
   { "platforms", logging::ePlatforms },
-  { "stack", logging::eStack },
   { "text", logging::eText },
   { "tree", logging::eTree },
 
   { "DOMEvents", logging::eDOMEvents },
   { "focus", logging::eFocus },
   { "selection", logging::eSelection },
-  { "notifications", logging::eNotifications }
+  { "notifications", logging::eNotifications },
+
+  { "stack", logging::eStack },
+  { "verbose", logging::eVerbose }
 };
 
 static void
 EnableLogging(const char* aModulesStr)
 {
   sModules = 0;
   if (!aModulesStr)
     return;
@@ -162,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));
 
@@ -387,19 +393,19 @@ static const char* sDocEventTitle = "DOC
 static const char* sFocusTitle = "FOCUS";
 
 void
 logging::DocLoad(const char* aMsg, nsIWebProgress* aWebProgress,
                  nsIRequest* aRequest, uint32_t aStateFlags)
 {
   MsgBegin(sDocLoadTitle, aMsg);
 
-  nsCOMPtr<nsIDOMWindow> DOMWindow;
+  nsCOMPtr<mozIDOMWindowProxy> DOMWindow;
   aWebProgress->GetDOMWindow(getter_AddRefs(DOMWindow));
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(DOMWindow);
+  nsPIDOMWindowOuter* window = nsPIDOMWindowOuter::From(DOMWindow);
   if (!window) {
     MsgEnd();
     return;
   }
 
   nsCOMPtr<nsIDocument> documentNode = window->GetDoc();
   if (!documentNode) {
     MsgEnd();
@@ -602,16 +608,71 @@ logging::SelChange(nsISelection* aSelect
   bool isIgnored = !aDocument || !aDocument->IsContentLoaded();
   printf("\nSelection changed, selection type: %s, notification %s, reason: %d\n",
          strType, (isIgnored ? "ignored" : "pending"), aReason);
 
   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*));
+    }
+    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);
+    AccessibleInfo(aMsg1, aAcc);
+    Accessible* acc = aAcc->Document()->GetAccessible(aNode);
+    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);
+    AccessibleInfo("container", aParent);
+    for (uint32_t idx = 0; idx < aParent->ChildCount(); idx++) {
+      AccessibleInfo("child", aParent->GetChildAt(idx));
+    }
+    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);
@@ -732,16 +793,72 @@ logging::Document(DocAccessible* aDocume
          static_cast<void*>(aDocument->DocumentNode()));
 
   printf("    Document ");
   LogDocURI(aDocument->DocumentNode());
   printf("\n");
 }
 
 void
+logging::AccessibleInfo(const char* aDescr, Accessible* aAccessible)
+{
+  printf("    %s: %p; ", aDescr, static_cast<void*>(aAccessible));
+  if (!aAccessible) {
+    printf("\n");
+    return;
+  }
+  if (aAccessible->IsDefunct()) {
+    printf("defunct\n");
+    return;
+  }
+  if (!aAccessible->Document() || aAccessible->Document()->IsDefunct()) {
+    printf("document is shutting down, no info\n");
+    return;
+  }
+
+  nsAutoString role;
+  GetAccService()->GetStringRole(aAccessible->Role(), role);
+  printf("role: %s", NS_ConvertUTF16toUTF8(role).get());
+
+  nsAutoString name;
+  aAccessible->Name(name);
+  if (!name.IsEmpty()) {
+    printf(", name: '%s'", NS_ConvertUTF16toUTF8(name).get());
+  }
+
+  printf(", idx: %d", aAccessible->IndexInParent());
+
+  nsINode* node = aAccessible->GetNode();
+  if (!node) {
+    printf(", node: null\n");
+  }
+  else if (node->IsNodeOfType(nsINode::eDOCUMENT)) {
+    printf(", document node: %p\n", static_cast<void*>(node));
+  }
+  else if (node->IsNodeOfType(nsINode::eTEXT)) {
+    printf(", text node: %p\n", static_cast<void*>(node));
+  }
+  else if (node->IsElement()) {
+    dom::Element* el = node->AsElement();
+
+    nsAutoCString tag;
+    el->NodeInfo()->NameAtom()->ToUTF8String(tag);
+
+    nsIAtom* idAtom = el->GetID();
+    nsAutoCString id;
+    if (idAtom) {
+      idAtom->ToUTF8String(id);
+    }
+
+    printf(", element node: %p, %s@id='%s'\n",
+           static_cast<void*>(el), tag.get(), id.get());
+  }
+}
+
+void
 logging::AccessibleNNode(const char* aDescr, Accessible* aAccessible)
 {
   printf("    %s: %p; ", aDescr, static_cast<void*>(aAccessible));
   if (!aAccessible)
     return;
 
   nsAutoString role;
   GetAccService()->GetStringRole(aAccessible->Role(), role);
@@ -810,16 +927,22 @@ logging::Stack()
 
 bool
 logging::IsEnabled(uint32_t aModules)
 {
   return sModules & aModules;
 }
 
 bool
+logging::IsEnabledAll(uint32_t aModules)
+{
+  return (sModules & aModules) == aModules;
+}
+
+bool
 logging::IsEnabled(const nsAString& aModuleStr)
 {
   for (unsigned int idx = 0; idx < ArrayLength(sModuleMap); idx++) {
     if (aModuleStr.EqualsASCII(sModuleMap[idx].mStr))
       return sModules & sModuleMap[idx].mModule;
   }
 
   return false;
--- a/accessible/base/Logging.h
+++ b/accessible/base/Logging.h
@@ -30,32 +30,40 @@ namespace logging {
 enum EModules {
   eDocLoad = 1 << 0,
   eDocCreate = 1 << 1,
   eDocDestroy = 1 << 2,
   eDocLifeCycle = eDocLoad | eDocCreate | eDocDestroy,
 
   eEvents = 1 << 3,
   ePlatforms = 1 << 4,
-  eStack = 1 << 5,
-  eText = 1 << 6,
-  eTree = 1 << 7,
+  eText = 1 << 5,
+  eTree = 1 << 6,
 
-  eDOMEvents = 1 << 8,
-  eFocus = 1 << 9,
-  eSelection = 1 << 10,
-  eNotifications = eDOMEvents | eSelection | eFocus
+  eDOMEvents = 1 << 7,
+  eFocus = 1 << 8,
+  eSelection = 1 << 9,
+  eNotifications = eDOMEvents | eSelection | eFocus,
+
+  // extras
+  eStack = 1 << 10,
+  eVerbose = 1 << 11
 };
 
 /**
  * Return true if any of the given modules is logged.
  */
 bool IsEnabled(uint32_t aModules);
 
 /**
+ * Return true if all of the given modules are logged.
+ */
+bool IsEnabledAll(uint32_t aModules);
+
+/**
  * Return true if the given module is logged.
  */
 bool IsEnabled(const nsAString& aModules);
 
 /**
  * Log the document loading progress.
  */
 void DocLoad(const char* aMsg, nsIWebProgress* aWebProgress,
@@ -117,16 +125,25 @@ void FocusDispatched(Accessible* aTarget
 
 /**
  * Log the selection change.
  */
 void SelChange(nsISelection* aSelection, DocAccessible* aDocument,
                int16_t aReason);
 
 /**
+ * Log the given accessible elements info.
+ */
+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 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();
 
 /**
@@ -159,16 +176,17 @@ void Node(const char* aDescr, nsINode* a
 /**
  * Log the document accessible info as message entry.
  */
 void Document(DocAccessible* aDocument);
 
 /**
  * Log the accessible and its DOM node as a message entry.
  */
+void AccessibleInfo(const char* aDescr, Accessible* aAccessible);
 void AccessibleNNode(const char* aDescr, Accessible* aAccessible);
 void AccessibleNNode(const char* aDescr, nsINode* aNode);
 
 /**
  * Log the DOM event.
  */
 void DOMEvent(const char* aDescr, nsINode* aOrigTarget,
               const nsAString& aEventType);
@@ -184,14 +202,15 @@ void Stack();
 void Enable(const nsAFlatCString& aModules);
 
 /**
  * Enable logging of modules specified by A11YLOG environment variable,
  * all other modules aren't logged.
  */
 void CheckEnv();
 
-} // namespace logs
+} // namespace logging
+
 } // namespace a11y
 } // namespace mozilla
 
 #endif
 
--- a/accessible/base/NotificationController.cpp
+++ b/accessible/base/NotificationController.cpp
@@ -47,18 +47,28 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(Notificat
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(NotificationController)
   if (tmp->mDocument)
     tmp->Shutdown();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(NotificationController)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHangingChildDocuments)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContentInsertions)
+  for (auto it = tmp->mContentInsertions.ConstIter(); !it.Done(); it.Next()) {
+    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mContentInsertions key");
+    cb.NoteXPCOMChild(it.Key());
+    nsTArray<nsCOMPtr<nsIContent>>* list = it.UserData();
+    for (uint32_t i = 0; i < list->Length(); i++) {
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
+                                         "mContentInsertions value item");
+      cb.NoteXPCOMChild(list->ElementAt(i));
+    }
+  }
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvents)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRelocations)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(NotificationController, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(NotificationController, Release)
 
 ////////////////////////////////////////////////////////////////////////////////
 // NotificationCollector: public
 
@@ -81,35 +91,49 @@ NotificationController::Shutdown()
 
   mDocument = nullptr;
   mPresShell = nullptr;
 
   mTextHash.Clear();
   mContentInsertions.Clear();
   mNotifications.Clear();
   mEvents.Clear();
+  mRelocations.Clear();
 }
 
 void
 NotificationController::ScheduleChildDocBinding(DocAccessible* aDocument)
 {
   // Schedule child document binding to the tree.
   mHangingChildDocuments.AppendElement(aDocument);
   ScheduleProcessing();
 }
 
 void
 NotificationController::ScheduleContentInsertion(Accessible* aContainer,
                                                  nsIContent* aStartChildNode,
                                                  nsIContent* aEndChildNode)
 {
-  RefPtr<ContentInsertion> insertion = new ContentInsertion(mDocument,
-                                                              aContainer);
-  if (insertion && insertion->InitChildList(aStartChildNode, aEndChildNode) &&
-      mContentInsertions.AppendElement(insertion)) {
+  nsTArray<nsCOMPtr<nsIContent>>* list =
+    mContentInsertions.LookupOrAdd(aContainer);
+
+  bool needsProcessing = false;
+  nsIContent* node = aStartChildNode;
+  while (node != aEndChildNode) {
+    // Notification triggers for content insertion even if no content was
+    // actually inserted, check if the given content has a frame to discard
+    // this case early.
+    if (node->GetPrimaryFrame()) {
+      if (list->AppendElement(node))
+        needsProcessing = true;
+    }
+    node = node->GetNextSibling();
+  }
+
+  if (needsProcessing) {
     ScheduleProcessing();
   }
 }
 
 void
 NotificationController::ScheduleProcessing()
 {
   // If notification flush isn't planed yet start notification flush
@@ -123,27 +147,28 @@ NotificationController::ScheduleProcessi
 ////////////////////////////////////////////////////////////////////////////////
 // NotificationCollector: protected
 
 bool
 NotificationController::IsUpdatePending()
 {
   return mPresShell->IsLayoutFlushObserver() ||
     mObservingState == eRefreshProcessingForUpdate ||
-    mContentInsertions.Length() != 0 || mNotifications.Length() != 0 ||
+    mContentInsertions.Count() != 0 || mNotifications.Length() != 0 ||
     mTextHash.Count() != 0 ||
     !mDocument->HasLoadState(DocAccessible::eTreeConstructed);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // NotificationCollector: private
 
 void
 NotificationController::WillRefresh(mozilla::TimeStamp aTime)
 {
+  PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
   Telemetry::AutoTimer<Telemetry::A11Y_UPDATE_TIME> updateTimer;
 
   // If the document accessible that notification collector was created for is
   // now shut down, don't process notifications anymore.
   NS_ASSERTION(mDocument,
                "The document was shut down while refresh observer is attached!");
   if (!mDocument)
     return;
@@ -170,17 +195,17 @@ NotificationController::WillRefresh(mozi
       logging::MsgBegin("TREE", "initial tree created");
       logging::Address("document", mDocument);
       logging::MsgEnd();
     }
 #endif
 
     mDocument->DoInitialUpdate();
 
-    NS_ASSERTION(mContentInsertions.Length() == 0,
+    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
@@ -188,25 +213,23 @@ NotificationController::WillRefresh(mozi
   // 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.
-  nsTArray<RefPtr<ContentInsertion> > contentInsertions;
-  contentInsertions.SwapElements(mContentInsertions);
-
-  uint32_t insertionCount = contentInsertions.Length();
-  for (uint32_t idx = 0; idx < insertionCount; idx++) {
-    contentInsertions[idx]->Process();
-    if (!mDocument)
+  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
@@ -223,22 +246,23 @@ NotificationController::WillRefresh(mozi
       NS_ASSERTION(!textAcc,
                    "Text node isn't rendered but accessible is kept alive!");
       continue;
     }
 
     nsIContent* containerElm = containerNode->IsElement() ?
       containerNode->AsElement() : nullptr;
 
-    nsAutoString text;
-    textFrame->GetRenderedText(&text);
+    nsIFrame::RenderedText text = textFrame->GetRenderedText(0,
+        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.IsEmpty()) {
+      if (text.mString.IsEmpty()) {
   #ifdef A11Y_LOG
         if (logging::IsEnabled(logging::eTree | logging::eText)) {
           logging::MsgBegin("TREE", "text node lost its content");
           logging::Node("container", containerElm);
           logging::Node("content", textNode);
           logging::MsgEnd();
         }
   #endif
@@ -251,27 +275,27 @@ NotificationController::WillRefresh(mozi
   #ifdef A11Y_LOG
       if (logging::IsEnabled(logging::eText)) {
         logging::MsgBegin("TEXT", "text may be changed");
         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).get());
+                          NS_ConvertUTF16toUTF8(text.mString).get());
         logging::MsgEnd();
       }
   #endif
 
-      TextUpdater::Run(mDocument, textAcc->AsTextLeaf(), text);
+      TextUpdater::Run(mDocument, textAcc->AsTextLeaf(), text.mString);
       continue;
     }
 
     // Append an accessible if rendered text is not empty.
-    if (!text.IsEmpty()) {
+    if (!text.mString.IsEmpty()) {
   #ifdef A11Y_LOG
       if (logging::IsEnabled(logging::eTree | logging::eText)) {
         logging::MsgBegin("TREE", "text node gains new content");
         logging::Node("container", containerElm);
         logging::Node("content", textNode);
         logging::MsgEnd();
       }
   #endif
@@ -346,16 +370,26 @@ NotificationController::WillRefresh(mozi
     if (!mDocument)
       return;
   }
 
   // Process invalidation list of the document after all accessible tree
   // modification are done.
   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]);
+  }
+  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;
 
   ProcessEventQueue();
 
   if (IPCAccessibilityActive()) {
@@ -371,77 +405,29 @@ NotificationController::WillRefresh(mozi
         parentIPCDoc->SendBindChildDoc(ipcDoc, id);
         continue;
       }
 
       ipcDoc = new DocAccessibleChild(childDoc);
       childDoc->SetIPCDoc(ipcDoc);
       nsCOMPtr<nsITabChild> tabChild =
         do_GetInterface(mDocument->DocumentNode()->GetDocShell());
-      static_cast<TabChild*>(tabChild.get())->
-        SendPDocAccessibleConstructor(ipcDoc, parentIPCDoc, id);
+      if (tabChild) {
+        static_cast<TabChild*>(tabChild.get())->
+          SendPDocAccessibleConstructor(ipcDoc, parentIPCDoc, id);
+      }
     }
   }
 
   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.IsEmpty() && mNotifications.IsEmpty() &&
+  if (mContentInsertions.Count() == 0 && mNotifications.IsEmpty() &&
       mEvents.IsEmpty() && mTextHash.Count() == 0 &&
       mHangingChildDocuments.IsEmpty() &&
       mDocument->HasLoadState(DocAccessible::eCompletelyLoaded) &&
       mPresShell->RemoveRefreshObserver(this, Flush_Display)) {
     mObservingState = eNotObservingRefresh;
   }
 }
-
-////////////////////////////////////////////////////////////////////////////////
-// NotificationController: content inserted notification
-
-NotificationController::ContentInsertion::
-  ContentInsertion(DocAccessible* aDocument, Accessible* aContainer) :
-  mDocument(aDocument), mContainer(aContainer)
-{
-}
-
-bool
-NotificationController::ContentInsertion::
-  InitChildList(nsIContent* aStartChildNode, nsIContent* aEndChildNode)
-{
-  bool haveToUpdate = false;
-
-  nsIContent* node = aStartChildNode;
-  while (node != aEndChildNode) {
-    // Notification triggers for content insertion even if no content was
-    // actually inserted, check if the given content has a frame to discard
-    // this case early.
-    if (node->GetPrimaryFrame()) {
-      if (mInsertedContent.AppendElement(node))
-        haveToUpdate = true;
-    }
-
-    node = node->GetNextSibling();
-  }
-
-  return haveToUpdate;
-}
-
-NS_IMPL_CYCLE_COLLECTION(NotificationController::ContentInsertion,
-                         mContainer)
-
-NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(NotificationController::ContentInsertion,
-                                     AddRef)
-NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(NotificationController::ContentInsertion,
-                                       Release)
-
-void
-NotificationController::ContentInsertion::Process()
-{
-  mDocument->ProcessContentInserted(mContainer, &mInsertedContent);
-
-  mDocument = nullptr;
-  mContainer = nullptr;
-  mInsertedContent.Clear();
-}
-
--- a/accessible/base/NotificationController.h
+++ b/accessible/base/NotificationController.h
@@ -117,28 +117,45 @@ public:
    */
   void ScheduleChildDocBinding(DocAccessible* aDocument);
 
   /**
    * Schedule the accessible tree update because of rendered text changes.
    */
   inline void ScheduleTextUpdate(nsIContent* aTextNode)
   {
-    if (mTextHash.PutEntry(aTextNode))
-      ScheduleProcessing();
+    // Make sure we are not called with a node that is not in the DOM tree or
+    // not visible.
+    MOZ_ASSERT(aTextNode->GetParentNode(), "A text node is not in DOM");
+    MOZ_ASSERT(aTextNode->GetPrimaryFrame(), "A text node doesn't have a frame");
+    MOZ_ASSERT(aTextNode->GetPrimaryFrame()->StyleVisibility()->IsVisible(),
+               "A text node is not visible");
+
+    mTextHash.PutEntry(aTextNode);
+    ScheduleProcessing();
   }
 
   /**
    * Pend accessible tree update for content insertion.
    */
   void ScheduleContentInsertion(Accessible* aContainer,
                                 nsIContent* aStartChildNode,
                                 nsIContent* aEndChildNode);
 
   /**
+   * Pend an accessible subtree relocation.
+   */
+  void ScheduleRelocation(Accessible* aOwner)
+  {
+    if (!mRelocations.Contains(aOwner) && mRelocations.AppendElement(aOwner)) {
+      ScheduleProcessing();
+    }
+  }
+
+  /**
    * Start to observe refresh to make notifications and events processing after
    * layout.
    */
   void ScheduleProcessing();
 
   /**
    * Process the generic notification synchronously if there are no pending
    * layout changes and no notifications are pending or being processed right
@@ -225,54 +242,20 @@ private:
   nsIPresShell* mPresShell;
 
   /**
    * Child documents that needs to be bound to the tree.
    */
   nsTArray<RefPtr<DocAccessible> > mHangingChildDocuments;
 
   /**
-   * Storage for content inserted notification information.
+   * Pending accessible tree update notifications for content insertions.
    */
-  class ContentInsertion
-  {
-  public:
-    ContentInsertion(DocAccessible* aDocument, Accessible* aContainer);
-
-    NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(ContentInsertion)
-    NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(ContentInsertion)
-
-    bool InitChildList(nsIContent* aStartChildNode, nsIContent* aEndChildNode);
-    void Process();
-
-  protected:
-    virtual ~ContentInsertion() { mDocument = nullptr; }
-
-  private:
-    ContentInsertion();
-    ContentInsertion(const ContentInsertion&);
-    ContentInsertion& operator = (const ContentInsertion&);
-
-    // The document used to process content insertion, matched to document of
-    // the notification controller that this notification belongs to, therefore
-    // it's ok to keep it as weak ref.
-    DocAccessible* mDocument;
-
-    // The container accessible that content insertion occurs within.
-    RefPtr<Accessible> mContainer;
-
-    // Array of inserted contents.
-    nsTArray<nsCOMPtr<nsIContent> > mInsertedContent;
-  };
-
-  /**
-   * A pending accessible tree update notifications for content insertions.
-   * Don't make this an nsAutoTArray; we use SwapElements() on it.
-   */
-  nsTArray<RefPtr<ContentInsertion> > mContentInsertions;
+  nsClassHashtable<nsRefPtrHashKey<Accessible>,
+                   nsTArray<nsCOMPtr<nsIContent>>> mContentInsertions;
 
   template<class T>
   class nsCOMPtrHashKey : public PLDHashEntryHdr
   {
   public:
     typedef T* KeyType;
     typedef const T* KeyTypePointer;
 
@@ -289,23 +272,28 @@ private:
 
     enum { ALLOW_MEMMOVE = true };
 
    protected:
      nsCOMPtr<T> mKey;
   };
 
   /**
-   * A pending accessible tree update notifications for rendered text changes.
+   * Pending accessible tree update notifications for rendered text changes.
    */
   nsTHashtable<nsCOMPtrHashKey<nsIContent> > mTextHash;
 
   /**
-   * Other notifications like DOM events. Don't make this an nsAutoTArray; we
+   * Other notifications like DOM events. Don't make this an AutoTArray; we
    * use SwapElements() on it.
    */
   nsTArray<RefPtr<Notification> > mNotifications;
+
+  /**
+   * Holds all scheduled relocations.
+   */
+  nsTArray<RefPtr<Accessible> > mRelocations;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif // mozilla_a11y_NotificationController_h_
--- a/accessible/base/StyleInfo.cpp
+++ b/accessible/base/StyleInfo.cpp
@@ -53,16 +53,17 @@ StyleInfo::TextIndent(nsAString& aValue)
   switch (styleCoord.GetUnit()) {
     case eStyleUnit_Coord:
       coordVal = styleCoord.GetCoordValue();
       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());
       break;
     }
 
     case eStyleUnit_Null:
@@ -83,16 +84,17 @@ StyleInfo::TextIndent(nsAString& aValue)
 
   aValue.AppendFloat(nsPresContext::AppUnitsToFloatCSSPixels(coordVal));
   aValue.AppendLiteral("px");
 }
 
 void
 StyleInfo::Margin(css::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");
 }
 
 void
new file mode 100644
--- /dev/null
+++ b/accessible/base/TextRange-inl.h
@@ -0,0 +1,29 @@
+/* -*- 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_TextRange_inl_h__
+#define mozilla_a11y_TextRange_inl_h__
+
+#include "TextRange.h"
+#include "HyperTextAccessible.h"
+
+namespace mozilla {
+namespace a11y {
+
+inline Accessible*
+TextRange::Container() const
+{
+  uint32_t pos1 = 0, pos2 = 0;
+  AutoTArray<Accessible*, 30> parents1, parents2;
+  return CommonParent(mStartContainer, mEndContainer,
+                      &parents1, &pos1, &parents2, &pos2);
+}
+
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
--- a/accessible/base/TextRange.cpp
+++ b/accessible/base/TextRange.cpp
@@ -1,18 +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/. */
 
-#include "TextRange.h"
+#include "TextRange-inl.h"
 
 #include "Accessible-inl.h"
-#include "HyperTextAccessible.h"
 #include "nsAccUtils.h"
 
 namespace mozilla {
 namespace a11y {
 
 ////////////////////////////////////////////////////////////////////////////////
 // TextPoint
 
@@ -20,17 +19,17 @@ bool
 TextPoint::operator <(const TextPoint& aPoint) const
 {
   if (mContainer == aPoint.mContainer)
     return mOffset < aPoint.mOffset;
 
   // Build the chain of parents
   Accessible* p1 = mContainer;
   Accessible* p2 = aPoint.mContainer;
-  nsAutoTArray<Accessible*, 30> parents1, parents2;
+  AutoTArray<Accessible*, 30> parents1, parents2;
   do {
     parents1.AppendElement(p1);
     p1 = p1->Parent();
   } while (p1);
   do {
     parents2.AppendElement(p2);
     p2 = p2->Parent();
   } while (p2);
@@ -54,90 +53,37 @@ TextPoint::operator <(const TextPoint& a
 TextRange::TextRange(HyperTextAccessible* aRoot,
                      HyperTextAccessible* aStartContainer, int32_t aStartOffset,
                      HyperTextAccessible* aEndContainer, int32_t aEndOffset) :
   mRoot(aRoot), mStartContainer(aStartContainer), mEndContainer(aEndContainer),
   mStartOffset(aStartOffset), mEndOffset(aEndOffset)
 {
 }
 
-Accessible*
-TextRange::Container() const
-{
-  if (mStartContainer == mEndContainer)
-    return mStartContainer;
-
-  // Build the chain of parents
-  Accessible* p1 = mStartContainer;
-  Accessible* p2 = mEndContainer;
-  nsAutoTArray<Accessible*, 30> parents1, parents2;
-  do {
-    parents1.AppendElement(p1);
-    p1 = p1->Parent();
-  } while (p1);
-  do {
-    parents2.AppendElement(p2);
-    p2 = p2->Parent();
-  } while (p2);
-
-  // Find where the parent chain differs
-  uint32_t pos1 = parents1.Length();
-  uint32_t pos2 = parents2.Length();
-  Accessible* parent = nullptr;
-  uint32_t len = 0;
-  for (len = std::min(pos1, pos2); len > 0; --len) {
-    Accessible* child1 = parents1.ElementAt(--pos1);
-    Accessible* child2 = parents2.ElementAt(--pos2);
-    if (child1 != child2)
-      break;
-
-    parent = child1;
-  }
-
-  return parent;
-}
-
 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))
         aChildren->AppendElement(child);
     }
     return;
   }
 
   Accessible* p1 = mStartContainer->GetChildAtOffset(mStartOffset);
   Accessible* p2 = mEndContainer->GetChildAtOffset(mEndOffset);
-  nsAutoTArray<Accessible*, 30> parents1, parents2;
-  do {
-    parents1.AppendElement(p1);
-    p1 = p1->Parent();
-  } while (p1);
-  do {
-    parents2.AppendElement(p2);
-    p2 = p2->Parent();
-  } while (p2);
 
-  // Find deepest common container.
-  uint32_t pos1 = parents1.Length();
-  uint32_t pos2 = parents2.Length();
-  Accessible* container = nullptr;
-  for (uint32_t len = std::min(pos1, pos2); len > 0; --len) {
-    Accessible* child1 = parents1.ElementAt(--pos1);
-    Accessible* child2 = parents2.ElementAt(--pos2);
-    if (child1 != child2)
-      break;
-
-    container = child1;
-  }
+  uint32_t pos1 = 0, pos2 = 0;
+  AutoTArray<Accessible*, 30> parents1, parents2;
+  Accessible* container =
+    CommonParent(p1, p2, &parents1, &pos1, &parents2, &pos2);
 
   // 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);
@@ -191,16 +137,105 @@ TextRange::Bounds(nsTArray<nsIntRect> aR
 }
 
 void
 TextRange::Normalize(ETextUnit aUnit)
 {
 
 }
 
+bool
+TextRange::Crop(Accessible* aContainer)
+{
+  uint32_t boundaryPos = 0, containerPos = 0;
+  AutoTArray<Accessible*, 30> boundaryParents, containerParents;
+
+  // Crop the start boundary.
+  Accessible* container = nullptr;
+  Accessible* boundary = mStartContainer->GetChildAtOffset(mStartOffset);
+  if (boundary != aContainer) {
+    CommonParent(boundary, aContainer, &boundaryParents, &boundaryPos,
+                 &containerParents, &containerPos);
+
+    if (boundaryPos == 0) {
+      if (containerPos != 0) {
+        // The container is contained by the start boundary, reduce the range to
+        // the point starting at the container.
+        aContainer->ToTextPoint(mStartContainer.StartAssignment(), &mStartOffset);
+        static_cast<Accessible*>(mStartContainer)->AddRef();
+      }
+      else {
+        // The start boundary and the container are siblings.
+        container = aContainer;
+      }
+    }
+    else if (containerPos != 0) {
+      // The container does not contain the start boundary.
+      boundary = boundaryParents[boundaryPos];
+      container = containerParents[containerPos];
+    }
+
+    if (container) {
+      // If the range start is after the container, then make the range invalid.
+      if (boundary->IndexInParent() > container->IndexInParent()) {
+        return !!(mRoot = nullptr);
+      }
+
+      // If the range starts before the container, then reduce the range to
+      // the point starting at the container.
+      if (boundary->IndexInParent() < container->IndexInParent()) {
+        container->ToTextPoint(mStartContainer.StartAssignment(), &mStartOffset);
+        mStartContainer.get()->AddRef();
+      }
+    }
+
+    boundaryParents.SetLengthAndRetainStorage(0);
+    containerParents.SetLengthAndRetainStorage(0);
+  }
+
+  boundary = mEndContainer->GetChildAtOffset(mEndOffset);
+  if (boundary == aContainer) {
+    return true;
+  }
+
+  // Crop the end boundary.
+  container = nullptr;
+  CommonParent(boundary, aContainer, &boundaryParents, &boundaryPos,
+               &containerParents, &containerPos);
+
+  if (boundaryPos == 0) {
+    if (containerPos != 0) {
+      aContainer->ToTextPoint(mEndContainer.StartAssignment(), &mEndOffset, false);
+      static_cast<Accessible*>(mEndContainer)->AddRef();
+    }
+    else {
+      container = aContainer;
+    }
+  }
+  else if (containerPos != 0) {
+    boundary = boundaryParents[boundaryPos];
+    container = containerParents[containerPos];
+  }
+
+  if (!container) {
+    return true;
+  }
+
+  if (boundary->IndexInParent() < container->IndexInParent()) {
+    return !!(mRoot = nullptr);
+  }
+
+  if (boundary->IndexInParent() > container->IndexInParent()) {
+    container->ToTextPoint(mEndContainer.StartAssignment(), &mEndOffset, false);
+    static_cast<Accessible*>(mEndContainer)->AddRef();
+  }
+
+  return true;
+}
+
 void
 TextRange::FindText(const nsAString& aText, EDirection aDirection,
                     nsCaseTreatment aCaseSensitive, TextRange* aFoundRange) const
 {
 
 }
 
 void
@@ -291,10 +326,51 @@ TextRange::TextInternal(nsAString& aText
 void
 TextRange::MoveInternal(ETextUnit aUnit, int32_t aCount,
                         HyperTextAccessible& aContainer, int32_t aOffset,
                         HyperTextAccessible* aStopContainer, int32_t aStopOffset)
 {
 
 }
 
+Accessible*
+TextRange::CommonParent(Accessible* aAcc1, Accessible* aAcc2,
+                        nsTArray<Accessible*>* aParents1, uint32_t* aPos1,
+                        nsTArray<Accessible*>* aParents2, uint32_t* aPos2) const
+{
+  if (aAcc1 == aAcc2) {
+    return aAcc1;
+  }
+
+  MOZ_ASSERT(aParents1->Length() == 0 || aParents2->Length() == 0,
+             "Wrong arguments");
+
+  // Build the chain of parents.
+  Accessible* p1 = aAcc1;
+  Accessible* p2 = aAcc2;
+  do {
+    aParents1->AppendElement(p1);
+    p1 = p1->Parent();
+  } while (p1);
+  do {
+    aParents2->AppendElement(p2);
+    p2 = p2->Parent();
+  } while (p2);
+
+  // Find where the parent chain differs
+  *aPos1 = aParents1->Length();
+  *aPos2 = aParents2->Length();
+  Accessible* parent = nullptr;
+  uint32_t len = 0;
+  for (len = std::min(*aPos1, *aPos2); len > 0; --len) {
+    Accessible* child1 = aParents1->ElementAt(--(*aPos1));
+    Accessible* child2 = aParents2->ElementAt(--(*aPos2));
+    if (child1 != child2)
+      break;
+
+    parent = child1;
+  }
+
+  return parent;
+}
+
 } // namespace a11y
 } // namespace mozilla
--- a/accessible/base/TextRange.h
+++ b/accessible/base/TextRange.h
@@ -126,16 +126,22 @@ public:
   void MoveEnd(ETextUnit aUnit, int32_t aCount)
     { MoveInternal(aUnit, aCount, *mEndContainer, mEndOffset); }
 
   /**
    * Move the range points to the closest unit boundaries.
    */
   void Normalize(ETextUnit aUnit);
 
+  /**
+   * Crops the range if it overlaps the given accessible element boundaries,
+   * returns true if the range was cropped successfully.
+   */
+  bool Crop(Accessible* aContainer);
+
   enum EDirection {
     eBackward,
     eForward
   };
 
   /**
    * Return range enclosing the found text.
    */
@@ -238,16 +244,24 @@ private:
   bool TextInternal(nsAString& aText, Accessible* aCurrent,
                     uint32_t aStartIntlOffset) const;
 
   void MoveInternal(ETextUnit aUnit, int32_t aCount,
                     HyperTextAccessible& aContainer, int32_t aOffset,
                     HyperTextAccessible* aStopContainer = nullptr,
                     int32_t aStopOffset = 0);
 
+  /**
+   * A helper method returning a common parent for two given accessible
+   * elements.
+   */
+  Accessible* CommonParent(Accessible* aAcc1, Accessible* aAcc2,
+                           nsTArray<Accessible*>* aParents1, uint32_t* aPos1,
+                           nsTArray<Accessible*>* aParents2, uint32_t* aPos2) const;
+
   RefPtr<HyperTextAccessible> mRoot;
   RefPtr<HyperTextAccessible> mStartContainer;
   RefPtr<HyperTextAccessible> mEndContainer;
   int32_t mStartOffset;
   int32_t mEndOffset;
 };
 
 
--- a/accessible/base/TreeWalker.cpp
+++ b/accessible/base/TreeWalker.cpp
@@ -16,131 +16,129 @@
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // TreeWalker
 ////////////////////////////////////////////////////////////////////////////////
 
 TreeWalker::
-  TreeWalker(Accessible* aContext, nsIContent* aContent, uint32_t aFlags) :
-  mDoc(aContext->Document()), mContext(aContext), mAnchorNode(aContent),
-  mFlags(aFlags)
+  TreeWalker(Accessible* aContext) :
+  mDoc(aContext->Document()), mContext(aContext), mAnchorNode(nullptr),
+  mARIAOwnsIdx(0),
+  mChildFilter(nsIContent::eSkipPlaceholderContent), mFlags(0)
 {
-  NS_ASSERTION(aContent, "No node for the accessible tree walker!");
+  mChildFilter |= mContext->NoXBLKids() ?
+    nsIContent::eAllButXBL : nsIContent::eAllChildren;
+
+  mAnchorNode = mContext->IsDoc() ?
+    mDoc->DocumentNode()->GetRootElement() : mContext->GetContent();
+
+  if (mAnchorNode) {
+    PushState(mAnchorNode);
+  }
 
-  mChildFilter = mContext->CanHaveAnonChildren() ?
-    nsIContent::eAllChildren : nsIContent::eAllButXBL;
-  mChildFilter |= nsIContent::eSkipPlaceholderContent;
+  MOZ_COUNT_CTOR(TreeWalker);
+}
 
-  if (aContent)
-    PushState(aContent);
+TreeWalker::
+  TreeWalker(Accessible* aContext, nsIContent* aAnchorNode, uint32_t aFlags) :
+  mDoc(aContext->Document()), mContext(aContext), mAnchorNode(aAnchorNode),
+  mARIAOwnsIdx(0),
+  mChildFilter(nsIContent::eSkipPlaceholderContent), mFlags(aFlags)
+{
+  MOZ_ASSERT(mFlags & eWalkCache, "This constructor cannot be used for tree creation");
+  MOZ_ASSERT(aAnchorNode, "No anchor node for the accessible tree walker");
+
+  mChildFilter |= mContext->NoXBLKids() ?
+    nsIContent::eAllButXBL : nsIContent::eAllChildren;
+
+  PushState(aAnchorNode);
 
   MOZ_COUNT_CTOR(TreeWalker);
 }
 
 TreeWalker::~TreeWalker()
 {
   MOZ_COUNT_DTOR(TreeWalker);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // TreeWalker: private
 
 Accessible*
-TreeWalker::NextChild()
+TreeWalker::Next()
 {
-  if (mStateStack.IsEmpty())
-    return nullptr;
+  if (mStateStack.IsEmpty()) {
+    return mDoc->ARIAOwnedAt(mContext, mARIAOwnsIdx++);
+  }
 
-  ChildrenIterator* top = &mStateStack[mStateStack.Length() - 1];
+  dom::AllChildrenIterator* top = &mStateStack[mStateStack.Length() - 1];
   while (top) {
-    Accessible* child = nullptr;
-    bool skipSubtree = false;
-    while (nsIContent* childNode = Next(top, &child, &skipSubtree)) {
-      if (child)
+    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.
+      if (child) {
+        if (child->IsRelocated()) {
+          continue;
+        }
         return child;
+      }
 
       // Walk down into subtree to find accessibles.
-      if (!skipSubtree && childNode->IsElement())
+      if (!skipSubtree && childNode->IsElement()) {
         top = PushState(childNode);
+      }
     }
-
     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)
-    return nullptr;
+  // 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) {
+      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);
-    while (nsIContent* childNode = Next(top)) {
-      if (childNode == mAnchorNode) {
-        mAnchorNode = parent;
-        return NextChild();
-      }
+    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 nullptr;
+  return Next();
 }
 
-nsIContent*
-TreeWalker::Next(ChildrenIterator* aIter, Accessible** aAccesible,
-                 bool* aSkipSubtree)
-{
-  nsIContent* childEl = aIter->mDOMIter.GetNextChild();
-  if (!aAccesible)
-    return childEl;
-
-  *aAccesible = nullptr;
-  *aSkipSubtree = false;
-
-  if (childEl) {
-    Accessible* accessible = mFlags & eWalkCache ?
-      mDoc->GetAccessible(childEl) :
-      GetAccService()->GetOrCreateAccessible(childEl, mContext, aSkipSubtree);
-
-    // Ignore the accessible and its subtree if it was repositioned by means of
-    // aria-owns.
-    if (accessible) {
-      if (accessible->IsRepositioned()) {
-        *aSkipSubtree = true;
-      } else {
-        *aAccesible = accessible;
-      }
-    }
-    return childEl;
-  }
-
-  // At last iterate over ARIA owned children.
-  Accessible* parent = mDoc->GetAccessible(aIter->mDOMIter.Parent());
-  if (parent) {
-    Accessible* child = mDoc->ARIAOwnedAt(parent, aIter->mARIAOwnsIdx++);
-    if (child) {
-      *aAccesible = child;
-      return child->GetContent();
-    }
-  }
-  return nullptr;
-}
-
-TreeWalker::ChildrenIterator*
+dom::AllChildrenIterator*
 TreeWalker::PopState()
 {
   size_t length = mStateStack.Length();
   mStateStack.RemoveElementAt(length - 1);
   return mStateStack.IsEmpty() ? nullptr : &mStateStack[mStateStack.Length() - 1];
 }
--- a/accessible/base/TreeWalker.h
+++ b/accessible/base/TreeWalker.h
@@ -28,71 +28,70 @@ public:
   enum {
     // used to walk the existing tree of the given node
     eWalkCache = 1,
     // used to walk the context tree starting from given node
     eWalkContextTree = 2 | eWalkCache
   };
 
   /**
-   * Constructor
+   * Used to navigate and create if needed the accessible children.
+   */
+  explicit TreeWalker(Accessible* aContext);
+
+  /**
+   * 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 aNode    [in] the node the search will be prepared relative to
+   * @param aAnchorNode [in] the node the search will be prepared relative to
    * @param aFlags   [in] flags (see enum above)
    */
-  TreeWalker(Accessible* aContext, nsIContent* aNode, uint32_t aFlags = 0);
+  TreeWalker(Accessible* aContext, nsIContent* aAnchorNode, uint32_t aFlags = eWalkCache);
+
   ~TreeWalker();
 
   /**
-   * Return the next child accessible.
+   * Return the next 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* NextChild();
+  Accessible* Next();
 
 private:
   TreeWalker();
   TreeWalker(const TreeWalker&);
   TreeWalker& operator =(const TreeWalker&);
 
-  struct ChildrenIterator {
-    ChildrenIterator(nsIContent* aNode, uint32_t aFilter) :
-      mDOMIter(aNode, aFilter), mARIAOwnsIdx(0) { }
-
-    dom::AllChildrenIterator mDOMIter;
-    uint32_t mARIAOwnsIdx;
-  };
-
-  nsIContent* Next(ChildrenIterator* aIter, Accessible** aAccessible = nullptr,
-                   bool* aSkipSubtree = nullptr);
-
   /**
    * Create new state for the given node and push it on top of stack.
    *
    * @note State stack is used to navigate up/down the DOM subtree during
    *        accessible children search.
    */
-  ChildrenIterator* PushState(nsIContent* aContent)
+  dom::AllChildrenIterator* PushState(nsIContent* aContent)
   {
-    return mStateStack.AppendElement(ChildrenIterator(aContent, mChildFilter));
+    return mStateStack.AppendElement(
+      dom::AllChildrenIterator(aContent, mChildFilter));
   }
 
   /**
    * Pop state from stack.
    */
-  ChildrenIterator* PopState();
+  dom::AllChildrenIterator* PopState();
 
   DocAccessible* mDoc;
   Accessible* mContext;
   nsIContent* mAnchorNode;
-  nsAutoTArray<ChildrenIterator, 20> mStateStack;
+
+  AutoTArray<dom::AllChildrenIterator, 20> mStateStack;
+  uint32_t mARIAOwnsIdx;
+
   int32_t mChildFilter;
   uint32_t mFlags;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif // mozilla_a11y_TreeWalker_h_
--- a/accessible/base/nsAccCache.h
+++ b/accessible/base/nsAccCache.h
@@ -7,45 +7,39 @@
 #define _nsAccCache_H_
 
 #include "xpcAccessibleDocument.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 // Accessible cache utils
 ////////////////////////////////////////////////////////////////////////////////
 
-/**
- * Shutdown and removes the accessible from cache.
- */
 template <class T>
-static PLDHashOperator
-ClearCacheEntry(const void* aKey, RefPtr<T>& aAccessible, void* aUserArg)
+void
+UnbindCacheEntriesFromDocument(
+  nsRefPtrHashtable<nsPtrHashKey<const void>, T>& aCache)
 {
-  NS_ASSERTION(aAccessible, "Calling ClearCacheEntry with a nullptr pointer!");
-  if (aAccessible && !aAccessible->IsDefunct())
-    aAccessible->Shutdown();
-
-  return PL_DHASH_REMOVE;
-}
-
-template <class T>
-static PLDHashOperator
-UnbindCacheEntryFromDocument(const void* aKey, RefPtr<T>& aAccessible,
-                             void* aUserArg)
-{
-  MOZ_ASSERT(aAccessible && !aAccessible->IsDefunct());
-  aAccessible->Document()->UnbindFromDocument(aAccessible);
-
-  return PL_DHASH_REMOVE;
+  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)
 {
-  aCache.Enumerate(ClearCacheEntry<T>, nullptr);
+  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);
+      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!");
 
--- 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
    */
--- a/accessible/base/nsAccessibilityService.cpp
+++ b/accessible/base/nsAccessibilityService.cpp
@@ -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);
+  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());
 }
 
@@ -591,17 +591,17 @@ nsAccessibilityService::ContentRemoved(n
     // 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.NextChild();
+      child = walker.Next();
     }
 
     if (child) {
       document->ContentRemoved(child->Parent(), aChildNode);
 #ifdef A11Y_LOG
       if (logging::IsEnabled(logging::eTree))
         logging::AccessibleNNode("real container", child->Parent());
 #endif
@@ -1086,34 +1086,32 @@ nsAccessibilityService::GetOrCreateAcces
                "Image map manages the area accessible creation!");
 #endif
 
   // Attempt to create an accessible based on what we know.
   RefPtr<Accessible> newAcc;
 
   // Create accessible for visible text frames.
   if (content->IsNodeOfType(nsINode::eTEXT)) {
-    nsAutoString text;
-    frame->GetRenderedText(&text, nullptr, nullptr, 0, UINT32_MAX);
+    nsIFrame::RenderedText text = frame->GetRenderedText(0,
+        UINT32_MAX, nsIFrame::TextOffsetType::OFFSETS_IN_CONTENT_TEXT,
+        nsIFrame::TrailingWhitespace::DONT_TRIM_TRAILING_WHITESPACE);
     // Ignore not rendered text nodes and whitespace text nodes between table
     // cells.
-    if (text.IsEmpty() ||
-        (aContext->IsTableRow() && nsCoreUtils::IsWhitespaceString(text))) {
+    if (text.mString.IsEmpty() ||
+        (aContext->IsTableRow() && nsCoreUtils::IsWhitespaceString(text.mString))) {
       if (aIsSubtreeHidden)
         *aIsSubtreeHidden = true;
 
       return nullptr;
     }
 
     newAcc = CreateAccessibleByFrameType(frame, content, aContext);
-    if (!aContext->IsAcceptableChild(newAcc))
-      return nullptr;
-
     document->BindToDocument(newAcc, nullptr);
-    newAcc->AsTextLeaf()->SetText(text);
+    newAcc->AsTextLeaf()->SetText(text.mString);
     return newAcc;
   }
 
   if (content->IsHTMLElement(nsGkAtoms::map)) {
     // Create hyper text accessible for HTML map if it is used to group links
     // (see http://www.w3.org/TR/WCAG10-HTML-TECHS/#group-bypass). If the HTML
     // map rect is empty then it is used for links grouping. Otherwise it should
     // be used in conjunction with HTML image element and in this case we don't
@@ -1125,24 +1123,21 @@ nsAccessibilityService::GetOrCreateAcces
                                               frame->GetParent()).IsEmpty()) {
       if (aIsSubtreeHidden)
         *aIsSubtreeHidden = true;
 
       return nullptr;
     }
 
     newAcc = new HyperTextAccessibleWrap(content, document);
-    if (!aContext->IsAcceptableChild(newAcc))
-      return nullptr;
-
-    document->BindToDocument(newAcc, aria::GetRoleMap(aNode));
+    document->BindToDocument(newAcc, aria::GetRoleMap(content->AsElement()));
     return newAcc;
   }
 
-  nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aNode);
+  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))
@@ -1285,20 +1280,19 @@ nsAccessibilityService::GetOrCreateAcces
       // Interesting HTML container which may have selectable text and/or embedded objects
       newAcc = new HyperTextAccessibleWrap(content, document);
     } else {  // XUL, SVG, MathML etc.
       // Interesting generic non-HTML container
       newAcc = new AccessibleWrap(content, document);
     }
   }
 
-  if (!newAcc || !aContext->IsAcceptableChild(newAcc))
-    return nullptr;
-
-  document->BindToDocument(newAcc, roleMapEntry);
+  if (newAcc) {
+    document->BindToDocument(newAcc, roleMapEntry);
+  }
   return newAcc;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessibilityService private
 
 bool
 nsAccessibilityService::Init()
@@ -1408,23 +1402,17 @@ nsAccessibilityService::Shutdown()
   gXPCApplicationAccessible = nullptr;
 }
 
 already_AddRefed<Accessible>
 nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
                                                DocAccessible* aDoc)
 {
   nsAutoString role;
-  for (const nsXBLBinding* binding = aContent->GetXBLBinding(); binding; binding = binding->GetBaseBinding()) {
-    nsIContent* bindingElm = binding->PrototypeBinding()->GetBindingElement();
-    bindingElm->GetAttr(kNameSpaceID_None, nsGkAtoms::role, role);
-    if (!role.IsEmpty())
-      break;
-  }
-
+  nsCoreUtils::XBLBindingRole(aContent, role);
   if (role.IsEmpty() || role.EqualsLiteral("none"))
     return nullptr;
 
   if (role.EqualsLiteral("outerdoc")) {
     RefPtr<Accessible> accessible = new OuterDocAccessible(aContent, aDoc);
     return accessible.forget();
   }
 
--- a/accessible/base/nsAccessibilityService.h
+++ b/accessible/base/nsAccessibilityService.h
@@ -379,13 +379,14 @@ static const char kEventTypeNames[][40] 
   "hyperlink number of anchors changed",     // EVENT_HYPERLINK_NUMBER_OF_ANCHORS_CHANGED
   "hyperlink selected link changed",         // EVENT_HYPERLINK_SELECTED_LINK_CHANGED
   "hypertext link activated",                // EVENT_HYPERTEXT_LINK_ACTIVATED
   "hypertext link selected",                 // EVENT_HYPERTEXT_LINK_SELECTED
   "hyperlink start index changed",           // EVENT_HYPERLINK_START_INDEX_CHANGED
   "hypertext changed",                       // EVENT_HYPERTEXT_CHANGED
   "hypertext links count changed",           // EVENT_HYPERTEXT_NLINKS_CHANGED
   "object attribute changed",                // EVENT_OBJECT_ATTRIBUTE_CHANGED
-  "virtual cursor changed"                   // EVENT_VIRTUALCURSOR_CHANGED
+  "virtual cursor changed",                   // EVENT_VIRTUALCURSOR_CHANGED
+  "text value change",                       // EVENT_TEXT_VALUE_CHANGE
 };
 
 #endif /* __nsIAccessibilityService_h__ */
 
--- a/accessible/base/nsCoreUtils.cpp
+++ b/accessible/base/nsCoreUtils.cpp
@@ -11,42 +11,55 @@
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDocument.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsRange.h"
 #include "nsIBoxObject.h"
 #include "nsIDOMXULElement.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/EventListenerManager.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/TouchEvents.h"
 #include "nsView.h"
 #include "nsGkAtoms.h"
 
 #include "nsComponentManagerUtils.h"
 
 #include "nsITreeBoxObject.h"
 #include "nsITreeColumns.h"
 #include "mozilla/dom/Element.h"
+#include "mozilla/dom/HTMLLabelElement.h"
 
 using namespace mozilla;
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsCoreUtils
 ////////////////////////////////////////////////////////////////////////////////
 
 bool
+nsCoreUtils::IsLabelWithControl(nsIContent* aContent)
+{
+  dom::HTMLLabelElement* label = dom::HTMLLabelElement::FromContent(aContent);
+  if (label && label->GetControl())
+    return true;
+
+  return false;
+}
+
+bool
 nsCoreUtils::HasClickListener(nsIContent *aContent)
 {
   NS_ENSURE_TRUE(aContent, false);
   EventListenerManager* listenerManager =
     aContent->GetExistingListenerManager();
 
   return listenerManager &&
     (listenerManager->HasListenersFor(nsGkAtoms::onclick) ||
@@ -145,17 +158,17 @@ nsCoreUtils::DispatchTouchEvent(EventMes
     return;
 
   WidgetTouchEvent event(true, aMessage, aRootWidget);
 
   event.time = 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),
-                                          nsIntPoint(1, 1), 0.0f, 1.0f);
+                                        LayoutDeviceIntPoint(1, 1), 0.0f, 1.0f);
   t->SetTarget(aContent);
   event.touches.AppendElement(t);
   nsEventStatus status = nsEventStatus_eIgnore;
   aPresShell->HandleEventWithTarget(&event, aFrame, aContent, &status);
 }
 
 uint32_t
 nsCoreUtils::GetAccessKeyFor(nsIContent* aContent)
@@ -205,38 +218,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;
@@ -642,8 +633,46 @@ nsCoreUtils::IsWhitespaceString(const ns
   aString.BeginReading(iterBegin);
   aString.EndReading(iterEnd);
 
   while (iterBegin != iterEnd && IsWhitespace(*iterBegin))
     ++iterBegin;
 
   return iterBegin == iterEnd;
 }
+
+bool
+nsCoreUtils::AccEventObserversExist()
+{
+  nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
+  NS_ENSURE_TRUE(obsService, false);
+
+  nsCOMPtr<nsISimpleEnumerator> observers;
+  obsService->EnumerateObservers(NS_ACCESSIBLE_EVENT_TOPIC,
+                                 getter_AddRefs(observers));
+  NS_ENSURE_TRUE(observers, false);
+
+  bool hasObservers = false;
+  observers->HasMoreElements(&hasObservers);
+
+  return hasObservers;
+}
+
+void
+nsCoreUtils::DispatchAccEvent(RefPtr<nsIAccessibleEvent> event)
+{
+  nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
+  NS_ENSURE_TRUE_VOID(obsService);
+
+  obsService->NotifyObservers(event, NS_ACCESSIBLE_EVENT_TOPIC, nullptr);
+}
+
+void
+nsCoreUtils::XBLBindingRole(const nsIContent* aEl, nsAString& aRole)
+{
+  for (const nsXBLBinding* binding = aEl->GetXBLBinding(); binding;
+       binding = binding->GetBaseBinding()) {
+    nsIContent* bindingElm = binding->PrototypeBinding()->GetBindingElement();
+    bindingElm->GetAttr(kNameSpaceID_None, nsGkAtoms::role, aRole);
+    if (!aRole.IsEmpty())
+      break;
+  }
+}
--- a/accessible/base/nsCoreUtils.h
+++ b/accessible/base/nsCoreUtils.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 nsCoreUtils_h_
 #define nsCoreUtils_h_
 
 #include "mozilla/EventForwards.h"
+#include "nsIAccessibleEvent.h"
 #include "nsIContent.h"
 #include "nsIDocument.h" // for GetShell()
 #include "nsIPresShell.h"
 
 #include "nsPoint.h"
 #include "nsTArray.h"
 
 class nsRange;
@@ -24,16 +25,21 @@ class nsIWidget;
 
 /**
  * Core utils.
  */
 class nsCoreUtils
 {
 public:
   /**
+   * Return true if the given node is a label of a control.
+   */
+  static bool IsLabelWithControl(nsIContent *aContent);
+
+  /**
    * Return true if the given node has registered click, mousedown or mouseup
    * event listeners.
    */
   static bool HasClickListener(nsIContent *aContent);
 
   /**
    * Dispatch click event to XUL tree cell.
    *
@@ -98,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
@@ -309,11 +304,26 @@ public:
   /**
    * Returns true if the given character is whitespace symbol.
    */
   static bool IsWhitespace(char16_t aChar)
   {
     return aChar == ' ' || aChar == '\n' ||
       aChar == '\r' || aChar == '\t' || aChar == 0xa0;
   }
+
+  /*
+   * Return true if there are any observers of accessible events.
+   */
+  static bool AccEventObserversExist();
+
+  /**
+   * Notify accessible event observers of an event.
+   */
+  static void DispatchAccEvent(RefPtr<nsIAccessibleEvent> aEvent);
+
+  /**
+   * Return a role attribute on XBL bindings of the element.
+   */
+  static void XBLBindingRole(const nsIContent* aEl, nsAString& aRole);
 };
 
 #endif
--- a/accessible/base/nsTextEquivUtils.cpp
+++ b/accessible/base/nsTextEquivUtils.cpp
@@ -134,18 +134,20 @@ nsTextEquivUtils::AppendTextEquivFromTex
           }
         }
       }
     }
     
     if (aContent->TextLength() > 0) {
       nsIFrame *frame = aContent->GetPrimaryFrame();
       if (frame) {
-        nsresult rv = frame->GetRenderedText(aString);
-        NS_ENSURE_SUCCESS(rv, rv);
+        nsIFrame::RenderedText text = frame->GetRenderedText(0,
+            UINT32_MAX, nsIFrame::TextOffsetType::OFFSETS_IN_CONTENT_TEXT,
+            nsIFrame::TrailingWhitespace::DONT_TRIM_TRAILING_WHITESPACE);
+        aString->Append(text.mString);
       } else {
         // If aContent is an object that is display: none, we have no a frame.
         aContent->AppendTextTo(*aString);
       }
       if (isHTMLBlock && !aString->IsEmpty()) {
         aString->Append(char16_t(' '));
       }
     }
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -76,16 +76,17 @@
 #include "mozilla/EventStates.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/MouseEvents.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
@@ -297,22 +298,16 @@ Accessible::AccessKey() const
 }
 
 KeyBinding
 Accessible::KeyboardShortcut() const
 {
   return KeyBinding();
 }
 
-bool
-Accessible::CanHaveAnonChildren()
-{
-  return true;
-}
-
 void
 Accessible::TranslateString(const nsString& aKey, nsAString& aStringOut)
 {
   nsCOMPtr<nsIStringBundleService> stringBundleService =
     services::GetStringBundleService();
   if (!stringBundleService)
     return;
 
@@ -389,20 +384,22 @@ Accessible::VisibilityState()
   // Zero area rects can occur in the first frame of a multi-frame text flow,
   // in which case the rendered text is not empty and the frame should not be
   // marked invisible.
   // XXX Can we just remove this check? Why do we need to mark empty
   // text invisible?
   if (frame->GetType() == nsGkAtoms::textFrame &&
       !(frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
       frame->GetRect().IsEmpty()) {
-    nsAutoString renderedText;
-    frame->GetRenderedText(&renderedText, nullptr, nullptr, 0, 1);
-    if (renderedText.IsEmpty())
+    nsIFrame::RenderedText text = frame->GetRenderedText(0,
+        UINT32_MAX, nsIFrame::TextOffsetType::OFFSETS_IN_CONTENT_TEXT,
+        nsIFrame::TrailingWhitespace::DONT_TRIM_TRAILING_WHITESPACE);
+    if (text.mString.IsEmpty()) {
       return states::INVISIBLE;
+    }
   }
 
   return 0;
 }
 
 uint64_t
 Accessible::NativeState()
 {
@@ -530,17 +527,17 @@ Accessible::ChildAtPoint(int32_t aX, int
   NS_ENSURE_TRUE(rootFrame, nullptr);
 
   nsIFrame* startFrame = rootFrame;
 
   // Check whether the point is at popup content.
   nsIWidget* rootWidget = rootFrame->GetView()->GetNearestWidget(nullptr);
   NS_ENSURE_TRUE(rootWidget, nullptr);
 
-  nsIntRect rootRect;
+  LayoutDeviceIntRect rootRect;
   rootWidget->GetScreenBounds(rootRect);
 
   WidgetMouseEvent dummyEvent(true, eMouseMove, rootWidget,
                               WidgetMouseEvent::eSynthesized);
   dummyEvent.refPoint = LayoutDeviceIntPoint(aX - rootRect.x, aY - rootRect.y);
 
   nsIFrame* popupFrame = nsLayoutUtils::
     GetPopupFrameForEventCoordinates(accDocument->PresContext()->GetRootPresContext(),
@@ -814,19 +811,27 @@ Accessible::XULElmName(DocAccessible* aD
   aName.CompressWhitespace();
   if (!aName.IsEmpty())
     return;
 
   // Can get text from title of <toolbaritem> if we're a child of a <toolbaritem>
   nsIContent *bindingParent = aElm->GetBindingParent();
   nsIContent* parent =
     bindingParent? bindingParent->GetParent() : aElm->GetParent();
+  nsAutoString ancestorTitle;
   while (parent) {
     if (parent->IsXULElement(nsGkAtoms::toolbaritem) &&
-        parent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aName)) {
+        parent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, ancestorTitle)) {
+      // Before returning this, check if the element itself has a tooltip:
+      if (aElm->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext, aName)) {
+        aName.CompressWhitespace();
+        return;
+      }
+
+      aName.Assign(ancestorTitle);
       aName.CompressWhitespace();
       return;
     }
     parent = parent->GetParent();
   }
 }
 
 nsresult
@@ -878,30 +883,18 @@ Accessible::HandleAccEvent(AccEvent* aEv
           break;
                                                      }
         default:
                                                          ipcDoc->SendEvent(id, aEvent->GetEventType());
       }
     }
   }
 
-  nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
-  NS_ENSURE_TRUE(obsService, NS_ERROR_FAILURE);
-
-  nsCOMPtr<nsISimpleEnumerator> observers;
-  obsService->EnumerateObservers(NS_ACCESSIBLE_EVENT_TOPIC,
-                                 getter_AddRefs(observers));
-
-  NS_ENSURE_STATE(observers);
-
-  bool hasObservers = false;
-  observers->HasMoreElements(&hasObservers);
-  if (hasObservers) {
-    nsCOMPtr<nsIAccessibleEvent> event = MakeXPCEvent(aEvent);
-    return obsService->NotifyObservers(event, NS_ACCESSIBLE_EVENT_TOPIC, nullptr);
+  if (nsCoreUtils::AccEventObserversExist()) {
+    nsCoreUtils::DispatchAccEvent(MakeXPCEvent(aEvent));
   }
 
   return NS_OK;
 }
 
 already_AddRefed<nsIPersistentProperties>
 Accessible::Attributes()
 {
@@ -1004,17 +997,17 @@ Accessible::NativeAttributes()
   // override properties on a widget they used in an iframe.
   nsIContent* startContent = mContent;
   while (startContent) {
     nsIDocument* doc = startContent->GetComposedDoc();
     if (!doc)
       break;
 
     nsAccUtils::SetLiveContainerAttributes(attributes, startContent,
-                                           nsCoreUtils::GetRoleContent(doc));
+                                           doc->GetRootElement());
 
     // Allow ARIA live region markup from outer documents to override
     nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = doc->GetDocShell();
     if (!docShellTreeItem)
       break;
 
     nsCOMPtr<nsIDocShellTreeItem> sameTypeParent;
     docShellTreeItem->GetSameTypeParent(getter_AddRefs(sameTypeParent));
@@ -1233,35 +1226,37 @@ Accessible::ApplyARIAState(uint64_t* aSt
 
     // We only force the readonly bit off if we have a real mapping for the aria
     // role. This preserves the ability for screen readers to use readonly
     // (primarily on the document) as the hint for creating a virtual buffer.
     if (mRoleMapEntry->role != roles::NOTHING)
       *aState &= ~states::READONLY;
 
     if (mContent->HasID()) {
-      // If has a role & ID and aria-activedescendant on the container, assume focusable
-      nsIContent *ancestorContent = mContent;
-      while ((ancestorContent = ancestorContent->GetParent()) != nullptr) {
-        if (ancestorContent->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_activedescendant)) {
-            // ancestor has activedescendant property, this content could be active
+      // If has a role & ID and aria-activedescendant on the container, assume
+      // focusable.
+      const Accessible* ancestor = this;
+      while ((ancestor = ancestor->Parent()) && !ancestor->IsDoc()) {
+        dom::Element* el = ancestor->Elm();
+        if (el &&
+            el->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_activedescendant)) {
           *aState |= states::FOCUSABLE;
           break;
         }
       }
     }
   }
 
   if (*aState & states::FOCUSABLE) {
-    // Special case: aria-disabled propagates from ancestors down to any focusable descendant
-    nsIContent *ancestorContent = mContent;
-    while ((ancestorContent = ancestorContent->GetParent()) != nullptr) {
-      if (ancestorContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_disabled,
-                                       nsGkAtoms::_true, eCaseMatters)) {
-          // ancestor has aria-disabled property, this is disabled
+    // Propogate aria-disabled from ancestors down to any focusable descendant.
+    const Accessible* ancestor = this;
+    while ((ancestor = ancestor->Parent()) && !ancestor->IsDoc()) {
+      dom::Element* el = ancestor->Elm();
+      if (el && el->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_disabled,
+                                nsGkAtoms::_true, eCaseMatters)) {
         *aState |= states::UNAVAILABLE;
         break;
       }
     }
   }
 
   // special case: A native button element whose role got transformed by ARIA to a toggle button
   // Also applies to togglable button menus, like in the Dev Tools Web Console.
@@ -1598,18 +1593,17 @@ Accessible::RelationByType(RelationType 
       if (mContent->IsXULElement(nsGkAtoms::description))
         rel.AppendIter(new IDRefsIterator(mDoc, mContent,
                                           nsGkAtoms::control));
 
       return rel;
     }
 
     case RelationType::NODE_CHILD_OF: {
-      Relation rel(new ARIAOwnedByIterator(this));
-
+      Relation rel;
       // This is an ARIA tree or treegrid that doesn't use owns, so we need to
       // get the parent the hard way.
       if (mRoleMapEntry && (mRoleMapEntry->role == roles::OUTLINEITEM ||
                             mRoleMapEntry->role == roles::LISTITEM ||
                             mRoleMapEntry->role == roles::ROW)) {
         rel.AppendTarget(GetGroupInfo()->ConceptualParent());
       }
 
@@ -1628,31 +1622,29 @@ Accessible::RelationByType(RelationType 
             rel.AppendTarget(Parent());
         }
       }
 
       return rel;
     }
 
     case RelationType::NODE_PARENT_OF: {
-      Relation rel(new ARIAOwnsIterator(this));
-
       // ARIA tree or treegrid can do the hierarchy by @aria-level, ARIA trees
       // also can be organized by groups.
       if (mRoleMapEntry &&
           (mRoleMapEntry->role == roles::OUTLINEITEM ||
            mRoleMapEntry->role == roles::LISTITEM ||
            mRoleMapEntry->role == roles::ROW ||
            mRoleMapEntry->role == roles::OUTLINE ||
            mRoleMapEntry->role == roles::LIST ||
            mRoleMapEntry->role == roles::TREE_TABLE)) {
-        rel.AppendIter(new ItemIterator(this));
+        return Relation(new ItemIterator(this));
       }
 
-      return rel;
+      return Relation();
     }
 
     case RelationType::CONTROLLED_BY:
       return Relation(new RelatedAccIterator(Document(), mContent,
                                              nsGkAtoms::aria_controls));
 
     case RelationType::CONTROLLER_FOR: {
       Relation rel(new IDRefsIterator(mDoc, mContent,
@@ -1986,16 +1978,20 @@ Accessible::BindToParent(Accessible* aPa
   // Note: this is currently only used for richlistitems and their children.
   if (mParent->HasNameDependentParent() || mParent->IsXULListItem())
     mContextFlags |= eHasNameDependentParent;
   else
     mContextFlags &= ~eHasNameDependentParent;
 
   if (mParent->IsARIAHidden() || aria::HasDefinedARIAHidden(mContent))
     SetARIAHidden(true);
+
+  mContextFlags |=
+    static_cast<uint32_t>((mParent->IsAlert() ||
+                           mParent->IsInsideAlert())) & eInsideAlert;
 }
 
 // Accessible protected
 void
 Accessible::UnbindFromParent()
 {
 #ifdef DEBUG
   AssertInMutatingSubtree();
@@ -2003,17 +1999,17 @@ Accessible::UnbindFromParent()
   mParent = nullptr;
   mIndexInParent = -1;
   mInt.mIndexOfEmbeddedChild = -1;
   if (IsProxy())
     MOZ_CRASH("this should never be called on proxy wrappers");
 
   delete mBits.groupInfo;
   mBits.groupInfo = nullptr;
-  mContextFlags &= ~eHasNameDependentParent;
+  mContextFlags &= ~eHasNameDependentParent & ~eInsideAlert;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // Accessible public methods
 
 RootAccessible*
 Accessible::RootAccessible() const
 {
@@ -2128,16 +2124,61 @@ Accessible::RemoveChild(Accessible* aChi
 
   aChild->UnbindFromParent();
   mChildren.RemoveElementAt(index);
   mEmbeddedObjCollector = nullptr;
 
   return true;
 }
 
+void
+Accessible::MoveChild(uint32_t aNewIndex, Accessible* aChild)
+{
+  MOZ_ASSERT(aChild, "No child was given");
+  MOZ_ASSERT(aChild->mParent == this, "A child from different subtree was given");
+  MOZ_ASSERT(aChild->mIndexInParent != -1, "Unbound child was given");
+  MOZ_ASSERT(static_cast<uint32_t>(aChild->mIndexInParent) != aNewIndex,
+             "No move, same index");
+  MOZ_ASSERT(aNewIndex <= mChildren.Length(), "Wrong new index was given");
+
+#ifdef DEBUG
+  // AutoTreeMutation should update group info.
+  AssertInMutatingSubtree();
+#endif
+
+  mEmbeddedObjCollector = nullptr;
+  mChildren.RemoveElementAt(aChild->mIndexInParent);
+
+  uint32_t startIdx = aNewIndex, endIdx = aChild->mIndexInParent;
+
+  // If the child is moved after its current position.
+  if (static_cast<uint32_t>(aChild->mIndexInParent) < aNewIndex) {
+    startIdx = aChild->mIndexInParent;
+
+    if (aNewIndex == mChildren.Length() + 1) {
+      // The child is moved to the end.
+      mChildren.AppendElement(aChild);
+      endIdx = mChildren.Length() - 1;
+    }
+    else {
+      mChildren.InsertElementAt(aNewIndex - 1, aChild);
+      endIdx = aNewIndex;
+    }
+  }
+  else {
+    // The child is moved prior its current position.
+    mChildren.InsertElementAt(aNewIndex, aChild);
+  }
+
+  for (uint32_t idx = startIdx; idx <= endIdx; idx++) {
+    mChildren[idx]->mIndexInParent = idx;
+    mChildren[idx]->mInt.mIndexOfEmbeddedChild = -1;
+  }
+}
+
 Accessible*
 Accessible::GetChildAt(uint32_t aIndex) const
 {
   Accessible* child = mChildren.SafeElementAt(aIndex, nullptr);
   if (!child)
     return nullptr;
 
 #ifdef DEBUG
@@ -2244,16 +2285,40 @@ Accessible::AnchorAt(uint32_t aAnchorInd
 
 already_AddRefed<nsIURI>
 Accessible::AnchorURIAt(uint32_t aAnchorIndex)
 {
   NS_PRECONDITION(IsLink(), "AnchorURIAt is called on not hyper link!");
   return nullptr;
 }
 
+void
+Accessible::ToTextPoint(HyperTextAccessible** aContainer, int32_t* aOffset,
+                        bool aIsBefore) const
+{
+  if (IsHyperText()) {
+    *aContainer = const_cast<Accessible*>(this)->AsHyperText();
+    *aOffset = aIsBefore ? 0 : (*aContainer)->CharacterCount();
+    return;
+  }
+
+  const Accessible* child = nullptr;
+  const Accessible* parent = this;
+  do {
+    child = parent;
+    parent = parent->Parent();
+  } while (parent && !parent->IsHyperText());
+
+  if (parent) {
+    *aContainer = const_cast<Accessible*>(parent)->AsHyperText();
+    *aOffset = (*aContainer)->GetChildOffset(
+      child->IndexInParent() + static_cast<int32_t>(!aIsBefore));
+  }
+}
+
 
 ////////////////////////////////////////////////////////////////////////////////
 // SelectAccessible
 
 void
 Accessible::SelectedItems(nsTArray<Accessible*>* aItems)
 {
   AccIterator iter(this, filters::GetSelected);
@@ -2476,23 +2541,22 @@ Accessible::LastRelease()
   }
   // ... then die.
   delete this;
 }
 
 void
 Accessible::CacheChildren()
 {
-  DocAccessible* doc = Document();
-  NS_ENSURE_TRUE_VOID(doc);
-
-  TreeWalker walker(this, mContent);
+  NS_ENSURE_TRUE_VOID(Document());
+
+  TreeWalker walker(this);
 
   Accessible* child = nullptr;
-  while ((child = walker.NextChild()) && AppendChild(child));
+  while ((child = walker.Next()) && AppendChild(child));
 }
 
 void
 Accessible::TestChildCache(Accessible* aCachedChild) const
 {
 #ifdef DEBUG
   int32_t childCount = mChildren.Length();
   if (childCount == 0) {
--- a/accessible/generic/Accessible.h
+++ b/accessible/generic/Accessible.h
@@ -391,16 +391,21 @@ public:
   /**
    * Append/insert/remove a child. Return true if operation was successful.
    */
   bool AppendChild(Accessible* aChild)
     { return InsertChildAt(mChildren.Length(), aChild); }
   virtual bool InsertChildAt(uint32_t aIndex, Accessible* aChild);
   virtual bool RemoveChild(Accessible* aChild);
 
+  /**
+   * Reallocates the child withing its parent.
+   */
+  void MoveChild(uint32_t aNewIndex, Accessible* aChild);
+
   //////////////////////////////////////////////////////////////////////////////
   // Accessible tree traverse methods
 
   /**
    * Return parent accessible.
    */
   Accessible* Parent() const { return mParent; }
 
@@ -485,24 +490,20 @@ public:
 
   /**
    * Handle accessible event, i.e. process it, notifies observers and fires
    * platform specific event.
    */
   virtual nsresult HandleAccEvent(AccEvent* aAccEvent);
 
   /**
-   * Return true if this accessible allows accessible children from anonymous subtree.
-   */
-  virtual bool CanHaveAnonChildren();
-
-  /**
    * Return true if the accessible is an acceptable child.
    */
-  virtual bool IsAcceptableChild(Accessible* aPossibleChild) const { return true; }
+  virtual bool IsAcceptableChild(nsIContent* aEl) const
+    { return true; }
 
   /**
    * Returns text of accessible if accessible has text role otherwise empty
    * string.
    *
    * @param aText         [in] returned text of the accessible
    * @param aStartOffset  [in, optional] start offset inside of the accessible,
    *                        if missed entire text is appended
@@ -562,16 +563,18 @@ public:
   //////////////////////////////////////////////////////////////////////////////
   // Downcasting and types
 
   inline bool IsAbbreviation() const
   {
     return mContent->IsAnyOfHTMLElements(nsGkAtoms::abbr, nsGkAtoms::acronym);
   }
 
+  bool IsAlert() const { return HasGenericType(eAlert); }
+
   bool IsApplication() const { return mType == eApplicationType; }
   ApplicationAccessible* AsApplication();
 
   bool IsAutoComplete() const { return HasGenericType(eAutoComplete); }
 
   bool IsAutoCompletePopup() const
     { return HasGenericType(eAutoCompletePopup); }
 
@@ -582,16 +585,17 @@ public:
   bool IsDoc() const { return HasGenericType(eDocument); }
   DocAccessible* AsDoc();
 
   bool IsGenericHyperText() const { return mType == eHyperTextType; }
   bool IsHyperText() const { return HasGenericType(eHyperText); }
   HyperTextAccessible* AsHyperText();
 
   bool IsHTMLBr() const { return mType == eHTMLBRType; }
+  bool IsHTMLCaption() const { return mType == eHTMLCaptionType; }
   bool IsHTMLCombobox() const { return mType == eHTMLComboboxType; }
   bool IsHTMLFileInput() const { return mType == eHTMLFileInputType; }
 
   bool IsHTMLListItem() const { return mType == eHTMLLiType; }
   HTMLLIAccessible* AsHTMLListItem();
 
   bool IsHTMLOptGroup() const { return mType == eHTMLOptGroupType; }
 
@@ -753,16 +757,22 @@ public:
    */
   virtual Accessible* AnchorAt(uint32_t aAnchorIndex);
 
   /**
    * Returns an anchor URI at the given index.
    */
   virtual already_AddRefed<nsIURI> AnchorURIAt(uint32_t aAnchorIndex);
 
+  /**
+   * Returns a text point for the accessible element.
+   */
+  void ToTextPoint(HyperTextAccessible** aContainer, int32_t* aOffset,
+                   bool aIsBefore = true) const;
+
   //////////////////////////////////////////////////////////////////////////////
   // SelectAccessible
 
   /**
    * Return an array of selected items.
    */
   virtual void SelectedItems(nsTArray<Accessible*>* aItems);
 
@@ -853,17 +863,17 @@ public:
   static void TranslateString(const nsString& aKey, nsAString& aStringOut);
 
   /**
    * Return true if the accessible is defunct.
    */
   bool IsDefunct() const { return mStateFlags & eIsDefunct; }
 
   /**
-   * Return true if the accessible is no longer in the document.
+   * Return false if the accessible is no longer in the document.
    */
   bool IsInDocument() const { return !(mStateFlags & eIsNotInDocument); }
 
   /**
    * Return true if the accessible should be contained by document node map.
    */
   bool IsNodeMapEntry() const
     { return HasOwnContent() && !(mStateFlags & eNotNodeMapEntry); }
@@ -905,39 +915,50 @@ public:
     else
       mStateFlags &= ~eSurvivingInUpdate;
   }
 
   /**
    * Get/set repositioned bit indicating that the accessible was moved in
    * the accessible tree, i.e. the accessible tree structure differs from DOM.
    */
-  bool IsRepositioned() const { return mStateFlags & eRepositioned; }
-  void SetRepositioned(bool aRepositioned)
+  bool IsRelocated() const { return mStateFlags & eRelocated; }
+  void SetRelocated(bool aRelocated)
   {
-    if (aRepositioned)
-      mStateFlags |= eRepositioned;
+    if (aRelocated)
+      mStateFlags |= eRelocated;
     else
-      mStateFlags &= ~eRepositioned;
+      mStateFlags &= ~eRelocated;
   }
 
   /**
+   * Return true if the accessible doesn't allow accessible children from XBL
+   * anonymous subtree.
+   */
+  bool NoXBLKids() { return mStateFlags & eNoXBLKids; }
+
+  /**
    * Return true if this accessible has a parent whose name depends on this
    * accessible.
    */
   bool HasNameDependentParent() const
     { return mContextFlags & eHasNameDependentParent; }
 
   /**
    * Return true if aria-hidden="true" is applied to the accessible or inherited
    * from the parent.
    */
   bool IsARIAHidden() const { return mContextFlags & eARIAHidden; }
   void SetARIAHidden(bool aIsDefined);
 
+  /**
+   * Return true if the element is inside an alert.
+   */
+  bool IsInsideAlert() const { return mContextFlags & eInsideAlert; }
+
 protected:
   virtual ~Accessible();
 
   /**
    * Return the accessible name provided by native markup. It doesn't take
    * into account ARIA markup used to specify the name.
    */
   virtual mozilla::a11y::ENameValueFlag NativeName(nsString& aName);
@@ -1004,29 +1025,31 @@ protected:
     eIsNotInDocument = 1 << 1, // accessible is not in document
     eSharedNode = 1 << 2, // accessible shares DOM node from another accessible
     eNotNodeMapEntry = 1 << 3, // accessible shouldn't be in document node map
     eHasNumericValue = 1 << 4, // accessible has a numeric value
     eGroupInfoDirty = 1 << 5, // accessible needs to update group info
     eSubtreeMutating = 1 << 6, // subtree is being mutated
     eIgnoreDOMUIEvent = 1 << 7, // don't process DOM UI events for a11y events
     eSurvivingInUpdate = 1 << 8, // parent drops children to recollect them
-    eRepositioned = 1 << 9, // accessible was moved in tree
+    eRelocated = 1 << 9, // accessible was moved in tree
+    eNoXBLKids = 1 << 10, // accessible don't allows XBL children
 
-    eLastStateFlag = eRepositioned
+    eLastStateFlag = eNoXBLKids
   };
 
   /**
    * Flags used for contextual information about the accessible.
    */
   enum ContextFlags {
     eHasNameDependentParent = 1 << 0, // Parent's name depends on this accessible.
     eARIAHidden = 1 << 1,
+    eInsideAlert = 1 << 2,
 
-    eLastContextFlag = eARIAHidden
+    eLastContextFlag = eInsideAlert
   };
 
 protected:
 
   //////////////////////////////////////////////////////////////////////////////
   // Miscellaneous helpers
 
   /**
@@ -1121,20 +1144,20 @@ protected:
   nsCOMPtr<nsIContent> mContent;
   DocAccessible* mDoc;
 
   RefPtr<Accessible> mParent;
   nsTArray<RefPtr<Accessible> > mChildren;
   int32_t mIndexInParent;
 
   static const uint8_t kChildrenFlagsBits = 2;
-  static const uint8_t kStateFlagsBits = 10;
-  static const uint8_t kContextFlagsBits = 2;
+  static const uint8_t kStateFlagsBits = 11;
+  static const uint8_t kContextFlagsBits = 3;
   static const uint8_t kTypeBits = 6;
-  static const uint8_t kGenericTypesBits = 14;
+  static const uint8_t kGenericTypesBits = 15;
 
   /**
    * Keep in sync with ChildrenFlags, StateFlags, ContextFlags, and AccTypes.
    */
   uint32_t mChildrenFlags : kChildrenFlagsBits;
   uint32_t mStateFlags : kStateFlagsBits;
   uint32_t mContextFlags : kContextFlagsBits;
   uint32_t mType : kTypeBits;
--- a/accessible/generic/ApplicationAccessible.cpp
+++ b/accessible/generic/ApplicationAccessible.cpp
@@ -10,17 +10,16 @@
 #include "nsAccessibilityService.h"
 #include "nsAccUtils.h"
 #include "Relation.h"
 #include "Role.h"
 #include "States.h"
 
 #include "nsIComponentManager.h"
 #include "nsIDOMDocument.h"
-#include "nsIDOMWindow.h"
 #include "nsIWindowMediator.h"
 #include "nsServiceManagerUtils.h"
 #include "mozilla/Services.h"
 #include "nsIStringBundle.h"
 
 using namespace mozilla::a11y;
 
 ApplicationAccessible::ApplicationAccessible() :
@@ -188,17 +187,17 @@ ApplicationAccessible::CacheChildren()
   if (NS_FAILED(rv))
     return;
 
   bool hasMore = false;
   windowEnumerator->HasMoreElements(&hasMore);
   while (hasMore) {
     nsCOMPtr<nsISupports> window;
     windowEnumerator->GetNext(getter_AddRefs(window));
-    nsCOMPtr<nsPIDOMWindow> DOMWindow = do_QueryInterface(window);
+    nsCOMPtr<nsPIDOMWindowOuter> DOMWindow = do_QueryInterface(window);
     if (DOMWindow) {
       nsCOMPtr<nsIDocument> docNode = DOMWindow->GetDoc();
       if (docNode) {
         GetAccService()->GetDocAccessible(docNode); // ensure creation
       }
     }
     windowEnumerator->HasMoreElements(&hasMore);
   }
--- a/accessible/generic/BaseAccessibles.cpp
+++ b/accessible/generic/BaseAccessibles.cpp
@@ -48,16 +48,23 @@ LeafAccessible::InsertChildAt(uint32_t a
 
 bool
 LeafAccessible::RemoveChild(Accessible* aChild)
 {
   NS_NOTREACHED("RemoveChild called on leaf accessible!");
   return false;
 }
 
+bool
+LeafAccessible::IsAcceptableChild(nsIContent* aEl) const
+{
+  // No children for leaf accessible.
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // LeafAccessible: Accessible private
 
 void
 LeafAccessible::CacheChildren()
 {
   // No children for leaf accessible.
 }
@@ -110,30 +117,34 @@ LinkableAccessible::Value(nsString& aVal
   if (isLink) {
     actionAcc->Value(aValue);
   }
 }
 
 uint8_t
 LinkableAccessible::ActionCount()
 {
-  bool isLink, isOnclick;
-  ActionWalk(&isLink, &isOnclick);
-  return (isLink || isOnclick) ? 1 : 0;
+  bool isLink, isOnclick, isLabelWithControl;
+  ActionWalk(&isLink, &isOnclick, &isLabelWithControl);
+  return (isLink || isOnclick || isLabelWithControl) ? 1 : 0;
 }
 
 Accessible*
-LinkableAccessible::ActionWalk(bool* aIsLink, bool* aIsOnclick)
+LinkableAccessible::ActionWalk(bool* aIsLink, bool* aIsOnclick,
+                               bool* aIsLabelWithControl)
 {
   if (aIsOnclick) {
     *aIsOnclick = false;
   }
   if (aIsLink) {
     *aIsLink = false;
   }
+  if (aIsLabelWithControl) {
+    *aIsLabelWithControl = false;
+  }
 
   if (nsCoreUtils::HasClickListener(mContent)) {
     if (aIsOnclick) {
       *aIsOnclick = true;
     }
     return nullptr;
   }
 
@@ -150,32 +161,39 @@ LinkableAccessible::ActionWalk(bool* aIs
     }
 
     if (nsCoreUtils::HasClickListener(walkUpAcc->GetContent())) {
       if (aIsOnclick) {
         *aIsOnclick = true;
       }
       return walkUpAcc;
     }
+
+    if (nsCoreUtils::IsLabelWithControl(walkUpAcc->GetContent())) {
+      if (aIsLabelWithControl) {
+        *aIsLabelWithControl = true;
+      }
+      return walkUpAcc;
+    }
   }
   return nullptr;
 }
 
 void
 LinkableAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
 {
   aName.Truncate();
 
   // Action 0 (default action): Jump to link
   if (aIndex == eAction_Jump) {
-    bool isOnclick, isLink;
-    ActionWalk(&isLink, &isOnclick);
+    bool isOnclick, isLink, isLabelWithControl;
+    ActionWalk(&isLink, &isOnclick, &isLabelWithControl);
     if (isLink) {
       aName.AssignLiteral("jump");
-    } else if (isOnclick) {
+    } else if (isOnclick || isLabelWithControl) {
       aName.AssignLiteral("click");
     }
   }
 }
 
 bool
 LinkableAccessible::DoAction(uint8_t aIndex)
 {
--- a/accessible/generic/BaseAccessibles.h
+++ b/accessible/generic/BaseAccessibles.h
@@ -33,16 +33,18 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
 
   // Accessible
   virtual Accessible* ChildAtPoint(int32_t aX, int32_t aY,
                                    EWhichChildAtPoint aWhichChild) override;
   virtual bool InsertChildAt(uint32_t aIndex, Accessible* aChild) override final;
   virtual bool RemoveChild(Accessible* aChild) override final;
 
+  virtual bool IsAcceptableChild(nsIContent* aEl) const override;
+
 protected:
   virtual ~LeafAccessible() {}
 
   // Accessible
   virtual void CacheChildren() override;
 };
 
 /**
@@ -71,17 +73,18 @@ public:
   // ActionAccessible
   virtual uint8_t ActionCount() override;
   virtual void ActionNameAt(uint8_t aIndex, nsAString& aName) override;
   virtual bool DoAction(uint8_t index) override;
   virtual KeyBinding AccessKey() const override;
 
   // ActionAccessible helpers
   Accessible* ActionWalk(bool* aIsLink = nullptr,
-                          bool* aIsOnclick = nullptr);
+                         bool* aIsOnclick = nullptr,
+                         bool* aIsLabelWithControl = nullptr);
   // HyperLinkAccessible
   virtual already_AddRefed<nsIURI> AnchorURIAt(uint32_t aAnchorIndex) override;
 
 protected:
   virtual ~LinkableAccessible() {}
 
 };
 
--- a/accessible/generic/DocAccessible-inl.h
+++ b/accessible/generic/DocAccessible-inl.h
@@ -8,16 +8,17 @@
 #define mozilla_a11y_DocAccessible_inl_h_
 
 #include "DocAccessible.h"
 #include "nsAccessibilityService.h"
 #include "nsAccessiblePivot.h"
 #include "NotificationController.h"
 #include "States.h"
 #include "nsIScrollableFrame.h"
+#include "nsIDocumentInlines.h"
 
 #ifdef A11Y_LOG
 #include "Logging.h"
 #endif
 
 namespace mozilla {
 namespace a11y {
 
@@ -73,16 +74,29 @@ DocAccessible::UpdateText(nsIContent* aT
   NS_ASSERTION(mNotificationController, "The document was shut down!");
 
   // Ignore the notification if initial tree construction hasn't been done yet.
   if (mNotificationController && HasLoadState(eTreeConstructed))
     mNotificationController->ScheduleTextUpdate(aTextNode);
 }
 
 inline void
+DocAccessible::UpdateRootElIfNeeded()
+{
+  dom::Element* rootEl = mDocumentNode->GetBodyElement();
+  if (!rootEl) {
+    rootEl = mDocumentNode->GetRootElement();
+  }
+  if (rootEl != mContent) {
+    mContent = rootEl;
+    SetRoleMapEntry(aria::GetRoleMap(rootEl));
+  }
+}
+
+inline void
 DocAccessible::AddScrollListener()
 {
   // Delay scroll initializing until the document has a root frame.
   if (!mPresShell->GetRootFrame())
     return;
 
   mDocFlags |= eScrollInitialized;
   nsIScrollableFrame* sf = mPresShell->GetRootScrollFrameAsScrollable();
@@ -119,17 +133,17 @@ DocAccessible::NotifyOfLoad(uint32_t aLo
   }
 }
 
 inline void
 DocAccessible::MaybeNotifyOfValueChange(Accessible* aAccessible)
 {
   a11y::role role = aAccessible->Role();
   if (role == roles::ENTRY || role == roles::COMBOBOX)
-    FireDelayedEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, aAccessible);
+    FireDelayedEvent(nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE, aAccessible);
 }
 
 inline Accessible*
 DocAccessible::GetAccessibleEvenIfNotInMapOrContainer(nsINode* aNode) const
 {
   Accessible* acc = GetAccessibleEvenIfNotInMap(aNode);
   return acc ? acc : GetContainerAccessible(aNode);
 }
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -71,19 +71,18 @@ static nsIAtom** kRelationAttrs[] =
 };
 
 static const uint32_t kRelationAttrsLen = ArrayLength(kRelationAttrs);
 
 ////////////////////////////////////////////////////////////////////////////////
 // Constructor/desctructor
 
 DocAccessible::
-  DocAccessible(nsIDocument* aDocument, nsIContent* aRootContent,
-                  nsIPresShell* aPresShell) :
-  HyperTextAccessibleWrap(aRootContent, this),
+  DocAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell) :
+  HyperTextAccessibleWrap(nullptr, this),
   // XXX aaronl should we use an algorithm for the initial cache size?
   mAccessibleCache(kDefaultCacheLength),
   mNodeToAccessibleMap(kDefaultCacheLength),
   mDocumentNode(aDocument),
   mScrollPositionChangedTicks(0),
   mLoadState(eTreeConstructionPending), mDocFlags(0), mLoadEventType(0),
   mVirtualCursor(nullptr),
   mPresShell(aPresShell), mIPCDoc(nullptr)
@@ -125,34 +124,35 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
       cb.NoteXPCOMChild(provider->mContent);
 
       NS_ASSERTION(provider->mContent->IsInDoc(),
                    "Referred content is not in document!");
     }
   }
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAccessibleCache)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnchorJumpElm)
-  for (uint32_t i = 0; i < tmp->mARIAOwnsInvalidationList.Length(); ++i) {
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mARIAOwnsInvalidationList[i].mOwner)
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mARIAOwnsInvalidationList[i].mChild)
+  for (auto it = tmp->mARIAOwnsHash.ConstIter(); !it.Done(); it.Next()) {
+    nsTArray<RefPtr<Accessible> >* ar = it.UserData();
+    for (uint32_t i = 0; i < ar->Length(); i++) {
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
+                                         "mARIAOwnsHash entry item");
+      cb.NoteXPCOMChild(ar->ElementAt(i));
+    }
   }
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DocAccessible, Accessible)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mNotificationController)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mVirtualCursor)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildDocuments)
   tmp->mDependentIDsHash.Clear();
   tmp->mNodeToAccessibleMap.Clear();
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mAccessibleCache)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnchorJumpElm)
-  for (uint32_t i = 0; i < tmp->mARIAOwnsInvalidationList.Length(); ++i) {
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(mARIAOwnsInvalidationList[i].mOwner)
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(mARIAOwnsInvalidationList[i].mChild)
-  }
+  tmp->mARIAOwnsHash.Clear();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DocAccessible)
   NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver)
   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_INTERFACE_MAP_ENTRY(nsIObserver)
   NS_INTERFACE_MAP_ENTRY(nsIAccessiblePivotObserver)
@@ -726,16 +726,20 @@ DocAccessible::AttributeWillChange(nsIDo
   }
 
   // Update dependent IDs cache. Take care of elements that are accessible
   // because dependent IDs cache doesn't contain IDs from non accessible
   // elements.
   if (aModType != nsIDOMMutationEvent::ADDITION)
     RemoveDependentIDsFor(accessible, aAttribute);
 
+  if (aAttribute == nsGkAtoms::id) {
+    RelocateARIAOwnedIfNeeded(aElement);
+  }
+
   // Store the ARIA attribute old value so that it can be used after
   // attribute change. Note, we assume there's no nested ARIA attribute
   // changes. If this happens then we should end up with keeping a stack of
   // old values.
 
   // XXX TODO: bugs 472142, 472143.
   // Here we will want to cache whatever attribute values we are interested
   // in, such as the existence of aria-pressed for button (so we know if we
@@ -901,16 +905,20 @@ DocAccessible::AttributeChangedImpl(Acce
     bool isOn = elm->AttrValueIs(aNameSpaceID, aAttribute, nsGkAtoms::_true,
                                  eCaseMatters);
     RefPtr<AccEvent> event =
       new AccStateChangeEvent(aAccessible, states::BUSY, isOn);
     FireDelayedEvent(event);
     return;
   }
 
+  if (aAttribute == nsGkAtoms::id) {
+    RelocateARIAOwnedIfNeeded(elm);
+  }
+
   // ARIA or XUL selection
   if ((aAccessible->GetContent()->IsXULElement() &&
        aAttribute == nsGkAtoms::selected) ||
       aAttribute == nsGkAtoms::aria_selected) {
     Accessible* widget =
       nsAccUtils::GetSelectableContainer(aAccessible, aAccessible->State());
     if (widget) {
       AccSelChangeEvent::SelChangeType selChangeType =
@@ -1025,26 +1033,35 @@ DocAccessible::ARIAAttributeChanged(Acce
 
   if (aAttribute == nsGkAtoms::aria_readonly) {
     RefPtr<AccEvent> event =
       new AccStateChangeEvent(aAccessible, states::READONLY);
     FireDelayedEvent(event);
     return;
   }
 
-  // Fire value change event whenever aria-valuetext is changed, or
-  // when aria-valuenow is changed and aria-valuetext is empty
-  if (aAttribute == nsGkAtoms::aria_valuetext ||
-      (aAttribute == nsGkAtoms::aria_valuenow &&
-       (!elm->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_valuetext) ||
-        elm->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_valuetext,
-                         nsGkAtoms::_empty, eCaseMatters)))) {
+  // Fire text value change event whenever aria-valuetext is changed.
+  if (aAttribute == nsGkAtoms::aria_valuetext) {
+    FireDelayedEvent(nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE, aAccessible);
+    return;
+  }
+
+  // Fire numeric value change event when aria-valuenow is changed and
+  // aria-valuetext is empty
+  if (aAttribute == nsGkAtoms::aria_valuenow &&
+      (!elm->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_valuetext) ||
+       elm->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_valuetext,
+                        nsGkAtoms::_empty, eCaseMatters))) {
     FireDelayedEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, aAccessible);
     return;
   }
+
+  if (aAttribute == nsGkAtoms::aria_owns) {
+    mNotificationController->ScheduleRelocation(aAccessible);
+  }
 }
 
 void
 DocAccessible::ARIAActiveDescendantChanged(Accessible* aAccessible)
 {
   nsIContent* elm = aAccessible->GetContent();
   if (elm && aAccessible->IsActiveWidget()) {
     nsAutoString id;
@@ -1266,16 +1283,25 @@ DocAccessible::BindToDocument(Accessible
     mNodeToAccessibleMap.Put(aAccessible->GetNode(), aAccessible);
 
   // Put into unique ID cache.
   mAccessibleCache.Put(aAccessible->UniqueID(), aAccessible);
 
   aAccessible->SetRoleMapEntry(aRoleMapEntry);
 
   AddDependentIDsFor(aAccessible);
+
+  if (aAccessible->HasOwnContent()) {
+    nsIContent* el = aAccessible->GetContent();
+    if (el->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_owns)) {
+      mNotificationController->ScheduleRelocation(aAccessible);
+    }
+
+    RelocateARIAOwnedIfNeeded(el);
+  }
 }
 
 void
 DocAccessible::UnbindFromDocument(Accessible* aAccessible)
 {
   NS_ASSERTION(mAccessibleCache.GetWeak(aAccessible->UniqueID()),
                "Unbinding the unbound accessible!");
 
@@ -1360,77 +1386,16 @@ DocAccessible::ProcessInvalidationList()
     if (!HasAccessible(content)) {
       Accessible* container = GetContainerAccessible(content);
       if (container)
         UpdateTreeOnInsertion(container);
     }
   }
 
   mInvalidationList.Clear();
-
-  // Alter the tree according to aria-owns (seize the trees).
-  for (uint32_t idx = 0; idx < mARIAOwnsInvalidationList.Length(); idx++) {
-    Accessible* owner = mARIAOwnsInvalidationList[idx].mOwner;
-    if (!owner->IsInDocument()) { // eventually died before we've got here
-      continue;
-    }
-
-    Accessible* child = GetAccessible(mARIAOwnsInvalidationList[idx].mChild);
-    if (!child || !child->IsInDocument()) {
-      continue;
-    }
-
-    Accessible* oldParent = child->Parent();
-    if (!oldParent) {
-      NS_ERROR("The accessible is in document but doesn't have a parent");
-      continue;
-    }
-    int32_t idxInParent = child->IndexInParent();
-
-    // XXX: update context flags
-    {
-      RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(oldParent);
-      RefPtr<AccMutationEvent> hideEvent =
-        new AccHideEvent(child, child->GetContent(), false);
-      FireDelayedEvent(hideEvent);
-      reorderEvent->AddSubMutationEvent(hideEvent);
-
-      AutoTreeMutation mut(oldParent);
-      oldParent->RemoveChild(child);
-
-      MaybeNotifyOfValueChange(oldParent);
-      FireDelayedEvent(reorderEvent);
-    }
-
-    bool isReinserted = false;
-    {
-      AutoTreeMutation mut(owner);
-      isReinserted = owner->AppendChild(child);
-    }
-
-    Accessible* newParent = owner;
-    if (!isReinserted) {
-      AutoTreeMutation mut(oldParent);
-      oldParent->InsertChildAt(idxInParent, child);
-      newParent = oldParent;
-    }
-
-    RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(newParent);
-    RefPtr<AccMutationEvent> showEvent =
-      new AccShowEvent(child, child->GetContent());
-    FireDelayedEvent(showEvent);
-    reorderEvent->AddSubMutationEvent(showEvent);
-
-    MaybeNotifyOfValueChange(newParent);
-    FireDelayedEvent(reorderEvent);
-
-    child->SetRepositioned(isReinserted);
-  }
-
-  mARIAOwnsInvalidationList.Clear();
 }
 
 Accessible*
 DocAccessible::GetAccessibleEvenIfNotInMap(nsINode* aNode) const
 {
 if (!aNode->IsContent() || !aNode->AsContent()->IsHTMLElement(nsGkAtoms::area))
     return GetAccessible(aNode);
 
@@ -1448,46 +1413,16 @@ if (!aNode->IsContent() || !aNode->AsCon
       return nullptr;
     }
   }
 
   return GetAccessible(aNode);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// Accessible protected
-
-void
-DocAccessible::CacheChildren()
-{
-  // Search for accessible children starting from the document element since
-  // some web pages tend to insert elements under it rather than document body.
-  dom::Element* rootElm = mDocumentNode->GetRootElement();
-  if (!rootElm)
-    return;
-
-  // Ignore last HTML:br, copied from HyperTextAccessible.
-  TreeWalker walker(this, rootElm);
-  Accessible* lastChild = nullptr;
-  while (Accessible* child = walker.NextChild()) {
-    if (lastChild)
-      AppendChild(lastChild);
-
-    lastChild = child;
-  }
-
-  if (lastChild) {
-    if (lastChild->IsHTMLBr())
-      Document()->UnbindFromDocument(lastChild);
-    else
-      AppendChild(lastChild);
-  }
-}
-
-////////////////////////////////////////////////////////////////////////////////
 // Protected members
 
 void
 DocAccessible::NotifyOfLoading(bool aIsReloading)
 {
   // Mark the document accessible as loading, if it stays alive then we'll mark
   // it as loaded when we receive proper notification.
   mLoadState &= ~eDOMLoaded;
@@ -1514,24 +1449,18 @@ DocAccessible::NotifyOfLoading(bool aIsR
 void
 DocAccessible::DoInitialUpdate()
 {
   if (nsCoreUtils::IsTabDocument(mDocumentNode))
     mDocFlags |= eTabDocument;
 
   mLoadState |= eTreeConstructed;
 
-  // The content element may be changed before the initial update and then we
-  // miss the notification (since content tree change notifications are ignored
-  // prior to initial update). Make sure the content element is valid.
-  nsIContent* contentElm = nsCoreUtils::GetRoleContent(mDocumentNode);
-  if (mContent != contentElm) {
-    mContent = contentElm;
-    SetRoleMapEntry(aria::GetRoleMap(mContent));
-  }
+  // Set up a root element and ARIA role mapping.
+  UpdateRootElIfNeeded();
 
   // Build initial tree.  Since its the initial tree there's no group info to
   // invalidate.
   AutoTreeMutation mut(this, false);
   CacheChildrenInSubtree(this);
 
   // Fire reorder event after the document tree is constructed. Note, since
   // this reorder event is processed by parent document then events targeted to
@@ -1540,17 +1469,17 @@ DocAccessible::DoInitialUpdate()
   if (!IsRoot()) {
     RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(Parent());
     ParentDocument()->FireDelayedEvent(reorderEvent);
   }
 
   uint32_t childCount = ChildCount();
   for (uint32_t i = 0; i < childCount; i++) {
     Accessible* child = GetChildAt(i);
-    RefPtr<AccShowEvent> event = new AccShowEvent(child, child->GetContent());
+    RefPtr<AccShowEvent> event = new AccShowEvent(child);
   FireDelayedEvent(event);
   }
 }
 
 void
 DocAccessible::ProcessLoad()
 {
   mLoadState |= eCompletelyLoaded;
@@ -1630,41 +1559,16 @@ DocAccessible::AddDependentIDsFor(Access
           // content is not accessible then store it to pend its container
           // children invalidation (this happens immediately after the caching
           // is finished).
           nsIContent* dependentContent = iter.GetElem(id);
           if (dependentContent) {
             if (!HasAccessible(dependentContent)) {
               mInvalidationList.AppendElement(dependentContent);
             }
-
-            // Update ARIA owns cache.
-            if (relAttr == nsGkAtoms::aria_owns) {
-              // ARIA owns cannot refer to itself or a parent. Ignore
-              // the element if so.
-              nsIContent* parentEl = relProviderEl;
-              while (parentEl && parentEl != dependentContent) {
-                parentEl = parentEl->GetParent();
-              }
-
-              if (!parentEl) {
-                // ARIA owns element cannot refer to an element in parents chain
-                // of other ARIA owns element (including that ARIA owns element)
-                // if it's inside of a dependent element subtree of that
-                // ARIA owns element. Applied recursively.
-                if (!IsInARIAOwnsLoop(relProviderEl, dependentContent)) {
-                  nsTArray<nsIContent*>* list =
-                    mARIAOwnsHash.LookupOrAdd(aRelProvider);
-                  list->AppendElement(dependentContent);
-
-                  mARIAOwnsInvalidationList.AppendElement(
-                    ARIAOwnsPair(aRelProvider, dependentContent));
-                }
-              }
-            }
           }
         }
       }
     }
 
     // If the relation attribute is given then we don't have anything else to
     // check.
     if (aRelAttr)
@@ -1704,118 +1608,24 @@ DocAccessible::RemoveDependentIDsFor(Acc
           else
             jdx++;
         }
         if (providers->Length() == 0)
           mDependentIDsHash.Remove(id);
       }
     }
 
-    // aria-owns has gone, put the children back.
-    if (relAttr == nsGkAtoms::aria_owns) {
-      nsTArray<nsIContent*>* children = mARIAOwnsHash.Get(aRelProvider);
-      if (children) {
-        nsTArray<RefPtr<Accessible> > containers;
-
-        // Remove ARIA owned elements from where they belonged.
-        RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(aRelProvider);
-        {
-          AutoTreeMutation mut(aRelProvider);
-          for (uint32_t idx = 0; idx < children->Length(); idx++) {
-            nsIContent* childEl = children->ElementAt(idx);
-            Accessible* child = GetAccessible(childEl);
-            if (child && child->IsRepositioned()) {
-              {
-                RefPtr<AccMutationEvent> hideEvent =
-                  new AccHideEvent(child, childEl, false);
-                FireDelayedEvent(hideEvent);
-                reorderEvent->AddSubMutationEvent(hideEvent);
-
-                aRelProvider->RemoveChild(child);
-              }
-
-              // Collect DOM-order containers to update their trees.
-              child->SetRepositioned(false);
-              Accessible* container = GetContainerAccessible(childEl);
-              if (!containers.Contains(container)) {
-                containers.AppendElement(container);
-              }
-            }
-          }
-        }
-
-        mARIAOwnsHash.Remove(aRelProvider);
-        for (uint32_t idx = 0; idx < mARIAOwnsInvalidationList.Length();) {
-          if (mARIAOwnsInvalidationList[idx].mOwner == aRelProvider) {
-            mARIAOwnsInvalidationList.RemoveElementAt(idx);
-            continue;
-          }
-          idx++;
-        }
-
-        MaybeNotifyOfValueChange(aRelProvider);
-        FireDelayedEvent(reorderEvent);
-
-        // Reinserted previously ARIA owned elements into the tree
-        // (restore a DOM-like order).
-        for (uint32_t idx = 0; idx < containers.Length(); idx++) {
-          if (containers[idx]->IsInDocument()) {
-            UpdateTreeOnInsertion(containers[idx]);
-          }
-        }
-      }
-    }
-
     // If the relation attribute is given then we don't have anything else to
     // check.
     if (aRelAttr)
       break;
   }
 }
 
 bool
-DocAccessible::IsInARIAOwnsLoop(nsIContent* aOwnerEl, nsIContent* aDependentEl)
-{
-  // ARIA owns element cannot refer to an element in parents chain of other ARIA
-  // owns element (including that ARIA owns element) if it's inside of
-  // a dependent element subtree of that ARIA owns element.
-  for (auto it = mARIAOwnsHash.Iter(); !it.Done(); it.Next()) {
-    Accessible* otherOwner = it.Key();
-    nsIContent* parentEl = otherOwner->GetContent();
-    while (parentEl && parentEl != aDependentEl) {
-      parentEl = parentEl->GetParent();
-    }
-
-    // The dependent element of this ARIA owns element contains some other ARIA
-    // owns element, make sure this ARIA owns element is not in a subtree of
-    // a dependent element of that other ARIA owns element. If not then
-    // continue a check recursively.
-    if (parentEl) {
-      nsTArray<nsIContent*>* childEls = it.UserData();
-      for (uint32_t idx = 0; idx < childEls->Length(); idx++) {
-        nsIContent* childEl = childEls->ElementAt(idx);
-        nsIContent* parentEl = aOwnerEl;
-        while (parentEl && parentEl != childEl) {
-          parentEl = parentEl->GetParent();
-        }
-        if (parentEl) {
-          return true;
-        }
-
-        if (IsInARIAOwnsLoop(aOwnerEl, childEl)) {
-          return true;
-        }
-      }
-    }
-  }
-
-  return false;
-}
-
-bool
 DocAccessible::UpdateAccessibleOnAttrChange(dom::Element* aElement,
                                             nsIAtom* aAttribute)
 {
   if (aAttribute == nsGkAtoms::role) {
     // It is common for js libraries to set the role on the body element after
     // the document has loaded. In this case we just update the role map entry.
     if (mContent == aElement) {
       SetRoleMapEntry(aria::GetRoleMap(aElement));
@@ -1873,31 +1683,28 @@ DocAccessible::ProcessContentInserted(Ac
 
     Accessible* container =
       GetContainerAccessible(aInsertedContent->ElementAt(idx));
     if (container != aContainer)
       continue;
 
     if (container == this) {
       // If new root content has been inserted then update it.
-      nsIContent* rootContent = nsCoreUtils::GetRoleContent(mDocumentNode);
-      if (rootContent != mContent) {
-        mContent = rootContent;
-        SetRoleMapEntry(aria::GetRoleMap(mContent));
-      }
+      UpdateRootElIfNeeded();
 
       // Continue to update the tree even if we don't have root content.
       // For example, elements may be inserted under the document element while
       // there is no HTML body element.
     }
 
-    // HTML comboboxes have no-content list accessible as an intermidiate
+    // HTML comboboxes have no-content list accessible as an intermediate
     // containing all options.
-    if (container->IsHTMLCombobox())
+    if (container && container->IsHTMLCombobox()) {
       container = container->FirstChild();
+    }
 
     // We have a DOM/layout change under the container accessible, and its tree
     // might need an update. Since DOM/layout change of the element may affect
     // on the accessibleness of adjacent elements (for example, insertion of
     // extra HTML:body make the old body accessible) then we have to recache
     // children of the container, and then fire show/hide events for a change.
     UpdateTreeOnInsertion(container);
     break;
@@ -1941,32 +1748,26 @@ DocAccessible::UpdateTreeOnInsertion(Acc
   }
 
   // Content insertion/removal is not cause of accessible tree change.
   if (updateFlags == eNoAccessible)
     return;
 
   // Check to see if change occurred inside an alert, and fire an EVENT_ALERT
   // if it did.
-  if (!(updateFlags & eAlertAccessible)) {
-    // XXX: tree traversal is perf issue, accessible should know if they are
-    // children of alert accessible to avoid this.
+  if (!(updateFlags & eAlertAccessible) &&
+      (aContainer->IsAlert() || aContainer->IsInsideAlert())) {
     Accessible* ancestor = aContainer;
-    while (ancestor) {
-      if (ancestor->ARIARole() == roles::ALERT) {
+    do {
+      if (ancestor->IsAlert()) {
         FireDelayedEvent(nsIAccessibleEvent::EVENT_ALERT, ancestor);
         break;
       }
-
-      // Don't climb above this document.
-      if (ancestor == this)
-        break;
-
-      ancestor = ancestor->Parent();
     }
+    while ((ancestor = ancestor->Parent()));
   }
 
   MaybeNotifyOfValueChange(aContainer);
   FireDelayedEvent(reorderEvent);
 }
 
 void
 DocAccessible::UpdateTreeOnRemoval(Accessible* aContainer, nsIContent* aChildNode)
@@ -1989,52 +1790,22 @@ DocAccessible::UpdateTreeOnRemoval(Acces
 
   uint32_t updateFlags = eNoAccessible;
   RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(aContainer);
   AutoTreeMutation mut(aContainer);
 
   if (child) {
     updateFlags |= UpdateTreeInternal(child, false, reorderEvent);
   } else {
-    // aChildNode may not coorespond to a particular accessible, to handle
-    // this we go through all the children of aContainer.  Then if a child
-    // has aChildNode as an ancestor, or does not have the node for
-    // aContainer as an ancestor remove that child of aContainer.  Note that
-    // when we are called aChildNode may already have been removed from the DOM
-    // so we can't expect it to have a parent or what was it's parent to have
-    // it as a child.
-    nsINode* containerNode = aContainer->GetNode();
-    for (uint32_t idx = 0; idx < aContainer->ContentChildCount();) {
-      Accessible* child = aContainer->ContentChildAt(idx);
-
-      // If accessible doesn't have its own content then we assume parent
-      // will handle its update.  If child is DocAccessible then we don't
-      // handle updating it here either.
-      if (!child->HasOwnContent() || child->IsDoc()) {
-        idx++;
-        continue;
-      }
-
-      nsINode* childNode = child->GetContent();
-      while (childNode != aChildNode && childNode != containerNode &&
-             (childNode = childNode->GetParentNode()));
-
-      if (childNode != containerNode) {
-        updateFlags |= UpdateTreeInternal(child, false, reorderEvent);
-      } else {
-        idx++;
-      }
+    TreeWalker walker(aContainer, aChildNode, TreeWalker::eWalkCache);
+    while (Accessible* child = walker.Next()) {
+      updateFlags |= UpdateTreeInternal(child, false, reorderEvent);
     }
   }
 
-  // We may not have an integral DOM tree to remove all aria-owns relations
-  // from the tree. Validate all relations after timeout to workaround that.
-  mNotificationController->ScheduleNotification<DocAccessible>
-    (this, &DocAccessible::ValidateARIAOwned);
-
   // Content insertion/removal is not cause of accessible tree change.
   if (updateFlags == eNoAccessible)
     return;
 
   MaybeNotifyOfValueChange(aContainer);
   FireDelayedEvent(reorderEvent);
 }
 
@@ -2045,17 +1816,16 @@ DocAccessible::UpdateTreeInternal(Access
   uint32_t updateFlags = eAccessible;
 
   // If a focused node has been shown then it could mean its frame was recreated
   // while the node stays focused and we need to fire focus event on
   // the accessible we just created. If the queue contains a focus event for
   // this node already then it will be suppressed by this one.
   Accessible* focusedAcc = nullptr;
 
-  nsINode* node = aChild->GetNode();
   if (aIsInsert) {
     // Create accessible tree for shown accessible.
     CacheChildrenInSubtree(aChild, &focusedAcc);
 
   } else {
     // Fire menupopup end event before hide event if a menu goes away.
 
     // XXX: We don't look into children of hidden subtree to find hiding
@@ -2067,19 +1837,19 @@ DocAccessible::UpdateTreeInternal(Access
     // handling.
     if (aChild->ARIARole() == roles::MENUPOPUP)
       FireDelayedEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END, aChild);
   }
 
   // Fire show/hide event.
   RefPtr<AccMutationEvent> event;
   if (aIsInsert)
-    event = new AccShowEvent(aChild, node);
+    event = new AccShowEvent(aChild);
   else
-    event = new AccHideEvent(aChild, node);
+    event = new AccHideEvent(aChild);
 
   FireDelayedEvent(event);
   aReorderEvent->AddSubMutationEvent(event);
 
   if (aIsInsert) {
     roles::Role ariaRole = aChild->ARIARole();
     if (ariaRole == roles::MENUPOPUP) {
       // Fire EVENT_MENUPOPUP_START if ARIA menu appears.
@@ -2109,30 +1879,284 @@ DocAccessible::UpdateTreeInternal(Access
     FocusMgr()->DispatchFocusEvent(this, focusedAcc);
     SelectionMgr()->SetControlSelectionListener(focusedAcc->GetNode()->AsElement());
   }
 
   return updateFlags;
 }
 
 void
+DocAccessible::RelocateARIAOwnedIfNeeded(nsIContent* aElement)
+{
+  if (!aElement->HasID())
+    return;
+
+  AttrRelProviderArray* list =
+    mDependentIDsHash.Get(nsDependentAtomString(aElement->GetID()));
+  if (list) {
+    for (uint32_t idx = 0; idx < list->Length(); idx++) {
+      if (list->ElementAt(idx)->mRelAttr == nsGkAtoms::aria_owns) {
+        Accessible* owner = GetAccessible(list->ElementAt(idx)->mContent);
+        if (owner) {
+          mNotificationController->ScheduleRelocation(owner);
+        }
+      }
+    }
+  }
+}
+
+void
 DocAccessible::ValidateARIAOwned()
 {
   for (auto it = mARIAOwnsHash.Iter(); !it.Done(); it.Next()) {
-    nsTArray<nsIContent*>* childEls = it.UserData();
-    for (uint32_t idx = 0; idx < childEls->Length(); idx++) {
-      nsIContent* childEl = childEls->ElementAt(idx);
-      Accessible* child = GetAccessible(childEl);
-      if (child && child->IsInDocument() && !child->GetFrame()) {
-        if (!child->Parent()) {
-          NS_ERROR("An element in the document doesn't have a parent?");
-          continue;
-        }
-        UpdateTreeOnRemoval(child->Parent(), childEl);
+    Accessible* owner = it.Key();
+    nsTArray<RefPtr<Accessible> >* children = it.UserData();
+
+    // Owner is about to die, put children back if applicable.
+    if (!mAccessibleCache.GetWeak(reinterpret_cast<void*>(owner)) ||
+        !owner->IsInDocument()) {
+      PutChildrenBack(children, 0);
+      it.Remove();
+      continue;
+    }
+
+    for (uint32_t idx = 0; idx < children->Length(); idx++) {
+      Accessible* child = children->ElementAt(idx);
+      if (!child->IsInDocument()) {
+        children->RemoveElementAt(idx);
+        idx--;
+        continue;
+      }
+
+      NS_ASSERTION(child->Parent(), "No parent for ARIA owned?");
+
+      // If DOM node doesn't have a frame anymore then shutdown its accessible.
+      if (child->Parent() && !child->GetFrame()) {
+        UpdateTreeOnRemoval(child->Parent(), child->GetContent());
+        children->RemoveElementAt(idx);
+        idx--;
+        continue;
+      }
+
+      NS_ASSERTION(child->Parent() == owner,
+                   "Illigally stolen ARIA owned child!");
+    }
+
+    if (children->Length() == 0) {
+      it.Remove();
+    }
+  }
+}
+
+void
+DocAccessible::DoARIAOwnsRelocation(Accessible* aOwner)
+{
+  nsTArray<RefPtr<Accessible> >* children = mARIAOwnsHash.LookupOrAdd(aOwner);
+
+  MOZ_ASSERT(aOwner, "aOwner must be a valid pointer");
+  MOZ_ASSERT(aOwner->Elm(), "aOwner->Elm() must be a valid pointer");
+
+  IDRefsIterator iter(this, aOwner->Elm(), nsGkAtoms::aria_owns);
+  Accessible* child = nullptr;
+
+  uint32_t arrayIdx = 0, insertIdx = aOwner->ChildCount() - children->Length();
+  while ((child = iter.Next())) {
+    // Same child on same position, no change.
+    if (child->Parent() == aOwner &&
+        child->IndexInParent() == static_cast<int32_t>(insertIdx)) {
+      NS_ASSERTION(child == children->ElementAt(arrayIdx), "Not in sync!");
+      insertIdx++; arrayIdx++;
+      continue;
+    }
+
+    NS_ASSERTION(children->SafeElementAt(arrayIdx) != child, "Already in place!");
+
+    nsTArray<RefPtr<Accessible> >::index_type idx = children->IndexOf(child);
+    if (idx < arrayIdx) {
+      continue; // ignore second entry of same ID
+    }
+
+    // A new child is found, check for loops.
+    if (child->Parent() != aOwner) {
+      Accessible* parent = aOwner;
+      while (parent && parent != child && !parent->IsDoc()) {
+        parent = parent->Parent();
+      }
+      // A referred child cannot be a parent of the owner.
+      if (parent == child) {
+        continue;
+      }
+    }
+
+    if (child->Parent() == aOwner) {
+      if (child->IsRelocated()) {
+        children->RemoveElement(child);
       }
+      MoveChild(child, insertIdx);
+      children->InsertElementAt(arrayIdx, child);
+      arrayIdx++;
+      insertIdx = child->IndexInParent() + 1;
+
+    } else if (SeizeChild(aOwner, child, insertIdx)) {
+      children->InsertElementAt(arrayIdx, child);
+      insertIdx++; arrayIdx++;
+    }
+  }
+
+  // Put back children that are not seized anymore.
+  PutChildrenBack(children, arrayIdx);
+  if (children->Length() == 0) {
+    mARIAOwnsHash.Remove(aOwner);
+  }
+}
+
+bool
+DocAccessible::SeizeChild(Accessible* aNewParent, Accessible* aChild,
+                          int32_t aIdxInParent)
+{
+  Accessible* oldParent = aChild->Parent();
+  if (!oldParent) {
+    NS_ERROR("No parent? The tree is broken!");
+    return false;
+  }
+
+  int32_t oldIdxInParent = aChild->IndexInParent();
+
+#ifdef A11Y_LOG
+  logging::TreeInfo("aria owns seize child", 0,
+                    "old parent", oldParent, "new parent", aNewParent,
+                    "child", aChild, nullptr);
+#endif
+
+  RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(oldParent);
+  RefPtr<AccMutationEvent> hideEvent = new AccHideEvent(aChild, false);
+  reorderEvent->AddSubMutationEvent(hideEvent);
+
+  {
+    AutoTreeMutation mut(oldParent);
+    oldParent->RemoveChild(aChild);
+  }
+
+  bool isReinserted = false;
+  {
+    AutoTreeMutation mut(aNewParent);
+    isReinserted = aNewParent->InsertChildAt(aIdxInParent, aChild);
+  }
+
+#ifdef A11Y_LOG
+    logging::TreeInfo("aria owns seize child: new parent tree after",
+                      logging::eVerbose, aNewParent);
+#endif
+
+  if (!isReinserted) {
+    AutoTreeMutation mut(oldParent);
+    oldParent->InsertChildAt(oldIdxInParent, aChild);
+    return false;
+  }
+
+  // The child may be stolen from other ARIA owns element.
+  if (aChild->IsRelocated()) {
+    nsTArray<RefPtr<Accessible> >* children = mARIAOwnsHash.Get(oldParent);
+    children->RemoveElement(aChild);
+  }
+
+  FireDelayedEvent(hideEvent);
+  MaybeNotifyOfValueChange(oldParent);
+  FireDelayedEvent(reorderEvent);
+
+  reorderEvent = new AccReorderEvent(aNewParent);
+  RefPtr<AccMutationEvent> showEvent = new AccShowEvent(aChild);
+  reorderEvent->AddSubMutationEvent(showEvent);
+
+  FireDelayedEvent(showEvent);
+  MaybeNotifyOfValueChange(aNewParent);
+  FireDelayedEvent(reorderEvent);
+
+  aChild->SetRelocated(true);
+  return true;
+}
+
+void
+DocAccessible::MoveChild(Accessible* aChild, int32_t aIdxInParent)
+{
+  NS_PRECONDITION(aChild->Parent(), "No parent?");
+
+  Accessible* parent = aChild->Parent();
+  RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(parent);
+  RefPtr<AccMutationEvent> hideEvent = new AccHideEvent(aChild, false);
+  reorderEvent->AddSubMutationEvent(hideEvent);
+
+#ifdef A11Y_LOG
+  logging::TreeInfo("aria owns move child", 0,
+                    "parent", parent, "child", aChild, nullptr);
+#endif
+
+  AutoTreeMutation mut(parent);
+  parent->MoveChild(aIdxInParent, aChild);
+  aChild->SetRelocated(true);
+
+#ifdef A11Y_LOG
+  logging::TreeInfo("aria owns move child: parent tree after",
+                    logging::eVerbose, parent);
+#endif
+
+  FireDelayedEvent(hideEvent);
+
+  RefPtr<AccMutationEvent> showEvent = new AccShowEvent(aChild);
+  reorderEvent->AddSubMutationEvent(showEvent);
+  FireDelayedEvent(showEvent);
+
+  MaybeNotifyOfValueChange(parent);
+  FireDelayedEvent(reorderEvent);
+}
+
+void
+DocAccessible::PutChildrenBack(nsTArray<RefPtr<Accessible> >* aChildren,
+                               uint32_t aStartIdx)
+{
+  nsTArray<RefPtr<Accessible> > containers;
+  for (auto idx = aStartIdx; idx < aChildren->Length(); idx++) {
+    Accessible* child = aChildren->ElementAt(idx);
+
+    // If the child is in the tree then remove it from the owner.
+    if (child->IsInDocument()) {
+      Accessible* owner = child->Parent();
+      if (!owner) {
+        NS_ERROR("Cannot put the child back. No parent, a broken tree.");
+        continue;
+      }
+      RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(owner);
+      RefPtr<AccMutationEvent> hideEvent = new AccHideEvent(child, false);
+      reorderEvent->AddSubMutationEvent(hideEvent);
+      FireDelayedEvent(hideEvent);
+
+      {
+        AutoTreeMutation mut(owner);
+        owner->RemoveChild(child);
+        child->SetRelocated(false);
+      }
+
+      MaybeNotifyOfValueChange(owner);
+      FireDelayedEvent(reorderEvent);
+    }
+
+    Accessible* container = GetContainerAccessible(child->GetContent());
+    if (container &&
+        containers.IndexOf(container) == nsTArray<Accessible*>::NoIndex) {
+      containers.AppendElement(container);
+    }
+  }
+
+  // And put it back where it belongs to.
+  aChildren->RemoveElementsAt(aStartIdx, aChildren->Length() - aStartIdx);
+  for (uint32_t idx = 0; idx < containers.Length(); idx++) {
+    NS_ASSERTION(containers[idx]->IsInDocument(),
+                 "A container has been destroyed.");
+    if (containers[idx]->IsInDocument()) {
+      UpdateTreeOnInsertion(containers[idx]);
     }
   }
 }
 
 void
 DocAccessible::CacheChildrenInSubtree(Accessible* aRoot,
                                       Accessible** aFocusedAcc)
 {
--- a/accessible/generic/DocAccessible.h
+++ b/accessible/generic/DocAccessible.h
@@ -45,18 +45,17 @@ class DocAccessible : public HyperTextAc
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DocAccessible, Accessible)
 
   NS_DECL_NSIOBSERVER
   NS_DECL_NSIACCESSIBLEPIVOTOBSERVER
 
 public:
 
-  DocAccessible(nsIDocument* aDocument, nsIContent* aRootContent,
-                nsIPresShell* aPresShell);
+  DocAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell);
 
   // nsIScrollPositionListener
   virtual void ScrollPositionWillChange(nscoord aX, nscoord aY) override {}
   virtual void ScrollPositionDidChange(nscoord aX, nscoord aY) override;
 
   // nsIDocumentObserver
   NS_DECL_NSIDOCUMENTOBSERVER
 
@@ -281,23 +280,19 @@ public:
    */
   Accessible* GetAccessibleOrDescendant(nsINode* aNode) const;
 
   /**
    * Returns aria-owns seized child at the given index.
    */
   Accessible* ARIAOwnedAt(Accessible* aParent, uint32_t aIndex) const
   {
-    nsTArray<nsIContent*>* childrenEl = mARIAOwnsHash.Get(aParent);
-    if (childrenEl) {
-      nsIContent* childEl = childrenEl->SafeElementAt(aIndex);
-      Accessible* child = GetAccessible(childEl);
-      if (child && child->IsRepositioned()) {
-        return child;
-      }
+    nsTArray<RefPtr<Accessible> >* children = mARIAOwnsHash.Get(aParent);
+    if (children) {
+      return children->SafeElementAt(aIndex);
     }
     return nullptr;
   }
 
   /**
    * Return true if the given ID is referred by relation attribute.
    *
    * @note Different elements may share the same ID if they are hosted inside
@@ -358,19 +353,16 @@ public:
    */
   DocAccessibleChild* IPCDoc() const { return mIPCDoc; }
 
 protected:
   virtual ~DocAccessible();
 
   void LastRelease();
 
-  // Accessible
-  virtual void CacheChildren() override;
-
   // DocAccessible
   virtual nsresult AddEventListeners();
   virtual nsresult RemoveEventListeners();
 
   /**
    * Marks this document as loaded or loading.
    */
   void NotifyOfLoad(uint32_t aLoadEventType);
@@ -380,16 +372,21 @@ protected:
 
   /**
    * Perform initial update (create accessible tree).
    * Can be overridden by wrappers to prepare initialization work.
    */
   virtual void DoInitialUpdate();
 
   /**
+   * Updates root element and picks up ARIA role on it if any.
+   */
+  void UpdateRootElIfNeeded();
+
+  /**
    * Process document load notification, fire document load and state busy
    * events if applicable.
    */
   void ProcessLoad();
 
   /**
    * Add/remove scroll listeners, @see nsIScrollPositionListener interface.
    */
@@ -432,22 +429,16 @@ protected:
    *
    * @param aRelProvider [in] accessible that element has relation attribute
    * @param aRelAttr     [in, optional] relation attribute
    */
   void RemoveDependentIDsFor(Accessible* aRelProvider,
                              nsIAtom* aRelAttr = nullptr);
 
   /**
-   * Return true if given ARIA owner element and its referred content make
-   * the loop closed.
-   */
-  bool IsInARIAOwnsLoop(nsIContent* aOwnerEl, nsIContent* aDependentEl);
-
-  /**
    * Update or recreate an accessible depending on a changed attribute.
    *
    * @param aElement   [in] the element the attribute was changed on
    * @param aAttribute [in] the changed attribute
    * @return            true if an action was taken on the attribute change
    */
   bool UpdateAccessibleOnAttrChange(mozilla::dom::Element* aElement,
                                     nsIAtom* aAttribute);
@@ -509,21 +500,48 @@ protected:
     eAccessible = 1,
     eAlertAccessible = 2
   };
 
   uint32_t UpdateTreeInternal(Accessible* aChild, bool aIsInsert,
                               AccReorderEvent* aReorderEvent);
 
   /**
+   * Schedule ARIA owned element relocation if needed.
+   */
+  void RelocateARIAOwnedIfNeeded(nsIContent* aEl);
+
+  /**
    * Validates all aria-owns connections and updates the tree accordingly.
    */
   void ValidateARIAOwned();
 
   /**
+   * Steals or puts back accessible subtrees.
+   */
+  void DoARIAOwnsRelocation(Accessible* aOwner);
+
+  /**
+   * Moves the child from old parent under new one.
+   */
+  bool SeizeChild(Accessible* aNewParent, Accessible* aChild,
+                  int32_t aIdxInParent);
+
+  /**
+   * Move the child under same parent.
+   */
+  void MoveChild(Accessible* aChild, int32_t aIdxInParent);
+
+  /**
+   * Moves children back under their original parents.
+   */
+  void PutChildrenBack(nsTArray<RefPtr<Accessible> >* aChildren,
+                       uint32_t aStartIdx);
+
+  /**
    * Create accessible tree.
    *
    * @param aRoot       [in] a root of subtree to create
    * @param aFocusedAcc [in, optional] a focused accessible under created
    *                      subtree if any
    */
   void CacheChildrenInSubtree(Accessible* aRoot,
                               Accessible** aFocusedAcc = nullptr);
@@ -644,54 +662,39 @@ protected:
     nsCOMPtr<nsIContent> mContent;
 
   private:
     AttrRelProvider();
     AttrRelProvider(const AttrRelProvider&);
     AttrRelProvider& operator =(const AttrRelProvider&);
   };
 
-  typedef nsTArray<nsAutoPtr<AttrRelProvider> > AttrRelProviderArray;
-  typedef nsClassHashtable<nsStringHashKey, AttrRelProviderArray>
-    DependentIDsHashtable;
-
   /**
    * The cache of IDs pointed by relation attributes.
    */
-  DependentIDsHashtable mDependentIDsHash;
+  typedef nsTArray<nsAutoPtr<AttrRelProvider> > AttrRelProviderArray;
+  nsClassHashtable<nsStringHashKey, AttrRelProviderArray>
+    mDependentIDsHash;
 
   friend class RelatedAccIterator;
 
   /**
    * Used for our caching algorithm. We store the list of nodes that should be
    * invalidated.
    *
    * @see ProcessInvalidationList
    */
   nsTArray<nsIContent*> mInvalidationList;
 
   /**
-   * Holds a list of aria-owns relations.
+   * Holds a list of aria-owns relocations.
    */
-  nsClassHashtable<nsPtrHashKey<Accessible>, nsTArray<nsIContent*> >
+  nsClassHashtable<nsPtrHashKey<Accessible>, nsTArray<RefPtr<Accessible> > >
     mARIAOwnsHash;
 
-  struct ARIAOwnsPair {
-    ARIAOwnsPair(Accessible* aOwner, nsIContent* aChild) :
-      mOwner(aOwner), mChild(aChild) { }
-    ARIAOwnsPair(const ARIAOwnsPair& aPair) :
-      mOwner(aPair.mOwner), mChild(aPair.mChild) { }
-    ARIAOwnsPair& operator =(const ARIAOwnsPair& aPair)
-      { mOwner = aPair.mOwner; mChild = aPair.mChild; return *this; }
-
-    RefPtr<Accessible> mOwner;
-    nsCOMPtr<nsIContent> mChild;
-  };
-  nsTArray<ARIAOwnsPair> mARIAOwnsInvalidationList;
-
   /**
    * Used to process notification from core and accessible events.
    */
   RefPtr<NotificationController> mNotificationController;
   friend class EventQueue;
   friend class NotificationController;
 
 private:
--- a/accessible/generic/HyperTextAccessible.cpp
+++ b/accessible/generic/HyperTextAccessible.cpp
@@ -279,17 +279,17 @@ HyperTextAccessible::DOMPointToOffset(ns
     }
 
     descendant = mDoc->GetAccessible(findNode);
     if (!descendant && findNode->IsContent()) {
       Accessible* container = mDoc->GetContainerAccessible(findNode);
       if (container) {
         TreeWalker walker(container, findNode->AsContent(),
                           TreeWalker::eWalkContextTree);
-        descendant = walker.NextChild();
+        descendant = walker.Next();
         if (!descendant)
           descendant = container;
       }
     }
   }
 
   return TransformOffset(descendant, offset, aIsEndOffset);
 }
@@ -403,25 +403,33 @@ HyperTextAccessible::OffsetToDOMPoint(in
 
   int32_t childIdx = GetChildIndexAtOffset(aOffset);
   if (childIdx == -1)
     return DOMPoint();
 
   Accessible* child = GetChildAt(childIdx);
   int32_t innerOffset = aOffset - GetChildOffset(childIdx);
 
-  // A text leaf case. The point is inside the text node.
+  // A text leaf case.
   if (child->IsTextLeaf()) {
-    nsIContent* content = child->GetContent();
-    int32_t idx = 0;
-    if (NS_FAILED(RenderedToContentOffset(content->GetPrimaryFrame(),
-                                          innerOffset, &idx)))
-      return DOMPoint();
+    // The point is inside the text node. This is always true for any text leaf
+    // except a last child one. See assertion below.
+    if (aOffset < GetChildOffset(childIdx + 1)) {
+      nsIContent* content = child->GetContent();
+      int32_t idx = 0;
+      if (NS_FAILED(RenderedToContentOffset(content->GetPrimaryFrame(),
+                                            innerOffset, &idx)))
+        return DOMPoint();
 
-    return DOMPoint(content, idx);
+      return DOMPoint(content, idx);
+    }
+
+    // Set the DOM point right after the text node.
+    MOZ_ASSERT(static_cast<uint32_t>(aOffset) == CharacterCount());
+    innerOffset = 1;
   }
 
   // Case of embedded object. The point is either before or after the element.
   NS_ASSERTION(innerOffset == 0 || innerOffset == 1, "A wrong inner offset!");
   nsINode* node = child->GetNode();
   nsINode* parentNode = node->GetParentNode();
   return parentNode ?
     DOMPoint(parentNode, parentNode->IndexOf(node) + innerOffset) :
@@ -1355,17 +1363,17 @@ HyperTextAccessible::SetSelectionRange(i
   if (isFocusable)
     return NS_OK;
 
   nsFocusManager* DOMFocusManager = nsFocusManager::GetFocusManager();
   if (DOMFocusManager) {
     NS_ENSURE_TRUE(mDoc, NS_ERROR_FAILURE);
     nsIDocument* docNode = mDoc->DocumentNode();
     NS_ENSURE_TRUE(docNode, NS_ERROR_FAILURE);
-    nsCOMPtr<nsPIDOMWindow> window = docNode->GetWindow();
+    nsCOMPtr<nsPIDOMWindowOuter> window = docNode->GetWindow();
     nsCOMPtr<nsIDOMElement> result;
     DOMFocusManager->MoveFocus(window, nullptr, nsIFocusManager::MOVEFOCUS_CARET,
                                nsIFocusManager::FLAG_BYMOVEFOCUS, getter_AddRefs(result));
   }
 
   return NS_OK;
 }
 
@@ -1461,17 +1469,17 @@ HyperTextAccessible::CaretLineNumber()
     if (hyperTextContent == caretFrame->GetContent()) {
       return lineNumber; // Must be in a single line hyper text, there is no line iterator
     }
     nsContainerFrame *parentFrame = caretFrame->GetParent();
     if (!parentFrame)
       break;
 
     // Add lines for the sibling frames before the caret
-    nsIFrame *sibling = parentFrame->GetFirstPrincipalChild();
+    nsIFrame *sibling = parentFrame->PrincipalChildList().FirstChild();
     while (sibling && sibling != caretFrame) {
       nsAutoLineIterator lineIterForSibling = sibling->GetLineIterator();
       if (lineIterForSibling) {
         // For the frames before that grab all the lines
         int32_t addLines = lineIterForSibling->GetNumLines();
         lineNumber += addLines;
       }
       sibling = sibling->GetNextSibling();
@@ -1489,44 +1497,44 @@ HyperTextAccessible::CaretLineNumber()
 
     caretFrame = parentFrame;
   }
 
   NS_NOTREACHED("DOM ancestry had this hypertext but frame ancestry didn't");
   return lineNumber;
 }
 
-nsIntRect
+LayoutDeviceIntRect
 HyperTextAccessible::GetCaretRect(nsIWidget** aWidget)
 {
   *aWidget = nullptr;
 
   RefPtr<nsCaret> caret = mDoc->PresShell()->GetCaret();
-  NS_ENSURE_TRUE(caret, nsIntRect());
+  NS_ENSURE_TRUE(caret, LayoutDeviceIntRect());
 
   bool isVisible = caret->IsVisible();
   if (!isVisible)
-    return nsIntRect();
+    return LayoutDeviceIntRect();
 
   nsRect rect;
   nsIFrame* frame = caret->GetGeometry(&rect);
   if (!frame || rect.IsEmpty())
-    return nsIntRect();
+    return LayoutDeviceIntRect();
 
   nsPoint offset;
   // Offset from widget origin to the frame origin, which includes chrome
   // on the widget.
   *aWidget = frame->GetNearestWidget(offset);
-  NS_ENSURE_TRUE(*aWidget, nsIntRect());
+  NS_ENSURE_TRUE(*aWidget, LayoutDeviceIntRect());
   rect.MoveBy(offset);
 
-  nsIntRect caretRect;
-  caretRect = rect.ToOutsidePixels(frame->PresContext()->AppUnitsPerDevPixel());
+  LayoutDeviceIntRect caretRect = LayoutDeviceIntRect::FromUnknownRect(
+    rect.ToOutsidePixels(frame->PresContext()->AppUnitsPerDevPixel()));
   // ((content screen origin) - (content offset in the widget)) = widget origin on the screen
-  caretRect.MoveBy((*aWidget)->WidgetToScreenOffsetUntyped() - (*aWidget)->GetClientOffset());
+  caretRect.MoveBy((*aWidget)->WidgetToScreenOffset() - (*aWidget)->GetClientOffset());
 
   // Correct for character size, so that caret always matches the size of
   // the character. This is important for font size transitions, and is
   // necessary because the Gecko caret uses the previous character's size as
   // the user moves forward in the text by character.
   nsIntRect charRect = CharBounds(CaretOffset(),
                                   nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE);
   if (!charRect.IsEmpty()) {
@@ -1764,17 +1772,17 @@ HyperTextAccessible::EnclosingRange(a11y
   } else {
     aRange.Set(mDoc, mDoc, 0, mDoc, mDoc->CharacterCount());
   }
 }
 
 void
 HyperTextAccessible::SelectionRanges(nsTArray<a11y::TextRange>* aRanges) const
 {
-  NS_ASSERTION(aRanges->Length() != 0, "TextRange array supposed to be empty");
+  MOZ_ASSERT(aRanges->Length() == 0, "TextRange array supposed to be empty");
 
   dom::Selection* sel = DOMSelection();
   if (!sel)
     return;
 
   aRanges->SetCapacity(sel->RangeCount());
 
   for (uint32_t idx = 0; idx < sel->RangeCount(); idx++) {
@@ -1930,41 +1938,16 @@ HyperTextAccessible::RelationByType(Rela
       break;
     default:
       break;
   }
 
   return rel;
 }
 
-void
-HyperTextAccessible::CacheChildren()
-{
-  // Trailing HTML br element don't play any difference. We don't need to expose
-  // it to AT (see bug https://bugzilla.mozilla.org/show_bug.cgi?id=899433#c16
-  // for details).
-
-  TreeWalker walker(this, mContent);
-  Accessible* child = nullptr;
-  Accessible* lastChild = nullptr;
-  while ((child = walker.NextChild())) {
-    if (lastChild)
-      AppendChild(lastChild);
-
-    lastChild = child;
-  }
-
-  if (lastChild) {
-    if (lastChild->IsHTMLBr())
-      Document()->UnbindFromDocument(lastChild);
-    else
-      AppendChild(lastChild);
-  }
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // HyperTextAccessible public static
 
 nsresult
 HyperTextAccessible::ContentToRenderedOffset(nsIFrame* aFrame, int32_t aContentOffset,
                                              uint32_t* aRenderedOffset) const
 {
   if (!aFrame) {
@@ -1979,27 +1962,20 @@ HyperTextAccessible::ContentToRenderedOf
     return NS_OK;
   }
 
   NS_ASSERTION(aFrame->GetType() == nsGkAtoms::textFrame,
                "Need text frame for offset conversion");
   NS_ASSERTION(aFrame->GetPrevContinuation() == nullptr,
                "Call on primary frame only");
 
-  gfxSkipChars skipChars;
-  gfxSkipCharsIterator iter;
-  // Only get info up to original offset, we know that will be larger than skipped offset
-  nsresult rv = aFrame->GetRenderedText(nullptr, &skipChars, &iter, 0, aContentOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  uint32_t ourRenderedStart = iter.GetSkippedOffset();
-  int32_t ourContentStart = iter.GetOriginalOffset();
-
-  *aRenderedOffset = iter.ConvertOriginalToSkipped(aContentOffset + ourContentStart) -
-                    ourRenderedStart;
+  nsIFrame::RenderedText text = aFrame->GetRenderedText(aContentOffset,
+      aContentOffset + 1, nsIFrame::TextOffsetType::OFFSETS_IN_CONTENT_TEXT,
+      nsIFrame::TrailingWhitespace::DONT_TRIM_TRAILING_WHITESPACE);
+  *aRenderedOffset = text.mOffsetWithinNodeRenderedText;
 
   return NS_OK;
 }
 
 nsresult
 HyperTextAccessible::RenderedToContentOffset(nsIFrame* aFrame, uint32_t aRenderedOffset,
                                              int32_t* aContentOffset) const
 {
@@ -2011,26 +1987,20 @@ HyperTextAccessible::RenderedToContentOf
   *aContentOffset = 0;
   NS_ENSURE_TRUE(aFrame, NS_ERROR_FAILURE);
 
   NS_ASSERTION(aFrame->GetType() == nsGkAtoms::textFrame,
                "Need text frame for offset conversion");
   NS_ASSERTION(aFrame->GetPrevContinuation() == nullptr,
                "Call on primary frame only");
 
-  gfxSkipChars skipChars;
-  gfxSkipCharsIterator iter;
-  // We only need info up to skipped offset -- that is what we're converting to original offset
-  nsresult rv = aFrame->GetRenderedText(nullptr, &skipChars, &iter, 0, aRenderedOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  uint32_t ourRenderedStart = iter.GetSkippedOffset();
-  int32_t ourContentStart = iter.GetOriginalOffset();
-
-  *aContentOffset = iter.ConvertSkippedToOriginal(aRenderedOffset + ourRenderedStart) - ourContentStart;
+  nsIFrame::RenderedText text = aFrame->GetRenderedText(aRenderedOffset,
+      aRenderedOffset + 1, nsIFrame::TextOffsetType::OFFSETS_IN_RENDERED_TEXT,
+      nsIFrame::TrailingWhitespace::DONT_TRIM_TRAILING_WHITESPACE);
+  *aContentOffset = text.mOffsetWithinNodeText;
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // HyperTextAccessible public
 
 int32_t
--- a/accessible/generic/HyperTextAccessible.h
+++ b/accessible/generic/HyperTextAccessible.h
@@ -253,17 +253,17 @@ public:
   /**
    * Return text offset of the given child accessible within hypertext
    * accessible.
    *
    * @param  aChild           [in] accessible child to get text offset for
    * @param  aInvalidateAfter [in, optional] indicates whether invalidate
    *                           cached offsets for next siblings of the child
    */
-  int32_t GetChildOffset(Accessible* aChild,
+  int32_t GetChildOffset(const Accessible* aChild,
                          bool aInvalidateAfter = false) const
   {
     int32_t index = GetIndexOf(aChild);
     return index == -1 ? -1 : GetChildOffset(index, aInvalidateAfter);
   }
 
   /**
    * Return text offset for the child accessible index.
@@ -330,17 +330,17 @@ public:
 
   /**
    * Return the caret rect and the widget containing the caret within this
    * text accessible.
    *
    * @param [out] the widget containing the caret
    * @return      the caret rect
    */
-  nsIntRect GetCaretRect(nsIWidget** aWidget);
+  mozilla::LayoutDeviceIntRect GetCaretRect(nsIWidget** aWidget);
 
   /**
    * Return selected regions count within the accessible.
    */
   int32_t SelectionCount();
 
   /**
    * Return the start and end offset of the specified selection.
@@ -429,17 +429,16 @@ public:
    */
   dom::Selection* DOMSelection() const;
 
 protected:
   virtual ~HyperTextAccessible() { }
 
   // Accessible
   virtual ENameValueFlag NativeName(nsString& aName) override;
-  virtual void CacheChildren() override;
 
   // HyperTextAccessible
 
   /**
    * Transform magic offset into text offset.
    */
   index_t ConvertMagicOffset(int32_t aOffset) const;
 
--- a/accessible/generic/ImageAccessible.cpp
+++ b/accessible/generic/ImageAccessible.cpp
@@ -127,21 +127,21 @@ ImageAccessible::DoAction(uint8_t aIndex
   if (!uri)
     return false;
 
   nsAutoCString utf8spec;
   uri->GetSpec(utf8spec);
   NS_ConvertUTF8toUTF16 spec(utf8spec);
 
   nsIDocument* document = mContent->OwnerDoc();
-  nsCOMPtr<nsPIDOMWindow> piWindow = document->GetWindow();
+  nsCOMPtr<nsPIDOMWindowOuter> piWindow = document->GetWindow();
   if (!piWindow)
     return false;
 
-  nsCOMPtr<nsPIDOMWindow> tmp;
+  nsCOMPtr<nsPIDOMWindowOuter> tmp;
   return NS_SUCCEEDED(piWindow->Open(spec, EmptyString(), EmptyString(),
                                      getter_AddRefs(tmp)));
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // ImageAccessible
 
 nsIntPoint
--- a/accessible/generic/RootAccessible.cpp
+++ b/accessible/generic/RootAccessible.cpp
@@ -54,19 +54,18 @@ using namespace mozilla::dom;
 // nsISupports
 
 NS_IMPL_ISUPPORTS_INHERITED0(RootAccessible, DocAccessible)
 
 ////////////////////////////////////////////////////////////////////////////////
 // Constructor/destructor
 
 RootAccessible::
-  RootAccessible(nsIDocument* aDocument, nsIContent* aRootContent,
-                 nsIPresShell* aPresShell) :
-  DocAccessibleWrap(aDocument, aRootContent, aPresShell)
+  RootAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell) :
+  DocAccessibleWrap(aDocument, aPresShell)
 {
   mType = eRootType;
 }
 
 RootAccessible::~RootAccessible()
 {
 }
 
@@ -447,18 +446,20 @@ RootAccessible::ProcessDOMEvent(nsIDOMEv
     FocusMgr()->ActiveItemChanged(nullptr);
 #ifdef A11Y_LOG
     if (logging::IsEnabled(logging::eFocus))
       logging::ActiveItemChangeCausedBy("DOMMenuBarInactive", accessible);
 #endif
   }
   else if (accessible->NeedsDOMUIEvent() &&
            eventType.EqualsLiteral("ValueChange")) {
-     targetDocument->FireDelayedEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
-                                      accessible);
+    uint32_t event = accessible->HasNumericValue()
+      ? nsIAccessibleEvent::EVENT_VALUE_CHANGE
+      : nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE;
+     targetDocument->FireDelayedEvent(event, accessible);
   }
 #ifdef DEBUG_DRAGDROPSTART
   else if (eventType.EqualsLiteral("mouseover")) {
     nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_DRAGDROP_START,
                             accessible);
   }
 #endif
 }
@@ -478,22 +479,20 @@ RootAccessible::Shutdown()
 }
 
 Relation
 RootAccessible::RelationByType(RelationType aType)
 {
   if (!mDocumentNode || aType != RelationType::EMBEDS)
     return DocAccessibleWrap::RelationByType(aType);
 
-  nsPIDOMWindow* rootWindow = mDocumentNode->GetWindow();
-  if (rootWindow) {
-    nsCOMPtr<nsIDOMWindow> contentWindow = nsGlobalWindow::Cast(rootWindow)->GetContent();
-    nsCOMPtr<nsPIDOMWindow> piWindow = do_QueryInterface(contentWindow);
-    if (piWindow) {
-      nsCOMPtr<nsIDocument> contentDocumentNode = piWindow->GetDoc();
+  if (nsPIDOMWindowOuter* rootWindow = mDocumentNode->GetWindow()) {
+    nsCOMPtr<nsPIDOMWindowOuter> contentWindow = nsGlobalWindow::Cast(rootWindow)->GetContent();
+    if (contentWindow) {
+      nsCOMPtr<nsIDocument> contentDocumentNode = contentWindow->GetDoc();
       if (contentDocumentNode) {
         DocAccessible* contentDocument =
           GetAccService()->GetDocAccessible(contentDocumentNode);
         if (contentDocument)
           return Relation(contentDocument);
       }
     }
   }
--- a/accessible/generic/RootAccessible.h
+++ b/accessible/generic/RootAccessible.h
@@ -17,18 +17,17 @@ namespace mozilla {
 namespace a11y {
 
 class RootAccessible : public DocAccessibleWrap,
                        public nsIDOMEventListener
 {
   NS_DECL_ISUPPORTS_INHERITED
 
 public:
-  RootAccessible(nsIDocument* aDocument, nsIContent* aRootContent,
-                 nsIPresShell* aPresShell);
+  RootAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell);
 
   // nsIDOMEventListener
   NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) override;
 
   // Accessible
   virtual void Shutdown() override;
   virtual mozilla::a11y::ENameValueFlag Name(nsString& aName) override;
   virtual Relation RelationByType(RelationType aType) override;
--- a/accessible/html/HTMLElementAccessibles.cpp
+++ b/accessible/html/HTMLElementAccessibles.cpp
@@ -63,23 +63,49 @@ HTMLLabelAccessible::NativeName(nsString
   return aName.IsEmpty() ? eNameOK : eNameFromSubtree;
 }
 
 Relation
 HTMLLabelAccessible::RelationByType(RelationType aType)
 {
   Relation rel = AccessibleWrap::RelationByType(aType);
   if (aType == RelationType::LABEL_FOR) {
-    RefPtr<dom::HTMLLabelElement> label = dom::HTMLLabelElement::FromContent(mContent);
+    dom::HTMLLabelElement* label = dom::HTMLLabelElement::FromContent(mContent);
     rel.AppendTarget(mDoc, label->GetControl());
   }
 
   return rel;
 }
 
+uint8_t
+HTMLLabelAccessible::ActionCount()
+{
+  return nsCoreUtils::IsLabelWithControl(mContent) ? 1 : 0;
+}
+
+void
+HTMLLabelAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
+{
+  if (aIndex == 0) {
+    if (nsCoreUtils::IsLabelWithControl(mContent))
+      aName.AssignLiteral("click");
+  }
+}
+
+bool
+HTMLLabelAccessible::DoAction(uint8_t aIndex)
+{
+  if (aIndex != 0)
+    return false;
+
+  DoCommand();
+  return true;
+}
+
+
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLOuputAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 NS_IMPL_ISUPPORTS_INHERITED0(HTMLOutputAccessible, HyperTextAccessible)
 
 Relation
 HTMLOutputAccessible::RelationByType(RelationType aType)
--- a/accessible/html/HTMLElementAccessibles.h
+++ b/accessible/html/HTMLElementAccessibles.h
@@ -57,16 +57,21 @@ public:
   HTMLLabelAccessible(nsIContent* aContent, DocAccessible* aDoc) :
     HyperTextAccessibleWrap(aContent, aDoc) {}
 
   NS_DECL_ISUPPORTS_INHERITED
 
   // Accessible
   virtual Relation RelationByType(RelationType aType) override;
 
+  // ActionAccessible
+  virtual uint8_t ActionCount() override;
+  virtual void ActionNameAt(uint8_t aIndex, nsAString& aName) override;
+  virtual bool DoAction(uint8_t aIndex) override;
+
 protected:
   virtual ~HTMLLabelAccessible() {}
   virtual ENameValueFlag NativeName(nsString& aName) override;
 };
 
 /**
  * Used for HTML output element.
  */
--- a/accessible/html/HTMLImageMapAccessible.cpp
+++ b/accessible/html/HTMLImageMapAccessible.cpp
@@ -104,29 +104,28 @@ HTMLImageMapAccessible::UpdateChildAreas
     RemoveChild(area);
     treeChanged = true;
   }
 
   // Insert new areas into the tree.
   uint32_t areaElmCount = imageMapObj->AreaCount();
   for (uint32_t idx = 0; idx < areaElmCount; idx++) {
     nsIContent* areaContent = imageMapObj->GetAreaAt(idx);
-
     Accessible* area = mChildren.SafeElementAt(idx);
     if (!area || area->GetContent() != areaContent) {
       RefPtr<Accessible> area = new HTMLAreaAccessible(areaContent, mDoc);
-      mDoc->BindToDocument(area, aria::GetRoleMap(areaContent));
+      mDoc->BindToDocument(area, aria::GetRoleMap(areaContent->AsElement()));
 
       if (!InsertChildAt(idx, area)) {
         mDoc->UnbindFromDocument(area);
         break;
       }
 
       if (aDoFireEvents) {
-        RefPtr<AccShowEvent> event = new AccShowEvent(area, areaContent);
+        RefPtr<AccShowEvent> event = new AccShowEvent(area);
         mDoc->FireDelayedEvent(event);
         reorderEvent->AddSubMutationEvent(event);
       }
 
       treeChanged = true;
     }
   }
 
--- a/accessible/html/HTMLListAccessible.cpp
+++ b/accessible/html/HTMLListAccessible.cpp
@@ -106,17 +106,17 @@ HTMLLIAccessible::UpdateBullet(bool aHas
   AutoTreeMutation mut(this);
 
   DocAccessible* document = Document();
   if (aHasBullet) {
     mBullet = new HTMLListBulletAccessible(mContent, mDoc);
     document->BindToDocument(mBullet, nullptr);
     InsertChildAt(0, mBullet);
 
-    RefPtr<AccShowEvent> event = new AccShowEvent(mBullet, mBullet->GetContent());
+    RefPtr<AccShowEvent> event = new AccShowEvent(mBullet);
     mDoc->FireDelayedEvent(event);
     reorderEvent->AddSubMutationEvent(event);
   } else {
     RefPtr<AccHideEvent> event = new AccHideEvent(mBullet, mBullet->GetContent());
     mDoc->FireDelayedEvent(event);
     reorderEvent->AddSubMutationEvent(event);
 
     RemoveChild(mBullet);
--- a/accessible/html/HTMLSelectAccessible.cpp
+++ b/accessible/html/HTMLSelectAccessible.cpp
@@ -109,45 +109,22 @@ HTMLSelectListAccessible::CurrentItem()
 void
 HTMLSelectListAccessible::SetCurrentItem(Accessible* aItem)
 {
   aItem->GetContent()->SetAttr(kNameSpaceID_None,
                                nsGkAtoms::selected, NS_LITERAL_STRING("true"),
                                true);
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// HTMLSelectListAccessible: Accessible protected
-
-void
-HTMLSelectListAccessible::CacheChildren()
+bool
+HTMLSelectListAccessible::IsAcceptableChild(nsIContent* aEl) const
 {
-  // Cache accessibles for <optgroup> and <option> DOM decendents as children,
-  // as well as the accessibles for them. Avoid whitespace text nodes. We want
-  // to count all the <optgroup>s and <option>s as children because we want
-  // a flat tree under the Select List.
-  for (nsIContent* childContent = mContent->GetFirstChild(); childContent;
-       childContent = childContent->GetNextSibling()) {
-    if (!childContent->IsHTMLElement()) {
-      continue;
-    }
-
-    if (childContent->IsAnyOfHTMLElements(nsGkAtoms::option,
-                                          nsGkAtoms::optgroup)) {
-
-      // Get an accessible for option or optgroup and cache it.
-      RefPtr<Accessible> accessible =
-        GetAccService()->GetOrCreateAccessible(childContent, this);
-      if (accessible)
-        AppendChild(accessible);
-    }
-  }
+  return aEl->IsAnyOfHTMLElements(nsGkAtoms::option, nsGkAtoms::optgroup);
 }
 
-
 ////////////////////////////////////////////////////////////////////////////////
 // HTMLSelectOptionAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 HTMLSelectOptionAccessible::
   HTMLSelectOptionAccessible(nsIContent* aContent, DocAccessible* aDoc) :
   HyperTextAccessibleWrap(aContent, aDoc)
 {
--- a/accessible/html/HTMLSelectAccessible.h
+++ b/accessible/html/HTMLSelectAccessible.h
@@ -46,20 +46,17 @@ public:
 
   // Widgets
   virtual bool IsWidget() const override;
   virtual bool IsActiveWidget() const override;
   virtual bool AreItemsOperable() const override;
   virtual Accessible* CurrentItem() override;
   virtual void SetCurrentItem(Accessible* aItem) override;
 
-protected:
-
-  // Accessible
-  virtual void CacheChildren() override;
+  virtual bool IsAcceptableChild(nsIContent* aEl) const override;
 };
 
 /*
  * Options inside the select, contained within the list
  */
 class HTMLSelectOptionAccessible : public HyperTextAccessibleWrap
 {
 public:
--- a/accessible/html/HTMLTableAccessible.cpp
+++ b/accessible/html/HTMLTableAccessible.cpp
@@ -388,34 +388,24 @@ HTMLTableRowAccessible::GroupPosition()
 // HTMLTableAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 NS_IMPL_ISUPPORTS_INHERITED0(HTMLTableAccessible, Accessible)
 
 ////////////////////////////////////////////////////////////////////////////////
 // HTMLTableAccessible: Accessible
 
-void
-HTMLTableAccessible::CacheChildren()
+bool
+HTMLTableAccessible::InsertChildAt(uint32_t aIndex, Accessible* aChild)
 {
   // Move caption accessible so that it's the first child. Check for the first
   // caption only, because nsAccessibilityService ensures we don't create
   // accessibles for the other captions, since only the first is actually
   // visible.
-  TreeWalker walker(this, mContent);
-
-  Accessible* child = nullptr;
-  while ((child = walker.NextChild())) {
-    if (child->Role() == roles::CAPTION) {
-      InsertChildAt(0, child);
-      while ((child = walker.NextChild()) && AppendChild(child));
-      break;
-    }
-    AppendChild(child);
-  }
+  return Accessible::InsertChildAt(aChild->IsHTMLCaption() ? 0 : aIndex, aChild);
 }
 
 role
 HTMLTableAccessible::NativeRole()
 {
   if (mContent->IsMathMLElement(nsGkAtoms::mtable_)) {
     return roles::MATHML_TABLE;
   }
--- a/accessible/html/HTMLTableAccessible.h
+++ b/accessible/html/HTMLTableAccessible.h
@@ -152,22 +152,23 @@ public:
   // Accessible
   virtual TableAccessible* AsTable() override { return this; }
   virtual void Description(nsString& aDescription) override;
   virtual a11y::role NativeRole() override;
   virtual uint64_t NativeState() override;
   virtual already_AddRefed<nsIPersistentProperties> NativeAttributes() override;
   virtual Relation RelationByType(RelationType aRelationType) override;
 
+  bool InsertChildAt(uint32_t aIndex, Accessible* aChild) override;
+
 protected:
   virtual ~HTMLTableAccessible() {}
 
   // Accessible
   virtual ENameValueFlag NativeName(nsString& aName) override;
-  virtual void CacheChildren() override;
 
   // HTMLTableAccessible
 
   /**
    * Add row or column to selection.
    *
    * @param aIndex   [in] index of row or column to be selected
    * @param aTarget  [in] indicates what should be selected, either row or column
@@ -204,17 +205,17 @@ protected:
 
 /**
  * HTML caption accessible (html:caption).
  */
 class HTMLCaptionAccessible : public HyperTextAccessibleWrap
 {
 public:
   HTMLCaptionAccessible(nsIContent* aContent, DocAccessible* aDoc) :
-    HyperTextAccessibleWrap(aContent, aDoc) { }
+    HyperTextAccessibleWrap(aContent, aDoc) { mType = eHTMLCaptionType; }
 
   // Accessible
   virtual a11y::role NativeRole() override;
   virtual Relation RelationByType(RelationType aRelationType) override;
 
 protected:
   virtual ~HTMLCaptionAccessible() { }
 };
--- a/accessible/interfaces/ia2/Makefile.in
+++ b/accessible/interfaces/ia2/Makefile.in
@@ -6,16 +6,17 @@ IA2DIR        = $(topsrcdir)/other-licen
 
 GARBAGE       += $(MIDL_GENERATED_FILES)
 
 # Please keep this list in sync with the moz.build file until the rest of this
 # Makefile is ported over.
 MIDL_INTERFACES = \
   Accessible2.idl \
   Accessible2_2.idl \
+  Accessible2_3.idl \
   AccessibleAction.idl \
   AccessibleApplication.idl \
   AccessibleComponent.idl \
   AccessibleDocument.idl \
   AccessibleEditableText.idl \
   AccessibleHyperlink.idl \
   AccessibleHypertext.idl \
   AccessibleHypertext2.idl \
--- a/accessible/interfaces/ia2/moz.build
+++ b/accessible/interfaces/ia2/moz.build
@@ -12,8 +12,16 @@ DEFFILE = SRCDIR + '/IA2Marshal.def'
 
 OS_LIBS += [
     'uuid',
     'kernel32',
     'rpcrt4',
     'ole32',
     'oleaut32',
 ]
+
+# The Windows MIDL code generator creates things like:
+#
+#   #endif !_MIDL_USE_GUIDDEF_
+#
+# which clang-cl complains about.  MSVC doesn't, so turn this warning off.
+if CONFIG['CLANG_CL']:
+    CXXFLAGS += ['-Wno-extra-tokens']
--- a/accessible/interfaces/msaa/moz.build
+++ b/accessible/interfaces/msaa/moz.build
@@ -20,8 +20,16 @@ DEFINES['REGISTER_PROXY_DLL'] = True
 
 DEFFILE = SRCDIR + '/AccessibleMarshal.def'
 
 OS_LIBS += [
     'kernel32',
     'rpcrt4',
     'oleaut32',
 ]
+
+# The Windows MIDL code generator creates things like:
+#
+#   #endif !_MIDL_USE_GUIDDEF_
+#
+# which clang-cl complains about.  MSVC doesn't, so turn this warning off.
+if CONFIG['CLANG_CL']:
+    CFLAGS += ['-Wno-extra-tokens']
--- a/accessible/interfaces/nsIAccessibleCaretMoveEvent.idl
+++ b/accessible/interfaces/nsIAccessibleCaretMoveEvent.idl
@@ -3,16 +3,16 @@
  * 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 "nsIAccessibleEvent.idl"
 
 /**
  * Fired when the caret changes position in text.
  */
-[scriptable, builtinclass, uuid(5675c486-a230-4d85-a4bd-33670826d5ff)]
+[scriptable, builtinclass, uuid(ed1982e4-57d7-41a8-8cd8-9023f809383e)]
 interface nsIAccessibleCaretMoveEvent: nsIAccessibleEvent
 {
   /**
    * Return caret offset.
    */
   readonly attribute long caretOffset;
 };
--- a/accessible/interfaces/nsIAccessibleDocument.idl
+++ b/accessible/interfaces/nsIAccessibleDocument.idl
@@ -2,29 +2,29 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsIAccessiblePivot;
 interface nsIDOMDocument;
-interface nsIDOMWindow;
+interface mozIDOMWindowProxy;
 
 /**
  * An interface for in-process accessibility clients
  * that wish to retrieve information about a document.
  * When accessibility is turned on in Gecko,
  * there is an nsIAccessibleDocument for each document
  * whether it is XUL, HTML or whatever.
  * You can QueryInterface to nsIAccessibleDocument from the nsIAccessible for
  * the root node of a document or you can get one from
  * nsIAccessible::GetDocument().
  */
-[scriptable, uuid(2be938df-0210-4609-9ece-26b197a517e5)]
+[scriptable, uuid(5cad5f91-fcce-40e7-913e-4671701d19b4)]
 interface nsIAccessibleDocument : nsISupports
 {
   /**
    * The URL of the document
    */
   readonly attribute AString URL;
 
   /**
@@ -45,17 +45,17 @@ interface nsIAccessibleDocument : nsISup
   /**
    * The nsIDOMDocument interface associated with this document.
    */
   readonly attribute nsIDOMDocument DOMDocument;
 
   /**
    * The nsIDOMWindow that the document resides in.
    */
-  readonly attribute nsIDOMWindow window;
+  readonly attribute mozIDOMWindowProxy window;
 
   /**
    * Return the parent document accessible.
    */
   readonly attribute nsIAccessibleDocument parentDocument;
 
   /**
    * Return the count of child document accessibles.
--- a/accessible/interfaces/nsIAccessibleEvent.idl
+++ b/accessible/interfaces/nsIAccessibleEvent.idl
@@ -20,17 +20,17 @@ interface nsIDOMNode;
  * the event and its target. To listen to in-process accessibility invents,
  * make your object an nsIObserver, and listen for accessible-event by 
  * using code something like this:
  *   nsCOMPtr<nsIObserverService> observerService = 
  *     do_GetService("@mozilla.org/observer-service;1", &rv);
  *   if (NS_SUCCEEDED(rv)) 
  *     rv = observerService->AddObserver(this, "accessible-event", PR_TRUE);
  */
-[scriptable, builtinclass, uuid(7f66a33a-9ed7-4fd4-87a8-e431b0f43368)]
+[scriptable, builtinclass, uuid(20c69a40-6c2c-42a3-a578-6f4473aab9dd)]
 interface nsIAccessibleEvent : nsISupports
 {
   /**
    * An object has been created.
    */
   const unsigned long EVENT_SHOW = 0x0001;
 
   /**
@@ -70,17 +70,17 @@ interface nsIAccessibleEvent : nsISuppor
   const unsigned long EVENT_NAME_CHANGE = 0x0008;
 
   /**
    * An object's Description property has changed.
    */
   const unsigned long EVENT_DESCRIPTION_CHANGE = 0x0009;
 
   /**
-   * An object's Value property has changed.
+   * An object's numeric Value has changed.
    */
   const unsigned long EVENT_VALUE_CHANGE = 0x000A;
 
   /**
    * An object's help has changed.
    */
   const unsigned long EVENT_HELP_CHANGE = 0x000B;
 
@@ -408,19 +408,24 @@ interface nsIAccessibleEvent : nsISuppor
   const unsigned long EVENT_OBJECT_ATTRIBUTE_CHANGED = 0x0055;
 
   /**
    * A cursorable's virtual cursor has changed.
    */
   const unsigned long EVENT_VIRTUALCURSOR_CHANGED = 0x0056;
 
   /**
+   * An object's text Value has changed.
+   */
+  const unsigned long EVENT_TEXT_VALUE_CHANGE = 0x0057;
+
+  /**
    * Help make sure event map does not get out-of-line.
    */
-  const unsigned long EVENT_LAST_ENTRY = 0x0057;
+  const unsigned long EVENT_LAST_ENTRY = 0x0058;
 
   /**
    * The type of event, based on the enumerated event values
    * defined in this interface.
    */
   readonly attribute unsigned long eventType;
   
   /**
--- a/accessible/interfaces/nsIAccessibleHideEvent.idl
+++ b/accessible/interfaces/nsIAccessibleHideEvent.idl
@@ -3,17 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIAccessibleEvent.idl"
 
 /**
  * Fired when a accessible and its subtree are removed from the tree.
  */
-[scriptable, builtinclass, uuid(a2bd2eca-3afa-489b-afb2-f93ef32ad99c)]
+[scriptable, builtinclass, uuid(2051709a-4e0d-4be5-873d-b49d1dee35fa)]
 interface nsIAccessibleHideEvent: nsIAccessibleEvent
 {
   /**
    * Return an accessible that was a parent of the target.
    */
   readonly attribute nsIAccessible targetParent;
 
   /**
--- a/accessible/interfaces/nsIAccessibleObjectAttributeChangedEvent.idl
+++ b/accessible/interfaces/nsIAccessibleObjectAttributeChangedEvent.idl
@@ -6,16 +6,16 @@
 
 #include "nsIAccessibleEvent.idl"
 
 interface nsIAtom;
 
 /**
  * Fired when an attribute of an accessible changes.
  */
-[scriptable, builtinclass, uuid(4CA96609-23C8-4771-86E7-77C8B651CA24)]
+[scriptable, builtinclass, uuid(ce41add2-096e-4606-b1ca-7408c6d5b4c3)]
 interface nsIAccessibleObjectAttributeChangedEvent : nsIAccessibleEvent
 {
   /**
    * Return the accessible attribute that changed.
    */
   readonly attribute nsIAtom changedAttribute;
 };
--- a/accessible/interfaces/nsIAccessibleRetrieval.idl
+++ b/accessible/interfaces/nsIAccessibleRetrieval.idl
@@ -4,17 +4,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsIDOMNode;
 interface nsIAccessible;
 interface nsIWeakReference;
 interface nsIPresShell;
-interface nsIDOMWindow;
 interface nsIAccessiblePivot;
 
 /**
  * An interface for in-process accessibility clients wishing to get an
  * nsIAccessible for a given DOM node.  More documentation at:
  *   http://www.mozilla.org/projects/ui/accessibility
  */
 [scriptable, uuid(17f86615-1a3d-4021-b227-3a2ef5cbffd8)]
--- a/accessible/interfaces/nsIAccessibleStateChangeEvent.idl
+++ b/accessible/interfaces/nsIAccessibleStateChangeEvent.idl
@@ -3,17 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIAccessibleEvent.idl"
 
 /**
  * Fired when a state of an accessible changes.
  */
-[scriptable, builtinclass, uuid(0d2d77c5-7b16-4a15-8b20-c484ceb5ac0d)]
+[scriptable, builtinclass, uuid(58b74954-1835-46ed-9ccd-c906490106f6)]
 interface nsIAccessibleStateChangeEvent : nsIAccessibleEvent
 {
   /**
    * Returns the state of accessible (see constants declared
    * in nsIAccessibleStates).
    */
   readonly attribute unsigned long state;
 
--- a/accessible/interfaces/nsIAccessibleTableChangeEvent.idl
+++ b/accessible/interfaces/nsIAccessibleTableChangeEvent.idl
@@ -1,16 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIAccessibleEvent.idl"
 
-[scriptable, builtinclass, uuid(df517997-ed52-4ea2-b310-2f8e0fe64572)]
+[scriptable, builtinclass, uuid(9fb3a8a4-d254-43d3-80a5-20e171d52b21)]
 interface nsIAccessibleTableChangeEvent: nsIAccessibleEvent
 {
   /**
    * Return the row or column index.
    */
   readonly attribute long rowOrColIndex;
 
   /**
--- a/accessible/interfaces/nsIAccessibleTextChangeEvent.idl
+++ b/accessible/interfaces/nsIAccessibleTextChangeEvent.idl
@@ -3,17 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIAccessibleEvent.idl"
 
 /**
  * Fired when an accessible's text changes.
  */
-[scriptable, builtinclass, uuid(21e0f8bd-5638-4964-870b-3c8e944ac4c4)]
+[scriptable, builtinclass, uuid(1fcc0dfa-93e6-48f4-bbd4-f80eb1d9f2e6)]
 interface nsIAccessibleTextChangeEvent : nsIAccessibleEvent
 {
   /**
    * Returns offset of changed text in accessible.
    */
   readonly attribute long start;
 
   /**
--- a/accessible/interfaces/nsIAccessibleTextRange.idl
+++ b/accessible/interfaces/nsIAccessibleTextRange.idl
@@ -8,17 +8,17 @@
 interface nsIAccessible;
 interface nsIAccessibleText;
 interface nsIArray;
 interface nsIVariant;
 
 /**
  * A range representing a piece of text in the document.
  */
-[scriptable, uuid(525b3401-8a67-4822-b35d-661065767cd8)]
+[scriptable, uuid(c4515623-55f9-4543-a3d5-c1e9afa588f4)]
 interface nsIAccessibleTextRange : nsISupports
 {
   readonly attribute nsIAccessibleText startContainer;
   readonly attribute long startOffset;
   readonly attribute nsIAccessibleText endContainer;
   readonly attribute long endOffset;
 
   /**
@@ -77,16 +77,21 @@ interface nsIAccessibleTextRange : nsISu
   void moveEnd(in unsigned long aUnit, in long aCount);
 
   /**
    * Normalize the range to the closest unit of the given type.
    */
   void normalize(in unsigned long aUnit);
 
   /**
+   * Crops the range by the given accessible element.
+   */
+  boolean crop(in nsIAccessible aContainer);
+
+  /**
    * Return range enclosing the found text.
    */
   nsIAccessibleTextRange findText(in AString aText, in boolean aIsBackward,
                                   in boolean aIsIgnoreCase);
 
   /**
    * Text attributes. Used in conjunction with findAttrs().
    */
--- a/accessible/interfaces/nsIAccessibleVirtualCursorChangeEvent.idl
+++ b/accessible/interfaces/nsIAccessibleVirtualCursorChangeEvent.idl
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIAccessibleEvent.idl"
 
 /*
  * An interface for virtual cursor changed events.
  * Passes previous cursor position and text offsets.
  */
-[scriptable, builtinclass, uuid(370e8b9b-2bbc-4bff-a9c7-16ddc54aea21)]
+[scriptable, builtinclass, uuid(a58693b1-009e-4cc9-ae93-9c7d8f85cfdf)]
 interface nsIAccessibleVirtualCursorChangeEvent : nsIAccessibleEvent
 {
   /**
    * Previous object pointed at by virtual cursor. null if none.
    */
   readonly attribute nsIAccessible oldAccessible;
 
   /**
--- a/accessible/ipc/DocAccessibleChild.cpp
+++ b/accessible/ipc/DocAccessibleChild.cpp
@@ -368,16 +368,40 @@ DocAccessibleChild::RecvGetLevelInternal
   Accessible* acc = IdToAccessible(aID);
   if (acc) {
     *aLevel = acc->GetLevelInternal();
   }
   return true;
 }
 
 bool
+DocAccessibleChild::RecvScrollTo(const uint64_t& aID,
+                                 const uint32_t& aScrollType)
+{
+  Accessible* acc = IdToAccessible(aID);
+  if (acc) {
+    nsCoreUtils::ScrollTo(acc->Document()->PresShell(), acc->GetContent(),
+                          aScrollType);
+  }
+
+  return true;
+}
+
+bool
+DocAccessibleChild::RecvScrollToPoint(const uint64_t& aID, const uint32_t& aScrollType, const int32_t& aX, const int32_t& aY)
+{
+  Accessible* acc = IdToAccessible(aID);
+  if (acc) {
+    acc->ScrollToPoint(aScrollType, aX, aY);
+  }
+
+  return true;
+}
+
+bool
 DocAccessibleChild::RecvCaretLineNumber(const uint64_t& aID, int32_t* aLineNumber)
 {
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   *aLineNumber = acc && acc->IsTextRole() ? acc->CaretLineNumber() : 0;
   return true;
 }
 
 bool
@@ -1019,17 +1043,17 @@ DocAccessibleChild::RecvRowExtent(const 
 }
 
 bool
 DocAccessibleChild::RecvColHeaderCells(const uint64_t& aID,
                                        nsTArray<uint64_t>* aCells)
 {
   TableCellAccessible* acc = IdToTableCellAccessible(aID);
   if (acc) {
-    nsAutoTArray<Accessible*, 10> headerCells;
+    AutoTArray<Accessible*, 10> headerCells;
     acc->ColHeaderCells(&headerCells);
     aCells->SetCapacity(headerCells.Length());
     for (uint32_t i = 0; i < headerCells.Length(); ++i) {
       aCells->AppendElement(
         reinterpret_cast<uint64_t>(headerCells[i]->UniqueID()));
     }
   }
 
@@ -1037,17 +1061,17 @@ DocAccessibleChild::RecvColHeaderCells(c
 }
 
 bool
 DocAccessibleChild::RecvRowHeaderCells(const uint64_t& aID,
                                        nsTArray<uint64_t>* aCells)
 {
   TableCellAccessible* acc = IdToTableCellAccessible(aID);
   if (acc) {
-    nsAutoTArray<Accessible*, 10> headerCells;
+    AutoTArray<Accessible*, 10> headerCells;
     acc->RowHeaderCells(&headerCells);
     aCells->SetCapacity(headerCells.Length());
     for (uint32_t i = 0; i < headerCells.Length(); ++i) {
       aCells->AppendElement(
         reinterpret_cast<uint64_t>(headerCells[i]->UniqueID()));
     }
   }
 
@@ -1339,17 +1363,17 @@ DocAccessibleChild::RecvTableSelectedRow
 }
 
 bool
 DocAccessibleChild::RecvTableSelectedCells(const uint64_t& aID,
                                            nsTArray<uint64_t>* aCellIDs)
 {
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
-    nsAutoTArray<Accessible*, 30> cells;
+    AutoTArray<Accessible*, 30> cells;
     acc->SelectedCells(&cells);
     aCellIDs->SetCapacity(cells.Length());
     for (uint32_t i = 0; i < cells.Length(); ++i) {
       aCellIDs->AppendElement(
         reinterpret_cast<uint64_t>(cells[i]->UniqueID()));
     }
   }
 
@@ -1500,17 +1524,17 @@ DocAccessibleChild::RecvAtkTableRowHeade
 }
 
 bool
 DocAccessibleChild::RecvSelectedItems(const uint64_t& aID,
                                       nsTArray<uint64_t>* aSelectedItemIDs)
 {
   Accessible* acc = IdToAccessibleSelect(aID);
   if (acc) {
-    nsAutoTArray<Accessible*, 10> selectedItems;
+    AutoTArray<Accessible*, 10> selectedItems;
     acc->SelectedItems(&selectedItems);
     aSelectedItemIDs->SetCapacity(selectedItems.Length());
     for (size_t i = 0; i < selectedItems.Length(); ++i) {
       aSelectedItemIDs->AppendElement(
         reinterpret_cast<uint64_t>(selectedItems[i]->UniqueID()));
     }
   }
 
--- a/accessible/ipc/DocAccessibleChild.h
+++ b/accessible/ipc/DocAccessibleChild.h
@@ -93,16 +93,21 @@ public:
   virtual bool RecvLandmarkRole(const uint64_t& aID, nsString* aLandmark) override;
 
   virtual bool RecvARIARoleAtom(const uint64_t& aID, nsString* aRole) override;
 
   virtual bool RecvGetLevelInternal(const uint64_t& aID, int32_t* aLevel) override;
 
   virtual bool RecvAttributes(const uint64_t& aID,
                               nsTArray<Attribute> *aAttributes) override;
+  virtual bool RecvScrollTo(const uint64_t& aID, const uint32_t& aScrollType)
+    override;
+  virtual bool RecvScrollToPoint(const uint64_t& aID,
+                                 const uint32_t& aScrollType,
+                                 const int32_t& aX, const int32_t& aY) override;
 
   virtual bool RecvCaretLineNumber(const uint64_t& aID, int32_t* aLineNumber)
     override;
   virtual bool RecvCaretOffset(const uint64_t& aID, int32_t* aOffset)
     override;
   virtual bool RecvSetCaretOffset(const uint64_t& aID, const int32_t& aOffset)
     override;
 
--- a/accessible/ipc/DocAccessibleParent.cpp
+++ b/accessible/ipc/DocAccessibleParent.cpp
@@ -4,16 +4,20 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DocAccessibleParent.h"
 #include "nsAutoPtr.h"
 #include "mozilla/a11y/Platform.h"
 #include "ProxyAccessible.h"
 #include "mozilla/dom/TabParent.h"
+#include "xpcAccessibleDocument.h"
+#include "xpcAccEvents.h"
+#include "nsAccUtils.h"
+#include "nsCoreUtils.h"
 
 namespace mozilla {
 namespace a11y {
 
 bool
 DocAccessibleParent::RecvShowEvent(const ShowEventData& aData)
 {
   if (mShutdown)
@@ -139,44 +143,88 @@ DocAccessibleParent::RecvEvent(const uin
 {
   ProxyAccessible* proxy = GetAccessible(aID);
   if (!proxy) {
     NS_ERROR("no proxy for event!");
     return true;
   }
 
   ProxyEvent(proxy, aEventType);
+
+  if (!nsCoreUtils::AccEventObserversExist()) {
+    return true;
+  }
+
+  xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(proxy);
+  xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
+  nsIDOMNode* node = nullptr;
+  bool fromUser = true; // XXX fix me
+  RefPtr<xpcAccEvent> event = new xpcAccEvent(aEventType, xpcAcc, doc, node,
+                                              fromUser);
+  nsCoreUtils::DispatchAccEvent(Move(event));
+
   return true;
 }
 
 bool
 DocAccessibleParent::RecvStateChangeEvent(const uint64_t& aID,
                                           const uint64_t& aState,
                                           const bool& aEnabled)
 {
   ProxyAccessible* target = GetAccessible(aID);
   if (!target) {
     NS_ERROR("we don't know about the target of a state change event!");
     return true;
   }
 
   ProxyStateChangeEvent(target, aState, aEnabled);
+
+  if (!nsCoreUtils::AccEventObserversExist()) {
+    return true;
+  }
+
+  xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(target);
+  xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
+  uint32_t type = nsIAccessibleEvent::EVENT_STATE_CHANGE;
+  bool extra;
+  uint32_t state = nsAccUtils::To32States(aState, &extra);
+  bool fromUser = true; // XXX fix this
+  nsIDOMNode* node = nullptr; // XXX can we do better?
+  RefPtr<xpcAccStateChangeEvent> event =
+    new xpcAccStateChangeEvent(type, xpcAcc, doc, node, fromUser, state, extra,
+                               aEnabled);
+  nsCoreUtils::DispatchAccEvent(Move(event));
+
   return true;
 }
 
 bool
 DocAccessibleParent::RecvCaretMoveEvent(const uint64_t& aID, const int32_t& aOffset)
 {
   ProxyAccessible* proxy = GetAccessible(aID);
   if (!proxy) {
     NS_ERROR("unknown caret move event target!");
     return true;
   }
 
   ProxyCaretMoveEvent(proxy, aOffset);
+
+  if (!nsCoreUtils::AccEventObserversExist()) {
+    return true;
+  }
+
+  xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(proxy);
+  xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
+  nsIDOMNode* node = nullptr;
+  bool fromUser = true; // XXX fix me
+  uint32_t type = nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED;
+  RefPtr<xpcAccCaretMoveEvent> event =
+    new xpcAccCaretMoveEvent(type, xpcAcc, doc, node, fromUser, aOffset);
+  nsCoreUtils::DispatchAccEvent(Move(event));
+
   return true;
 }
 
 bool
 DocAccessibleParent::RecvTextChangeEvent(const uint64_t& aID,
                                          const nsString& aStr,
                                          const int32_t& aStart,
                                          const uint32_t& aLen,
@@ -186,31 +234,45 @@ DocAccessibleParent::RecvTextChangeEvent
   ProxyAccessible* target = GetAccessible(aID);
   if (!target) {
     NS_ERROR("text change event target is unknown!");
     return true;
   }
 
   ProxyTextChangeEvent(target, aStr, aStart, aLen, aIsInsert, aFromUser);
 
+  if (!nsCoreUtils::AccEventObserversExist()) {
+    return true;
+  }
+
+  xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(target);
+  xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
+  uint32_t type = nsIAccessibleEvent::EVENT_TEXT_CHANGED;
+  nsIDOMNode* node = nullptr;
+  RefPtr<xpcAccTextChangeEvent> event =
+    new xpcAccTextChangeEvent(type, xpcAcc, doc, node, aFromUser, aStart, aLen,
+                              aIsInsert, aStr);
+  nsCoreUtils::DispatchAccEvent(Move(event));
+
   return true;
 }
 
 bool
 DocAccessibleParent::RecvBindChildDoc(PDocAccessibleParent* aChildDoc, const uint64_t& aID)
 {
   // One document should never directly be the child of another.
   // We should always have at least an outer doc accessible in between.
   MOZ_ASSERT(aID);
   if (!aID)
     return false;
 
   MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
 
   auto childDoc = static_cast<DocAccessibleParent*>(aChildDoc);
+  childDoc->Unbind();
   bool result = AddChildDoc(childDoc, aID, false);
   MOZ_ASSERT(result);
   MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
   return result;
 }
 
 bool
 DocAccessibleParent::AddChildDoc(DocAccessibleParent* aChildDoc,
@@ -261,16 +323,18 @@ DocAccessibleParent::Destroy()
   for (uint32_t i = childDocCount - 1; i < childDocCount; i--)
     mChildDocs[i]->Destroy();
 
   for (auto iter = mAccessibles.Iter(); !iter.Done(); iter.Next()) {
     MOZ_ASSERT(iter.Get()->mProxy != this);
     ProxyDestroyed(iter.Get()->mProxy);
     iter.Remove();
   }
+
+  DocManager::NotifyOfRemoteDocShutdown(this);
   ProxyDestroyed(this);
   if (mParentDoc)
     mParentDoc->RemoveChildDoc(this);
   else if (IsTopLevel())
     GetAccService()->RemoteDocShutdown(this);
 }
 
 bool
@@ -284,10 +348,18 @@ DocAccessibleParent::CheckDocTree() cons
     if (!mChildDocs[i]->CheckDocTree()) {
       return false;
     }
   }
 
   return true;
 }
 
+xpcAccessibleGeneric*
+DocAccessibleParent::GetXPCAccessible(ProxyAccessible* aProxy)
+{
+  xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
+  MOZ_ASSERT(doc);
+
+  return doc->GetXPCAccessible(aProxy);
+}
 } // a11y
 } // mozilla
--- a/accessible/ipc/DocAccessibleParent.h
+++ b/accessible/ipc/DocAccessibleParent.h
@@ -12,16 +12,18 @@
 #include "mozilla/a11y/PDocAccessibleParent.h"
 #include "nsClassHashtable.h"
 #include "nsHashKeys.h"
 #include "nsISupportsImpl.h"
 
 namespace mozilla {
 namespace a11y {
 
+class xpcAccessibleGeneric;
+
 /*
  * These objects live in the main process and comunicate with and represent
  * an accessible document in a content process.
  */
 class DocAccessibleParent : public ProxyAccessible,
     public PDocAccessibleParent
 {
 public:
@@ -59,17 +61,20 @@ public:
                                    const int32_t& aStart, const uint32_t& aLen,
                                    const bool& aIsInsert,
                                    const bool& aFromUser) override;
 
   virtual bool RecvBindChildDoc(PDocAccessibleParent* aChildDoc, const uint64_t& aID) override;
   void Unbind()
   {
     mParent = nullptr;
-    ParentDoc()->mChildDocs.RemoveElement(this);
+    if (DocAccessibleParent* parent = ParentDoc()) {
+      parent->mChildDocs.RemoveElement(this);
+    }
+
     mParentDoc = nullptr;
   }
 
   virtual bool RecvShutdown() override;
   void Destroy();
   virtual void ActorDestroy(ActorDestroyReason aWhy) override
   {
     MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
@@ -151,16 +156,17 @@ private:
 
     ProxyAccessible* mProxy;
   };
 
   uint32_t AddSubtree(ProxyAccessible* aParent,
                       const nsTArray<AccessibleData>& aNewTree, uint32_t aIdx,
                       uint32_t aIdxInParent);
   MOZ_WARN_UNUSED_RESULT bool CheckDocTree() const;
+  xpcAccessibleGeneric* GetXPCAccessible(ProxyAccessible* aProxy);
 
   nsTArray<DocAccessibleParent*> mChildDocs;
   DocAccessibleParent* mParentDoc;
 
   /*
    * Conceptually this is a map from IDs to proxies, but we store the ID in the
    * proxy object so we can't use a real map.
    */
--- a/accessible/ipc/PDocAccessible.ipdl
+++ b/accessible/ipc/PDocAccessible.ipdl
@@ -43,54 +43,57 @@ struct RelationTargets
   uint64_t[] Targets;
 };
 
 prio(normal upto high) sync protocol PDocAccessible
 {
   manager PBrowser;
 
 parent:
-  Shutdown();
+  async Shutdown();
 
   /*
    * Notify the parent process the document in the child process is firing an
    * event.
    */
-  Event(uint64_t aID, uint32_t type);
-  ShowEvent(ShowEventData data);
-  HideEvent(uint64_t aRootID);
-  StateChangeEvent(uint64_t aID, uint64_t aState, bool aEnabled);
-  CaretMoveEvent(uint64_t aID, int32_t aOffset);
-  TextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart, uint32_t aLen,
-                  bool aIsInsert, bool aFromUser);
+  async Event(uint64_t aID, uint32_t type);
+  async ShowEvent(ShowEventData data);
+  async HideEvent(uint64_t aRootID);
+  async StateChangeEvent(uint64_t aID, uint64_t aState, bool aEnabled);
+  async CaretMoveEvent(uint64_t aID, int32_t aOffset);
+  async TextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart, uint32_t aLen,
+                        bool aIsInsert, bool aFromUser);
 
   /*
    * Tell the parent document to bind the existing document as a new child
    * document.
    */
-  BindChildDoc(PDocAccessible aChildDoc, uint64_t aID);
+  async BindChildDoc(PDocAccessible aChildDoc, uint64_t aID);
 
 child:
-  __delete__();
+  async __delete__();
 
   // Accessible
   prio(high) sync State(uint64_t aID) returns(uint64_t states);
   prio(high) sync NativeState(uint64_t aID) returns(uint64_t states);
   prio(high) sync Name(uint64_t aID) returns(nsString name);
   prio(high) sync Value(uint64_t aID) returns(nsString value);
   prio(high) sync Help(uint64_t aID) returns(nsString help);
   prio(high) sync Description(uint64_t aID) returns(nsString desc);
   prio(high) sync Attributes(uint64_t aID) returns(Attribute[] attributes);
   prio(high) sync RelationByType(uint64_t aID, uint32_t aRelationType)
     returns(uint64_t[] targets);
   prio(high) sync Relations(uint64_t aID) returns(RelationTargets[] relations);
   prio(high) sync IsSearchbox(uint64_t aID) returns(bool retval);
   prio(high) sync LandmarkRole(uint64_t aID) returns(nsString landmark);
   prio(high) sync ARIARoleAtom(uint64_t aID) returns(nsString role);
   prio(high) sync GetLevelInternal(uint64_t aID) returns(int32_t aLevel);
+  async ScrollTo(uint64_t aID, uint32_t aScrollType);
+  async ScrollToPoint(uint64_t aID, uint32_t aScrollType, int32_t aX,
+                      int32_t aY);
 
   // AccessibleText
 
   // TextSubstring is getText in IDL.
   prio(high) sync CaretLineNumber(uint64_t aID) returns(int32_t aLineNumber);
   prio(high) sync CaretOffset(uint64_t aID) returns(int32_t aOffset);
    async SetCaretOffset(uint64_t aID, int32_t aOffset);
   prio(high) sync CharacterCount(uint64_t aID) returns(int32_t aCount);
@@ -124,23 +127,23 @@ child:
   prio(high) sync SetSelectionBoundsAt(uint64_t aID, int32_t aSelectionNum,
                                        int32_t aStartOffset, int32_t aEndOffset)
     returns(bool aSucceeded);
   prio(high) sync AddToSelection(uint64_t aID, int32_t aStartOffset, int32_t aEndOffset)
     returns(bool aSucceeded);
   prio(high) sync RemoveFromSelection(uint64_t aID, int32_t aSelectionNum)
     returns(bool aSucceeded);
 
-  ScrollSubstringTo(uint64_t aID, int32_t aStartOffset, int32_t aEndOffset,
-                    uint32_t aScrollType);
-  ScrollSubstringToPoint(uint64_t aID,
-                         int32_t aStartOffset,
-                         int32_t aEndOffset,
-                         uint32_t aCoordinateType,
-                         int32_t aX, int32_t aY);
+  async ScrollSubstringTo(uint64_t aID, int32_t aStartOffset, int32_t aEndOffset,
+                          uint32_t aScrollType);
+  async ScrollSubstringToPoint(uint64_t aID,
+                               int32_t aStartOffset,
+                               int32_t aEndOffset,
+                               uint32_t aCoordinateType,
+                               int32_t aX, int32_t aY);
 
   prio(high) sync Text(uint64_t aID) returns(nsString aText);
   prio(high) sync ReplaceText(uint64_t aID, nsString aText);
   prio(high) sync InsertText(uint64_t aID, nsString aText, int32_t aPosition)
     returns(bool aValid);
   prio(high) sync CopyText(uint64_t aID, int32_t aStartPos, int32_t aEndPos)
     returns(bool aValid);
   prio(high) sync CutText(uint64_t aID, int32_t aStartPos, int32_t aEndPos)
--- a/accessible/ipc/ProxyAccessible.cpp
+++ b/accessible/ipc/ProxyAccessible.cpp
@@ -9,25 +9,31 @@
 #include "DocAccessible.h"
 #include "mozilla/a11y/DocManager.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/unused.h"
 #include "mozilla/a11y/Platform.h"
 #include "RelationType.h"
 #include "mozilla/a11y/Role.h"
+#include "xpcAccessibleDocument.h"
 
 namespace mozilla {
 namespace a11y {
 
 void
 ProxyAccessible::Shutdown()
 {
   MOZ_DIAGNOSTIC_ASSERT(!IsDoc());
   NS_ASSERTION(!mOuterDoc, "Why do we still have a child doc?");
+  xpcAccessibleDocument* xpcDoc =
+    GetAccService()->GetCachedXPCDocument(Document());
+  if (xpcDoc) {
+    xpcDoc->NotifyOfShutdown(this);
+  }
 
   // XXX Ideally  this wouldn't be necessary, but it seems OuterDoc accessibles
   // can be destroyed before the doc they own.
   if (!mOuterDoc) {
     uint32_t childCount = mChildren.Length();
     for (uint32_t idx = 0; idx < childCount; idx++)
       mChildren[idx]->Shutdown();
   } else {
@@ -75,63 +81,63 @@ ProxyAccessible::MustPruneChildren() con
   return mChildren[0]->Role() == roles::TEXT_LEAF
     || mChildren[0]->Role() == roles::STATICTEXT;
 }
 
 uint64_t
 ProxyAccessible::State() const
 {
   uint64_t state = 0;
-  unused << mDoc->SendState(mID, &state);
+  Unused << mDoc->SendState(mID, &state);
   return state;
 }
 
 uint64_t
 ProxyAccessible::NativeState() const
 {
   uint64_t state = 0;
-  unused << mDoc->SendNativeState(mID, &state);
+  Unused << mDoc->SendNativeState(mID, &state);
   return state;
 }
 
 void
 ProxyAccessible::Name(nsString& aName) const
 {
-  unused << mDoc->SendName(mID, &aName);
+  Unused << mDoc->SendName(mID, &aName);
 }
 
 void
 ProxyAccessible::Value(nsString& aValue) const
 {
-  unused << mDoc->SendValue(mID, &aValue);
+  Unused << mDoc->SendValue(mID, &aValue);
 }
 
 void
 ProxyAccessible::Help(nsString& aHelp) const
 {
-  unused << mDoc->SendHelp(mID, &aHelp);
+  Unused << mDoc->SendHelp(mID, &aHelp);
 }
 
 void
 ProxyAccessible::Description(nsString& aDesc) const
 {
-  unused << mDoc->SendDescription(mID, &aDesc);
+  Unused << mDoc->SendDescription(mID, &aDesc);
 }
 
 void
 ProxyAccessible::Attributes(nsTArray<Attribute> *aAttrs) const
 {
-  unused << mDoc->SendAttributes(mID, aAttrs);
+  Unused << mDoc->SendAttributes(mID, aAttrs);
 }
 
 nsTArray<ProxyAccessible*>
 ProxyAccessible::RelationByType(RelationType aType) const
 {
   nsTArray<uint64_t> targetIDs;
-  unused << mDoc->SendRelationByType(mID, static_cast<uint32_t>(aType),
+  Unused << mDoc->SendRelationByType(mID, static_cast<uint32_t>(aType),
                                      &targetIDs);
 
   size_t targetCount = targetIDs.Length();
   nsTArray<ProxyAccessible*> targets(targetCount);
   for (size_t i = 0; i < targetCount; i++)
     if (ProxyAccessible* proxy = mDoc->GetAccessible(targetIDs[i]))
       targets.AppendElement(proxy);
 
@@ -139,17 +145,17 @@ ProxyAccessible::RelationByType(Relation
 }
 
 void
 ProxyAccessible::Relations(nsTArray<RelationType>* aTypes,
                            nsTArray<nsTArray<ProxyAccessible*>>* aTargetSets)
   const
 {
   nsTArray<RelationTargets> ipcRelations;
-  unused << mDoc->SendRelations(mID, &ipcRelations);
+  Unused << mDoc->SendRelations(mID, &ipcRelations);
 
   size_t relationCount = ipcRelations.Length();
   aTypes->SetCapacity(relationCount);
   aTargetSets->SetCapacity(relationCount);
   for (size_t i = 0; i < relationCount; i++) {
     uint32_t type = ipcRelations[i].Type();
     if (type > static_cast<uint32_t>(RelationType::LAST))
       continue;
@@ -167,977 +173,989 @@ ProxyAccessible::Relations(nsTArray<Rela
     aTypes->AppendElement(static_cast<RelationType>(type));
   }
 }
 
 bool
 ProxyAccessible::IsSearchbox() const
 {
   bool retVal = false;
-  unused << mDoc->SendIsSearchbox(mID, &retVal);
+  Unused << mDoc->SendIsSearchbox(mID, &retVal);
   return retVal;
 }
 
 nsIAtom*
 ProxyAccessible::LandmarkRole() const
 {
   nsString landmark;
-  unused << mDoc->SendLandmarkRole(mID, &landmark);
+  Unused << mDoc->SendLandmarkRole(mID, &landmark);
   return NS_GetStaticAtom(landmark);
 }
 
 nsIAtom*
 ProxyAccessible::ARIARoleAtom() const
 {
   nsString role;
-  unused << mDoc->SendARIARoleAtom(mID, &role);
+  Unused << mDoc->SendARIARoleAtom(mID, &role);
   return NS_GetStaticAtom(role);
 }
 
 int32_t
 ProxyAccessible::GetLevelInternal()
 {
   int32_t level = 0;
-  unused << mDoc->SendGetLevelInternal(mID, &level);
+  Unused << mDoc->SendGetLevelInternal(mID, &level);
   return level;
 }
 
+void
+ProxyAccessible::ScrollTo(uint32_t aScrollType)
+{
+  Unused << mDoc->SendScrollTo(mID, aScrollType);
+}
+
+void
+ProxyAccessible::ScrollToPoint(uint32_t aScrollType, int32_t aX, int32_t aY)
+{
+  Unused << mDoc->SendScrollToPoint(mID, aScrollType, aX, aY);
+}
+
 int32_t
 ProxyAccessible::CaretLineNumber()
 {
   int32_t line = -1;
-  unused << mDoc->SendCaretOffset(mID, &line);
+  Unused << mDoc->SendCaretOffset(mID, &line);
   return line;
 }
 
 int32_t
 ProxyAccessible::CaretOffset()
 {
   int32_t offset = 0;
-  unused << mDoc->SendCaretOffset(mID, &offset);
+  Unused << mDoc->SendCaretOffset(mID, &offset);
   return offset;
 }
 
 void
 ProxyAccessible::SetCaretOffset(int32_t aOffset)
 {
-  unused << mDoc->SendSetCaretOffset(mID, aOffset);
+  Unused << mDoc->SendSetCaretOffset(mID, aOffset);
 }
 
 int32_t
 ProxyAccessible::CharacterCount()
 {
   int32_t count = 0;
-  unused << mDoc->SendCharacterCount(mID, &count);
+  Unused << mDoc->SendCharacterCount(mID, &count);
   return count;
 }
 
 int32_t
 ProxyAccessible::SelectionCount()
 {
   int32_t count = 0;
-  unused << mDoc->SendSelectionCount(mID, &count);
+  Unused << mDoc->SendSelectionCount(mID, &count);
   return count;
 }
 
 bool
 ProxyAccessible::TextSubstring(int32_t aStartOffset, int32_t aEndOfset,
                                nsString& aText) const
 {
   bool valid;
-  unused << mDoc->SendTextSubstring(mID, aStartOffset, aEndOfset, &aText, &valid);
+  Unused << mDoc->SendTextSubstring(mID, aStartOffset, aEndOfset, &aText, &valid);
   return valid;
 }
 
 void
 ProxyAccessible::GetTextAfterOffset(int32_t aOffset,
                                     AccessibleTextBoundary aBoundaryType,
                                     nsString& aText, int32_t* aStartOffset,
                                     int32_t* aEndOffset)
 {
-  unused << mDoc->SendGetTextAfterOffset(mID, aOffset, aBoundaryType,
+  Unused << mDoc->SendGetTextAfterOffset(mID, aOffset, aBoundaryType,
                                          &aText, aStartOffset, aEndOffset);
 }
 
 void
 ProxyAccessible::GetTextAtOffset(int32_t aOffset,
                                  AccessibleTextBoundary aBoundaryType,
                                  nsString& aText, int32_t* aStartOffset,
                                  int32_t* aEndOffset)
 {
-  unused << mDoc->SendGetTextAtOffset(mID, aOffset, aBoundaryType,
+  Unused << mDoc->SendGetTextAtOffset(mID, aOffset, aBoundaryType,
                                       &aText, aStartOffset, aEndOffset);
 }
 
 void
 ProxyAccessible::GetTextBeforeOffset(int32_t aOffset,
                                      AccessibleTextBoundary aBoundaryType,
                                      nsString& aText, int32_t* aStartOffset,
                                      int32_t* aEndOffset)
 {
-  unused << mDoc->SendGetTextBeforeOffset(mID, aOffset, aBoundaryType,
+  Unused << mDoc->SendGetTextBeforeOffset(mID, aOffset, aBoundaryType,
                                           &aText, aStartOffset, aEndOffset);
 }
 
 char16_t
 ProxyAccessible::CharAt(int32_t aOffset)
 {
   uint16_t retval = 0;
-  unused << mDoc->SendCharAt(mID, aOffset, &retval);
+  Unused << mDoc->SendCharAt(mID, aOffset, &retval);
   return static_cast<char16_t>(retval);
 }
 
 void
 ProxyAccessible::TextAttributes(bool aIncludeDefAttrs,
                                 int32_t aOffset,
                                 nsTArray<Attribute>* aAttributes,
                                 int32_t* aStartOffset,
                                 int32_t* aEndOffset)
 {
-  unused << mDoc->SendTextAttributes(mID, aIncludeDefAttrs, aOffset,
+  Unused << mDoc->SendTextAttributes(mID, aIncludeDefAttrs, aOffset,
                                      aAttributes, aStartOffset, aEndOffset);
 }
 
 void
 ProxyAccessible::DefaultTextAttributes(nsTArray<Attribute>* aAttrs)
 {
-  unused << mDoc->SendDefaultTextAttributes(mID, aAttrs);
+  Unused << mDoc->SendDefaultTextAttributes(mID, aAttrs);
 }
 
 nsIntRect
 ProxyAccessible::TextBounds(int32_t aStartOffset, int32_t aEndOffset,
                             uint32_t aCoordType)
 {
   nsIntRect rect;
-  unused <<
+  Unused <<
     mDoc->SendTextBounds(mID, aStartOffset, aEndOffset, aCoordType, &rect);
   return rect;
 }
 
 nsIntRect
 ProxyAccessible::CharBounds(int32_t aOffset, uint32_t aCoordType)
 {
   nsIntRect rect;
-  unused <<
+  Unused <<
     mDoc->SendCharBounds(mID, aOffset, aCoordType, &rect);
   return rect;
 }
 
 int32_t
 ProxyAccessible::OffsetAtPoint(int32_t aX, int32_t aY, uint32_t aCoordType)
 {
   int32_t retVal = -1;
-  unused << mDoc->SendOffsetAtPoint(mID, aX, aY, aCoordType, &retVal);
+  Unused << mDoc->SendOffsetAtPoint(mID, aX, aY, aCoordType, &retVal);
   return retVal;
 }
 
 bool
 ProxyAccessible::SelectionBoundsAt(int32_t aSelectionNum,
                                    nsString& aData,
                                    int32_t* aStartOffset,
                                    int32_t* aEndOffset)
 {
   bool retVal = false;
-  unused << mDoc->SendSelectionBoundsAt(mID, aSelectionNum, &retVal, &aData,
+  Unused << mDoc->SendSelectionBoundsAt(mID, aSelectionNum, &retVal, &aData,
                                         aStartOffset, aEndOffset);
   return retVal;
 }
 
 bool
 ProxyAccessible::SetSelectionBoundsAt(int32_t aSelectionNum,
                                       int32_t aStartOffset,
                                       int32_t aEndOffset)
 {
   bool retVal = false;
-  unused << mDoc->SendSetSelectionBoundsAt(mID, aSelectionNum, aStartOffset,
+  Unused << mDoc->SendSetSelectionBoundsAt(mID, aSelectionNum, aStartOffset,
                                            aEndOffset, &retVal);
   return retVal;
 }
 
 bool
 ProxyAccessible::AddToSelection(int32_t aStartOffset,
                                 int32_t aEndOffset)
 {
   bool retVal = false;
-  unused << mDoc->SendAddToSelection(mID, aStartOffset, aEndOffset, &retVal);
+  Unused << mDoc->SendAddToSelection(mID, aStartOffset, aEndOffset, &retVal);
   return retVal;
 }
 
 bool
 ProxyAccessible::RemoveFromSelection(int32_t aSelectionNum)
 {
   bool retVal = false;
-  unused << mDoc->SendRemoveFromSelection(mID, aSelectionNum, &retVal);
+  Unused << mDoc->SendRemoveFromSelection(mID, aSelectionNum, &retVal);
   return retVal;
 }
 
 void
 ProxyAccessible::ScrollSubstringTo(int32_t aStartOffset, int32_t aEndOffset,
                                    uint32_t aScrollType)
 {
-  unused << mDoc->SendScrollSubstringTo(mID, aStartOffset, aEndOffset, aScrollType);
+  Unused << mDoc->SendScrollSubstringTo(mID, aStartOffset, aEndOffset, aScrollType);
 }
 
 void
 ProxyAccessible::ScrollSubstringToPoint(int32_t aStartOffset,
                                         int32_t aEndOffset,
                                         uint32_t aCoordinateType,
                                         int32_t aX, int32_t aY)
 {
-  unused << mDoc->SendScrollSubstringToPoint(mID, aStartOffset, aEndOffset,
+  Unused << mDoc->SendScrollSubstringToPoint(mID, aStartOffset, aEndOffset,
                                              aCoordinateType, aX, aY);
 }
 
 void
 ProxyAccessible::Text(nsString* aText)
 {
-  unused << mDoc->SendText(mID, aText);
+  Unused << mDoc->SendText(mID, aText);
 }
 
 void
 ProxyAccessible::ReplaceText(const nsString& aText)
 {
-  unused << mDoc->SendReplaceText(mID, aText);
+  Unused << mDoc->SendReplaceText(mID, aText);
 }
 
 bool
 ProxyAccessible::InsertText(const nsString& aText, int32_t aPosition)
 {
   bool valid;
-  unused << mDoc->SendInsertText(mID, aText, aPosition, &valid);
+  Unused << mDoc->SendInsertText(mID, aText, aPosition, &valid);
   return valid;
 }
 
 bool
 ProxyAccessible::CopyText(int32_t aStartPos, int32_t aEndPos)
 {
   bool valid;
-  unused << mDoc->SendCopyText(mID, aStartPos, aEndPos, &valid);
+  Unused << mDoc->SendCopyText(mID, aStartPos, aEndPos, &valid);
   return valid;
 }
 
 bool
 ProxyAccessible::CutText(int32_t aStartPos, int32_t aEndPos)
 {
   bool valid;
-  unused << mDoc->SendCutText(mID, aStartPos, aEndPos, &valid);
+  Unused << mDoc->SendCutText(mID, aStartPos, aEndPos, &valid);
   return valid;
 }
 
 bool
 ProxyAccessible::DeleteText(int32_t aStartPos, int32_t aEndPos)
 {
   bool valid;
-  unused << mDoc->SendDeleteText(mID, aStartPos, aEndPos, &valid);
+  Unused << mDoc->SendDeleteText(mID, aStartPos, aEndPos, &valid);
   return valid;
 }
 
 bool
 ProxyAccessible::PasteText(int32_t aPosition)
 {
   bool valid;
-  unused << mDoc->SendPasteText(mID, aPosition, &valid);
+  Unused << mDoc->SendPasteText(mID, aPosition, &valid);
   return valid;
 }
 
 nsIntPoint
 ProxyAccessible::ImagePosition(uint32_t aCoordType)
 {
   nsIntPoint retVal;
-  unused << mDoc->SendImagePosition(mID, aCoordType, &retVal);
+  Unused << mDoc->SendImagePosition(mID, aCoordType, &retVal);
   return retVal;
 }
 
 nsIntSize
 ProxyAccessible::ImageSize()
 {
   nsIntSize retVal;
-  unused << mDoc->SendImageSize(mID, &retVal);
+  Unused << mDoc->SendImageSize(mID, &retVal);
   return retVal;
 }
 
 uint32_t
 ProxyAccessible::StartOffset(bool* aOk)
 {
   uint32_t retVal = 0;
-  unused << mDoc->SendStartOffset(mID, &retVal, aOk);
+  Unused << mDoc->SendStartOffset(mID, &retVal, aOk);
   return retVal;
 }
 
 uint32_t
 ProxyAccessible::EndOffset(bool* aOk)
 {
   uint32_t retVal = 0;
-  unused << mDoc->SendEndOffset(mID, &retVal, aOk);
+  Unused << mDoc->SendEndOffset(mID, &retVal, aOk);
   return retVal;
 }
 
 bool
 ProxyAccessible::IsLinkValid()
 {
   bool retVal = false;
-  unused << mDoc->SendIsLinkValid(mID, &retVal);
+  Unused << mDoc->SendIsLinkValid(mID, &retVal);
   return retVal;
 }
 
 uint32_t
 ProxyAccessible::AnchorCount(bool* aOk)
 {
   uint32_t retVal = 0;
-  unused << mDoc->SendAnchorCount(mID, &retVal, aOk);
+  Unused << mDoc->SendAnchorCount(mID, &retVal, aOk);
   return retVal;
 }
 
 void
 ProxyAccessible::AnchorURIAt(uint32_t aIndex, nsCString& aURI, bool* aOk)
 {
-  unused << mDoc->SendAnchorURIAt(mID, aIndex, &aURI, aOk);
+  Unused << mDoc->SendAnchorURIAt(mID, aIndex, &aURI, aOk);
 }
 
 ProxyAccessible*
 ProxyAccessible::AnchorAt(uint32_t aIndex)
 {
   uint64_t id = 0;
   bool ok = false;
-  unused << mDoc->SendAnchorAt(mID, aIndex, &id, &ok);
+  Unused << mDoc->SendAnchorAt(mID, aIndex, &id, &ok);
   return ok ? mDoc->GetAccessible(id) : nullptr;
 }
 
 uint32_t
 ProxyAccessible::LinkCount()
 {
   uint32_t retVal = 0;
-  unused << mDoc->SendLinkCount(mID, &retVal);
+  Unused << mDoc->SendLinkCount(mID, &retVal);
   return retVal;
 }
 
 ProxyAccessible*
 ProxyAccessible::LinkAt(const uint32_t& aIndex)
 {
   uint64_t linkID = 0;
   bool ok = false;
-  unused << mDoc->SendLinkAt(mID, aIndex, &linkID, &ok);
+  Unused << mDoc->SendLinkAt(mID, aIndex, &linkID, &ok);
   return ok ? mDoc->GetAccessible(linkID) : nullptr;
 }
 
 int32_t
 ProxyAccessible::LinkIndexOf(ProxyAccessible* aLink)
 {
   int32_t retVal = -1;
   if (aLink) {
-    unused << mDoc->SendLinkIndexOf(mID, aLink->ID(), &retVal);
+    Unused << mDoc->SendLinkIndexOf(mID, aLink->ID(), &retVal);
   }
 
   return retVal;
 }
 
 int32_t
 ProxyAccessible::LinkIndexAtOffset(uint32_t aOffset)
 {
   int32_t retVal = -1;
-  unused << mDoc->SendLinkIndexAtOffset(mID, aOffset, &retVal);
+  Unused << mDoc->SendLinkIndexAtOffset(mID, aOffset, &retVal);
   return retVal;
 }
 
 ProxyAccessible*
 ProxyAccessible::TableOfACell()
 {
   uint64_t tableID = 0;
   bool ok = false;
-  unused << mDoc->SendTableOfACell(mID, &tableID, &ok);
+  Unused << mDoc->SendTableOfACell(mID, &tableID, &ok);
   return ok ? mDoc->GetAccessible(tableID) : nullptr;
 }
 
 uint32_t
 ProxyAccessible::ColIdx()
 {
   uint32_t index = 0;
-  unused << mDoc->SendColIdx(mID, &index);
+  Unused << mDoc->SendColIdx(mID, &index);
   return index;
 }
 
 uint32_t
 ProxyAccessible::RowIdx()
 {
   uint32_t index = 0;
-  unused << mDoc->SendRowIdx(mID, &index);
+  Unused << mDoc->SendRowIdx(mID, &index);
   return index;
 }
 
 uint32_t
 ProxyAccessible::ColExtent()
 {
   uint32_t extent = 0;
-  unused << mDoc->SendColExtent(mID, &extent);
+  Unused << mDoc->SendColExtent(mID, &extent);
   return extent;
 }
 
 uint32_t
 ProxyAccessible::RowExtent()
 {
   uint32_t extent = 0;
-  unused << mDoc->SendRowExtent(mID, &extent);
+  Unused << mDoc->SendRowExtent(mID, &extent);
   return extent;
 }
 
 void
 ProxyAccessible::ColHeaderCells(nsTArray<ProxyAccessible*>* aCells)
 {
   nsTArray<uint64_t> targetIDs;
-  unused << mDoc->SendColHeaderCells(mID, &targetIDs);
+  Unused << mDoc->SendColHeaderCells(mID, &targetIDs);
 
   size_t targetCount = targetIDs.Length();
   for (size_t i = 0; i < targetCount; i++) {
     aCells->AppendElement(mDoc->GetAccessible(targetIDs[i]));
   }
 }
 
 void
 ProxyAccessible::RowHeaderCells(nsTArray<ProxyAccessible*>* aCells)
 {
   nsTArray<uint64_t> targetIDs;
-  unused << mDoc->SendRowHeaderCells(mID, &targetIDs);
+  Unused << mDoc->SendRowHeaderCells(mID, &targetIDs);
 
   size_t targetCount = targetIDs.Length();
   for (size_t i = 0; i < targetCount; i++) {
     aCells->AppendElement(mDoc->GetAccessible(targetIDs[i]));
   }
 }
 
 bool
 ProxyAccessible::IsCellSelected()
 {
   bool selected = false;
-  unused << mDoc->SendIsCellSelected(mID, &selected);
+  Unused << mDoc->SendIsCellSelected(mID, &selected);
   return selected;
 }
 
 ProxyAccessible*
 ProxyAccessible::TableCaption()
 {
   uint64_t captionID = 0;
   bool ok = false;
-  unused << mDoc->SendTableCaption(mID, &captionID, &ok);
+  Unused << mDoc->SendTableCaption(mID, &captionID, &ok);
   return ok ? mDoc->GetAccessible(captionID) : nullptr;
 }
 
 void
 ProxyAccessible::TableSummary(nsString& aSummary)
 {
-  unused << mDoc->SendTableSummary(mID, &aSummary);
+  Unused << mDoc->SendTableSummary(mID, &aSummary);
 }
 
 uint32_t
 ProxyAccessible::TableColumnCount()
 {
   uint32_t count = 0;
-  unused << mDoc->SendTableColumnCount(mID, &count);
+  Unused << mDoc->SendTableColumnCount(mID, &count);
   return count;
 }
 
 uint32_t
 ProxyAccessible::TableRowCount()
 {
   uint32_t count = 0;
-  unused << mDoc->SendTableRowCount(mID, &count);
+  Unused << mDoc->SendTableRowCount(mID, &count);
   return count;
 }
 
 ProxyAccessible*
 ProxyAccessible::TableCellAt(uint32_t aRow, uint32_t aCol)
 {
   uint64_t cellID = 0;
   bool ok = false;
-  unused << mDoc->SendTableCellAt(mID, aRow, aCol, &cellID, &ok);
+  Unused << mDoc->SendTableCellAt(mID, aRow, aCol, &cellID, &ok);
   return ok ? mDoc->GetAccessible(cellID) : nullptr;
 }
 
 int32_t
 ProxyAccessible::TableCellIndexAt(uint32_t aRow, uint32_t aCol)
 {
   int32_t index = 0;
-  unused << mDoc->SendTableCellIndexAt(mID, aRow, aCol, &index);
+  Unused << mDoc->SendTableCellIndexAt(mID, aRow, aCol, &index);
   return index;
 }
 
 int32_t
 ProxyAccessible::TableColumnIndexAt(uint32_t aCellIndex)
 {
   int32_t index = 0;
-  unused << mDoc->SendTableColumnIndexAt(mID, aCellIndex, &index);
+  Unused << mDoc->SendTableColumnIndexAt(mID, aCellIndex, &index);
   return index;
 }
 
 int32_t
 ProxyAccessible::TableRowIndexAt(uint32_t aCellIndex)
 {
   int32_t index = 0;
-  unused << mDoc->SendTableRowIndexAt(mID, aCellIndex, &index);
+  Unused << mDoc->SendTableRowIndexAt(mID, aCellIndex, &index);
   return index;
 }
 
 void
 ProxyAccessible::TableRowAndColumnIndicesAt(uint32_t aCellIndex,
                                             int32_t* aRow, int32_t* aCol)
 {
-  unused << mDoc->SendTableRowAndColumnIndicesAt(mID, aCellIndex, aRow, aCol);
+  Unused << mDoc->SendTableRowAndColumnIndicesAt(mID, aCellIndex, aRow, aCol);
 }
 
 uint32_t
 ProxyAccessible::TableColumnExtentAt(uint32_t aRow, uint32_t aCol)
 {
   uint32_t extent = 0;
-  unused << mDoc->SendTableColumnExtentAt(mID, aRow, aCol, &extent);
+  Unused << mDoc->SendTableColumnExtentAt(mID, aRow, aCol, &extent);
   return extent;
 }
 
 uint32_t
 ProxyAccessible::TableRowExtentAt(uint32_t aRow, uint32_t aCol)
 {
   uint32_t extent = 0;
-  unused << mDoc->SendTableRowExtentAt(mID, aRow, aCol, &extent);
+  Unused << mDoc->SendTableRowExtentAt(mID, aRow, aCol, &extent);
   return extent;
 }
 
 void
 ProxyAccessible::TableColumnDescription(uint32_t aCol, nsString& aDescription)
 {
-  unused << mDoc->SendTableColumnDescription(mID, aCol, &aDescription);
+  Unused << mDoc->SendTableColumnDescription(mID, aCol, &aDescription);
 }
 
 void
 ProxyAccessible::TableRowDescription(uint32_t aRow, nsString& aDescription)
 {
-  unused << mDoc->SendTableRowDescription(mID, aRow, &aDescription);
+  Unused << mDoc->SendTableRowDescription(mID, aRow, &aDescription);
 }
 
 bool
 ProxyAccessible::TableColumnSelected(uint32_t aCol)
 {
   bool selected = false;
-  unused << mDoc->SendTableColumnSelected(mID, aCol, &selected);
+  Unused << mDoc->SendTableColumnSelected(mID, aCol, &selected);
   return selected;
 }
 
 bool
 ProxyAccessible::TableRowSelected(uint32_t aRow)
 {
   bool selected = false;
-  unused << mDoc->SendTableRowSelected(mID, aRow, &selected);
+  Unused << mDoc->SendTableRowSelected(mID, aRow, &selected);
   return selected;
 }
 
 bool
 ProxyAccessible::TableCellSelected(uint32_t aRow, uint32_t aCol)
 {
   bool selected = false;
-  unused << mDoc->SendTableCellSelected(mID, aRow, aCol, &selected);
+  Unused << mDoc->SendTableCellSelected(mID, aRow, aCol, &selected);
   return selected;
 }
 
 uint32_t
 ProxyAccessible::TableSelectedCellCount()
 {
   uint32_t count = 0;
-  unused << mDoc->SendTableSelectedCellCount(mID, &count);
+  Unused << mDoc->SendTableSelectedCellCount(mID, &count);
   return count;
 }
 
 uint32_t
 ProxyAccessible::TableSelectedColumnCount()
 {
   uint32_t count = 0;
-  unused << mDoc->SendTableSelectedColumnCount(mID, &count);
+  Unused << mDoc->SendTableSelectedColumnCount(mID, &count);
   return count;
 }
 
 uint32_t
 ProxyAccessible::TableSelectedRowCount()
 {
   uint32_t count = 0;
-  unused << mDoc->SendTableSelectedRowCount(mID, &count);
+  Unused << mDoc->SendTableSelectedRowCount(mID, &count);
   return count;
 }
 
 void
 ProxyAccessible::TableSelectedCells(nsTArray<ProxyAccessible*>* aCellIDs)
 {
-  nsAutoTArray<uint64_t, 30> cellIDs;
-  unused << mDoc->SendTableSelectedCells(mID, &cellIDs);
+  AutoTArray<uint64_t, 30> cellIDs;
+  Unused << mDoc->SendTableSelectedCells(mID, &cellIDs);
   aCellIDs->SetCapacity(cellIDs.Length());
   for (uint32_t i = 0; i < cellIDs.Length(); ++i) {
     aCellIDs->AppendElement(mDoc->GetAccessible(cellIDs[i]));
   }
 }
 
 void
 ProxyAccessible::TableSelectedCellIndices(nsTArray<uint32_t>* aCellIndices)
 {
-  unused << mDoc->SendTableSelectedCellIndices(mID, aCellIndices);
+  Unused << mDoc->SendTableSelectedCellIndices(mID, aCellIndices);
 }
 
 void
 ProxyAccessible::TableSelectedColumnIndices(nsTArray<uint32_t>* aColumnIndices)
 {
-  unused << mDoc->SendTableSelectedColumnIndices(mID, aColumnIndices);
+  Unused << mDoc->SendTableSelectedColumnIndices(mID, aColumnIndices);
 }
 
 void
 ProxyAccessible::TableSelectedRowIndices(nsTArray<uint32_t>* aRowIndices)
 {
-  unused << mDoc->SendTableSelectedRowIndices(mID, aRowIndices);
+  Unused << mDoc->SendTableSelectedRowIndices(mID, aRowIndices);
 }
 
 void
 ProxyAccessible::TableSelectColumn(uint32_t aCol)
 {
-  unused << mDoc->SendTableSelectColumn(mID, aCol);
+  Unused << mDoc->SendTableSelectColumn(mID, aCol);
 }
 
 void
 ProxyAccessible::TableSelectRow(uint32_t aRow)
 {
-  unused << mDoc->SendTableSelectRow(mID, aRow);
+  Unused << mDoc->SendTableSelectRow(mID, aRow);
 }
 
 void
 ProxyAccessible::TableUnselectColumn(uint32_t aCol)
 {
-  unused << mDoc->SendTableUnselectColumn(mID, aCol);
+  Unused << mDoc->SendTableUnselectColumn(mID, aCol);
 }
 
 void
 ProxyAccessible::TableUnselectRow(uint32_t aRow)
 {
-  unused << mDoc->SendTableUnselectRow(mID, aRow);
+  Unused << mDoc->SendTableUnselectRow(mID, aRow);
 }
 
 bool
 ProxyAccessible::TableIsProbablyForLayout()
 {
   bool forLayout = false;
-  unused << mDoc->SendTableIsProbablyForLayout(mID, &forLayout);
+  Unused << mDoc->SendTableIsProbablyForLayout(mID, &forLayout);
   return forLayout;
 }
 
 ProxyAccessible*
 ProxyAccessible::AtkTableColumnHeader(int32_t aCol)
 {
   uint64_t headerID = 0;
   bool ok = false;
-  unused << mDoc->SendAtkTableColumnHeader(mID, aCol, &headerID, &ok);
+  Unused << mDoc->SendAtkTableColumnHeader(mID, aCol, &headerID, &ok);
   return ok ? mDoc->GetAccessible(headerID) : nullptr;
 }
 
 ProxyAccessible*
 ProxyAccessible::AtkTableRowHeader(int32_t aRow)
 {
   uint64_t headerID = 0;
   bool ok = false;
-  unused << mDoc->SendAtkTableRowHeader(mID, aRow, &headerID, &ok);
+  Unused << mDoc->SendAtkTableRowHeader(mID, aRow, &headerID, &ok);
   return ok ? mDoc->GetAccessible(headerID) : nullptr;
 }
 
 void
 ProxyAccessible::SelectedItems(nsTArray<ProxyAccessible*>* aSelectedItems)
 {
-  nsAutoTArray<uint64_t, 10> itemIDs;
-  unused << mDoc->SendSelectedItems(mID, &itemIDs);
+  AutoTArray<uint64_t, 10> itemIDs;
+  Unused << mDoc->SendSelectedItems(mID, &itemIDs);
   aSelectedItems->SetCapacity(itemIDs.Length());
   for (size_t i = 0; i < itemIDs.Length(); ++i) {
     aSelectedItems->AppendElement(mDoc->GetAccessible(itemIDs[i]));
   }
 }
 
 uint32_t
 ProxyAccessible::SelectedItemCount()
 {
   uint32_t count = 0;
-  unused << mDoc->SendSelectedItemCount(mID, &count);
+  Unused << mDoc->SendSelectedItemCount(mID, &count);
   return count;
 }
 
 ProxyAccessible*
 ProxyAccessible::GetSelectedItem(uint32_t aIndex)
 {
   uint64_t selectedItemID = 0;
   bool ok = false;
-  unused << mDoc->SendGetSelectedItem(mID, aIndex, &selectedItemID, &ok);
+  Unused << mDoc->SendGetSelectedItem(mID, aIndex, &selectedItemID, &ok);
   return ok ? mDoc->GetAccessible(selectedItemID) : nullptr;
 }
 
 bool
 ProxyAccessible::IsItemSelected(uint32_t aIndex)
 {
   bool selected = false;
-  unused << mDoc->SendIsItemSelected(mID, aIndex, &selected);
+  Unused << mDoc->SendIsItemSelected(mID, aIndex, &selected);
   return selected;
 }
  
 bool
 ProxyAccessible::AddItemToSelection(uint32_t aIndex)
 {
   bool success = false;
-  unused << mDoc->SendAddItemToSelection(mID, aIndex, &success);
+  Unused << mDoc->SendAddItemToSelection(mID, aIndex, &success);
   return success;
 }
 
 bool
 ProxyAccessible::RemoveItemFromSelection(uint32_t aIndex)
 {
   bool success = false;
-  unused << mDoc->SendRemoveItemFromSelection(mID, aIndex, &success);
+  Unused << mDoc->SendRemoveItemFromSelection(mID, aIndex, &success);
   return success;
 }
 
 bool
 ProxyAccessible::SelectAll()
 {
   bool success = false;
-  unused << mDoc->SendSelectAll(mID, &success);
+  Unused << mDoc->SendSelectAll(mID, &success);
   return success;
 }
 
 bool
 ProxyAccessible::UnselectAll()
 {
   bool success = false;
-  unused << mDoc->SendUnselectAll(mID, &success);
+  Unused << mDoc->SendUnselectAll(mID, &success);
   return success;
 }
 
 void
 ProxyAccessible::TakeSelection()
 {
-  unused << mDoc->SendTakeSelection(mID);
+  Unused << mDoc->SendTakeSelection(mID);
 }
 
 void
 ProxyAccessible::SetSelected(bool aSelect)
 {
-  unused << mDoc->SendSetSelected(mID, aSelect);
+  Unused << mDoc->SendSetSelected(mID, aSelect);
 }
 
 bool
 ProxyAccessible::DoAction(uint8_t aIndex)
 {
   bool success = false;
-  unused << mDoc->SendDoAction(mID, aIndex, &success);
+  Unused << mDoc->SendDoAction(mID, aIndex, &success);
   return success;
 }
 
 uint8_t
 ProxyAccessible::ActionCount()
 {
   uint8_t count = 0;
-  unused << mDoc->SendActionCount(mID, &count);
+  Unused << mDoc->SendActionCount(mID, &count);
   return count;
 }
 
 void
 ProxyAccessible::ActionDescriptionAt(uint8_t aIndex, nsString& aDescription)
 {
-  unused << mDoc->SendActionDescriptionAt(mID, aIndex, &aDescription);
+  Unused << mDoc->SendActionDescriptionAt(mID, aIndex, &aDescription);
 }
 
 void
 ProxyAccessible::ActionNameAt(uint8_t aIndex, nsString& aName)
 {
-  unused << mDoc->SendActionNameAt(mID, aIndex, &aName);
+  Unused << mDoc->SendActionNameAt(mID, aIndex, &aName);
 }
 
 KeyBinding
 ProxyAccessible::AccessKey()
 {
   uint32_t key = 0;
   uint32_t modifierMask = 0;
-  unused << mDoc->SendAccessKey(mID, &key, &modifierMask);
+  Unused << mDoc->SendAccessKey(mID, &key, &modifierMask);
   return KeyBinding(key, modifierMask);
 }
 
 KeyBinding
 ProxyAccessible::KeyboardShortcut()
 {
   uint32_t key = 0;
   uint32_t modifierMask = 0;
-  unused << mDoc->SendKeyboardShortcut(mID, &key, &modifierMask);
+  Unused << mDoc->SendKeyboardShortcut(mID, &key, &modifierMask);
   return KeyBinding(key, modifierMask);
 }
 
 void
 ProxyAccessible::AtkKeyBinding(nsString& aBinding)
 {
-  unused << mDoc->SendAtkKeyBinding(mID, &aBinding);
+  Unused << mDoc->SendAtkKeyBinding(mID, &aBinding);
 }
 
 double
 ProxyAccessible::CurValue()
 {
   double val = UnspecifiedNaN<double>();
-  unused << mDoc->SendCurValue(mID, &val);
+  Unused << mDoc->SendCurValue(mID, &val);
   return val;
 }
 
 bool
 ProxyAccessible::SetCurValue(double aValue)
 {
   bool success = false;
-  unused << mDoc->SendSetCurValue(mID, aValue, &success);
+  Unused << mDoc->SendSetCurValue(mID, aValue, &success);
   return success;
 }
 
 double
 ProxyAccessible::MinValue()
 {
   double val = UnspecifiedNaN<double>();
-  unused << mDoc->SendMinValue(mID, &val);
+  Unused << mDoc->SendMinValue(mID, &val);
   return val;
 }
 
 double
 ProxyAccessible::MaxValue()
 {
   double val = UnspecifiedNaN<double>();
-  unused << mDoc->SendMaxValue(mID, &val);
+  Unused << mDoc->SendMaxValue(mID, &val);
   return val;
 }
 
 double
 ProxyAccessible::Step()
 {
   double step = UnspecifiedNaN<double>();
-  unused << mDoc->SendStep(mID, &step);
+  Unused << mDoc->SendStep(mID, &step);
   return step;
 }
 
 void
 ProxyAccessible::TakeFocus()
 {
-  unused << mDoc->SendTakeFocus(mID);
+  Unused << mDoc->SendTakeFocus(mID);
 }
 
 uint32_t
 ProxyAccessible::EmbeddedChildCount() const
 {
   uint32_t count;
-  unused << mDoc->SendEmbeddedChildCount(mID, &count);
+  Unused << mDoc->SendEmbeddedChildCount(mID, &count);
   return count;
 }
 
 int32_t
 ProxyAccessible::IndexOfEmbeddedChild(const ProxyAccessible* aChild)
 {
   uint64_t childID = aChild->mID;
   uint32_t childIdx;
-  unused << mDoc->SendIndexOfEmbeddedChild(mID, childID, &childIdx);
+  Unused << mDoc->SendIndexOfEmbeddedChild(mID, childID, &childIdx);
   return childIdx;
 }
 
 ProxyAccessible*
 ProxyAccessible::EmbeddedChildAt(size_t aChildIdx)
 {
   // For an outer doc the only child is a document, which is of course an
   // embedded child.  Further asking the child process for the id of the child
   // document won't work because the id of the child doc will be 0, which we
   // would interpret as being our parent document.
   if (mOuterDoc) {
     return ChildAt(aChildIdx);
   }
 
   uint64_t childID;
-  unused << mDoc->SendEmbeddedChildAt(mID, aChildIdx, &childID);
+  Unused << mDoc->SendEmbeddedChildAt(mID, aChildIdx, &childID);
   return mDoc->GetAccessible(childID);
 }
 
 ProxyAccessible*
 ProxyAccessible::FocusedChild()
 {
   uint64_t childID = 0;
   bool ok = false;
-  unused << mDoc->SendFocusedChild(mID, &childID, &ok);
+  Unused << mDoc->SendFocusedChild(mID, &childID, &ok);
   return ok ? mDoc->GetAccessible(childID) : nullptr;
 }
 
 ProxyAccessible*
 ProxyAccessible::ChildAtPoint(int32_t aX, int32_t aY,
                               Accessible::EWhichChildAtPoint aWhichChild)
 {
   uint64_t childID = 0;
   bool ok = false;
-  unused << mDoc->SendAccessibleAtPoint(mID, aX, aY, false,
+  Unused << mDoc->SendAccessibleAtPoint(mID, aX, aY, false,
                                         static_cast<uint32_t>(aWhichChild),
                                         &childID, &ok);
   return ok ? mDoc->GetAccessible(childID) : nullptr;
 }
 
 nsIntRect
 ProxyAccessible::Bounds()
 {
   nsIntRect rect;
-  unused << mDoc->SendExtents(mID, false,
+  Unused << mDoc->SendExtents(mID, false,
                               &(rect.x), &(rect.y),
                               &(rect.width), &(rect.height));
   return rect;
 }
 
 void
 ProxyAccessible::Language(nsString& aLocale)
 {
-  unused << mDoc->SendLanguage(mID, &aLocale);
+  Unused << mDoc->SendLanguage(mID, &aLocale);
 }
 
 void
 ProxyAccessible::DocType(nsString& aType)
 {
-  unused << mDoc->SendDocType(mID, &aType);
+  Unused << mDoc->SendDocType(mID, &aType);
 }
 
 void
 ProxyAccessible::Title(nsString& aTitle)
 {
-  unused << mDoc->SendTitle(mID, &aTitle);
+  Unused << mDoc->SendTitle(mID, &aTitle);
 }
 
 void
 ProxyAccessible::URL(nsString& aURL)
 {
-  unused << mDoc->SendURL(mID, &aURL);
+  Unused << mDoc->SendURL(mID, &aURL);
 }
 
 void
 ProxyAccessible::MimeType(nsString aMime)
 {
-  unused << mDoc->SendMimeType(mID, &aMime);
+  Unused << mDoc->SendMimeType(mID, &aMime);
 }
 
 void
 ProxyAccessible::URLDocTypeMimeType(nsString& aURL, nsString& aDocType,
                                     nsString& aMimeType)
 {
-  unused << mDoc->SendURLDocTypeMimeType(mID, &aURL, &aDocType, &aMimeType);
+  Unused << mDoc->SendURLDocTypeMimeType(mID, &aURL, &aDocType, &aMimeType);
 }
 
 ProxyAccessible*
 ProxyAccessible::AccessibleAtPoint(int32_t aX, int32_t aY,
                                    bool aNeedsScreenCoords)
 {
   uint64_t childID = 0;
   bool ok = false;
-  unused <<
+  Unused <<
     mDoc->SendAccessibleAtPoint(mID, aX, aY, aNeedsScreenCoords,
                                 static_cast<uint32_t>(Accessible::eDirectChild),
                                 &childID, &ok);
   return ok ? mDoc->GetAccessible(childID) : nullptr;
 }
 
 void
 ProxyAccessible::Extents(bool aNeedsScreenCoords, int32_t* aX, int32_t* aY,
                         int32_t* aWidth, int32_t* aHeight)
 {
-  unused << mDoc->SendExtents(mID, aNeedsScreenCoords, aX, aY, aWidth, aHeight);
+  Unused << mDoc->SendExtents(mID, aNeedsScreenCoords, aX, aY, aWidth, aHeight);
 }
 
 Accessible*
 ProxyAccessible::OuterDocOfRemoteBrowser() const
 {
   auto tab = static_cast<dom::TabParent*>(mDoc->Manager());
   dom::Element* frame = tab->GetOwnerElement();
   NS_ASSERTION(frame, "why isn't the tab in a frame!");
--- a/accessible/ipc/ProxyAccessible.h
+++ b/accessible/ipc/ProxyAccessible.h
@@ -41,16 +41,31 @@ public:
     MOZ_ASSERT(!mWrapper);
   }
 
   void AddChildAt(uint32_t aIdx, ProxyAccessible* aChild)
   { mChildren.InsertElementAt(aIdx, aChild); }
 
   uint32_t ChildrenCount() const { return mChildren.Length(); }
   ProxyAccessible* ChildAt(uint32_t aIdx) const { return mChildren[aIdx]; }
+  ProxyAccessible* FirstChild() const
+    { return mChildren.Length() ? mChildren[0] : nullptr; }
+  ProxyAccessible* LastChild() const
+    { return mChildren.Length() ? mChildren[mChildren.Length() - 1] : nullptr; }
+  ProxyAccessible* PrevSibling() const
+  {
+    size_t idx = IndexInParent();
+    return idx > 0 ? Parent()->mChildren[idx - 1] : nullptr;
+  }
+  ProxyAccessible* NextSibling() const
+  {
+    size_t idx = IndexInParent();
+    return idx < Parent()->mChildren.Length() ? Parent()->mChildren[idx + 1]
+    : nullptr;
+  }
 
   // XXX evaluate if this is fast enough.
   size_t IndexInParent() const { return Parent()->mChildren.IndexOf(this); }
   uint32_t EmbeddedChildCount() const;
   int32_t IndexOfEmbeddedChild(const ProxyAccessible*);
   ProxyAccessible* EmbeddedChildAt(size_t aChildIdx);
   bool MustPruneChildren() const;
 
@@ -124,16 +139,18 @@ public:
 
   bool IsSearchbox() const;
 
   nsIAtom* LandmarkRole() const;
 
   nsIAtom* ARIARoleAtom() const;
 
   int32_t GetLevelInternal();
+  void ScrollTo(uint32_t aScrollType);
+  void ScrollToPoint(uint32_t aScrollType, int32_t aX, int32_t aY);
 
   int32_t CaretLineNumber();
   int32_t CaretOffset();
   void SetCaretOffset(int32_t aOffset);
 
   int32_t CharacterCount();
   int32_t SelectionCount();
 
--- a/accessible/ipc/moz.build
+++ b/accessible/ipc/moz.build
@@ -19,16 +19,17 @@ if CONFIG['ACCESSIBILITY']:
         'DocAccessibleChild.cpp',
         'DocAccessibleParent.cpp',
         'ProxyAccessible.cpp'
     ]
 
     LOCAL_INCLUDES += [
         '../base',
         '../generic',
+        '../xpcom',
     ]
 
     if CONFIG['MOZ_ENABLE_GTK']:
         LOCAL_INCLUDES += [
             '/accessible/atk',
         ]
     elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
         LOCAL_INCLUDES += [
--- a/accessible/jsat/AccessFu.jsm
+++ b/accessible/jsat/AccessFu.jsm
@@ -41,17 +41,17 @@ this.AccessFu = { // jshint ignore:line
       if (aWindow.navigator.mozSettings) {
         let lock = aWindow.navigator.mozSettings.createLock();
         let req = lock.get(SCREENREADER_SETTING);
         req.addEventListener('success', () => {
           this._systemPref = req.result[SCREENREADER_SETTING];
           this._enableOrDisable();
         });
         aWindow.navigator.mozSettings.addObserver(
-          SCREENREADER_SETTING, this.handleEvent.bind(this));
+          SCREENREADER_SETTING, this.handleEvent);
       }
     }
 
     this._activatePref = new PrefCache(
       'accessibility.accessfu.activate', this._enableOrDisable.bind(this));
 
     this._enableOrDisable();
   },
@@ -63,38 +63,45 @@ this.AccessFu = { // jshint ignore:line
     // Avoid disabling twice.
     if (this._enabled) {
       this._disable();
     }
     if (Utils.MozBuildApp === 'mobile/android') {
       Services.obs.removeObserver(this, 'Accessibility:Settings');
     } else if (Utils.win.navigator.mozSettings) {
       Utils.win.navigator.mozSettings.removeObserver(
-        SCREENREADER_SETTING, this.handleEvent.bind(this));
+        SCREENREADER_SETTING, this.handleEvent);
     }
     delete this._activatePref;
     Utils.uninit();
   },
 
   /**
+   * A lazy getter for event handler that binds the scope to AccessFu object.
+   */
+  get handleEvent() {
+    delete this.handleEvent;
+    this.handleEvent = this._handleEvent.bind(this);
+    return this.handleEvent;
+  },
+
+  /**
    * Start AccessFu mode, this primarily means controlling the virtual cursor
    * with arrow keys.
    */
   _enable: function _enable() {
     if (this._enabled) {
       return;
     }
     this._enabled = true;
 
     Cu.import('resource://gre/modules/accessibility/Utils.jsm');
     Cu.import('resource://gre/modules/accessibility/PointerAdapter.jsm');
     Cu.import('resource://gre/modules/accessibility/Presentation.jsm');
 
-    Logger.info('Enabled');
-
     for (let mm of Utils.AllMessageManagers) {
       this._addMessageListeners(mm);
       this._loadFrameScript(mm);
     }
 
     // Add stylesheet
     let stylesheetURL = 'chrome://global/content/accessibility/AccessFu.css';
     let stylesheet = Utils.win.document.createProcessingInstruction(
@@ -141,39 +148,31 @@ this.AccessFu = { // jshint ignore:line
     Utils.win.addEventListener('TabClose', this);
     Utils.win.addEventListener('TabSelect', this);
 
     if (this.readyCallback) {
       this.readyCallback();
       delete this.readyCallback;
     }
 
-    if (Utils.MozBuildApp !== 'mobile/android') {
-      this.announce('screenReaderStarted');
-    }
+    Logger.info('AccessFu:Enabled');
   },
 
   /**
    * Disable AccessFu and return to default interaction mode.
    */
   _disable: function _disable() {
     if (!this._enabled) {
       return;
     }
 
     this._enabled = false;
 
-    Logger.info('Disabled');
-
     Utils.win.document.removeChild(this.stylesheet.get());
 
-    if (Utils.MozBuildApp !== 'mobile/android') {
-      this.announce('screenReaderStopped');
-    }
-
     for (let mm of Utils.AllMessageManagers) {
       mm.sendAsyncMessage('AccessFu:Stop');
       this._removeMessageListeners(mm);
     }
 
     this.Input.stop();
     Output.stop();
     PointerAdapter.stop();
@@ -195,16 +194,18 @@ this.AccessFu = { // jshint ignore:line
 
     delete this._quicknavModesPref;
     delete this._notifyOutputPref;
 
     if (this.doneCallback) {
       this.doneCallback();
       delete this.doneCallback;
     }
+
+    Logger.info('AccessFu:Disabled');
   },
 
   _enableOrDisable: function _enableOrDisable() {
     try {
       if (!this._activatePref) {
         return;
       }
       let activatePref = this._activatePref.value;
@@ -338,26 +339,26 @@ this.AccessFu = { // jshint ignore:line
       case 'Accessibility:MoveByGranularity':
         this.Input.moveByGranularity(JSON.parse(aData));
         break;
       case 'remote-browser-shown':
       case 'inprocess-browser-shown':
       {
         // Ignore notifications that aren't from a BrowserOrApp
         let frameLoader = aSubject.QueryInterface(Ci.nsIFrameLoader);
-        if (!frameLoader.ownerIsBrowserOrAppFrame) {
+        if (!frameLoader.ownerIsMozBrowserOrAppFrame) {
           return;
         }
         this._handleMessageManager(frameLoader.messageManager);
         break;
       }
     }
   },
 
-  handleEvent: function handleEvent(aEvent) {
+  _handleEvent: function _handleEvent(aEvent) {
     switch (aEvent.type) {
       case 'TabOpen':
       {
         let mm = Utils.getMessageManager(aEvent.target);
         this._handleMessageManager(mm);
         break;
       }
       case 'TabClose':
@@ -517,19 +518,20 @@ var Output = {
   },
 
   start: function start() {
     Cu.import('resource://gre/modules/Geometry.jsm');
   },
 
   stop: function stop() {
     if (this.highlightBox) {
-      let doc = Utils.win.document;
-      (doc.body || doc.documentElement).documentElement.removeChild(
-        this.highlightBox.get());
+      let highlightBox = this.highlightBox.get();
+      if (highlightBox) {
+        highlightBox.remove();
+      }
       delete this.highlightBox;
     }
   },
 
   B2G: function B2G(aDetails) {
     Utils.dispatchChromeEvent('accessibility-output', aDetails);
   },
 
--- a/accessible/jsat/EventManager.jsm
+++ b/accessible/jsat/EventManager.jsm
@@ -72,17 +72,17 @@ this.EventManager.prototype = {
   // late). It is only called when the AccessFu is disabled explicitly.
   stop: function stop() {
     if (!this._started) {
       return;
     }
     Logger.debug('EventManager.stop');
     AccessibilityEventObserver.removeListener(this);
     try {
-      this._preDialogPosition.clear();
+      this._preDialogPosition = new WeakMap();
       this.webProgress.removeProgressListener(this);
       this.removeEventListener('wheel', this, true);
       this.removeEventListener('scroll', this, true);
       this.removeEventListener('resize', this, true);
     } catch (x) {
       // contentScope is dead.
     } finally {
       this._started = false;
@@ -297,16 +297,17 @@ this.EventManager.prototype = {
           // positioned inside it.
           break;
         }
         this._preDialogPosition.set(aEvent.accessible.DOMNode, position);
         this.contentControl.autoMove(aEvent.accessible, { delay: 500 });
         break;
       }
       case Events.VALUE_CHANGE:
+      case Events.TEXT_VALUE_CHANGE:
       {
         let position = this.contentControl.vc.position;
         let target = aEvent.accessible;
         if (position === target ||
             Utils.getEmbeddedControl(position) === target) {
           this.present(Presentation.valueChanged(target));
         } else {
           let {liveRegion, isPolite} = this._handleLiveRegion(aEvent,
@@ -612,17 +613,17 @@ const AccessibilityEventObserver = {
    * Stop an AccessibilityEventObserver.
    */
   stop: function stop() {
     if (!this.started) {
       return;
     }
     Services.obs.removeObserver(this, 'accessible-event');
     // Clean up all registered event managers.
-    this.eventManagers.clear();
+    this.eventManagers = new WeakMap();
     this.listenerCount = 0;
     this.started = false;
   },
 
   /**
    * Register an EventManager and start listening to the
    * 'accessible-event' messages.
    *
--- a/accessible/jsat/Gestures.jsm
+++ b/accessible/jsat/Gestures.jsm
@@ -8,20 +8,18 @@
 /******************************************************************************
   All gestures have the following pathways when being resolved(v)/rejected(x):
                Tap -> DoubleTap        (x)
                    -> Dwell            (x)
                    -> Swipe            (x)
 
          DoubleTap -> TripleTap        (x)
                    -> TapHold          (x)
-                   -> Explore          (x)
 
          TripleTap -> DoubleTapHold    (x)
-                   -> Explore          (x)
 
              Dwell -> DwellEnd         (v)
 
              Swipe -> Explore          (x)
 
            TapHold -> TapHoldEnd       (v)
 
      DoubleTapHold -> DoubleTapHoldEnd (v)
@@ -34,17 +32,16 @@
 
         ExploreEnd -> Explore          (x)
 
            Explore -> ExploreEnd       (v)
 ******************************************************************************/
 
 'use strict';
 
-const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 this.EXPORTED_SYMBOLS = ['GestureSettings', 'GestureTracker']; // jshint ignore:line
 
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 
 XPCOMUtils.defineLazyModuleGetter(this, 'Utils', // jshint ignore:line
   'resource://gre/modules/accessibility/Utils.jsm');
@@ -68,22 +65,24 @@ const MAX_CONSECUTIVE_GESTURE_DELAY = 20
 const DWELL_THRESHOLD = 250;
 // Minimal swipe distance in inches
 const SWIPE_MIN_DISTANCE = 0.4;
 // Maximum distance the pointer could move during a tap in inches
 const TAP_MAX_RADIUS = 0.2;
 // Directness coefficient. It is based on the maximum 15 degree angle between
 // consequent pointer move lines.
 const DIRECTNESS_COEFF = 1.44;
-// The virtual touch ID generated by a mouse event.
-const MOUSE_ID = 'mouse';
 // Amount in inches from the edges of the screen for it to be an edge swipe
 const EDGE = 0.1;
 // Multiply timeouts by this constant, x2 works great too for slower users.
 const TIMEOUT_MULTIPLIER = 1;
+// A single pointer down/up sequence periodically precedes the tripple swipe
+// gesture on Android. This delay acounts for that.
+const IS_ANDROID = Utils.MozBuildApp === 'mobile/android' &&
+  Utils.AndroidSdkVersion >= 14;
 
 /**
  * A point object containing distance travelled data.
  * @param {Object} aPoint A point object that looks like: {
  *   x: x coordinate in pixels,
  *   y: y coordinate in pixels
  * }
  */
@@ -152,16 +151,24 @@ this.GestureSettings = { // jshint ignor
   /**
    * Maximum consecutive pointer event timeout.
    * @type {Number}
    */
   maxConsecutiveGestureDelay:
     MAX_CONSECUTIVE_GESTURE_DELAY * TIMEOUT_MULTIPLIER,
 
   /**
+   * A maximum time we wait for a next pointer down event to consider a sequence
+   * a multi-action gesture.
+   * @type {Number}
+   */
+  maxGestureResolveTimeout:
+    MAX_CONSECUTIVE_GESTURE_DELAY * TIMEOUT_MULTIPLIER,
+
+  /**
    * Delay before tap turns into dwell
    * @type {Number}
    */
   dwellThreshold: DWELL_THRESHOLD * TIMEOUT_MULTIPLIER,
 
   /**
    * Minimum distance that needs to be travelled for the pointer move to be
    * fired.
@@ -189,23 +196,22 @@ this.GestureTracker = { // jshint ignore
 
   /**
    * Create a new gesture object and attach resolution handler to it as well as
    * handle the incoming pointer event.
    * @param  {Object} aDetail A new pointer event detail.
    * @param  {Number} aTimeStamp A new pointer event timeStamp.
    * @param  {Function} aGesture A gesture constructor (default: Tap).
    */
-  _init: function GestureTracker__init(aDetail, aTimeStamp, aGesture = Tap) {
+  _init: function GestureTracker__init(aDetail, aTimeStamp, aGesture) {
     // Only create a new gesture on |pointerdown| event.
     if (aDetail.type !== 'pointerdown') {
       return;
     }
-    let points = aDetail.points;
-    let GestureConstructor = aGesture;
+    let GestureConstructor = aGesture || (IS_ANDROID ? DoubleTap : Tap);
     this._create(GestureConstructor);
     this._update(aDetail, aTimeStamp);
   },
 
   /**
    * Handle the incoming pointer event with the existing gesture object(if
    * present) or with the newly created one.
    * @param  {Object} aDetail A new pointer event detail.
@@ -253,16 +259,17 @@ this.GestureTracker = { // jshint ignore
     if (!current || current.id !== id) {
       return;
     }
     // Only create a gesture if we got a constructor.
     if (gestureType) {
       this._create(gestureType, current.startTime, current.points,
         current.lastEvent);
     } else {
+      this.current.clearTimer();
       delete this.current;
     }
   }
 };
 
 /**
  * Compile a mozAccessFuGesture detail structure.
  * @param  {String} aType A gesture type.
@@ -354,17 +361,17 @@ Gesture.prototype = {
    * started the gesture resolution sequence.
    */
   startTimer: function Gesture_startTimer(aTimeStamp) {
     Logger.gesture('startTimer', this.type);
     this.clearTimer();
     let delay = this._getDelay(aTimeStamp);
     let handler = () => {
       Logger.gesture('timer handler');
-      delete this._timer;
+      this.clearTimer();
       if (!this._inProgress) {
         this._deferred.reject();
       } else if (this._rejectToOnWait) {
         this._deferred.reject(this._rejectToOnWait);
       }
     };
     if (delay <= 0) {
       handler();
@@ -497,16 +504,17 @@ Gesture.prototype = {
    * }
    */
   _handleResolve: function Gesture__handleResolve() {
     if (this.isComplete) {
       return;
     }
     Logger.gesture('Resolving', this.id, 'gesture.');
     this.isComplete = true;
+    this.clearTimer();
     let detail = this.compile();
     if (detail) {
       this._emit(detail);
     }
     return {
       id: this.id,
       gestureType: this.resolveTo
     };
@@ -521,16 +529,17 @@ Gesture.prototype = {
    * }
    */
   _handleReject: function Gesture__handleReject(aRejectTo) {
     if (this.isComplete) {
       return;
     }
     Logger.gesture('Rejecting', this.id, 'gesture.');
     this.isComplete = true;
+    this.clearTimer();
     return {
       id: this.id,
       gestureType: aRejectTo
     };
   },
 
   /**
    * A default compilation function used to build the mozAccessFuGesture event
@@ -589,16 +598,19 @@ function TravelGesture(aTimeStamp, aPoin
 
 TravelGesture.prototype = Object.create(Gesture.prototype);
 
 /**
  * Test the gesture points for travel. The gesture will be rejected to
  * this._travelTo gesture iff at least one point crosses this._threshold.
  */
 TravelGesture.prototype.test = function TravelGesture_test() {
+  if (!this._travelTo) {
+    return;
+  }
   for (let identifier in this.points) {
     let point = this.points[identifier];
     if (point.totalDistanceTraveled / Utils.dpi > this._threshold) {
       this._deferred.reject(this._travelTo);
       return;
     }
   }
 };
@@ -661,20 +673,20 @@ DoubleTapHoldEnd.prototype.type = 'doubl
  * A common tap gesture object.
  * @param {Number} aTimeStamp An original pointer event's timeStamp that started
  * the gesture resolution sequence.
  * @param {Object} aPoints An existing set of points (from previous events).
  * @param {?String} aLastEvent Last pointer event type.
  * @param {Function} aRejectToOnWait A constructor for the next gesture to
  * reject to in case no pointermove or pointerup happens within the
  * GestureSettings.dwellThreshold.
+ * @param {Function} aTravelTo An optional constuctor for the next gesture to
+ * reject to in case the the TravelGesture test fails.
  * @param {Function} aRejectToOnPointerDown A constructor for the gesture to
  * reject to if a finger comes down immediately after the tap.
- * @param {Function} aTravelTo An optional constuctor for the next gesture to
- * reject to in case the the TravelGesture test fails.
  */
 function TapGesture(aTimeStamp, aPoints, aLastEvent, aRejectToOnWait, aTravelTo, aRejectToOnPointerDown) {
   this._rejectToOnWait = aRejectToOnWait;
   this._rejectToOnPointerDown = aRejectToOnPointerDown;
   // If the pointer travels, reject to aTravelTo.
   TravelGesture.call(this, aTimeStamp, aPoints, aLastEvent, aTravelTo,
     TAP_MAX_RADIUS);
 }
@@ -687,36 +699,38 @@ TapGesture.prototype._getDelay = functio
   return GestureSettings.dwellThreshold;
 };
 
 TapGesture.prototype.pointerup = function TapGesture_pointerup(aPoints) {
     if (this._rejectToOnPointerDown) {
       let complete = this._update(aPoints, 'pointerup', false, true);
       if (complete) {
         this.clearTimer();
-        if (GestureSettings.maxConsecutiveGestureDelay) {
+        if (GestureSettings.maxGestureResolveTimeout) {
           this._pointerUpTimer = setTimeout(() => {
+            clearTimeout(this._pointerUpTimer);
             delete this._pointerUpTimer;
             this._deferred.resolve();
-          }, GestureSettings.maxConsecutiveGestureDelay);
+          }, GestureSettings.maxGestureResolveTimeout);
         } else {
           this._deferred.resolve();
         }
       }
     } else {
       TravelGesture.prototype.pointerup.call(this, aPoints);
     }
 };
 
 TapGesture.prototype.pointerdown = function TapGesture_pointerdown(aPoints, aTimeStamp) {
-  TravelGesture.prototype.pointerdown.call(this, aPoints, aTimeStamp);
   if (this._pointerUpTimer) {
     clearTimeout(this._pointerUpTimer);
     delete this._pointerUpTimer;
     this._deferred.reject(this._rejectToOnPointerDown);
+  } else {
+    TravelGesture.prototype.pointerdown.call(this, aPoints, aTimeStamp);
   }
 };
 
 
 /**
  * Tap gesture.
  * @param {Number} aTimeStamp An original pointer event's timeStamp that started
  * the gesture resolution sequence.
@@ -751,17 +765,17 @@ DoubleTap.prototype.type = 'doubletap';
  * Triple Tap gesture.
  * @param {Number} aTimeStamp An original pointer event's timeStamp that started
  * the gesture resolution sequence.
  * @param {Object} aPoints An existing set of points (from previous events).
  * @param {?String} aLastEvent Last pointer event type.
  */
 function TripleTap(aTimeStamp, aPoints, aLastEvent) {
   this._inProgress = true;
-  TapGesture.call(this, aTimeStamp, aPoints, aLastEvent, DoubleTapHold);
+  TapGesture.call(this, aTimeStamp, aPoints, aLastEvent, DoubleTapHold, null, null);
 }
 
 TripleTap.prototype = Object.create(TapGesture.prototype);
 TripleTap.prototype.type = 'tripletap';
 
 /**
  * Common base object for gestures that are created as resolved.
  * @param {Number} aTimeStamp An original pointer event's timeStamp that started
--- a/accessible/jsat/Presentation.jsm
+++ b/accessible/jsat/Presentation.jsm
@@ -693,17 +693,19 @@ this.Presentation = { // jshint ignore:l
     this.displayedAccessibles = new WeakMap();
     return this.displayedAccessibles;
   },
 
   pivotChanged: function Presentation_pivotChanged(
     aPosition, aOldPosition, aReason, aStartOffset, aEndOffset, aIsUserInput) {
     let context = new PivotContext(
       aPosition, aOldPosition, aStartOffset, aEndOffset);
-    this.displayedAccessibles.set(context.accessible.document.window, context);
+    if (context.accessible) {
+      this.displayedAccessibles.set(context.accessible.document.window, context);
+    }
 
     return this.presenters.map(p => p.pivotChanged(context, aReason, aIsUserInput));
   },
 
   actionInvoked: function Presentation_actionInvoked(aObject, aActionName) {
     return this.presenters.map(p => p.actionInvoked(aObject, aActionName));
   },
 
--- a/accessible/mac/AccessibleWrap.mm
+++ b/accessible/mac/AccessibleWrap.mm
@@ -109,16 +109,17 @@ AccessibleWrap::HandleAccEvent(AccEvent*
   }
 
   uint32_t eventType = aEvent->GetEventType();
 
   // ignore everything but focus-changed, value-changed, caret, selection
   // and document load complete events for now.
   if (eventType != nsIAccessibleEvent::EVENT_FOCUS &&
       eventType != nsIAccessibleEvent::EVENT_VALUE_CHANGE &&
+      eventType != nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE &&
       eventType != nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED &&
       eventType != nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED &&
       eventType != nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE)
     return NS_OK;
 
   Accessible* accessible = aEvent->GetAccessible();
   NS_ENSURE_STATE(accessible);
 
@@ -243,16 +244,17 @@ a11y::FireNativeEvent(mozAccessible* aNa
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   switch (aEventType) {
     case nsIAccessibleEvent::EVENT_FOCUS:
       [aNativeAcc didReceiveFocus];
       break;
     case nsIAccessibleEvent::EVENT_VALUE_CHANGE:
+    case nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE:
       [aNativeAcc valueDidChange];
       break;
     case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED:
     case nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED:
       [aNativeAcc selectedTextDidChange];
       break;
     case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE:
       [aNativeAcc documentLoadComplete];
--- a/accessible/mac/DocAccessibleWrap.h
+++ b/accessible/mac/DocAccessibleWrap.h
@@ -9,18 +9,17 @@
 #include "DocAccessible.h"
 
 namespace mozilla {
 namespace a11y {
 
 class DocAccessibleWrap : public DocAccessible
 {
 public:
-  DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
-                    nsIPresShell* aPresShell);
+  DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
   virtual ~DocAccessibleWrap();
 
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/mac/DocAccessibleWrap.mm
+++ b/accessible/mac/DocAccessibleWrap.mm
@@ -5,18 +5,17 @@
 
 #include "DocAccessibleWrap.h"
 
 #import "mozAccessible.h"
 
 using namespace mozilla::a11y;
 
 DocAccessibleWrap::
-  DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
-                    nsIPresShell* aPresShell) :
-  DocAccessible(aDocument, aRootContent, aPresShell)
+  DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
+  DocAccessible(aDocument, aPresShell)
 {
 }
 
 DocAccessibleWrap::~DocAccessibleWrap()
 {
 }
 
--- a/accessible/mac/Platform.mm
+++ b/accessible/mac/Platform.mm
@@ -67,16 +67,17 @@ ProxyDestroyed(ProxyAccessible* aProxy)
 
 void
 ProxyEvent(ProxyAccessible* aProxy, uint32_t aEventType)
 {
   // ignore everything but focus-changed, value-changed, caret and selection
   // events for now.
   if (aEventType != nsIAccessibleEvent::EVENT_FOCUS &&
       aEventType != nsIAccessibleEvent::EVENT_VALUE_CHANGE &&
+      aEventType != nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE &&
       aEventType != nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED &&
       aEventType != nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED)
     return;
 
   mozAccessible* wrapper = GetNativeFromProxy(aProxy);
   if (wrapper)
     FireNativeEvent(wrapper, aEventType);
 }
--- a/accessible/mac/RootAccessibleWrap.h
+++ b/accessible/mac/RootAccessibleWrap.h
@@ -13,18 +13,17 @@
 #include "RootAccessible.h"
 
 namespace mozilla {
 namespace a11y {
 
 class RootAccessibleWrap : public RootAccessible
 {
 public:
-  RootAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
-                     nsIPresShell* aPresShell);
+  RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
   virtual ~RootAccessibleWrap();
 
     Class GetNativeType ();
 
     // let's our native accessible get in touch with the
     // native cocoa view that is our accessible parent.
     void GetNativeWidget (void **aOutView);
 };
--- a/accessible/mac/RootAccessibleWrap.mm
+++ b/accessible/mac/RootAccessibleWrap.mm
@@ -11,19 +11,18 @@
 #include "nsObjCExceptions.h"
 #include "nsIFrame.h"
 #include "nsView.h"
 #include "nsIWidget.h"
 
 using namespace mozilla::a11y;
 
 RootAccessibleWrap::
-  RootAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
-                     nsIPresShell* aPresShell) :
-  RootAccessible(aDocument, aRootContent, aPresShell)
+  RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
+  RootAccessible(aDocument, aPresShell)
 {
 }
 
 RootAccessibleWrap::~RootAccessibleWrap()
 {
 }
 
 Class
--- a/accessible/mac/mozAccessible.mm
+++ b/accessible/mac/mozAccessible.mm
@@ -95,17 +95,17 @@ a11y::GetProxyUnignoredChildren(const Pr
     return;
 
   uint32_t childCount = aProxy->ChildrenCount();
   for (size_t childIdx = 0; childIdx < childCount; childIdx++) {
     ProxyAccessible* childProxy = aProxy->ChildAt(childIdx);
 
     // If element is ignored, then add its children as substitutes.
     if (IsProxyIgnored(childProxy)) {
-      GetProxyUnignoredChildren(aProxy, aChildrenArray);
+      GetProxyUnignoredChildren(childProxy, aChildrenArray);
       continue;
     }
 
     aChildrenArray->AppendElement(childProxy);
   }
 }
 
 BOOL
@@ -415,17 +415,17 @@ ConvertToNSArray(nsTArray<ProxyAccessibl
       // Per the MathML 3 spec, the latter happens iff the linethickness
       // attribute is of the form [zero-float][optional-unit]. In that case we
       // set line thickness to zero and in the other cases we set it to one.
       nsAutoString thickness;
       if (accWrap) {
         nsCOMPtr<nsIPersistentProperties> attributes = accWrap->Attributes();
         nsAccUtils::GetAccAttr(attributes, nsGkAtoms::linethickness_, thickness);
       } else {
-        nsAutoTArray<Attribute, 10> attrs;
+        AutoTArray<Attribute, 10> attrs;
         proxy->Attributes(&attrs);
         for (size_t i = 0 ; i < attrs.Length() ; i++) {
           if (attrs.ElementAt(i).Name() == "thickness") {
             thickness = attrs.ElementAt(i).Value();
             break;
           }
         }
       }
@@ -547,17 +547,17 @@ ConvertToNSArray(nsTArray<ProxyAccessibl
     return nil;
 
   // Convert the given screen-global point in the cocoa coordinate system (with
   // origin in the bottom-left corner of the screen) into point in the Gecko
   // coordinate system (with origin in a top-left screen point).
   NSScreen* mainView = [[NSScreen screens] objectAtIndex:0];
   NSPoint tmpPoint = NSMakePoint(point.x,
                                  [mainView frame].size.height - point.y);
-  nsIntPoint geckoPoint = nsCocoaUtils::
+  LayoutDeviceIntPoint geckoPoint = nsCocoaUtils::
     CocoaPointsToDevPixels(tmpPoint, nsCocoaUtils::GetBackingScaleFactor(mainView));
 
   mozAccessible* nativeChild = nil;
   if (accWrap) {
     Accessible* child = accWrap->ChildAtPoint(geckoPoint.x, geckoPoint.y,
                                   Accessible::eDeepestChild);
     if (child)
       nativeChild = GetNativeFromGeckoAccessible(child);
@@ -679,21 +679,21 @@ ConvertToNSArray(nsTArray<ProxyAccessibl
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
 
   AccessibleWrap* accWrap = [self getGeckoAccessible];
   if (mChildren || (accWrap && !accWrap->AreChildrenCached()))
     return mChildren;
 
   // get the array of children.
   if (accWrap) {
-    nsAutoTArray<Accessible*, 10> childrenArray;
+    AutoTArray<Accessible*, 10> childrenArray;
     accWrap->GetUnignoredChildren(&childrenArray);
     mChildren = ConvertToNSArray(childrenArray);
   } else if (ProxyAccessible* proxy = [self getProxyAccessible]) {
-    nsAutoTArray<ProxyAccessible*, 10> childrenArray;
+    AutoTArray<ProxyAccessible*, 10> childrenArray;
     GetProxyUnignoredChildren(proxy, &childrenArray);
     mChildren = ConvertToNSArray(childrenArray);
   }
 
 #ifdef DEBUG_hakan
   // make sure we're not returning any ignored accessibles.
   NSEnumerator *e = [mChildren objectEnumerator];
   mozAccessible *m = nil;
--- a/accessible/mac/mozActionElements.mm
+++ b/accessible/mac/mozActionElements.mm
@@ -246,21 +246,23 @@ enum CheckboxValue {
 
 /**
  * Returns the selected tab (the mozAccessible)
  */
 - (id)value
 {
   mozAccessible* nativeAcc = nil;
   if (AccessibleWrap* accWrap = [self getGeckoAccessible]) {
-    Accessible* accTab = accWrap->GetSelectedItem(0);
-    accTab->GetNativeInterface((void**)&nativeAcc);
+    if (Accessible* accTab = accWrap->GetSelectedItem(0)) {
+      accTab->GetNativeInterface((void**)&nativeAcc);
+    }
   } else if (ProxyAccessible* proxy = [self getProxyAccessible]) {
-    ProxyAccessible* proxyTab = proxy->GetSelectedItem(0);
-    nativeAcc = GetNativeFromProxy(proxyTab);
+    if (ProxyAccessible* proxyTab = proxy->GetSelectedItem(0)) {
+      nativeAcc = GetNativeFromProxy(proxyTab);
+    }
   }
 
   return nativeAcc;
 }
 
 /**
  * Return the mozAccessibles that are the tabs.
  */
--- a/accessible/mac/mozTableAccessible.mm
+++ b/accessible/mac/mozTableAccessible.mm
@@ -202,22 +202,22 @@
     TableCellAccessible* cell = accWrap->AsTableCell();
     if ([attribute isEqualToString:NSAccessibilityRowIndexRangeAttribute])
       return [NSValue valueWithRange:NSMakeRange(cell->RowIdx(),
                                                  cell->RowExtent())];
     if ([attribute isEqualToString:NSAccessibilityColumnIndexRangeAttribute])
       return [NSValue valueWithRange:NSMakeRange(cell->ColIdx(),
                                                  cell->ColExtent())];
     if ([attribute isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) {
-      nsAutoTArray<Accessible*, 10> headerCells;
+      AutoTArray<Accessible*, 10> headerCells;
       cell->RowHeaderCells(&headerCells);
       return ConvertToNSArray(headerCells);
     }
     if ([attribute isEqualToString:NSAccessibilityColumnHeaderUIElementsAttribute]) {
-      nsAutoTArray<Accessible*, 10> headerCells;
+      AutoTArray<Accessible*, 10> headerCells;
       cell->ColHeaderCells(&headerCells);
       return ConvertToNSArray(headerCells);
     }
   } else if (ProxyAccessible* proxy = [self getProxyAccessible]) {
     if ([attribute isEqualToString:NSAccessibilityRowIndexRangeAttribute])
       return [NSValue valueWithRange:NSMakeRange(proxy->RowIdx(),
                                                  proxy->RowExtent())];
     if ([attribute isEqualToString:NSAccessibilityColumnIndexRangeAttribute])
--- a/accessible/mac/mozTextAccessible.mm
+++ b/accessible/mac/mozTextAccessible.mm
@@ -213,21 +213,23 @@ ToNSString(id aValue)
 #if DEBUG
       NSLog(@"%@:no range", attribute);
 #endif
       return nil;
     }
 
     int32_t start = range.location;
     int32_t end = start + range.length;
-    nsIntRect bounds;
+    DesktopIntRect bounds;
     if (textAcc) {
-      bounds = textAcc->TextBounds(start, end);
+      bounds =
+        DesktopIntRect::FromUnknownRect(textAcc->TextBounds(start, end));
     } else if (proxy) {
-      bounds = proxy->TextBounds(start, end);
+      bounds =
+        DesktopIntRect::FromUnknownRect(proxy->TextBounds(start, end));
     }
 
     return [NSValue valueWithRect:nsCocoaUtils::GeckoRectToCocoaRect(bounds)];
   }
 
 #if DEBUG
   NSLog(@"unhandled attribute:%@ forParameter:%@", attribute, parameter);
 #endif
--- a/accessible/tests/mochitest/actions/test_general.html
+++ b/accessible/tests/mochitest/actions/test_general.html
@@ -34,21 +34,29 @@
           ID: "li_clickable3",
           actionName: "click",
           events: CLICK_EVENTS
         },
         {
           ID: "onclick_img",
           actionName: "click",
           events: CLICK_EVENTS
+        },
+        {
+          ID: "label1",
+          actionName: "click",
+          events: CLICK_EVENTS
         }
+
       ];
 
       testActions(actionsArray);
 
+      is(getAccessible("label1").firstChild.actionCount, 1, "label text should have 1 action");
+
       getAccessible("onclick_img").takeFocus();
       is(getAccessible("link1").actionCount, 1, "links should have one action");
       is(getAccessible("link2").actionCount, 1, "link with onclick handler should have 1 action");
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
@@ -82,10 +90,18 @@
     <li id="li_clickable3" onmouseup="">Clickable list item</li>
   </ul>
 
   <!-- linkable accessibles -->
   <img id="onclick_img" onclick="" src="../moz.png">
 
   <a id="link1" href="www">linkable textleaf accessible</a>
   <div id="link2" onclick="">linkable textleaf accessible</div>
+
+  <div>
+    <label for="TextBox_t2" id="label1">
+      <span>Explicit</span>
+    </label>
+    <input name="in2" id="TextBox_t2" type="text" maxlength="17">
+  </div>
+
 </body>
 </html>
--- a/accessible/tests/mochitest/actions/test_general.xul
+++ b/accessible/tests/mochitest/actions/test_general.xul
@@ -56,27 +56,34 @@
           events: XUL_EVENTS
         },
         {
           ID: "buttonmenu",
           actionName: "press",
           events: CLICK_EVENTS
         },
         {
+          ID: "name_entry_label",
+          actionName: "click",
+          events: CLICK_EVENTS
+        },
+        {
           ID: "labelWithPopup",
           actionName: "click",
           events: CLICK_EVENTS
         }/*, // XXX: bug 490288
         {
           ID: "buttonmenu_item",
           actionName: "click",
           events: CLICK_EVENTS
         }*/
       ];
 
+      is(getAccessible("name_entry_label").firstChild.actionCount, 1, "label text should have 1 action");
+
       testActions(actionsArray);
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   ]]>
   </script>
 
@@ -120,12 +127,16 @@
           <menuitem label="item1" id="buttonmenu_item"/>
           <menuitem label="item1"/>
         </menupopup>
       </button>
 
       <label id="labelWithPopup" value="file name"
              popup="fileContext"
              tabindex="0"/>
+      <hbox>
+        <label id="name_entry_label" value="Name" control="name_entry"/>
+        <textbox id="name_entry"/>
+      </hbox>
     </vbox>
   </hbox>
 </window>
 
--- a/accessible/tests/mochitest/attributes/test_obj_group.html
+++ b/accessible/tests/mochitest/attributes/test_obj_group.html
@@ -186,16 +186,22 @@
       testGroupAttrs("combo1_opt3", 3, 4);
       testGroupAttrs("combo1_opt4", 4, 4);
 
       //////////////////////////////////////////////////////////////////////////
       // ARIA table
       testGroupAttrs("table_cell", 3, 4);
       testGroupAttrs("table_row", 2, 2);
 
+      //////////////////////////////////////////////////////////////////////////
+      // ARIA list constructed by ARIA owns
+      testGroupAttrs("t1_li1", 1, 3);
+      testGroupAttrs("t1_li2", 2, 3);
+      testGroupAttrs("t1_li3", 3, 3);
+
       // Test that group position information updates after deleting node.
       testGroupAttrs("tree4_ti1", 1, 2, 1);
       testGroupAttrs("tree4_ti2", 2, 2, 1);
       var tree4element = document.getElementById("tree4_ti1");
       var tree4acc = getAccessible("tree4");
       tree4element.parentNode.removeChild(tree4element);
       waitForEvent(EVENT_REORDER, tree4acc, function() {
         testGroupAttrs("tree4_ti2", 1, 1, 1);
@@ -448,10 +454,16 @@
     <input type="radio" id="radio5" name="group3">
   </form>
 
   <div role="table" aria-colcount="4" aria-rowcount="2">
     <div role="row" id="table_row" aria-rowindex="2">
       <div role="cell" id="table_cell" aria-colindex="3">cell</div>
     </div>
   </div>
+
+  <div role="list" aria-owns="t1_li1 t1_li2 t1_li3">
+    <div role="listitem" id="t1_li2">Apples</div>
+    <div role="listitem" id="t1_li1">Oranges</div>
+  </span>
+  <div role="listitem" id="t1_li3">Bananas</div>
 </body>
 </html>
--- a/accessible/tests/mochitest/common.js
+++ b/accessible/tests/mochitest/common.js
@@ -106,16 +106,51 @@ function disableLogging()
   gAccRetrieval.setLogging("");
 }
 function isLogged(aModule)
 {
   return gAccRetrieval.isLogged(aModule);
 }
 
 /**
+ * Dumps the accessible tree into console.
+ */
+function dumpTree(aId, aMsg)
+{
+  function dumpTreeIntl(acc, indent)
+  {
+    dump(indent + prettyName(acc) + "\n");
+
+    var children = acc.children;
+    for (var i = 0; i < children.length; i++) {
+      var child = children.queryElementAt(i, nsIAccessible);
+      dumpTreeIntl(child, indent + "  ");
+    }
+  }
+
+  function dumpDOMTreeIntl(node, indent)
+  {
+    dump(indent + prettyName(node) + "\n");
+
+    var children = node.childNodes;
+    for (var i = 0; i < children.length; i++) {
+      var child = children.item(i);
+      dumpDOMTreeIntl(child, indent + "  ");
+    }
+  }
+
+  dump(aMsg + "\n");
+  var root = getAccessible(aId);
+  dumpTreeIntl(root, "  ");
+
+  dump("DOM tree:\n");
+  dumpDOMTreeIntl(getNode(aId), "  ");
+}
+
+/**
  * Invokes the given function when document is loaded and focused. Preferable
  * to mochitests 'addLoadEvent' function -- additionally ensures state of the
  * document accessible is not busy.
  *
  * @param aFunc  the function to invoke
  */
 function addA11yLoadEvent(aFunc, aWindow)
 {
@@ -354,24 +389,17 @@ function testAccessibleTree(aAccOrElmOrI
 {
   var acc = getAccessible(aAccOrElmOrID);
   if (!acc)
     return;
 
   var accTree = aAccTree;
 
   // Support of simplified accessible tree object.
-  var key = Object.keys(accTree)[0];
-  var roleName = "ROLE_" + key;
-  if (roleName in nsIAccessibleRole) {
-    accTree = {
-      role: nsIAccessibleRole[roleName],
-      children: accTree[key]
-    };
-  }
+  accTree = normalizeAccTreeObj(accTree);
 
   // Test accessible properties.
   for (var prop in accTree) {
     var msg = "Wrong value of property '" + prop + "' for " +
                prettyName(acc) + ".";
 
     switch (prop) {
     case "actions": {
@@ -460,36 +488,29 @@ function testAccessibleTree(aAccOrElmOrI
           accChild = children.queryElementAt(i, nsIAccessible);
 
           if (!testChild) {
             ok(false, prettyName(acc) + " has an extra child at index " + i +
               " : " + prettyName(accChild));
             continue;
           }
 
-          var key = Object.keys(testChild)[0];
-          var roleName = "ROLE_" + key;
-          if (roleName in nsIAccessibleRole) {
-            testChild = {
-              role: nsIAccessibleRole[roleName],
-              children: testChild[key]
-            };
-          }
-
+          testChild = normalizeAccTreeObj(testChild);
           if (accChild.role !== testChild.role) {
             ok(false, prettyName(accTree) + " and " + prettyName(acc) +
               " have different children at index " + i + " : " +
               prettyName(testChild) + ", " + prettyName(accChild));
           }
           info("Matching " + prettyName(accTree) + " and " + prettyName(acc) +
                " child at index " + i + " : " + prettyName(accChild));
 
         } catch (e) {
           ok(false, prettyName(accTree) + " is expected to have a child at index " + i +
-             " : " + prettyName(testChild) + ", " + e);
+             " : " + prettyName(testChild) + ", original tested: " +
+             prettyName(aAccOrElmOrID) + ", " + e);
         }
       }
     } else {
       if (aFlags & kSkipTreeFullCheck) {
         for (var i = 0; i < childCount; i++) {
           var child = children.queryElementAt(i, nsIAccessible);
           testAccessibleTree(child, accTree.children[i], aFlags);
         }
@@ -750,16 +771,33 @@ function prettyName(aIdentifier)
 
     return msg;
   }
 
   if (aIdentifier instanceof nsIDOMNode)
     return "[ " + getNodePrettyName(aIdentifier) + " ]";
 
   if (aIdentifier && typeof aIdentifier === "object" ) {
+    var treeObj = normalizeAccTreeObj(aIdentifier);
+    if ("role" in treeObj) {
+      function stringifyTree(aObj) {
+        var text = roleToString(aObj.role) + ": [ ";
+        if ("children" in aObj) {
+          for (var i = 0; i < aObj.children.length; i++) {
+            var c = normalizeAccTreeObj(aObj.children[i]);
+            text += stringifyTree(c);
+            if (i < aObj.children.length - 1) {
+              text += ", ";
+            }
+          }
+        }
+        return text + "] ";
+      }
+      return `{ ${stringifyTree(treeObj)} }`;
+    }
     return JSON.stringify(aIdentifier);
   }
 
   return " '" + aIdentifier + "' ";
 }
 
 /**
  * Shorten a long string if it exceeds MAX_TRIM_LENGTH.
@@ -854,8 +892,21 @@ function getTestPluginTag(aPluginName)
     if (tag.name == name) {
       return tag;
     }
   }
 
   ok(false, "Could not find plugin tag with plugin name '" + name + "'");
   return null;
 }
+
+function normalizeAccTreeObj(aObj)
+{
+  var key = Object.keys(aObj)[0];
+  var roleName = "ROLE_" + key;
+  if (roleName in nsIAccessibleRole) {
+    return {
+      role: nsIAccessibleRole[roleName],
+      children: aObj[key]
+    };
+  }
+  return aObj;
+}
--- a/accessible/tests/mochitest/editabletext/editabletext.js
+++ b/accessible/tests/mochitest/editabletext/editabletext.js
@@ -57,16 +57,17 @@ function editableTextTest(aID)
    * setTextContents test.
    */
   this.setTextContents = function setTextContents(aValue, aSkipStartOffset)
   {
     var testID = "setTextContents '" + aValue + "' for " + prettyName(aID);
 
     function setTextContentsInvoke()
     {
+      dump(`\nsetTextContents '${aValue}'\n`);
       var acc = getAccessible(aID, nsIAccessibleEditableText);
       acc.setTextContents(aValue);
     }
 
     aSkipStartOffset = aSkipStartOffset || 0;
     var insertTripple = aValue ?
       [ aSkipStartOffset, aSkipStartOffset + aValue.length, aValue ] : null;
     var oldValue = getValue(aID);
@@ -82,16 +83,17 @@ function editableTextTest(aID)
    */
   this.insertText = function insertText(aStr, aPos, aResStr, aResPos)
   {
     var testID = "insertText '" + aStr + "' at " + aPos + " for " +
       prettyName(aID);
 
     function insertTextInvoke()
     {
+      dump(`\ninsertText '${aStr}' at ${aPos} pos\n`);
       var acc = getAccessible(aID, nsIAccessibleEditableText);
       acc.insertText(aStr, aPos);
     }
 
     var resPos = (aResPos != undefined) ? aResPos : aPos;
     this.generateTest(aID, null, [resPos, resPos + aStr.length, aStr],
                       insertTextInvoke, getValueChecker(aID, aResStr), testID);
   }
--- a/accessible/tests/mochitest/elm/test_HTMLSpec.html
+++ b/accessible/tests/mochitest/elm/test_HTMLSpec.html
@@ -369,17 +369,17 @@
           { role: ROLE_TEXT_LEAF } // HTML:del text
         ]
       };
       testElm("del_container", obj);
 
       //////////////////////////////////////////////////////////////////////////
       // HTML:details
 
-      todo(isAccessible("details"), "details element is not accessible");
+      ok(isAccessible("details"), "details element is not accessible");
 
       //////////////////////////////////////////////////////////////////////////
       // HTML:dfn contained by paragraph
 
       obj = {
         role: ROLE_PARAGRAPH,
         textAttrs: {
           0: { "font-style": "italic" },
--- a/accessible/tests/mochitest/elm/test_canvas.html
+++ b/accessible/tests/mochitest/elm/test_canvas.html
@@ -13,32 +13,36 @@
   <script type="application/javascript"
           src="../common.js"></script>
   <script type="application/javascript"
           src="../role.js"></script>
   <script type="application/javascript"
           src="../layout.js"></script>
 
   <script type="application/javascript">
+    var kX = 10, kY = 10, kWidth = 150, kHeight = 100;
     function doTest()
     {
       var canv = document.getElementById("c");
       var context = canv.getContext('2d');
       var element = document.getElementById("showA");
       context.beginPath();
-      context.rect(10, 10, 150, 100);
+      context.rect(kX, kY, kWidth, kHeight);
       context.addHitRegion({control: element});
-      var input = getAccessible("showA");
+
       var input = getAccessible("showA");
       var [cnvX, cnvY, cnvWidth, cnvHeight] = getBoundsForDOMElm(canv);
       var [accX, accY, accWidth, accHeight] = getBounds(input);
-      is(accX, cnvX + 10, "accX should be 10 and not " + accX);
-      is(accY, cnvY + 10, "accY should be 10 and not " + accY);
-      is(accWidth, 150, "accWidth should be 150 and not " + accWidth);
-      is(accHeight, 100, "accHeight should be 100 and not " + accHeight);
+
+      var [x, y, w, h] = CSSToDevicePixels(window, kX, kY, kWidth, kHeight);
+      is(accX, cnvX + x, "wrong accX");
+      is(accY, cnvY + y, "wrong accY");
+      is(accWidth, w, "wrong accWidth");
+      is(accHeight, h, "wrong accHeight");
+
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(function() {
       SpecialPowers.pushPrefEnv({"set": [['canvas.hitregions.enabled', true]]}, doTest);
     });
 
--- a/accessible/tests/mochitest/events.js
+++ b/accessible/tests/mochitest/events.js
@@ -23,16 +23,17 @@ const EVENT_SELECTION_WITHIN = nsIAccess
 const EVENT_SHOW = nsIAccessibleEvent.EVENT_SHOW;
 const EVENT_STATE_CHANGE = nsIAccessibleEvent.EVENT_STATE_CHANGE;
 const EVENT_TEXT_ATTRIBUTE_CHANGED = nsIAccessibleEvent.EVENT_TEXT_ATTRIBUTE_CHANGED;
 const EVENT_TEXT_CARET_MOVED = nsIAccessibleEvent.EVENT_TEXT_CARET_MOVED;
 const EVENT_TEXT_INSERTED = nsIAccessibleEvent.EVENT_TEXT_INSERTED;
 const EVENT_TEXT_REMOVED = nsIAccessibleEvent.EVENT_TEXT_REMOVED;
 const EVENT_TEXT_SELECTION_CHANGED = nsIAccessibleEvent.EVENT_TEXT_SELECTION_CHANGED;
 const EVENT_VALUE_CHANGE = nsIAccessibleEvent.EVENT_VALUE_CHANGE;
+const EVENT_TEXT_VALUE_CHANGE = nsIAccessibleEvent.EVENT_TEXT_VALUE_CHANGE;
 const EVENT_VIRTUALCURSOR_CHANGED = nsIAccessibleEvent.EVENT_VIRTUALCURSOR_CHANGED;
 
 const kNotFromUserInput = 0;
 const kFromUserInput = 1;
 
 ////////////////////////////////////////////////////////////////////////////////
 // General
 
@@ -339,20 +340,27 @@ function eventQueue(aEventType)
               // Report everythign is ok.
               for (var idx = 0; idx < eventSeq.length; idx++) {
                 var checker = eventSeq[idx];
 
                 var typeStr = eventQueue.getEventTypeAsString(checker);
                 var msg = "Test with ID = '" + this.getEventID(checker) +
                   "' succeed. ";
 
-                if (checker.unexpected)
-                  ok(true, msg + "There's no unexpected " + typeStr + " event.");
-                else
+                if (checker.unexpected) {
+                  if (checker.todo) {
+                    todo(false, "Event " + typeStr + " event is still missing");
+                  }
+                  else {
+                    ok(true, msg + "There's no unexpected " + typeStr + " event.");
+                  }
+                }
+                else {
                   ok(true, msg + "Event " + typeStr + " was handled.");
+                }
               }
             }
           }
         }
 
         // We don't have completely matched scenario. Report each failure/success
         // for every scenario.
         if (matchIdx == -1) {
@@ -365,18 +373,23 @@ function eventQueue(aEventType)
               var typeStr = eventQueue.getEventTypeAsString(checker);
               var msg = "Scenario #" + scnIdx + " of test with ID = '" +
                 this.getEventID(checker) + "' failed. ";
 
               if (checker.wasCaught > 1)
                 ok(false, msg + "Dupe " + typeStr + " event.");
 
               if (checker.unexpected) {
-                if (checker.wasCaught)
+                if (checker.todo) {
+                  todo(checker.wasCaught,
+                       "Event " + typeStr + " event is still missing");
+                }
+                else if (checker.wasCaught) {
                   ok(false, msg + "There's unexpected " + typeStr + " event.");
+                }
               } else if (!checker.wasCaught) {
                 ok(false, msg + typeStr + " event was missed.");
               }
             }
           }
         }
       }
     }
@@ -1662,16 +1675,28 @@ function invokerChecker(aEventType, aTar
     return prettyName(this.mTarget);
   }
 
   this.mTarget = aTargetOrFunc;
   this.mTargetFuncArg = aTargetFuncArg;
 }
 
 /**
+ * Generic invoker checker for todo events.
+ */
+function todo_invokerChecker(aEventType, aTargetOrFunc, aTargetFuncArg)
+{
+  this.__proto__ = new invokerChecker(aEventType, aTargetOrFunc,
+                                      aTargetFuncArg, true);
+
+  this.unexpected = true;
+  this.todo = true;
+}
+
+/**
  * Generic invoker checker for unexpected events.
  */
 function unexpectedInvokerChecker(aEventType, aTargetOrFunc, aTargetFuncArg)
 {
   this.__proto__ = new invokerChecker(aEventType, aTargetOrFunc,
                                       aTargetFuncArg, true);
 
   this.unexpected = true;
--- a/accessible/tests/mochitest/events/test_aria_menu.html
+++ b/accessible/tests/mochitest/events/test_aria_menu.html
@@ -46,19 +46,21 @@
         return "focus menu '" + aMenuID + "'";
       }
     }
 
     function showMenu(aMenuID, aParentMenuID, aHow)
     {
       this.menuNode = getNode(aMenuID);
 
+      // Because of aria-owns processing we may have menupopup start fired before
+      // related show event.
       this.eventSeq = [
         new invokerChecker(EVENT_SHOW, this.menuNode),
-        new invokerChecker(EVENT_MENUPOPUP_START, this.menuNode),
+        new asyncInvokerChecker(EVENT_MENUPOPUP_START, this.menuNode),
         new invokerChecker(EVENT_REORDER, getNode(aParentMenuID))
       ];
 
       this.invoke = function showMenu_invoke()
       {
         if (aHow == kViaDisplayStyle)
           this.menuNode.style.display = "block";
         else
--- a/accessible/tests/mochitest/events/test_focus_aria_activedescendant.html
+++ b/accessible/tests/mochitest/events/test_focus_aria_activedescendant.html
@@ -46,41 +46,42 @@ https://bugzilla.mozilla.org/show_bug.cg
         new focusChecker(aNewItemID)
       ];
 
       this.invoke = function insertItemNFocus_invoke()
       {
         var container  = getNode(aID);
         var itemNode = document.createElement("div");
         itemNode.setAttribute("id", aNewItemID);
-        itemNode.textContent = "item3";
+        itemNode.textContent = aNewItemID;
         container.appendChild(itemNode);
 
         container.setAttribute("aria-activedescendant", aNewItemID);
       }
 
       this.getID = function insertItemNFocus_getID()
       {
         return "insert new node and focus it with ID: " + aNewItemID;
       }
     }
 
     var gQueue = null;
     function doTest()
     {
       gQueue = new eventQueue();
 
-      gQueue.push(new synthFocus("container", new focusChecker("item1")));
-      gQueue.push(new changeARIAActiveDescendant("container", "item2"));
+      gQueue.push(new synthFocus("listbox", new focusChecker("item1")));
+      gQueue.push(new changeARIAActiveDescendant("listbox", "item2"));
+      gQueue.push(new changeARIAActiveDescendant("listbox", "item3"));
 
       gQueue.push(new synthFocus("combobox_entry", new focusChecker("combobox_entry")));
       gQueue.push(new changeARIAActiveDescendant("combobox", "combobox_option2"));
 
       todo(false, "No focus for inserted element, bug 687011");
-      //gQueue.push(new insertItemNFocus("container", "item3"));
+      //gQueue.push(new insertItemNFocus("listbox", "item4"));
 
       gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
@@ -96,20 +97,22 @@ https://bugzilla.mozilla.org/show_bug.cg
      title="Focus may be missed when ARIA active-descendant is changed on active composite widget">
     Mozilla Bug 761102
   </a>
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
-  <div role="listbox" aria-activedescendant="item1" id="container" tabindex="1">
+  <div role="listbox" aria-activedescendant="item1" id="listbox" tabindex="1"
+       aria-owns="item3">
     <div role="listitem" id="item1">item1</div>
     <div role="listitem" id="item2">item2</div>
   </div>
+  <div role="listitem" id="item3">item3</div>
 
   <div role="combobox" id="combobox">
     <input id="combobox_entry">
     <ul>
       <li role="option" id="combobox_option1">option1</li>
       <li role="option" id="combobox_option2">option2</li>
     </ul>
   </div>
--- a/accessible/tests/mochitest/events/test_mutation.html
+++ b/accessible/tests/mochitest/events/test_mutation.html
@@ -353,16 +353,35 @@
       }
 
       this.getID = function insertReferredElm_getID()
       {
         return "insert inaccessible element and then insert referring element to make it accessible";
       }
     }
 
+    function showHiddenParentOfVisibleChild()
+    {
+      this.eventSeq = [
+        new todo_invokerChecker(EVENT_HIDE, getNode("c4_child")),
+        new invokerChecker(EVENT_SHOW, getNode("c4_middle")),
+        new invokerChecker(EVENT_REORDER, getNode("c4"))
+      ];
+
+      this.invoke = function showHiddenParentOfVisibleChild_invoke()
+      {
+        getNode("c4_middle").style.visibility = 'visible';
+      }
+
+      this.getID = function showHiddenParentOfVisibleChild_getID()
+      {
+        return "show hidden parent of visible child";
+      }
+    }
+
     /**
      * Target getters.
      */
     function getFirstChild(aNode)
     {
       return [aNode.firstChild];
     }
     function getLastChild(aNode)
@@ -479,16 +498,17 @@
       gQueue.push(new changeClass("container3", "link8", "visibilityHidden",
                                   kHideEvents));
 
       gQueue.push(new test1("testContainer"));
       gQueue.push(new test2("testContainer", "testContainer2"));
       gQueue.push(new test2("testContainer", "testNestedContainer"));
       gQueue.push(new test3("testContainer"));
       gQueue.push(new insertReferredElm("testContainer3"));
+      gQueue.push(new showHiddenParentOfVisibleChild());
 
       gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTests);
   </script>
 </head>
@@ -539,10 +559,16 @@
     <a id="link6" href="http://www.google.com">Link #6</a>
 
     <div id="container2" class="displayNone"><a id="link7">Link #7</a></div>
     <div id="container3" class="visibilityHidden"><a id="link8">Link #8</a></div>
     <div id="testNestedContainer"></div>
   </div>
   <div id="testContainer2"></div>
   <div id="testContainer3"></div>
+
+  <div id="c4">
+    <div style="visibility:hidden" id="c4_middle">
+     <div style="visibility:visible" id="c4_child"></div>
+   </div>
+  </div>
 </body>
 </html>
--- a/accessible/tests/mochitest/events/test_text.html
+++ b/accessible/tests/mochitest/events/test_text.html
@@ -175,17 +175,18 @@
 
     /**
      * Remove text from HTML input.
      */
     function removeTextFromInput(aID, aStart, aEnd, aText)
     {
       this.__proto__ = new textRemoveInvoker(aID, aStart, aEnd, aText);
 
-      this.eventSeq.push(new invokerChecker(EVENT_VALUE_CHANGE, this.DOMNode));
+      this.eventSeq.push(new invokerChecker(EVENT_TEXT_VALUE_CHANGE,
+                                            this.DOMNode));
 
       this.invoke = function removeTextFromInput_invoke()
       {
         const nsIDOMNSEditableElement =
           Components.interfaces.nsIDOMNSEditableElement;
 
         this.DOMNode.focus();
         this.DOMNode.setSelectionRange(aStart, aEnd);
@@ -202,17 +203,18 @@
 
     /**
      * Add text into HTML input.
      */
     function insertTextIntoInput(aID, aStart, aEnd, aText)
     {
       this.__proto__ = new textInsertInvoker(aID, aStart, aEnd, aText);
 
-      this.eventSeq.push(new invokerChecker(EVENT_VALUE_CHANGE, this.DOMNode));
+      this.eventSeq.push(new invokerChecker(EVENT_TEXT_VALUE_CHANGE,
+                                            this.DOMNode));
 
       this.invoke = function insertTextIntoInput_invoke()
       {
         this.DOMNode.focus();
         synthesizeKey("a", {});
       }
 
       this.getID = function insertTextIntoInput_getID()
--- a/accessible/tests/mochitest/events/test_valuechange.html
+++ b/accessible/tests/mochitest/events/test_valuechange.html
@@ -15,27 +15,29 @@
           src="../common.js"></script>
   <script type="application/javascript"
           src="../events.js"></script>
 
   <script type="application/javascript"
           src="../value.js"></script>
 
   <script type="application/javascript">
-
-
     /**
      * Do tests.
      */
     var gQueue = null;
 
     // Value change invoker
     function changeARIAValue(aNodeOrID, aValuenow, aValuetext)
     {
       this.DOMNode = getNode(aNodeOrID);
+      this.eventSeq = [ new invokerChecker(aValuetext ?
+                                           EVENT_TEXT_VALUE_CHANGE :
+                                           EVENT_VALUE_CHANGE, this.DOMNode)
+        ];
 
       this.invoke = function changeARIAValue_invoke() {
 
         // Note: this should not fire an EVENT_VALUE_CHANGE when aria-valuetext
         // is not empty
         if (aValuenow != undefined)
           this.DOMNode.setAttribute("aria-valuenow", aValuenow);
  
@@ -58,16 +60,19 @@
       this.getID = function changeARIAValue_getID() {
         return prettyName(aNodeOrID) + " value changed";
       }
     }
 
     function changeValue(aID, aValue)
     {
       this.DOMNode = getNode(aID);
+      this.eventSeq = [new invokerChecker(EVENT_TEXT_VALUE_CHANGE,
+                                          this.DOMNode)
+        ];
 
       this.invoke = function changeValue_invoke()
       {
         this.DOMNode.value = aValue;
       }
 
       this.check = function changeValue_check()
       {
@@ -79,16 +84,17 @@
       {
         return prettyName(aID) + " value changed";
       }
     }
 
     function changeProgressValue(aID, aValue)
     {
       this.DOMNode = getNode(aID);
+      this.eventSeq = [new invokerChecker(EVENT_VALUE_CHANGE, this.DOMNode)];
 
       this.invoke = function changeProgressValue_invoke()
       {
          this.DOMNode.value = aValue;
       }
 
       this.check = function changeProgressValue_check()
       {
@@ -100,16 +106,17 @@
       {
         return prettyName(aID) + " value changed";
       }
     }
 
     function changeRangeValue(aID)
     {
       this.DOMNode = getNode(aID);
+      this.eventSeq = [new invokerChecker(EVENT_VALUE_CHANGE, this.DOMNode)];
 
       this.invoke = function changeRangeValue_invoke()
       {
         synthesizeMouse(getNode(aID), 5, 5, { });
       }
 
       this.finalCheck = function changeRangeValue_finalCheck()
       {
@@ -118,39 +125,66 @@
       }
 
       this.getID = function changeRangeValue_getID()
       {
         return prettyName(aID) + " range value changed";
       }
     }
 
+    function changeSelectValue(aID, aKey, aValue)
+    {
+      this.eventSeq =
+        [ new invokerChecker(EVENT_TEXT_VALUE_CHANGE, getAccessible(aID)) ];
+
+      this.invoke = function changeSelectValue_invoke()
+      {
+        getNode(aID).focus();
+        synthesizeKey(aKey, {}, window);
+      }
+
+      this.finalCheck = function changeSelectValue_finalCheck()
+      {
+        is(getAccessible(aID).value, aValue, "Wrong value for " + prettyName(aID));
+      }
+
+      this.getID = function changeSelectValue_getID()
+      {
+        return `${prettyName(aID)} closed select value change on '${aKey}'' key press`;
+      }
+    }
+
+    //enableLogging("DOMEvents");
+    //gA11yEventDumpToConsole = true;
     function doTests()
     {
       // Test initial values
       testValue("slider_vn", "5", 5, 0, 1000, 0);
       testValue("slider_vnvt", "plain", 0, 0, 5, 0);
       testValue("slider_vt", "hi", 0, 0, 3, 0);
       testValue("scrollbar", "5", 5, 0, 1000, 0);
       testValue("progress", "22%", 22, 0, 100, 0);
       testValue("range", "6", 6, 0, 10, 1);
 
       // Test value change events
-      gQueue = new eventQueue(nsIAccessibleEvent.EVENT_VALUE_CHANGE);
+      gQueue = new eventQueue();
 
       gQueue.push(new changeARIAValue("slider_vn", "6", undefined));
       gQueue.push(new changeARIAValue("slider_vt", undefined, "hey!"));
       gQueue.push(new changeARIAValue("slider_vnvt", "3", "sweet"));
       gQueue.push(new changeARIAValue("scrollbar", "6", undefined));
 
       gQueue.push(new changeValue("combobox", "hello"));
 
       gQueue.push(new changeProgressValue("progress", "50"));
       gQueue.push(new changeRangeValue("range"));
 
+      gQueue.push(new changeSelectValue("select", "VK_DOWN", "2nd"));
+      gQueue.push(new changeSelectValue("select", "3", "3rd"));
+
       gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTests);
   </script>
 </head>
 
@@ -207,10 +241,15 @@
   <input id="combobox" role="combobox" aria-autocomplete="inline">
 
   <!-- progress bar -->
   <progress id="progress" value="22" max="100"></progress>
 
   <!-- input@type="range" -->
   <input type="range" id="range" min="0" max="10" value="6">
 
+  <select id="select">
+    <option>1st</option>
+    <option>2nd</option>
+    <option>3rd</option>
+  </select>
 </body>
 </html>
--- a/accessible/tests/mochitest/hittest/test_canvas_hitregion.html
+++ b/accessible/tests/mochitest/hittest/test_canvas_hitregion.html
@@ -36,39 +36,41 @@
       if (document.activeElement == element)
         context.drawFocusIfNeeded(element);
       context.addHitRegion({control: element});
       context.restore();
     }
 
     function doTest()
     {
+      var offsetX = 20, offsetY = 40;
       getNode("hitcanvas").scrollIntoView(true);
 
       var context = document.getElementById("hitcanvas").getContext('2d');
-      redrawCheckbox(context, document.getElementById('hitcheck'), 20, 40);
+      redrawCheckbox(context, document.getElementById('hitcheck'),
+                     offsetX, offsetY);
 
       var hitcanvas = getAccessible("hitcanvas");
       var hitcheck = getAccessible("hitcheck");
 
       var [hitX, hitY, hitWidth, hitHeight] = getBounds(hitcanvas);
+      var [deltaX, deltaY] = CSSToDevicePixels(window, offsetX, offsetY);
 
       var docAcc = getAccessible(document);
-      var tgtX = hitX+25;
-      var tgtY = hitY+45;
-      hitAcc = docAcc.getDeepestChildAtPoint(tgtX, tgtY);
+
       // test if we hit the region associated with the shadow dom checkbox
-      is(hitAcc, hitcheck, "Hit match at " + tgtX + "," + tgtY +
-                          ". Found: " + prettyName(hitAcc));
+      var tgtX = hitX + deltaX;
+      var tgtY = hitY + deltaY;
+      hitAcc = docAcc.getDeepestChildAtPoint(tgtX, tgtY);
+      isObject(hitAcc, hitcheck, `Hit match at (${tgtX}, ${tgtY}`);
 
-      tgtY = hitY+75;
+      // test that we don't hit the region associated with the shadow dom checkbox
+      tgtY = hitY + deltaY * 2;
       hitAcc = docAcc.getDeepestChildAtPoint(tgtX, tgtY);
-      // test that we don't hit the region associated with the shadow dom checkbox
-      is(hitAcc, hitcanvas, "Hit match at " + tgtX + "," + tgtY +
-                          ". Found: " + prettyName(hitAcc));
+      isObject(hitAcc, hitcanvas, `Hit match at (${tgtX}, ${tgtY}`);
 
       SimpleTest.finish();
     }
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(function() {
       SpecialPowers.pushPrefEnv({"set": [['canvas.hitregions.enabled', true]]}, doTest);
     });
  </script>
--- a/accessible/tests/mochitest/hyperlink/test_general.html
+++ b/accessible/tests/mochitest/hyperlink/test_general.html
@@ -193,25 +193,16 @@ https://bugzilla.mozilla.org/show_bug.cg
       id = "linkWithTitleNameFromImg";
       linkAcc = getAccessible(id, [nsIAccessibleHyperLink]);
       testThis(id, linkAcc, ROLE_LINK, 1, "The title for link", true, 447,
                448);
       testStates(linkAcc, STATE_LINKED, 0);
       testAction(id, linkAcc, "jump");
 
       //////////////////////////////////////////////////////////////////////////
-      // Link with label, no name from the subtree (bug 438325).
-      id = "linkWithLabelNoNameFromSubtree";
-      linkAcc = getAccessible(id, [nsIAccessibleHyperLink]);
-      testThis(id, linkAcc, ROLE_LINK, 1, "Link with label and nested image:",
-               true, 450, 451);
-      testStates(linkAcc, STATE_LINKED, 0);
-      testAction(id, linkAcc, "jump");
-
-      //////////////////////////////////////////////////////////////////////////
       // Text accessible shouldn't implement nsIAccessibleHyperLink
       var res = isAccessible(getNode("namedAnchor").firstChild,
                              [nsIAccessibleHyperLink]);
       ok(!res, "Text accessible shouldn't implement nsIAccessibleHyperLink");
 
       //////////////////////////////////////////////////////////////////////////
       // Test focus
       gQueue = new eventQueue();
@@ -273,19 +264,16 @@ https://bugzilla.mozilla.org/show_bug.cg
       id="linkWithTitleNoNameFromSubtree" href="http://www.heise.de/"
       title="Link with title"><img src=""/></a
   ><br>Link with title attribute (name from subtree): <a 
       id="linkWithTitleNameFromSubtree" href="http://www.heise.de/"
       title="Link with title">the name from subtree</a
   ><br>Link with title attribute (name from nested image): <a 
       id="linkWithTitleNameFromImg" href="http://www.heise.de/"
       title="Link with title"><img src="" alt="The title for link"/></a
-  ><br><label for="linkWithLabelNoNameFromSubtree">Link with label and nested image: </label><a